diff --git a/.build_rtd_docs/conf.py b/.build_rtd_docs/conf.py index ff291a2bc19..d93113678be 100644 --- a/.build_rtd_docs/conf.py +++ b/.build_rtd_docs/conf.py @@ -6,13 +6,14 @@ # -- Path setup -------------------------------------------------------------- +import os +import shutil + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import sys -import os -import shutil from subprocess import Popen, PIPE sys.path.insert(0, os.path.abspath(os.path.join("..", "doc"))) @@ -118,15 +119,10 @@ "sphinx.ext.autosectionlabel", "nbsphinx", "nbsphinx_link", - "recommonmark", + "myst_parser", "sphinx_markdown_tables", ] -source_suffix = { - ".rst": "restructuredtext", - ".md": "markdown", -} - # # Tell sphinx what the pygments highlight language should be. # highlight_language = 'fortran' diff --git a/.build_rtd_docs/requirements.txt b/.build_rtd_docs/requirements.rtd.txt similarity index 80% rename from .build_rtd_docs/requirements.txt rename to .build_rtd_docs/requirements.rtd.txt index cb154aac3f3..04b86269661 100644 --- a/.build_rtd_docs/requirements.txt +++ b/.build_rtd_docs/requirements.rtd.txt @@ -1,10 +1,12 @@ +numpy +bmipy sphinx_markdown_tables nbsphinx nbsphinx_link ipython ipykernel rtds_action -recommonmark +myst_parser sphinx_rtd_theme diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..bbfd8d081ab --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,28 @@ +--- +name: Bug report +about: Create a report to help us improve MODFLOW 6 +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. macOS, Linux, Windows] + - Version [e.g. 22] diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..530a4a1e493 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for MODFLOW 6 +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/help.md b/.github/ISSUE_TEMPLATE/help.md new file mode 100644 index 00000000000..25eea26ede5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/help.md @@ -0,0 +1,10 @@ +--- +name: Help +about: Where to go for help with MODFLOW 6 +title: '' +labels: '' +assignees: '' + +--- + +If you need help using MODFLOW 6 do not open an issue on this GitHub repository. Instead submit your question to the [MODFLOW Google Group](https://groups.google.com/g/modflow) diff --git a/.github/common/checkout-regression-branch.sh b/.github/common/checkout-regression-branch.sh deleted file mode 100755 index 5a3a7c85047..00000000000 --- a/.github/common/checkout-regression-branch.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -cd ../modflow6-testmodels -if git show-ref -q --heads ${BRANCH}; then - git checkout ${BRANCH}; echo switched to modflow6-testmodels branch ${BRANCH}; -else echo using modflow6-testmodels branch master; fi -git branch -cd ../modflow6 -ls ../ diff --git a/.github/common/fortran-format-check.sh b/.github/common/fortran-format-check.sh new file mode 100755 index 00000000000..09992ba1184 --- /dev/null +++ b/.github/common/fortran-format-check.sh @@ -0,0 +1,47 @@ +#! /bin/bash + +SEARCHPATHS=(src srcbmi utils/zonebudget/src) +EXCLUDEDIRS=(src/Utilities/Libraries/blas # external library blas + src/Utilities/Libraries/daglib # external library dag + src/Utilities/Libraries/rcm # external library rcm + src/Utilities/Libraries/sparsekit # external library sparsekit + src/Utilities/Libraries/sparskit2) # external library sparsekit2 +EXCLUDEFILES=(src/Utilities/InputOutput.f90) # excluded until refactored + +fformatfails=() +checkcount=0 + +for path in "${SEARCHPATHS[@]}"; do + readarray -d '' files < <(find "${path}" -type f -print0 | grep -z '\.[fF]9[05]$') + for file in "${files[@]}"; do + exclude=0 + + for d in "${EXCLUDEDIRS[@]}"; do + [[ "${d}" == $(dirname "${file}") ]] && exclude=1 && break; done + if [[ ${exclude} == 1 ]]; then continue; fi + + for f in "${EXCLUDEFILES[@]}"; do + [[ "${f}" == "${file}" ]] && exclude=1 && break; done + if [[ ${exclude} == 1 ]]; then continue; fi + + ((checkcount++)) + + if [[ ! -z $(fprettify -d -c ./distribution/.fprettify.yaml "${file}" 2>&1) ]]; then + fformatfails+=("${file}") + fi + done +done + +echo -e "\nFortran source files checked: ${checkcount}" +echo -e "Fortran source files failed: ${#fformatfails[@]}\n" + +if [[ ${#fformatfails[@]} > 0 ]]; then + for f in "${fformatfails[@]}"; do echo "${f}"; done + + echo -e "\nTo verify file format diff and/or warn in local environment run:" + echo -e " 'fprettify -d -c /distribution/.fprettify.yaml '\n\n" + + exit 1 +fi + +exit 0 diff --git a/.github/common/get-examples-regression-files.sh b/.github/common/get-examples-regression-files.sh deleted file mode 100755 index 73686e26de1..00000000000 --- a/.github/common/get-examples-regression-files.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -echo $HOME -pwd -git clone https://github.com/MODFLOW-USGS/modflow6-examples ../modflow6-examples diff --git a/.github/common/get-largetests-regression-files.sh b/.github/common/get-largetests-regression-files.sh deleted file mode 100755 index 8f4647d717d..00000000000 --- a/.github/common/get-largetests-regression-files.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -echo $HOME -pwd -git clone https://github.com/MODFLOW-USGS/modflow6-largetestmodels ../modflow6-largetestmodels diff --git a/.github/common/get-regression-files.sh b/.github/common/get-regression-files.sh deleted file mode 100755 index 1a0af86b1c3..00000000000 --- a/.github/common/get-regression-files.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -echo $HOME -pwd -git clone https://github.com/MODFLOW-USGS/modflow6-testmodels ../modflow6-testmodels diff --git a/.github/common/git-branch-export.sh b/.github/common/git-branch-export.sh deleted file mode 100755 index 416c05328a5..00000000000 --- a/.github/common/git-branch-export.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -echo GITHUB_REF branch name ${GITHUB_REF##*/} -echo GITHUB_REF=${GITHUB_REF} -echo GITHUB_HEAD_REF=${GITHUB_HEAD_REF} -echo GITHUB_BASE_REF=${GITHUB_BASE_REF} -if [ -z ${GITHUB_BASE_REF+x} ]; then - export BRANCH=${GITHUB_REF##*/}; -else export BRANCH=${GITHUB_HEAD_REF}; fi -echo BRANCH=${BRANCH} diff --git a/.github/common/install-python-std.sh b/.github/common/install-python-std.sh deleted file mode 100755 index b0175a33dbe..00000000000 --- a/.github/common/install-python-std.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -pip install wheel -pip install requests appdirs numpy matplotlib pytest pytest-xdist meson ninja -pip install https://github.com/modflowpy/flopy/zipball/develop -pip install https://github.com/modflowpy/pymake/zipball/master -pip install https://github.com/Deltares/xmipy/zipball/develop -pip install https://github.com/MODFLOW-USGS/modflowapi/zipball/develop diff --git a/.github/common/python-version.py b/.github/common/python-version.py deleted file mode 100644 index 24797aa6e25..00000000000 --- a/.github/common/python-version.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -import pytest -import numpy as np -import matplotlib as mpl -import flopy -import pymake - -flopypth = flopy.__path__[0] -pymakepth = pymake.__path__[0] -print("python version: {}".format(sys.version)) -print("pytest version: {}".format(pytest.__version__)) -print("numpy version: {}".format(np.__version__)) -print("matplotlib version: {}".format(mpl.__version__)) -print("flopy version: {}".format(flopy.__version__)) -print("pymake version: {}".format(pymake.__version__)) -print("") -print("flopy is installed in: {}".format(flopypth)) -print("pymake is installed in: {}".format(pymakepth)) diff --git a/.github/common/python-version.sh b/.github/common/python-version.sh deleted file mode 100755 index 68a384ae5ca..00000000000 --- a/.github/common/python-version.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -cd .github/common -python python-version.py -cd ../../ diff --git a/.github/common/update-flopy.sh b/.github/common/update-flopy.sh deleted file mode 100755 index 226030c4952..00000000000 --- a/.github/common/update-flopy.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -cd autotest -python update_flopy.py -cd .. diff --git a/.github/intel-scripts/README.md b/.github/intel-scripts/README.md deleted file mode 100644 index e78bd4be4a5..00000000000 --- a/.github/intel-scripts/README.md +++ /dev/null @@ -1,17 +0,0 @@ -These scripts install the ifort compiler on the CI machines. - -The content has been directly copied from the Intel OneAPI-CI examples, found -here: - -https://github.com/oneapi-src/oneapi-ci - -Note that on Linux and macOS, shell scripts must be marked as executable: not -doing so for these scripts will result in a permission error during the GitHub -Action. Windows does not have such a permission system, but you can mark a -script nonetheless with git: - -``` -git update-index --chmod=+x {name_of_script} -``` - -Then commit and push. diff --git a/.github/intel-scripts/cache_exclude_linux.sh b/.github/intel-scripts/cache_exclude_linux.sh deleted file mode 100755 index 0e835d28b2e..00000000000 --- a/.github/intel-scripts/cache_exclude_linux.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - -#shellcheck disable=SC2010 -LATEST_VERSION=$(ls -1 /opt/intel/oneapi/compiler/ | grep -v latest | sort | tail -1) - -sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/compiler/lib/ia32_lin -sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/bin/ia32 -sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/lib/emu -sudo rm -rf /opt/intel/oneapi/compiler/"$LATEST_VERSION"/linux/lib/oclfpga \ No newline at end of file diff --git a/.github/intel-scripts/cache_exclude_windows.sh b/.github/intel-scripts/cache_exclude_windows.sh deleted file mode 100644 index f396a94abe6..00000000000 --- a/.github/intel-scripts/cache_exclude_windows.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - -#shellcheck disable=SC2010 -LATEST_VERSION=$(ls -1 "C:\Program Files (x86)\Intel\oneAPI\compiler" | grep -v latest | sort | tail -1) - -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\compiler\lib\ia32_win" -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\bin\intel64_ia32" -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\lib\emu" -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\lib\oclfpga" -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\lib\ocloc" -rm -rf "C:\Program Files (x86)\Intel\oneAPI\compiler\'$LATEST_VERSION'\windows\lib\x86" \ No newline at end of file diff --git a/.github/intel-scripts/ifortvars_windows.bat b/.github/intel-scripts/ifortvars_windows.bat deleted file mode 100644 index d3d116777cd..00000000000 --- a/.github/intel-scripts/ifortvars_windows.bat +++ /dev/null @@ -1,16 +0,0 @@ -REM SPDX-FileCopyrightText: 2020 Intel Corporation -REM -REM SPDX-License-Identifier: MIT - -set LANGUAGE=%1 -set VS_VER=%2 - -IF "%VS_VER%"=="2017_build_tools" ( -@call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat" -) - -IF "%VS_VER%"=="2019_build_tools" ( -@call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat" -) -for /f "tokens=* usebackq" %%f in (`dir /b "C:\Program Files (x86)\Intel\oneAPI\compiler\" ^| findstr /V latest ^| sort`) do @set "LATEST_VERSION=%%f" -@call "C:\Program Files (x86)\Intel\oneAPI\compiler\%LATEST_VERSION%\env\vars.bat" diff --git a/.github/intel-scripts/install_linux.sh b/.github/intel-scripts/install_linux.sh deleted file mode 100755 index 527944721d2..00000000000 --- a/.github/intel-scripts/install_linux.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - -URL=$1 -COMPONENTS=$2 - -curl --output webimage.sh --url "$URL" --retry 5 --retry-delay 5 -chmod +x webimage.sh -./webimage.sh -x -f webimage_extracted --log extract.log -rm -rf webimage.sh -WEBIMAGE_NAME=$(ls -1 webimage_extracted/) -if [ -z "$COMPONENTS" ]; then - sudo webimage_extracted/"$WEBIMAGE_NAME"/bootstrapper -s --action install --eula=accept --log-dir=. - installer_exit_code=$? -else - sudo webimage_extracted/"$WEBIMAGE_NAME"/bootstrapper -s --action install --components="$COMPONENTS" --eula=accept --log-dir=. - installer_exit_code=$? -fi -rm -rf webimage_extracted -exit $installer_exit_code \ No newline at end of file diff --git a/.github/intel-scripts/install_macos.sh b/.github/intel-scripts/install_macos.sh deleted file mode 100755 index 729080ef257..00000000000 --- a/.github/intel-scripts/install_macos.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - -URL=$1 -COMPONENTS=$2 - -curl --output webimage.dmg --url "$URL" --retry 5 --retry-delay 5 -hdiutil attach webimage.dmg -if [ -z "$COMPONENTS" ]; then - sudo /Volumes/"$(basename "$URL" .dmg)"/bootstrapper.app/Contents/MacOS/bootstrapper -s --action install --eula=accept --continue-with-optional-error=yes --log-dir=. - installer_exit_code=$? -else - sudo /Volumes/"$(basename "$URL" .dmg)"/bootstrapper.app/Contents/MacOS/bootstrapper -s --action install --components="$COMPONENTS" --eula=accept --log-dir=. - installer_exit_code=$? -fi -hdiutil detach /Volumes/"$(basename "$URL" .dmg)" -quiet -exit $installer_exit_code \ No newline at end of file diff --git a/.github/intel-scripts/install_windows.bat b/.github/intel-scripts/install_windows.bat deleted file mode 100644 index d3e0a1d84c3..00000000000 --- a/.github/intel-scripts/install_windows.bat +++ /dev/null @@ -1,15 +0,0 @@ -REM SPDX-FileCopyrightText: 2020 Intel Corporation -REM -REM SPDX-License-Identifier: MIT - -set URL=%1 -set COMPONENTS=%2 - -curl.exe --output webimage.exe --url %URL% --retry 5 --retry-delay 5 -start /b /wait webimage.exe -s -x -f webimage_extracted --log extract.log -del webimage.exe -if "%COMPONENTS%"=="" ( - webimage_extracted\bootstrapper.exe -s --action install --eula=accept -p=NEED_VS2017_INTEGRATION=0 -p=NEED_VS2019_INTEGRATION=0 --log-dir=. -) else ( - webimage_extracted\bootstrapper.exe -s --action install --components=%COMPONENTS% --eula=accept -p=NEED_VS2017_INTEGRATION=0 -p=NEED_VS2019_INTEGRATION=0 --log-dir=. -) \ No newline at end of file diff --git a/.github/workflows/ci-check-warnings-gfortran.yml b/.github/workflows/ci-check-warnings-gfortran.yml deleted file mode 100644 index 39323efc254..00000000000 --- a/.github/workflows/ci-check-warnings-gfortran.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: check warnings - gfortran - -on: - push: - branches: - - develop - pull_request: - branches: - - develop - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - defaults: - run: - shell: bash - - steps: - - name: Checkout repo - uses: actions/checkout@v2.3.4 - - - name: Setup Python 3.8 - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.8 - - - name: Setup symbolic links on Linux - if: runner.os == 'Linux' - run: | - sudo ln -fs /usr/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/bin/g++-10 /usr/local/bin/g++ - - - name: Setup symbolic link to gfortran on macOS - if: runner.os == 'macOS' - shell: bash - run: | - sudo ln -fs /usr/local/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/local/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/local/bin/g++-10 /usr/local/bin/g++ - - - name: Print GNU compiler versions - run: | - gfortran --version - gcc --version - g++ --version - - - name: Install python packages - run: | - .github/common/install-python-std.sh - - - name: Print python package versions - run: | - .github/common/python-version.sh - - - name: Setup modflow - run: | - meson setup builddir -Ddebug=false -Dwerror=true - - - name: Build modflow and check for warnings - run: | - meson compile -C builddir diff --git a/.github/workflows/ci-large-tests.yml b/.github/workflows/ci-large-tests.yml deleted file mode 100644 index 141984f956d..00000000000 --- a/.github/workflows/ci-large-tests.yml +++ /dev/null @@ -1,136 +0,0 @@ -# Parts of configuration file are based on the examples in this repository: -# https://github.com/oneapi-src/oneapi-ci -# -# Which have the following copyright: -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - - -## add this back in to on: if there is a need to debug the large tests -# -#pull_request: -# branches: -# - develop - - -name: Run and test modflow6-largetestmodels and modflow6-examples (z03) - -on: - schedule: - - cron: '0 6 * * *' # run at 6 AM UTC every day - -env: - WINDOWS_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18417/w_HPCKit_p_2022.1.0.93_offline.exe - LINUX_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18438/l_HPCKit_p_2022.1.1.97_offline.sh - MACOS_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18341/m_HPCKit_p_2022.1.0.86_offline.dmg - WINDOWS_FORTRAN_COMPONENTS: intel.oneapi.win.ifort-compiler - LINUX_FORTRAN_COMPONENTS_WEB: intel.oneapi.lin.ifort-compiler - MACOS_FORTRAN_COMPONENTS: intel.oneapi.mac.ifort-compiler - -jobs: - test: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - FC: [ ifort, gfortran ] - test_script: [ largetests, examples ] - defaults: - run: - shell: bash - - if: github.repository_owner == 'MODFLOW-USGS' - steps: - - name: Checkout repo - uses: actions/checkout@v2.3.4 - - - name: Setup Python 3.8 - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.8 - - - name: set FC=ifort environmental variable - if: matrix.FC == 'ifort' - run: | - echo "FC=ifort" >> $GITHUB_ENV - - - name: cache install ifort on linux - if: matrix.FC == 'ifort' - id: cache-install-linux - uses: actions/cache@v2 - with: - path: | - /opt/intel/oneapi - key: install-${{ env.LINUX_HPCKIT_URL }}-${{ env.LINUX_FORTRAN_COMPONENTS_WEB }}-compiler-${{ hashFiles('**/.github/intel-scripts/cache_exclude_linux.sh') }} - - - name: install ifort on linux - if: matrix.FC == 'ifort' && steps.cache-install-linux.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/install_linux.sh $LINUX_HPCKIT_URL $LINUX_FORTRAN_COMPONENTS_WEB - - - name: Setup symbolic links on Linux - if: matrix.FC == 'gfortran' - run: | - sudo ln -fs /usr/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/bin/g++-10 /usr/local/bin/g++ - - - name: Install python packages - run: | - .github/common/install-python-std.sh - - - name: Install additional python packages - run: | - pip install jupyter jupytext shapely scipy pandas pyshp - - - name: Print python package versions - run: | - .github/common/python-version.sh - - - name: Set and print branch name - run: | - .github/common/git-branch-export.sh - - - name: Get the appropriate large or example regression test files - run: | - .github/common/get-${{ matrix.test_script }}-regression-files.sh - - - name: Update flopy MODFLOW 6 classes - run: | - .github/common/update-flopy.sh - - - name: Run script to build example scripts - if: matrix.test_script == 'examples' - run: | - cd ../modflow6-examples/etc/ - python ci_build_files.py - ls -lh ../examples/ - cd ../../modflow6 - - - name: activate ifort and build applications - if: matrix.FC == 'ifort' - run: | - source /opt/intel/oneapi/setvars.sh - meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin - meson install -C builddir - cd autotest - pytest -v --durations=0 get_exes.py - - - name: Build gfortran applications - if: matrix.FC == 'gfortran' - run: | - meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin - meson install -C builddir - cd autotest - pytest -v --durations=0 get_exes.py - - - name: Test applications - working-directory: autotest - run: | - pytest -v -n=auto --durations=0 test_z03_${{ matrix.test_script }}.py - - - name: exclude unused files from cache on linux - if: matrix.FC == 'ifort' && steps.cache-install-linux.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/cache_exclude_linux.sh diff --git a/.github/workflows/ci-tests-gfortran-latest.yml b/.github/workflows/ci-tests-gfortran-latest.yml deleted file mode 100644 index fa45b3d4fe5..00000000000 --- a/.github/workflows/ci-tests-gfortran-latest.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: tests - gfortran - latest version - -on: - push: - branches: - - develop - pull_request: - branches: - - develop - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - defaults: - run: - shell: bash - - steps: - - name: Checkout repo - uses: actions/checkout@v2.3.4 - - - name: Setup Python 3.8 - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.8 - - - name: Setup symbolic links on Linux - if: runner.os == 'Linux' - run: | - sudo ln -fs /usr/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/bin/g++-10 /usr/local/bin/g++ - - - name: Setup symbolic link to gfortran on macOS - if: runner.os == 'macOS' - shell: bash - run: | - sudo ln -fs /usr/local/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/local/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/local/bin/g++-10 /usr/local/bin/g++ - - - name: Print GNU compiler versions - run: | - gfortran --version - gcc --version - g++ --version - - - name: Install python packages - run: | - .github/common/install-python-std.sh - - - name: Print python package versions - run: | - .github/common/python-version.sh - - - name: Set and print branch name - run: | - .github/common/git-branch-export.sh - - - name: Test make for MODFLOW 6 programs - working-directory: ./distribution - run: | - pytest -v -n=auto build_makefiles.py - - - name: Get regression test files - run: | - .github/common/get-regression-files.sh - - - name: Check out the correct regression test branch - run: | - .github/common/checkout-regression-branch.sh - - - name: Update flopy MODFLOW 6 classes - run: | - .github/common/update-flopy.sh - - - name: Setup modflow - run: | - meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin - - - name: Build and install modflow - run: | - meson install -C builddir - - - name: Get executables - working-directory: autotest - run: | - pytest -v --durations=0 get_exes.py - - - name: Test applications - working-directory: autotest - run: | - pytest -v -n=auto --durations=0 diff --git a/.github/workflows/ci-tests-gfortran-previous.yml b/.github/workflows/ci-tests-gfortran-previous.yml deleted file mode 100644 index 408cf942b22..00000000000 --- a/.github/workflows/ci-tests-gfortran-previous.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: tests - gfortran - previous versions - -on: - push: - branches: - - develop - pull_request: - branches: - - develop - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-18.04] - GCC_V: [5, 6, 7, 8] - defaults: - run: - shell: bash - - steps: - - name: Checkout repo - uses: actions/checkout@v2.3.4 - - - name: Setup Python 3.8 - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.8 - - - name: Set up gfortran ${{ matrix.GCC_V }} - run: | - sudo apt-get install -y --no-install-recommends gcc-${{ matrix.GCC_V }} g++-${{ matrix.GCC_V }} gfortran-${{ matrix.GCC_V }} - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ matrix.GCC_V }} 100 \ - --slave /usr/bin/g++ g++ /usr/bin/g++-${{ matrix.GCC_V }} \ - --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${{ matrix.GCC_V }} \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-${{ matrix.GCC_V }} - - - name: Print GNU compiler versions - run: | - gcc --version - gfortran --version - g++ --version - gcov --version - - - name: Install python packages - run: | - .github/common/install-python-std.sh - - - name: Print python package versions - run: | - .github/common/python-version.sh - - - name: Set and print branch name - run: | - .github/common/git-branch-export.sh - - - name: Get regression test files - run: | - .github/common/get-regression-files.sh - - - name: Check out the correct regression test branch - run: | - .github/common/checkout-regression-branch.sh - - - name: Update flopy MODFLOW 6 classes - run: | - .github/common/update-flopy.sh - - - name: Setup modflow - run: | - meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin - - - name: Build and install modflow - run: | - meson install -C builddir - - - name: Get executables - working-directory: autotest - run: | - pytest -v --durations=0 get_exes.py - - - name: Test applications - working-directory: autotest - run: | - pytest -v -n=auto --durations=0 diff --git a/.github/workflows/ci-tests-ifort.yml b/.github/workflows/ci-tests-ifort.yml deleted file mode 100644 index 954b6ec8860..00000000000 --- a/.github/workflows/ci-tests-ifort.yml +++ /dev/null @@ -1,155 +0,0 @@ -# Parts of configuration file are based on the examples in this repository: -# https://github.com/oneapi-src/oneapi-ci -# -# Which have the following copyright: -# SPDX-FileCopyrightText: 2020 Intel Corporation -# -# SPDX-License-Identifier: MIT - -name: tests - ifort - -on: - push: - branches: - - develop - pull_request: - branches: - - develop - -env: - WINDOWS_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18417/w_HPCKit_p_2022.1.0.93_offline.exe - LINUX_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18438/l_HPCKit_p_2022.1.1.97_offline.sh - MACOS_HPCKIT_URL: https://registrationcenter-download.intel.com/akdlm/irc_nas/18341/m_HPCKit_p_2022.1.0.86_offline.dmg - WINDOWS_FORTRAN_COMPONENTS: intel.oneapi.win.ifort-compiler - LINUX_FORTRAN_COMPONENTS_WEB: intel.oneapi.lin.ifort-compiler - MACOS_FORTRAN_COMPONENTS: intel.oneapi.mac.ifort-compiler - FC: ifort - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - - os: macos-latest - - os: windows-2019 - defaults: - run: - shell: bash - - steps: - - name: Checkout repo - uses: actions/checkout@v2.3.4 - - - name: Setup Python 3.8 - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.8 - - - name: cache install ifort on linux - if: runner.os == 'Linux' - id: cache-install-linux - uses: actions/cache@v2 - with: - path: | - /opt/intel/oneapi - key: install-${{ env.LINUX_HPCKIT_URL }}-${{ env.LINUX_FORTRAN_COMPONENTS_WEB }}-compiler-${{ hashFiles('**/.github/intel-scripts/cache_exclude_linux.sh') }} - - - name: install ifort on linux - if: runner.os == 'Linux' && steps.cache-install-linux.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/install_linux.sh $LINUX_HPCKIT_URL $LINUX_FORTRAN_COMPONENTS_WEB - - - name: cache install ifort on macos - if: runner.os == 'macOS' - id: cache-install-macos - uses: actions/cache@v2 - with: - path: /opt/intel/oneapi - key: install-${{ env.MACOS_HPCKIT_URL }}-${{ env.MACOS_FORTRAN_COMPONENTS }} - - - name: install ifort on macos - if: runner.os == 'macOS' && steps.cache-install-macos.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/install_macos.sh $MACOS_HPCKIT_URL $MACOS_FORTRAN_COMPONENTS - - - name: cache install ifort on windows - if: runner.os == 'Windows' - id: cache-install-windows - uses: actions/cache@v2 - with: - path: C:\Program Files (x86)\Intel\oneAPI - key: install-${{ env.WINDOWS_HPCKIT_URL }}-${{ env.WINDOWS_FORTRAN_COMPONENTS }}-compiler-${{ hashFiles('**/.github/intel-scripts/cache_exclude_windows.sh') }} - - - name: install ifort on windows - if: runner.os == 'Windows' && steps.cache-install-windows.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/install_windows.bat $WINDOWS_HPCKIT_URL $WINDOWS_FORTRAN_COMPONENTS - - - name: Install python packages - run: | - .github/common/install-python-std.sh - - - name: Print python package versions - run: | - .github/common/python-version.sh - - - name: Test make for MODFLOW 6 programs - if: runner.os == 'Linux' || runner.os == 'macOS' - working-directory: ./distribution - run: | - source /opt/intel/oneapi/setvars.sh - pytest -v -n=auto build_makefiles.py - - - name: Set and print branch name - run: | - .github/common/git-branch-export.sh - - - name: Get regression test files - run: | - .github/common/get-regression-files.sh - - - name: Check out the correct regression test branch - run: | - .github/common/checkout-regression-branch.sh - - - name: Update flopy MODFLOW 6 classes - run: | - .github/common/update-flopy.sh - - - name: Build MODFLOW 6 (Linux or macOS) - if: runner.os == 'Linux' || runner.os == 'macOS' - run: | - source /opt/intel/oneapi/setvars.sh - meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin - meson install -C builddir - cd autotest - pytest -v --durations=0 get_exes.py - - - name: Build MODFLOW 6 (Windows) - if: runner.os == 'Windows' - shell: cmd - run: | - call ".github/intel-scripts/ifortvars_windows.bat" - meson setup builddir -Ddebug=false --prefix=%CD% --libdir=bin - meson install -C builddir - cd autotest - pytest -v --durations=0 get_exes.py - - - name: Test applications - working-directory: autotest - run: | - pytest -v -n=auto --durations=0 - - - name: exclude unused files from cache on linux - if: runner.os == 'Linux' && steps.cache-install-linux.outputs.cache-hit != 'true' - run: | - .github/intel-scripts/cache_exclude_linux.sh - - - name: exclude unused files from cache on windows - if: runner.os == 'Windows' && steps.cache-install-windows.outputs.cache-hit != 'true' - shell: bash - run: | - .github/intel-scripts/cache_exclude_windows.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..27caa9bde0e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,439 @@ +name: MODFLOW 6 continuous integration +on: + push: + branches: + - master + - develop + - ci-diagnose* + pull_request: + branches: + - master + - develop +jobs: + lint: + name: Lint (fprettify) + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + cache-downloads: true + cache-env: true + + - name: Check Fortran source formatting + run: | + .github/common/fortran-format-check.sh + + build: + name: Build (gfortran 12) + runs-on: ubuntu-22.04 + defaults: + run: + shell: bash -l {0} + env: + FC: gfortran + GCC_V: 12 + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + + - name: Setup gfortran ${{ env.GCC_V }} + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ env.GCC_V }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + cache-downloads: true + cache-env: true + + - name: Meson setup/compile + run: | + meson setup builddir -Ddebug=false -Dwerror=true + meson compile -C builddir + + - name: Meson test + run: | + meson test --verbose --no-rebuild -C builddir + + test_gfortran_latest: + name: Test (gfortran 12) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-22.04, macos-12, windows-2022 ] + defaults: + run: + shell: bash -l {0} + env: + FC: gfortran + GCC_V: 12 + steps: + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-testmodels + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-testmodels + path: modflow6-testmodels + + - name: Setup gfortran ${{ env.GCC_V }} + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ env.GCC_V }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Build modflow6 + working-directory: modflow6 + run: | + meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin + meson install -C builddir + meson test --verbose --no-rebuild -C builddir + + - name: Update flopy + working-directory: modflow6/autotest + run: | + python update_flopy.py + + - name: Get executables + working-directory: modflow6/autotest + run: | + pytest -v --durations 0 get_exes.py + + - name: Run tests + working-directory: modflow6/autotest + run: | + pytest -v -n auto --durations 0 + + test_gfortran_previous: + name: Test gfortran (${{ matrix.GCC_V }}, ${{ matrix.os }}) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-20.04 ] + GCC_V: [ 7, 8, 9, 10, 11 ] + defaults: + run: + shell: bash -l {0} + env: + FC: gfortran + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-testmodels + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-testmodels + path: modflow6-testmodels + + - name: Setup gfortran ${{ matrix.GCC_V }} + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ matrix.GCC_V }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Update flopy + working-directory: modflow6/autotest + run: | + python update_flopy.py + + - name: Build modflow6 + working-directory: modflow6 + run: | + meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin + meson install -C builddir + meson test --verbose --no-rebuild -C builddir + + - name: Get executables + working-directory: modflow6/autotest + run: | + pytest -v --durations 0 get_exes.py + + - name: Run tests + working-directory: modflow6/autotest + run: | + pytest -v -n auto --durations 0 + + test_ifort: + name: Test (ifort) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + defaults: + run: + shell: bash -l {0} + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-testmodels + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-testmodels + path: modflow6-testmodels + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Setup ifort + uses: modflowpy/install-intelfortran-action@v1 + + - name: Add Micromamba Scripts dir to path + if: runner.os == 'Windows' + shell: pwsh + run: | + # https://github.com/modflowpy/install-intelfortran-action#conda-scripts + $mamba_bin = "C:\Users\runneradmin\micromamba-root\envs\modflow6\Scripts" + echo $mamba_bin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Build modflow6 + if: runner.os != 'Windows' + working-directory: modflow6 + run: | + meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin + meson install -C builddir + meson test --verbose --no-rebuild -C builddir + + - name: Build modflow6 + if: runner.os == 'Windows' + working-directory: modflow6 + shell: pwsh + run: | + meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin + meson install -C builddir + meson test --verbose --no-rebuild -C builddir + + - name: Update flopy + working-directory: modflow6/autotest + run: | + python update_flopy.py + + - name: Get executables + if: runner.os != 'Windows' + working-directory: modflow6/autotest + run: | + pytest -v --durations 0 get_exes.py + + - name: Get executables + if: runner.os == 'Windows' + working-directory: modflow6/autotest + shell: pwsh + run: | + pytest -v --durations 0 get_exes.py + + - name: Run tests + if: runner.os != 'Windows' + working-directory: modflow6/autotest + run: | + pytest -v -n auto --durations 0 + + - name: Run tests + if: runner.os == 'Windows' + working-directory: modflow6/autotest + shell: pwsh + run: | + pytest -v -n auto --durations 0 + + test_makefiles_gfortran: + name: Test makefiles (gfortran ${{ matrix.gcc_v }}, ${{ matrix.os }}) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-22.04, macos-12, windows-2022] + gcc_v: [ 12 ] + defaults: + run: + shell: bash -l {0} + env: + FC: gfortran + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-testmodels + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-testmodels + path: modflow6-testmodels + + - name: Setup gfortran ${{ matrix.gcc_v }} + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ matrix.gcc_v }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Test makefiles + working-directory: modflow6/distribution + run: | + pytest -v -n auto build_makefiles.py + + test_makefiles_ifort: + name: Test makefiles (ifort, ${{ matrix.os }}) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + defaults: + run: + shell: bash -l {0} + env: + FC: ifort + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-testmodels + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-testmodels + path: modflow6-testmodels + + - name: Setup ifort + uses: modflowpy/install-intelfortran-action@v1 + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Test makefiles + working-directory: modflow6/distribution + run: | + pytest -v -n auto build_makefiles.py + + test_nightly_build_gfortran: + name: Test nightly build (gfortran 12) + needs: + - lint + - build + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + ostag: linux + - os: macos-12 + ostag: mac + - os: windows-2022 + ostag: win64 + env: + GCC_V: 12 + defaults: + run: + shell: bash -l {0} + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + + - name: Setup gfortran ${{ env.GCC_V }} + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ env.GCC_V }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + cache-downloads: true + cache-env: true + + - name: Print Python package versions + run: | + pip list + + - name: Update flopy + working-directory: autotest + run: | + python update_flopy.py + + - name: Run nightly build script + working-directory: distribution + run: | + python build_nightly.py + + - name: Make sure zip file exists + working-directory: distribution + run: | + path="temp_zip/${{ matrix.ostag }}.zip" + if [ -e "$path" ]; then + echo "Zipfile found: $path" + else + echo "Zipfile not found: $path" + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/docs.yml similarity index 81% rename from .github/workflows/ci-docs.yml rename to .github/workflows/docs.yml index 603e015415c..529b69cb588 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/docs.yml @@ -1,35 +1,41 @@ -name: docs - +name: MODFLOW 6 documentation on: push: - branches: [ master, develop ] + branches: + - master + - develop + - ci-diagnose* pull_request: - branches: [ develop ] - + branches: + - master + - develop jobs: rtd_build: runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} env: working-directory: .build_rtd_docs distribution-directory: distribution steps: - - uses: actions/checkout@v2.3.4 + - uses: actions/checkout@v3 - - name: Setup Python 3.8 - uses: actions/setup-python@v2 + - name: Install Conda environment from environment.yml + uses: mamba-org/provision-with-micromamba@main with: - python-version: 3.8 + cache-downloads: true + cache-env: true - - name: Upgrade pip and install packages for Sphinx + - name: Install additional packages for Sphinx using pip run: | - python -m pip install --upgrade pip - pip install -r requirements.txt + pip install -r requirements.rtd.txt working-directory: ${{env.working-directory}} - - name: Install additional python packages + - name: Print python package versions run: | - .github/common/install-python-std.sh + pip list - name: Install TeX Live run: | @@ -50,11 +56,8 @@ jobs: run: | pytest -v build_mfio_tex.py - - name: Setup symbolic links on Linux - run: | - sudo ln -fs /usr/bin/gfortran-10 /usr/local/bin/gfortran - sudo ln -fs /usr/bin/gcc-10 /usr/local/bin/gcc - sudo ln -fs /usr/bin/g++-10 /usr/local/bin/g++ + - name: Install gfortran + uses: modflowpy/install-gfortran-action@v1 - name: Run-time comparison run: | @@ -108,6 +111,9 @@ jobs: distribution-directory: distribution common-directory: .github/common branch-name: ${GITHUB_REF##*/} + defaults: + run: + shell: bash -l {0} steps: - uses: actions/checkout@v2.3.4 @@ -121,10 +127,15 @@ jobs: sudo apt-get update sudo apt-get install doxygen graphviz - - name: Setup Python 3.8 - uses: actions/setup-python@v2 + - name: Install Conda environment from environment.yml + uses: mamba-org/provision-with-micromamba@main with: - python-version: 3.8 + cache-downloads: true + cache-env: true + + - name: Print python package versions + run: | + pip list - name: update MODFLOW 6 version run: | diff --git a/.github/workflows/large.yml b/.github/workflows/large.yml new file mode 100644 index 00000000000..ed23cc21e4f --- /dev/null +++ b/.github/workflows/large.yml @@ -0,0 +1,97 @@ +name: MODFLOW 6 large models +on: + schedule: + - cron: '0 6 * * *' # run at 6 AM UTC every day +jobs: + test: + name: Test + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + fc: [ ifort, gfortran ] + repo: [ examples, largetestmodels ] + defaults: + run: + shell: bash -l {0} + env: + GCC_V: 12 + steps: + + - name: Checkout modflow6 + uses: actions/checkout@v3 + with: + path: modflow6 + + - name: Checkout modflow6-${{ matrix.repo }} + uses: actions/checkout@v3 + with: + repository: MODFLOW-USGS/modflow6-${{ matrix.repo }} + path: modflow6-${{ matrix.repo }} + + - name: Setup Micromamba + uses: mamba-org/provision-with-micromamba@main + with: + environment-file: modflow6/environment.yml + cache-downloads: true + cache-env: true + + - name: Setup gfortran ${{ env.GCC_V }} + if: matrix.FC == 'gfortran' + uses: awvwgk/setup-fortran@main + with: + compiler: gcc + version: ${{ env.GCC_V }} + + - name: Setup ifort + if: matrix.fc == 'ifort' + uses: modflowpy/install-intelfortran-action@v1 + + - name: Cache modflow6 examples + id: cache-examples + uses: actions/cache@v3 + with: + path: modflow6-examples/examples + key: modflow6-examples-${{ hashFiles('modflow6-examples/data/**') }} + + - name: Install extra Python packages + if: matrix.repo == 'examples' && steps.cache-examples.outputs.cache-hit != 'true' + working-directory: modflow6-examples/etc + run: | + pip install -r requirements.pip.txt + + - name: Build example models + if: matrix.repo == 'examples' && steps.cache-examples.outputs.cache-hit != 'true' + working-directory: modflow6-examples/etc + run: | + python ci_build_files.py + ls -lh ../examples/ + + - name: Add Micromamba Scripts dir to path (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + # add micromamba scripts dir to system path + $mamba_bin = "C:\Users\runneradmin\micromamba-root\envs\modflow6\Scripts" + echo $mamba_bin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Build modflow6 + working-directory: modflow6 + run: | + meson setup builddir -Ddebug=false --prefix=$(pwd) --libdir=bin + meson install -C builddir + + - name: Get executables + working-directory: modflow6/autotest + run: | + pytest -v --durations 0 get_exes.py + + - name: Update flopy + working-directory: modflow6/autotest + run: | + python update_flopy.py + + - name: Run tests + working-directory: modflow6/autotest + run: | + pytest -v -n auto --durations 0 test_z03_${{ matrix.repo }}.py \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7f32f35b1ff..c15a4fa32c6 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ autotest/*.html autotest/notebooks/ distribution/temp/ +distribution/temp_zip/ distribution/*.zip mod_temp/ diff --git a/.readthedocs.yml b/.readthedocs.yml index 41a6408fab0..086932137d8 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -18,7 +18,6 @@ formats: all # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 + version: 3.8 install: - - requirements: requirements.travis.txt - - requirements: .doc/requirements.txt + - requirements: .build_rtd_docs/requirements.rtd.txt diff --git a/.vscode/README.md b/.vscode/README.md index e09b4ea25f0..962fe1d07b2 100644 --- a/.vscode/README.md +++ b/.vscode/README.md @@ -21,72 +21,92 @@ Install the following VSCode extensions: - Modern Fortran: https://marketplace.visualstudio.com/items?itemName=krvajalm.linter-gfortran -- FORTRAN IntelliSense: https://marketplace.visualstudio.com/items?itemName=hansec.fortran-ls -- C/C++: https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools -- Fortran Breakpoint Support: - https://marketplace.visualstudio.com/items?itemName=ekibun.fortranbreaker -Now, configure the VSCode files for the modflow6 directory. Open the `modflow6` -directory in VSCode. Copy `.vscode/settings_template.json` to (untracked) `.vscode/settings.json` and make sure that in the copy, the following setting points toward your Python executable. +Note: The Remote - WSL extension may be required if you want to use a windows VSCode +installation in a WSL environment. -```json -{ - "python.defaultInterpreterPath": "/path/to/python", -} -``` +### Dependencies -In order to compile run: +Required and optional dependencies for MODFLOW 6 are discussed in [DEVELOPER.md](../DEVELOPER.md) -* Press `Ctrl + Shift + P` in VSCode. -* Type `Tasks`. -* Select `Run Task` (press Enter). -* Select the suitable task for your situation. +### Settings +Add [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) to the +`modflow6/.vscode` directory if not already there. The following settings can be considered a +starting place as the contents of this file are dictated both by desired VSCode behavior and +environmental factors: -### Language Server +In general, to determine the path of an installed tool in your environment run: +- bash: `which `, e.g. `which fortls` +- cmd: `where `, e.g. `where python` +- PowerShell: `Get-Command ` e.g. `Get-Command fprettify` -1. Install the fortran language server via: +1. Activate the conda environment: ```bash -pip install -U fortran-language-server +conda activate modflow6 ``` -2. Find out where the executable is - -- bash: `which fortls` -- cmd: `where fortls` -- PowerShell: `Get-Command fortls` +2. Determine the path of `fortls` and `fprettify` -3. Add this to `.vscode/settings.json`. In case this file does not exist yet, create a new one. Also remember to adapt `fortran-ls.executablePath` to the path you get in the step before. +3. Set the setting "fortran.fortls.path" and "fortran.formatting.path": +```json +{ + "fortran.fortls.path": "/path/to/fortls", + "fortran.formatting.path": "/path/to/fprettify", +} +``` +The fortran formatter can be integrated with VSCode using the following settings: ```json - "fortran-ls.executablePath": "/path/to/fortls", - "fortran-ls.hoverSignature": true, - "fortran-ls.lowercaseIntrinsics": true, - "fortran-ls.notifyInit": true, - "fortran-ls.variableHover": true, - "fortran.linterEnabled": false, - "fortran.provideHover": false, - "fortran.provideCompletion": false, - "fortran.provideSymbols": false, - "[FortranFreeForm]": { - "editor.acceptSuggestionOnEnter": "off", +{ + "[fortran]": { + "editor.formatOnSave": true, }, + "fortran.formatting.formatter": "fprettify", + "fortran.formatting.fprettifyArgs": ["-c", "/path/to/modflow6/.fprettify.yaml"], +} +``` + +Setting the formatter up in this way will cause a source file to reformat with each explicit save. + +### Running VSCode + +Open the top level `modflow6` repository directory on your system when starting VSCode. The program will +then look for the `modflow6/.vscode` directory to discover settings relevant to your session. + +A nice alternative on any system is to start VSCode from the shell. For example, in a bash or git bash +shell (windows), change to the `modflow6` directory and execute the command: + +```bash +code . ``` +Note the dot. Starting in this way, VSCode will open as desired, inheriting and discovering +expected runtime settings in the correct directory location. + +### Compiling +In order to compile Fortran source run: + +* Press `Ctrl + Shift + P` in VSCode. +* Type `Tasks`. +* Select `Run Task` (press Enter). +* Select the suitable task for your situation. ### Debugging Add a `launch.json` in `.vscode` similar to this. +Most of the time you will want to debug with gdb. +Only when compiling with ifort on Windows, vsdbg is the preferred debugger. ```json { "version": "0.2.0", "configurations": [ { - "name": "Launch Modflow Model", + "name": "Debug (gdb)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/bin/mf6.exe", @@ -105,6 +125,17 @@ Add a `launch.json` in `.vscode` similar to this. } ] } + { + "name": "Debug (vsdbg)", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/bin/mf6.exe", + "args": [], + "stopAtEntry": false, + "cwd": "/path/to/modflow6/model", + "environment": [], + "console": "integratedTerminal" + } ] } ```` diff --git a/.vscode/build_vscode.py b/.vscode/build_vscode.py index b889869562a..11fe1ab3c6f 100644 --- a/.vscode/build_vscode.py +++ b/.vscode/build_vscode.py @@ -2,6 +2,7 @@ import os import argparse import shutil +import shlex parser = argparse.ArgumentParser() parser.add_argument("--compiler", type=str) @@ -12,25 +13,30 @@ os.environ["FC"] = args.compiler builddir = f"builddir_{args.compiler}_{args.buildtype}" - if args.action == "rebuild" and os.path.isdir(builddir): shutil.rmtree(builddir) - if args.buildtype == "release": setup_flag = ["-Doptimization=2"] elif args.buildtype == "debug": setup_flag = ["-Doptimization=0"] if not os.path.isdir(builddir): + command = [ + "meson", + "setup", + builddir, + "--prefix", + os.getcwd(), + "--libdir", + "bin", + ] + setup_flag + print("Run:", shlex.join(command)) subprocess.run( - ["meson", "setup", builddir, "--prefix", os.getcwd(), "--libdir", "bin"] - + setup_flag, + command, check=True, ) -subprocess.run(["meson", "compile", "-C", builddir], check=True) - # Remove all files from bin folder bin_dir = os.path.join(os.getcwd(), "bin") if os.path.isdir(bin_dir): @@ -39,4 +45,6 @@ if os.path.isfile(path): os.remove(path) -subprocess.run(["meson", "install", "-C", builddir], check=True) +command = ["meson", "install", "-C", builddir] +print("Run:", shlex.join(command)) +subprocess.run(command, check=True) diff --git a/.vscode/run_python.cmd b/.vscode/run_python.cmd index 17dc572a922..87c6f3de58b 100644 --- a/.vscode/run_python.cmd +++ b/.vscode/run_python.cmd @@ -1,9 +1,10 @@ @echo off -if "%4" == "ifort" ( +if "%3" == "ifort" ( call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" ) +call conda activate modflow6 rem run python script -%1 %2 %3 %4 %5 %6 %7 +python %1 %2 %3 %4 %5 %6 diff --git a/.vscode/run_python.sh b/.vscode/run_python.sh index 49bc3df5a5d..cbd3b27fcc9 100755 --- a/.vscode/run_python.sh +++ b/.vscode/run_python.sh @@ -1,9 +1,12 @@ #!/usr/bin/env bash -if [[ "$4" == "ifort" ]]; +if [[ "$3" == "ifort" ]]; then source /opt/intel/oneapi/setvars.sh fi +eval "$(conda shell.bash hook)" +conda activate modflow6 + # run python script -$1 $2 $3 $4 $5 $6 $7 +python $1 $2 $3 $4 $5 $6 diff --git a/.vscode/settings_template.json b/.vscode/settings_template.json deleted file mode 100644 index b8648f2f8d1..00000000000 --- a/.vscode/settings_template.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "python.defaultInterpreterPath": "/path/to/python", - - "fortran-ls.executablePath": "/path/to/fortls", - "fortran-ls.hoverSignature": true, - "fortran-ls.lowercaseIntrinsics": true, - "fortran-ls.notifyInit": true, - "fortran-ls.variableHover": true, - "fortran.linterEnabled": false, - "fortran.provideHover": false, - "fortran.provideCompletion": false, - "fortran.provideSymbols": false, - "[FortranFreeForm]": { - "editor.acceptSuggestionOnEnter": "off", - }, -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 413e08e9624..49e18315c10 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,7 +9,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -20,7 +19,6 @@ "problemMatcher": "$msCompile" }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -39,7 +37,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -49,7 +46,6 @@ ], }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -68,7 +64,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -79,7 +74,6 @@ "problemMatcher": "$msCompile" }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -98,7 +92,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -108,7 +101,6 @@ ], }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -127,7 +119,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -138,7 +129,6 @@ "problemMatcher": "$msCompile" }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -157,7 +147,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -167,7 +156,6 @@ ], }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "ifort", @@ -186,7 +174,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -197,7 +184,6 @@ "problemMatcher": "$msCompile" }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -216,7 +202,6 @@ "windows": { "command": "${workspaceFolder}/.vscode/run_python.cmd", "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", @@ -226,7 +211,6 @@ ], }, "args": [ - "${config:python.defaultInterpreterPath}", "${workspaceFolder}/.vscode/build_vscode.py", "--compiler", "gfortran", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28e5cfcd23b..573acd3d821 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ Contributions to MODFLOW 6 are welcome from the community. As a contributor, her - [Feature Requests](#feature) - [Submission Guidelines](#submit) - [Coding Rules](#rules) + - [Format Rules](#format) - [Commit Message Guidelines](#commit) ## Code of Conduct @@ -135,6 +136,30 @@ from the main (upstream) repository: To ensure consistency throughout the source code, keep these rules in mind as you are working: * All features or bug fixes **must be tested** by one or more specs (unit-tests and/or integration/regression-tests). +* All Fortran souce code submissions must adhere to modflow6 [Format Rules](#format) + +## Format Rules + +Fortran souce code format rules are met by running the +[fprettify formatter](https://github.com/pseewald/fprettify) while specifying the [MODFLOW 6 +fprettify configuration](https://github.com/MODFLOW-USGS/modflow6/blob/develop/distribution/.fprettify.yaml). +The tool can be run from the command line or integrated into a +[VSCode](https://github.com/MODFLOW-USGS/modflow6/blob/develop/.vscode/README.md) or Visual Studio environment. + +The format configuration file reflects the current minimum standard for Fortran source +formatting. The main goal, however, is consistent and readable Fortran source code and as such +pay particular attention to consistency within and across files. As the formatting tool may at +times shift code in unexpected ways, check for formatting consistency after running. + +An example run of the command line tool from the MODFLOW 6 root directory: +`fprettify -c ./distribution/.fprettify.yaml ./utils/zonebudget/src/zbud6.f90` + +When run in this way, the tool will modify the file in place and generate no output if successful. The +tool will write stderr warnings when unable to complete formatting. In general, these warnings (e.g. +for excess line length) must be manually fixed before attempting to rerun the tool. + +Fortran source files can be excluded from the formatting standard if necessary, as is the case +for Fortran source found under the `modflow6/src/Utilities/Libraries` path. ## Commit Message Guidelines diff --git a/DEVELOPER.md b/DEVELOPER.md index 21ad9db31a6..ddafa361611 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -52,20 +52,33 @@ gfortran can be used to compile MODFLOW 6 and associated utilities and generate ### Python Install Python, for example via [miniconda](https://docs.conda.io/en/latest/miniconda.html) or [Anaconda](https://www.anaconda.com/products/individual). -Please make sure that your Python version is 3.7 or higher. -Then install all packages necessary to run the tests either by executing [install-python-std.sh](.github/common/install-python-std.sh) via bash directly or by installing the listed packages manually. +Then create a new environment by executing the following at the root of this repository +``` +conda env create --force -f environment.yml +``` ### ifort (optional) Intel fortran can be used to compile MODFLOW 6 and associated utilities and generate distributable files (if not using gfortran). Download the Intel oneAPI HPC Toolkit: https://software.intel.com/content/www/us/en/develop/tools/oneapi/hpc-toolkit/download.html -Documentation describing how to set the intel envrionment variables can be found [here](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-programming-guide/top/oneapi-development-environment-setup.html). + +Documentation describing how to set the intel environment variables can be found [here](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-programming-guide/top/oneapi-development-environment-setup.html). + +#### Windows + +- Visual Studio with the appropriate redistributable libraries must be installed for ifort to compile on Windows. +- Install Visual Studio, which can be found [here](https://visualstudio.microsoft.com/). Note: the latest version of Visual Studio, 2022, requires a sufficiently new version of the Intel OneAPI as well. +- The redistributable libraries can installed via ticking the "Desktop Development with C++" checkbox in the Visual Studio Installer in the Workloads tab. ### Doxygen & LaTeX (optional) [Doxygen](https://www.doxygen.nl/index.html) is used to generate the [MODFLOW 6 source code documentation](https://modflow-usgs.github.io/modflow6/). [Graphviz](https://graphviz.org/) is used by doxygen to produce source code diagrams. [LaTeX](https://www.latex-project.org/) is used to generate the MODFLOW 6 release notes and Input/Output documents (docs/mf6io/mf6io.nightlybuild). These programs can be installed from various sources, including by conda, macports, or from individual sources such as https://www.tug.org/. Details about USGS LaTeX libraries can be seen in addition to linux installs in the CI workflow for the docs (`.github/workflows/ci-docs.yml`). +### fprettify + +[fprettify](https://github.com/pseewald/fprettify) can be used to format Fortran source code and in combination with the [MODFLOW 6 fprettify configuration](https://github.com/MODFLOW-USGS/modflow6/blob/develop/distribution/.fprettify.yaml) establishes a contribution standard for properly formatted MODFLOW 6 Fortran source. This tool can be installed with `pip` or `conda` and used from the command line or integrated with a [VSCode](https://github.com/MODFLOW-USGS/modflow6/blob/develop/.vscode/README.md) or Visual Studio development environment. See [contribution guidelines](https://github.com/MODFLOW-USGS/modflow6/blob/develop/CONTRIBUTING.md) for additional information. + ## Getting the Sources Fork and clone the MODFLOW 6 repository: diff --git a/README.md b/README.md index 9dcd2345b60..ea9cdcec29c 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ This is the development repository for the USGS MODFLOW 6 Hydrologic Model. The official USGS distribution is available at [USGS Release Page](https://water.usgs.gov/ogw/modflow/MODFLOW.html). -### Version 6.3.0 +### Version 6.4.0 -[![tests - ifort](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-ifort.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-ifort.yml) -[![tests - gfortran - latest version](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-gfortran-latest.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-gfortran-latest.yml) -[![tests - gfortran - previous versions](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-gfortran-previous.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci-tests-gfortran-previous.yml) +[![MODFLOW 6 continuous integration](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/ci.yml) +[![MODFLOW 6 documentation](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/docs.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/docs.yml) +[![MODFLOW 6 large models](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/large.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6/actions/workflows/large.yml) [![MODFLOW 6 intel nightly build](https://github.com/MODFLOW-USGS/modflow6-nightly-build/actions/workflows/nightly-build-intel.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6-nightly-build/actions/workflows/nightly-build-intel.yml) [![MODFLOW 6 nightly build](https://github.com/MODFLOW-USGS/modflow6-nightly-build/actions/workflows/nightly-build.yml/badge.svg)](https://github.com/MODFLOW-USGS/modflow6-nightly-build/actions/workflows/nightly-build.yml) diff --git a/autotest/binary_file_writer.py b/autotest/binary_file_writer.py index a735ebbf0ce..5d8771a0424 100644 --- a/autotest/binary_file_writer.py +++ b/autotest/binary_file_writer.py @@ -126,7 +126,7 @@ def write_budget( # write auxiliary column names naux = ndat - 1 if naux > 0: - auxtxt = ["{:16}".format(colname) for colname in colnames[3:]] + auxtxt = [f"{colname:16}" for colname in colnames[3:]] auxtxt = tuple(auxtxt) dt = np.dtype([(colname, "S16") for colname in colnames[3:]]) h = np.array(auxtxt, dtype=dt) @@ -143,7 +143,7 @@ def write_budget( pass else: - raise Exception("unknown method code {}".format(imeth)) + raise Exception(f"unknown method code {imeth}") return diff --git a/autotest/budget_file_compare.py b/autotest/budget_file_compare.py index 0d19b351b18..cd69f2ccdac 100644 --- a/autotest/budget_file_compare.py +++ b/autotest/budget_file_compare.py @@ -12,6 +12,7 @@ import os + import numpy as np @@ -34,11 +35,11 @@ def eval_bud_diff(fpth, b0, b1, ia=None, dtol=1e-6): # open a summary file and write header f = open(fpth, "w") - line = "{:15s}".format("Time") - line += " {:15s}".format("Datatype") - line += " {:15s}".format("File 1") - line += " {:15s}".format("File 2") - line += " {:15s}".format("Difference") + line = f"{'Time':15s}" + line += f" {'Datatype':15s}" + line += f" {'File 1':15s}" + line += f" {'File 2':15s}" + line += f" {'Difference':15s}" f.write(line + "\n") f.write(len(line) * "-" + "\n") @@ -79,45 +80,41 @@ def eval_bud_diff(fpth, b0, b1, ia=None, dtol=1e-6): difftime = t if abs(diff) > dtol: fail = True - line = "{:15g}".format(t) - line += " {:15s}".format(key) - line += " {:15g}".format(v0) - line += " {:15g}".format(v1) - line += " {:15g}".format(diff) + line = f"{t:15g}" + line += f" {key:15s}" + line += f" {v0:15g}" + line += f" {v1:15g}" + line += f" {diff:15g}" f.write(line + "\n") # evaluate the sums diff = v0sum - v1sum if abs(diff) > dtol: fail = True - line = "{:15g}".format(t) - line += " {:15s}".format("TOTAL") - line += " {:15g}".format(v0sum) - line += " {:15g}".format(v1sum) - line += " {:15g}".format(diff) + line = f"{t:15g}" + line += f" {'TOTAL':15s}" + line += f" {v0sum:15g}" + line += f" {v1sum:15g}" + line += f" {diff:15g}" f.write(line + "\n") - msg = "\nSummary of changes in {}\n".format(os.path.basename(fpth)) + msg = f"\nSummary of changes in {os.path.basename(fpth)}\n" msg += "-" * 72 + "\n" - msg += "Maximum cbc difference: {}\n".format(diffmax) - msg += "Maximum cbc difference time: {}\n".format(difftime) - msg += "Maximum cbc datatype: {}\n".format(difftag) + msg += f"Maximum cbc difference: {diffmax}\n" + msg += f"Maximum cbc difference time: {difftime}\n" + msg += f"Maximum cbc datatype: {difftag}\n" if fail: - msg += "Maximum cbc criteria exceeded: {}".format(dtol) + msg += f"Maximum cbc criteria exceeded: {dtol}" assert not fail, msg # close summary file and print the final message f.close() print(msg) - msg = "sum of first cbc file flows ({}) ".format( - v0sum - ) + "exceeds dtol ({})".format(dtol) + msg = f"sum of first cbc file flows ({v0sum}) " + f"exceeds dtol ({dtol})" assert abs(v0sum) < dtol, msg - msg = "sum of second cbc file flows ({}) ".format( - v1sum - ) + "exceeds dtol ({})".format(dtol) + msg = f"sum of second cbc file flows ({v1sum}) " + f"exceeds dtol ({dtol})" assert abs(v1sum) < dtol, msg return diff --git a/autotest/build_exes.py b/autotest/build_exes.py index 50f9437406c..fd9b22a51e7 100644 --- a/autotest/build_exes.py +++ b/autotest/build_exes.py @@ -7,9 +7,10 @@ # python -c "import build_exes; build_exes.test_build_modflow6()" import os +import pathlib as pl +import subprocess as sp import sys -import shutil -import pymake +from contextlib import contextmanager from framework import running_on_CI @@ -17,8 +18,7 @@ print("running on CI environment") os.environ["PYMAKE_DOUBLE"] = "1" - -# make sure exe extension is used on windows +# set OS dependent extensions eext = "" soext = ".so" if sys.platform.lower() == "win32": @@ -42,6 +42,28 @@ ) +@contextmanager +def set_directory(path: str): + """Sets the cwd within the context + + Args: + path (Path): The path to the cwd + + Yields: + None + """ + + origin = os.path.abspath(os.getcwd()) + path = os.path.abspath(path) + try: + os.chdir(path) + print(f"change from {origin} -> {path}") + yield + finally: + os.chdir(origin) + print(f"change from {path} -> {origin}") + + def relpath_fallback(pth): try: # throws ValueError on Windows if pth is on a different drive @@ -59,131 +81,61 @@ def create_dir(pth): assert os.path.exists(pth), msg -def get_compiler_envvar(fc): - env_var = os.environ.get("FC") - if env_var is not None: - if env_var != fc: - fc = env_var - return fc - - -def build_mf6(srcdir=None, appdir=None): - pm = pymake.Pymake() - pm.target = f"mf6{eext}" - if srcdir is None: - srcdir = os.path.join("..", "src") - pm.srcdir = srcdir - if appdir is None: - appdir = os.path.join("..", "bin") - pm.appdir = appdir - pm.include_subdirs = True - pm.inplace = True - pm.makeclean = True - - # reset compiler based on environmental variable, if defined - pm.fc = get_compiler_envvar(pm.fc) - - # add strict flags if gfortran is being used - if pm.fc == "gfortran": - pm.fflags = strict_flags - - # build the application - pm.build() - - msg = "{} does not exist.".format(pm.target) - assert pm.returncode == 0, msg - - -def build_mf6_so(): - pm = pymake.Pymake(verbose=True) - pm.target = f"libmf6{soext}" - pm.srcdir = os.path.join("..", "srcbmi") - pm.srcdir2 = os.path.join("..", "src") - pm.appdir = os.path.join("..", "bin") - pm.excludefiles = [os.path.join(pm.srcdir2, "mf6.f90")] - pm.include_subdirs = True - pm.inplace = True - pm.makeclean = True - - # reset compiler based on environmental variable, if defined - pm.fc = get_compiler_envvar(pm.fc) - - # add strict flags if gfortran is being used - if pm.fc == "gfortran": - pm.fflags = strict_flags - - # build the application - pm.build() +def set_compiler_environment_variable(): + fc = None - msg = "{} does not exist.".format(pm.target) - assert pm.returncode == 0, msg - - -def build_mf5to6(): - # define default compilers - fc = "gfortran" - cc = None - fflags = None - - # reset compiler based on environmental variable, if defined - fc = get_compiler_envvar(fc) - - # determine if fortran compiler specified on the command line + # parse command line arguments for idx, arg in enumerate(sys.argv): - if arg == "-fc": + if arg.lower() == "-fc": fc = sys.argv[idx + 1] - elif arg in ("-ff", "--fflags"): - fflags = sys.argv[idx + 1] - - # set source and target paths - srcdir = os.path.join("..", "utils", "mf5to6", "src") - appdir = os.path.join("..", "bin") - target = f"mf5to6{eext}" - extrafiles = os.path.join( - "..", "utils", "mf5to6", "pymake", "extrafiles.txt" + elif arg.lower().startswith("-fc="): + fc = arg.split("=")[1] + + # determine if fc needs to be set to the FC environmental variable + env_var = os.getenv("FC", default="gfortran") + if fc is None and fc != env_var: + fc = env_var + + # validate Fortran compiler + fc_options = ( + "gfortran", + "ifort", ) - - # build modflow 5 to 6 converter - pymake.main( - srcdir, - target, - fc=fc, - cc=cc, - fflags=fflags, - include_subdirs=True, - extrafiles=extrafiles, - inplace=True, - appdir=appdir, - makeclean=True, - ) - target_pth = os.path.join(appdir, target) - msg = f"{relpath_fallback(target_pth)} does not exist." - assert os.path.isfile(target_pth), msg - - -def build_zbud6(): - pm = pymake.Pymake() - pm.target = f"zbud6{eext}" - pm.srcdir = os.path.join("..", "utils", "zonebudget", "src") - pm.appdir = os.path.join("..", "bin") - pm.extrafiles = os.path.join( - "..", "utils", "zonebudget", "pymake", "extrafiles.txt" - ) - pm.inplace = True - pm.makeclean = True - - # reset compiler based on environmental variable, if defined - pm.fc = get_compiler_envvar(pm.fc) - - # add strict flags if gfortran is being used - if pm.fc == "gfortran": - pm.fflags = strict_flags - - # build the application - pm.build() - - msg = "{} does not exist.".format(pm.target) - assert pm.returncode == 0, msg + if fc not in fc_options: + raise ValueError( + f"Fortran compiler {fc} not supported. Fortran compile must be " + + f"[{', '.join(str(value) for value in fc_options)}]." + ) + + # set FC environment variable + os.environ["FC"] = fc + + +def meson_build( + dir_path: str = "..", + libdir: str = "bin", +): + set_compiler_environment_variable() + is_windows = sys.platform.lower() == "win32" + with set_directory(dir_path): + cmd = ( + "meson setup builddir " + + f"--bindir={os.path.abspath(libdir)} " + + f"--libdir={os.path.abspath(libdir)} " + + "--prefix=" + ) + if is_windows: + cmd += "%CD%" + else: + cmd += "$(pwd)" + if pl.Path("builddir").is_dir(): + cmd += " --wipe" + print(f"setup meson\nrunning...\n {cmd}") + sp.run(cmd, shell=True, check=True) + + cmd = "meson install -C builddir" + print(f"build and install with meson\nrunning...\n {cmd}") + sp.run(cmd, shell=True, check=True) def test_create_dirs(): @@ -195,25 +147,10 @@ def test_create_dirs(): return -def test_build_modflow6(): - build_mf6() - - -def test_build_modflow6_so(): - build_mf6_so() - - -def test_build_mf5to6(): - build_mf5to6() - - -def test_build_zbud6(): - build_zbud6() +def test_meson_build(): + meson_build() if __name__ == "__main__": test_create_dirs() - test_build_modflow6() - test_build_modflow6_so() - test_build_mf5to6() - test_build_zbud6() + test_meson_build() diff --git a/autotest/build_mfio_tex.py b/autotest/build_mfio_tex.py index c2464053a68..b95bd6a37c9 100644 --- a/autotest/build_mfio_tex.py +++ b/autotest/build_mfio_tex.py @@ -62,9 +62,7 @@ def test_rebuild_from_dfn(): # run python argv = ["python", "mf6ivar.py"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} with {}".format( - ierr, argv[0], argv[1] - ) + msg = f"\nERROR {ierr}: could not run {argv[0]} with {argv[1]}" assert ierr == 0, buff + msg # get list for dfn files @@ -85,13 +83,14 @@ def test_rebuild_from_dfn(): for f in dfnfiles: if "common" in f: continue - fpth = "{}-desc".format(f) + fpth = f"{f}-desc" if fpth not in texfiles: icnt += 1 - missing += " {:3d} {}.tex\n".format(icnt, fpth) - msg = "\n{} TeX file(s) are missing. ".format( - icnt - ) + "Missing files:\n{}".format(missing) + missing += f" {icnt:3d} {fpth}.tex\n" + msg = ( + "\n{} TeX file(s) are missing. ".format(icnt) + + f"Missing files:\n{missing}" + ) assert icnt == 0, msg return @@ -114,30 +113,22 @@ def test_build_mfio(): # build pdf argv = ["pdflatex", f"{base_name}.tex"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} on {}".format( - ierr, argv[0], argv[1] - ) + msg = f"\nERROR {ierr}: could not run {argv[0]} on {argv[1]}" assert ierr == 0, buff + msg argv = ["bibtex", f"{base_name}.aux"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} on {}".format( - ierr, argv[0], argv[1] - ) + msg = f"\nERROR {ierr}: could not run {argv[0]} on {argv[1]}" assert ierr == 0, buff + msg argv = ["pdflatex", f"{base_name}.tex"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} on {}".format( - ierr, argv[0], argv[1] - ) + msg = f"\nERROR {ierr}: could not run {argv[0]} on {argv[1]}" assert ierr == 0, buff + msg argv = ["pdflatex", f"{base_name}.tex"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} on {}".format( - ierr, argv[0], argv[1] - ) + msg = f"\nERROR {ierr}: could not run {argv[0]} on {argv[1]}" assert ierr == 0, buff + msg return @@ -161,10 +152,10 @@ def delete_files(files, pth, allow_failure=False): for file in files: fpth = os.path.join(pth, file) try: - print("removing...{}".format(file)) + print(f"removing...{file}") os.remove(fpth) except: - print("could not remove...{}".format(file)) + print(f"could not remove...{file}") if not allow_failure: return False return True @@ -194,7 +185,7 @@ def run_command(argv, pth, timeout=10): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) print("running...test_rebuild_from_dfn()") @@ -210,7 +201,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/common_regression.py b/autotest/common_regression.py index 0069a9f0488..65951f5b6d5 100644 --- a/autotest/common_regression.py +++ b/autotest/common_regression.py @@ -48,7 +48,7 @@ def get_home_dir(): home = os.path.join(*cwd_list[:ipos]) - print("HOME: {}".format(home)) + print(f"HOME: {home}") return home @@ -67,8 +67,8 @@ def is_directory_available(example_basedir): if example_basedir is not None: available = os.path.isdir(example_basedir) if not available: - print('"{}" does not exist'.format(example_basedir)) - print("no need to run {}".format(os.path.basename(__file__))) + print(f'"{example_basedir}" does not exist') + print(f"no need to run {os.path.basename(__file__)}") return available @@ -83,7 +83,7 @@ def get_example_basedir(home, find_dir, subdir=None): break if example_basedir is not None: example_basedir = os.path.abspath(example_basedir) - print("Example base directory: {}".format(example_basedir)) + print(f"Example base directory: {example_basedir}") break return example_basedir diff --git a/autotest/data/vsc04-laktab/stg-vol-surfarea.dat b/autotest/data/vsc04-laktab/stg-vol-surfarea.dat new file mode 100644 index 00000000000..edc44af27e1 --- /dev/null +++ b/autotest/data/vsc04-laktab/stg-vol-surfarea.dat @@ -0,0 +1,152 @@ +stage,Volume,Surf Area +29.5656,0,0 +29.602176,7645.54858,3870.96 +29.638752,15291.09716,7741.92 +29.675328,22936.64574,11612.88 +29.711904,30582.19432,15483.84 +29.74848,38227.7429,19354.8 +29.785056,45873.29148,23225.76 +29.821632,53518.84006,27096.72 +29.858208,61164.38864,30967.68 +29.894784,68809.93722,34838.64 +29.93136,76455.4858,38709.6 +29.967936,84101.03438,42580.56 +30.004512,91746.58296,46451.52 +30.041088,99392.13154,50322.48 +30.077664,107037.6801,54193.44 +30.11424,114683.2287,58064.4 +30.150816,122328.7773,61935.36 +30.187392,129974.3259,65806.32 +30.223968,137619.8744,69677.28 +30.260544,145265.423,73548.24 +30.29712,152910.9716,77419.2 +30.333696,160556.5202,81290.16 +30.370272,168202.0688,85161.12 +30.406848,175847.6173,89032.08 +30.443424,183493.1659,92903.04 +30.48,191138.7145,96774 +30.516576,198784.2631,100644.96 +30.553152,206429.8117,104515.92 +30.589728,214075.3602,108386.88 +30.626304,221720.9088,112257.84 +30.66288,229366.4574,116128.8 +30.699456,237012.006,119999.76 +30.736032,244657.5546,123870.72 +30.772608,252303.1031,127741.68 +30.809184,259948.6517,131612.64 +30.84576,267594.2003,135483.6 +30.882336,275239.7489,139354.56 +30.918912,282885.2975,143225.52 +30.955488,290530.846,147096.48 +30.992064,298176.3946,150967.44 +31.02864,305821.9432,154838.4 +31.065216,313467.4918,158709.36 +31.101792,321113.0404,162580.32 +31.138368,328758.5889,166451.28 +31.174944,336404.1375,170322.24 +31.21152,344049.6861,174193.2 +31.248096,351695.2347,178064.16 +31.284672,359340.7833,181935.12 +31.321248,366986.3318,185806.08 +31.357824,374631.8804,189677.04 +31.3944,382277.429,193548 +31.430976,389922.9776,197418.96 +31.467552,397568.5262,201289.92 +31.504128,405214.0747,205160.88 +31.540704,412859.6233,209031.84 +31.57728,420505.1719,212902.8 +31.613856,428150.7205,216773.76 +31.650432,435796.2691,220644.72 +31.687008,443441.8176,224515.68 +31.723584,451087.3662,228386.64 +31.76016,458732.9148,232257.6 +31.796736,466378.4634,236128.56 +31.833312,474024.012,239999.52 +31.869888,481669.5605,243870.48 +31.906464,489315.1091,247741.44 +31.94304,496960.6577,251612.4 +31.979616,504606.2063,255483.36 +32.016192,512251.7548,259354.32 +32.052768,519897.3034,263225.28 +32.089344,527542.852,267096.24 +32.12592,535188.4006,270967.2 +32.162496,542833.9492,274838.16 +32.199072,550479.4977,278709.12 +32.235648,558125.0463,282580.08 +32.272224,565770.5949,286451.04 +32.3088,573416.1435,290322 +32.345376,581061.6921,294192.96 +32.381952,588707.2406,298063.92 +32.418528,596352.7892,301934.88 +32.455104,603998.3378,305805.84 +32.49168,611643.8864,309676.8 +32.528256,619289.435,313547.76 +32.564832,626934.9835,317418.72 +32.601408,634580.5321,321289.68 +32.637984,651287.4716,325160.64 +32.67456,672525.1066,329031.6 +32.711136,693762.7415,332902.56 +32.747712,715000.3764,336773.52 +32.784288,736238.0114,340644.48 +32.820864,757475.6463,344515.44 +32.85744,778713.2813,348386.4 +32.894016,799950.9162,352257.36 +32.930592,821188.5512,356128.32 +32.967168,842426.1861,359999.28 +33.003744,863663.8211,363870.24 +33.04032,884901.456,367741.2 +33.076896,906139.0909,371612.16 +33.113472,927376.7259,375483.12 +33.150048,948614.3608,379354.08 +33.186624,969851.9958,383225.04 +33.2232,991089.6307,387096 +33.259776,1012327.266,390966.96 +33.296352,1033564.901,394837.92 +33.332928,1054802.536,398708.88 +33.369504,1076040.17,402579.84 +33.40608,1097277.805,406450.8 +33.442656,1118515.44,410321.76 +33.479232,1139753.075,414192.72 +33.515808,1160990.71,418063.68 +33.552384,1182228.345,421934.64 +33.58896,1203465.98,425805.6 +33.625536,1224703.615,429676.56 +33.662112,1245941.25,433547.52 +33.698688,1267178.885,437418.48 +33.735264,1288416.52,441289.44 +33.77184,1309654.155,445160.4 +33.808416,1330891.79,449031.36 +33.844992,1352129.425,452902.32 +33.881568,1373367.06,456773.28 +33.918144,1394604.695,460644.24 +33.95472,1415842.33,464515.2 +33.991296,1437079.965,468386.16 +34.027872,1458317.599,472257.12 +34.064448,1479555.234,476128.08 +34.101024,1500792.869,479999.04 +34.1376,1522030.504,483870 +34.174176,1543268.139,487740.96 +34.210752,1564505.774,491611.92 +34.247328,1585743.409,495482.88 +34.283904,1606981.044,499353.84 +34.32048,1628218.679,503224.8 +34.357056,1649456.314,507095.76 +34.393632,1670693.949,510966.72 +34.430208,1691931.584,514837.68 +34.466784,1713169.219,518708.64 +34.50336,1734406.854,522579.6 +34.539936,1755644.489,526450.56 +34.576512,1776882.124,530321.52 +34.613088,1798119.759,534192.48 +34.649664,1819357.394,538063.44 +34.68624,1840595.028,541934.4 +34.722816,1861832.663,545805.36 +34.759392,1883070.298,549676.32 +34.795968,1904307.933,553547.28 +34.832544,1925545.568,557418.24 +34.86912,1946783.203,561289.2 +34.905696,1968020.838,565160.16 +34.942272,1989258.473,569031.12 +34.978848,2010496.108,572902.08 +35.015424,2031733.743,576773.04 +35.052,2052971.378,580644 diff --git a/autotest/disu_util.py b/autotest/disu_util.py index 364258d2173..041e728622b 100644 --- a/autotest/disu_util.py +++ b/autotest/disu_util.py @@ -2,6 +2,12 @@ def get_disu_kwargs(nlay, nrow, ncol, delr, delc, tp, botm): + """ + Simple utility for creating args needed to construct + a disu package + + """ + def get_nn(k, i, j): return k * nrow * ncol + i * ncol + j diff --git a/autotest/get_exes.py b/autotest/get_exes.py index a58dc97cd02..7530f31ca3f 100644 --- a/autotest/get_exes.py +++ b/autotest/get_exes.py @@ -2,8 +2,11 @@ import os import shutil + +from flaky import flaky import pymake +from build_exes import meson_build from framework import running_on_CI if running_on_CI(): @@ -50,52 +53,41 @@ def create_dir(pth): print(f"creating... {os.path.abspath(pth)}") os.makedirs(pth, exist_ok=True) - msg = "could not create... {}".format(os.path.abspath(pth)) + msg = f"could not create... {os.path.abspath(pth)}" assert os.path.exists(pth), msg def rebuild_mf6_release(): - pm = pymake.Pymake(verbose=True) - pm.target = "mf6" - pm.appdir = rebuilt_bindir + target = "mf6" download_pth = os.path.join("temp") - target_dict = pymake.usgs_program_data.get_target(pm.target) + target_dict = pymake.usgs_program_data.get_target(target) - pm.download_target(pm.target, download_path=download_pth, verify=False) + pymake.download_and_unzip( + target_dict["url"], + pth=download_pth, + verbose=True, + ) - # Set MODFLOW 6 to compile develop version of the release + # update IDEVELOP MODE in the release srcpth = os.path.join( download_pth, target_dict["dirname"], target_dict["srcdir"] ) fpth = os.path.join(srcpth, "Utilities", "version.f90") with open(fpth) as f: lines = f.read().splitlines() - - assert len(lines) > 0, "could not update {}".format(srcpth) + assert len(lines) > 0, f"could not update {srcpth}" f = open(fpth, "w") for line in lines: tag = "IDEVELOPMODE = 0" if tag in line: line = line.replace(tag, "IDEVELOPMODE = 1") - f.write("{}\n".format(line)) + f.write(f"{line}\n") f.close() - # reset compiler based on environmental variable, if defined - pm.fc = get_compiler_envvar(pm.fc) - - # add strict flags if gfortran is being used - if pm.fc == "gfortran": - pm.fflags = strict_flags - - # build the release version of MODFLOW 6 - pm.build() - - msg = "{} does not exist.".format(pm.target) - assert pm.returncode == 0, msg - - # finalize the build - pm.finalize() + # build release source files with Meson + root_path = os.path.join(download_pth, target_dict["dirname"]) + meson_build(dir_path=root_path, libdir=os.path.abspath(rebuilt_bindir)) def test_create_dirs(): @@ -105,16 +97,18 @@ def test_create_dirs(): create_dir(pth) +@flaky(max_runs=3) def test_getmfexes(verify=True): pymake.getmfexes(mfexe_pth, verify=verify) for target in os.listdir(mfexe_pth): srcpth = os.path.join(mfexe_pth, target) if os.path.isfile(srcpth): dstpth = os.path.join(downloaded_bindir, target) - print("copying {} -> {}".format(srcpth, dstpth)) + print(f"copying {srcpth} -> {dstpth}") shutil.copy(srcpth, dstpth) +@flaky(max_runs=3) def test_rebuild_mf6_release(): rebuild_mf6_release() @@ -122,3 +116,4 @@ def test_rebuild_mf6_release(): if __name__ == "__main__": test_create_dirs() test_getmfexes(verify=False) + test_rebuild_mf6_release() diff --git a/autotest/simulation.py b/autotest/simulation.py index 69b2ecf8018..d9eb0b7cdb6 100644 --- a/autotest/simulation.py +++ b/autotest/simulation.py @@ -1,7 +1,8 @@ import os -import sys import shutil +import sys import time + import numpy as np try: @@ -56,9 +57,9 @@ def __init__( exe0 = targets.target_dict[key] exe = os.path.join(os.path.dirname(exe0), sys.argv[idx + 1]) msg = ( - "replacing {} executable ".format(key) - + '"{}" with '.format(targets.target_dict[key]) - + '"{}".'.format(exe) + f"replacing {key} executable " + + f'"{targets.target_dict[key]}" with ' + + f'"{exe}".' ) print(msg) targets.target_dict[key] = exe @@ -73,9 +74,9 @@ def __init__( exe0 = targets.target_dict[key] exe = os.path.join(os.path.dirname(exe0), value) msg = ( - "replacing {} executable ".format(key) - + '"{}" with '.format(targets.target_dict[key]) - + '"{}".'.format(exe) + f"replacing {key} executable " + + f'"{targets.target_dict[key]}" with ' + + f'"{exe}".' ) print(msg) targets.target_dict[key] = exe @@ -150,7 +151,7 @@ def set_model(self, pth, testModel=True): """ # make sure this is a valid path if not os.path.isdir(pth): - assert False, "{} is not a valid directory".format(pth) + assert False, f"{pth} is not a valid directory" self.simpath = pth @@ -177,7 +178,7 @@ def setup(self, src, dst): # write message print( "running pymake.setup_mf6 from " - + "{}".format(os.path.abspath(os.getcwd())) + + f"{os.path.abspath(os.getcwd())}" ) try: self.inpt, self.outp = pymake.setup_mf6(src=src, dst=dst) @@ -186,8 +187,8 @@ def setup(self, src, dst): success = True except: success = False - print("source: {}".format(src)) - print("destination: {}".format(dst)) + print(f"source: {src}") + print(f"destination: {dst}") assert success, "did not run pymake.setup_mf6" if success: @@ -197,6 +198,10 @@ def setup(self, src, dst): def setup_comparison(self, src, dst, testModel=True): + # evaluate if comparison should be made + if not self.make_comparison: + return + # adjust htol if it is smaller than IMS outer_dvclose dvclose = self._get_dvclose(dst) if dvclose is not None: @@ -421,7 +426,7 @@ def compare(self): pth = os.path.join(cpth, files_cmp[idx]) files2.append(pth) txt = sfmt.format( - "Comparison file {}".format(ipos + 1), + f"Comparison file {ipos + 1}", os.path.basename(pth), ) print(txt) @@ -462,7 +467,7 @@ def compare(self): exfile = exfiles[ipos] if exfile is not None: txt = sfmt.format( - "Exclusion file {}".format(ipos + 1), + f"Exclusion file {ipos + 1}", os.path.basename(exfile), ) print(txt) @@ -483,7 +488,7 @@ def compare(self): exfile=exfile, ) msg = sfmt.format( - "{} comparison {}".format(extdict[ext], ipos + 1), + f"{extdict[ext]} comparison {ipos + 1}", self.name, ) print(msg) @@ -551,7 +556,7 @@ def _get_mfsim_listing(self, lst_pth): i0 = 0 for line in lines[i0:]: if len(line) > 0: - msg += "{}\n".format(line) + msg += f"{line}\n" msg += 79 * "-" + "\n\n" return msg @@ -628,7 +633,7 @@ def _compare_heads(self, msgall, extensions="hds"): for idx, (fpth0, fpth1) in enumerate(zip(files0, files1)): outfile = os.path.splitext(os.path.basename(fpth0))[0] outfile = os.path.join( - self.simpath, outfile + ".{}.cmp.out".format(extension) + self.simpath, outfile + f".{extension}.cmp.out" ) success_tst = pymake.compare_heads( None, @@ -642,8 +647,8 @@ def _compare_heads(self, msgall, extensions="hds"): verbose=self.cmp_verbose, ) msg = sfmt.format( - "{} comparison {}".format(extdict[extension], ipos + 1), - "{} ({})".format(self.name, os.path.basename(fpth0)), + f"{extdict[extension]} comparison {ipos + 1}", + f"{self.name} ({os.path.basename(fpth0)})", ) ipos += 1 print(msg) @@ -664,7 +669,7 @@ def _compare_concentrations(self, msgall, extensions="ucn"): for idx, (fpth0, fpth1) in enumerate(zip(files0, files1)): outfile = os.path.splitext(os.path.basename(fpth0))[0] outfile = os.path.join( - self.simpath, outfile + ".{}.cmp.out".format(extension) + self.simpath, outfile + f".{extension}.cmp.out" ) success_tst = pymake.compare_heads( None, @@ -678,8 +683,8 @@ def _compare_concentrations(self, msgall, extensions="ucn"): verbose=self.cmp_verbose, ) msg = sfmt.format( - "{} comparison {}".format(extdict[extension], ipos + 1), - "{} ({})".format(self.name, os.path.basename(fpth0)), + f"{extdict[extension]} comparison {ipos + 1}", + f"{self.name} ({os.path.basename(fpth0)})", ) ipos += 1 print(msg) @@ -702,7 +707,7 @@ def _compare_budgets(self, msgall, extensions="cbc"): continue outfile = os.path.splitext(os.path.basename(fpth0))[0] outfile = os.path.join( - self.simpath, outfile + ".{}.cmp.out".format(extension) + self.simpath, outfile + f".{extension}.cmp.out" ) fcmp = open(outfile, "w") @@ -763,21 +768,21 @@ def _compare_budgets(self, msgall, extensions="cbc"): if diffmax > vmin_tol: success_tst = False msg = ( - "{} - ".format(os.path.basename(fpth0)) - + "{:16s} ".format(key) - + "difference ({:10.4g}) ".format(diffmax) - + "> {:10.4g} ".format(self.pdtol) - + "at {} nodes ".format(indices.size) - + " [first location ({})] ".format(indices[0] + 1) - + "at time {} ".format(t) + f"{os.path.basename(fpth0)} - " + + f"{key:16s} " + + f"difference ({diffmax:10.4g}) " + + f"> {self.pdtol:10.4g} " + + f"at {indices.size} nodes " + + f" [first location ({indices[0] + 1})] " + + f"at time {t} " ) - fcmp.write("{}\n".format(msg)) + fcmp.write(f"{msg}\n") if self.cmp_verbose: print(msg) msg = sfmt.format( - "{} comparison {}".format(extdict[extension], ipos + 1), - "{} ({})".format(self.name, os.path.basename(fpth0)), + f"{extdict[extension]} comparison {ipos + 1}", + f"{self.name} ({os.path.basename(fpth0)})", ) ipos += 1 print(msg) diff --git a/autotest/targets.py b/autotest/targets.py index af450405813..9202f39a3bf 100644 --- a/autotest/targets.py +++ b/autotest/targets.py @@ -1,6 +1,7 @@ import os -import sys import subprocess +import sys + import flopy @@ -35,38 +36,38 @@ def target_pth(target, pth): # create dictionary of valid executable targets for regression tests target_dict = {} -target = target_pth("mf2005dbl{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mf2005dbl{target_ext}", downloaded_bindir) target_dict["mf2005"] = target -target = target_pth("mfnwtdbl{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mfnwtdbl{target_ext}", downloaded_bindir) target_dict["mfnwt"] = target -target = target_pth("mfusgdbl{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mfusgdbl{target_ext}", downloaded_bindir) target_dict["mfusg"] = target -target = target_pth("mflgrdbl{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mflgrdbl{target_ext}", downloaded_bindir) target_dict["mflgr"] = target -target = target_pth("mf2005{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mf2005{target_ext}", downloaded_bindir) target_dict["mf2005s"] = target -target = target_pth("mt3dms{}".format(target_ext), downloaded_bindir) +target = target_pth(f"mt3dms{target_ext}", downloaded_bindir) target_dict["mt3dms"] = target -target = target_pth("mf6{}".format(target_ext), rebuilt_bindir) +target = target_pth(f"mf6{target_ext}", rebuilt_bindir) target_dict["mf6-regression"] = target # create MODFLOW 6 target name and add to dictionary -program = "mf6{}".format(target_ext) +program = f"mf6{target_ext}" target = os.path.join(bindir, program) target_dict["mf6"] = target # create MODFLOW 6 so/dll target name -tprog = "libmf6{}".format(target_so) +tprog = f"libmf6{target_so}" ttarg = os.path.join(bindir, tprog) target_dict["libmf6"] = ttarg # add MODFLOW 5 to 6 converter to dictionary of valid executable targets -tprog = "mf5to6{}".format(target_ext) +tprog = f"mf5to6{target_ext}" ttarg = os.path.join(bindir, tprog) target_dict["mf5to6"] = ttarg # add Zonebudget for 6 to dictionary of valid executable targets -tprog = "zbud6{}".format(target_ext) +tprog = f"zbud6{target_ext}" ttarg = os.path.join(bindir, tprog) target_dict["zbud6"] = ttarg @@ -80,7 +81,7 @@ def run_exe(argv, ws="."): if result is not None: c = result.decode("utf-8") c = c.rstrip("\r\n") - print("{}".format(c)) + print(f"{c}") buff.append(c) return proc.returncode, buff diff --git a/autotest/test_gwf_ats01.py b/autotest/test_gwf_ats01.py index 58bbed466d2..be62b72fdea 100644 --- a/autotest/test_gwf_ats01.py +++ b/autotest/test_gwf_ats01.py @@ -4,8 +4,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -70,16 +71,6 @@ def build_model(idx, dir): # create tdis package ats_filerecord = None - if True: - atsperiod = [ - (0, dt0, dtmin, dtmax, dtadj, dtfailadj), - (7, dt0, dtmin, dtmax, dtadj, dtfailadj), - ] - ats = flopy.mf6.ModflowUtlats( - sim, maxats=len(atsperiod), perioddata=atsperiod - ) - ats_filerecord = name + ".ats" - tdis = flopy.mf6.ModflowTdis( sim, ats_filerecord=ats_filerecord, @@ -87,6 +78,17 @@ def build_model(idx, dir): nper=nper, perioddata=tdis_rc, ) + if True: + ats_filerecord = name + ".ats" + atsperiod = [ + (0, dt0, dtmin, dtmax, dtadj, dtfailadj), + (7, dt0, dtmin, dtmax, dtadj, dtfailadj), + ] + tdis.ats.initialize( + maxats=len(atsperiod), + perioddata=atsperiod, + filename=ats_filerecord, + ) # create gwf model gwfname = name @@ -114,7 +116,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -175,8 +177,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -185,7 +187,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) obs_lst.append(["obs2", "head", (0, 0, 1)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -200,30 +202,30 @@ def eval_flow(sim): gwfname = name # This will fail if budget numbers cannot be read - fpth = os.path.join(sim.simpath, "{}.lst".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.lst") mflist = flopy.utils.Mf6ListBudget(fpth) names = mflist.get_record_names() inc = mflist.get_incremental() - msg = "budget times not monotically increasing {}.".format(inc["totim"]) + msg = f"budget times not monotically increasing {inc['totim']}." assert np.all(np.diff(inc["totim"]) > dtmin), msg v = inc["totim"][-1] - assert v == 10.0, "Last time should be 10. Found {}".format(v) + assert v == 10.0, f"Last time should be 10. Found {v}" # ensure obs results changing monotonically fpth = os.path.join(sim.simpath, gwfname + ".obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' - msg = "obs times not monotically increasing {}.".format(tc["time"]) + msg = f"obs times not monotically increasing {tc['time']}." assert np.all(np.diff(tc["time"]) > dtmin), msg for obsname in ["OBS1", "OBS2"]: v = tc[obsname] - msg = "{} not monotically decreasing: {}.".format(obsname, v) + msg = f"{obsname} not monotically decreasing: {v}." assert np.all(np.diff(v) < 0), msg v = tc["time"][-1] - assert v == 10.0, "Last time should be 10. Found {}".format(v) + assert v == 10.0, f"Last time should be 10. Found {v}" return @@ -256,7 +258,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ats02.py b/autotest/test_gwf_ats02.py index 005d46b1fb5..eea0c7c2fdd 100644 --- a/autotest/test_gwf_ats02.py +++ b/autotest/test_gwf_ats02.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -70,24 +71,24 @@ def build_model(idx, dir): ) # create tdis package - ats_filerecord = None - if True: - atsperiod = [ - (i, dt0, dtmin, dtmax, dtadj, dtfailadj) for i in range(nper) - ] - ats = flopy.mf6.ModflowUtlats( - sim, maxats=len(atsperiod), perioddata=atsperiod - ) - ats_filerecord = name + ".ats" - tdis = flopy.mf6.ModflowTdis( sim, - ats_filerecord=ats_filerecord, time_units="DAYS", nper=nper, perioddata=tdis_rc, ) + if True: + ats_filerecord = name + ".ats" + atsperiod = [ + (i, dt0, dtmin, dtmax, dtadj, dtfailadj) for i in range(nper) + ] + tdis.ats.initialize( + maxats=len(atsperiod), + perioddata=atsperiod, + filename=ats_filerecord, + ) + # create gwf model gwfname = name # newtonoptions = "NEWTON UNDER_RELAXATION" @@ -114,7 +115,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -173,8 +174,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -183,7 +184,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) obs_lst.append(["obs2", "head", (4, 0, 0)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -221,7 +222,7 @@ def make_plot(sim): marker="o", ls="-", color=botline.get_color(), - label="Layer {}".format(ilay + 1), + label=f"Layer {ilay + 1}", ) plt.legend() plt.show() @@ -237,21 +238,21 @@ def eval_flow(sim): make_plot(sim) # This will fail if budget numbers cannot be read - fpth = os.path.join(sim.simpath, "{}.lst".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.lst") mflist = flopy.utils.Mf6ListBudget(fpth) names = mflist.get_record_names() inc = mflist.get_incremental() - msg = "budget times not monotically increasing {}.".format(inc["totim"]) + msg = f"budget times not monotically increasing {inc['totim']}." assert np.all(np.diff(inc["totim"]) > dtmin), msg v = inc["totim"][-1] - assert v == 20.0, "Last time should be 20. Found {}".format(v) + assert v == 20.0, f"Last time should be 20. Found {v}" # ensure obs results changing monotonically fpth = os.path.join(sim.simpath, gwfname + ".obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # ensure layer 1 is dry with the DRY value assert ( np.max(tc["OBS1"][:201]) == -1.0e30 @@ -289,7 +290,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ats03.py b/autotest/test_gwf_ats03.py index 92a7817a015..8c4ee64715f 100644 --- a/autotest/test_gwf_ats03.py +++ b/autotest/test_gwf_ats03.py @@ -11,8 +11,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -75,21 +76,20 @@ def build_model(idx, dir): dtmax = 100.0 dtadj = 2.0 dtfailadj = 5.0 - ats_filerecord = None - if True: - atsperiod = [(0, dt0, dtmin, dtmax, dtadj, dtfailadj)] - ats = flopy.mf6.ModflowUtlats( - sim, maxats=len(atsperiod), perioddata=atsperiod - ) - ats_filerecord = name + ".ats" - tdis = flopy.mf6.ModflowTdis( sim, - ats_filerecord=ats_filerecord, time_units="DAYS", nper=nper, perioddata=tdis_rc, ) + if True: + ats_filerecord = name + ".ats" + atsperiod = [(0, dt0, dtmin, dtmax, dtadj, dtfailadj)] + tdis.ats.initialize( + maxats=len(atsperiod), + perioddata=atsperiod, + filename=ats_filerecord, + ) # create gwf model gwfname = name @@ -117,7 +117,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -193,8 +193,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -203,7 +203,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) obs_lst.append(["obs2", "head", (0, 0, ncol - 1)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -222,11 +222,11 @@ def eval_flow(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' x = np.array(tc["time"]) answer = 100.0 - x * 0.5 result = np.array(tc["OBS2"]) - msg = "obs2 must drop linearly from 100 down to 50: {}".format(result) + msg = f"obs2 must drop linearly from 100 down to 50: {result}" assert np.allclose(answer, result), msg @@ -259,7 +259,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ats_lak01.py b/autotest/test_gwf_ats_lak01.py index 2213eb338b3..f362b79a298 100644 --- a/autotest/test_gwf_ats_lak01.py +++ b/autotest/test_gwf_ats_lak01.py @@ -3,9 +3,10 @@ # a smaller time step. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -75,26 +76,27 @@ def build_model(idx, dir): dtmax = 10.0 dtadj = 2.0 dtfailadj = 5.0 - ats_filerecord = None - if True: - atsperiod = [ - (0, dt0, dtmin, dtmax, dtadj, dtfailadj), - (7, dt0, dtmin, dtmax, dtadj, dtfailadj), - ] - ats = flopy.mf6.ModflowUtlats( - sim, maxats=len(atsperiod), perioddata=atsperiod - ) - ats_filerecord = name + ".ats" # create tdis package tdis = flopy.mf6.ModflowTdis( sim, - ats_filerecord=ats_filerecord, time_units="DAYS", nper=nper, perioddata=tdis_rc, ) + if True: + ats_filerecord = name + ".ats" + atsperiod = [ + (0, dt0, dtmin, dtmax, dtadj, dtfailadj), + (7, dt0, dtmin, dtmax, dtadj, dtfailadj), + ] + tdis.ats.initialize( + maxats=len(atsperiod), + perioddata=atsperiod, + filename=ats_filerecord, + ) + # create gwf model gwfname = name global gwf @@ -113,7 +115,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) # number of columns to be a lake for layer 1, 2, , ... len(lakend) @@ -181,7 +183,7 @@ def build_model(idx, dir): ] # note: for specifying lake number, use fortran indexing! - fname = "{}.lak.obs.csv".format(gwfname) + fname = f"{gwfname}.lak.obs.csv" lak_obs = { fname: [ ("lakestage", "stage", 1), @@ -198,8 +200,8 @@ def build_model(idx, dir): print_input=True, print_flows=True, print_stage=True, - stage_filerecord="{}.lak.bin".format(gwfname), - budget_filerecord="{}.lak.bud".format(gwfname), + stage_filerecord=f"{gwfname}.lak.bin", + budget_filerecord=f"{gwfname}.lak.bud", nlakes=len(pak_data), ntables=0, packagedata=pak_data, @@ -221,8 +223,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -247,7 +249,7 @@ def make_plot_xsect(sim, headall, stageall): fig = plt.figure(figsize=(8, 4)) for ifig, itime in enumerate(itimes): - print("processing {} of {}".format(ifig + 1, nplots)) + print(f"processing {ifig + 1} of {nplots}") ax = fig.add_subplot(nplots, 1, ifig + 1, aspect="equal") stage = stageall[itime].flatten() xmin = 0 @@ -333,9 +335,9 @@ def eval_results(sim): all_passed = True for itime, t in enumerate(times): - print("processing totim {}".format(t)) + print(f"processing totim {t}") stage_current = stage[itime].flatten() - print("lake stage = {}".format(stage_current)) + print(f"lake stage = {stage_current}") qlakleak = np.zeros(idomain.shape, dtype=float).flatten() ilak = np.zeros(idomain.shape, dtype=int).flatten() @@ -465,7 +467,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_auxvars.py b/autotest/test_gwf_auxvars.py index c20eae4ff6c..8a7704586a7 100644 --- a/autotest/test_gwf_auxvars.py +++ b/autotest/test_gwf_auxvars.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -119,7 +120,7 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # MAW @@ -129,7 +130,7 @@ def build_model(idx, dir): wellperiodrecarray = [[0, "rate", -0.1]] maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(name), + filename=f"{name}.maw", print_input=True, print_head=True, print_flows=True, @@ -250,12 +251,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -348,7 +349,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_auxvars02.py b/autotest/test_gwf_auxvars02.py index 5fd43f23e99..80a38bc6fa3 100644 --- a/autotest/test_gwf_auxvars02.py +++ b/autotest/test_gwf_auxvars02.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -114,12 +115,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.bud", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -169,7 +170,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_boundname01.py b/autotest/test_gwf_boundname01.py index cb837fe06e9..d53c5852ce5 100644 --- a/autotest/test_gwf_boundname01.py +++ b/autotest/test_gwf_boundname01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -151,8 +152,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -239,7 +240,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_buy_lak01.py b/autotest/test_gwf_buy_lak01.py index beb317bf51c..0b9a7a8c668 100644 --- a/autotest/test_gwf_buy_lak01.py +++ b/autotest/test_gwf_buy_lak01.py @@ -10,9 +10,10 @@ # 3. Buoyancy package with lake and aquifer density = 1024.5 import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -168,7 +169,7 @@ def build_model(idx, dir): ] # note: for specifying lake number, use fortran indexing! - fname = "{}.lak.obs.csv".format(gwfname) + fname = f"{gwfname}.lak.obs.csv" lak_obs = { fname: [ ("lakestage", "stage", 1), @@ -194,8 +195,8 @@ def build_model(idx, dir): print_input=True, print_flows=True, print_stage=True, - stage_filerecord="{}.lak.bin".format(gwfname), - budget_filerecord="{}.lak.bud".format(gwfname), + stage_filerecord=f"{gwfname}.lak.bin", + budget_filerecord=f"{gwfname}.lak.bud", nlakes=len(pak_data), ntables=0, packagedata=pak_data, @@ -209,8 +210,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -246,7 +247,7 @@ def eval_results(sim): v0 += 1.0 * 1 # middle column v0 = v0 * 0.3 # specific yield v0 = v0 + (2.25 - 2.0) * 2 + (2.25 - 1.0) - print("initial volume of water in model = {}".format(v0)) + print(f"initial volume of water in model = {v0}") # calculate ending water volume in model h = head[0, 0, 0] @@ -254,10 +255,10 @@ def eval_results(sim): v = h * 4 + 2.0 * 2 + 1.0 * 1 v = v * 0.3 # specific yield v = v + (s - 2.0) * 2 + (s - 1.0) - print("final volume of water in model = {}".format(v)) + print(f"final volume of water in model = {v}") # check to make sure starting water volume same as equalized final volume - errmsg = "initial and final water volume not equal: {} {}".format(v0, v) + errmsg = f"initial and final water volume not equal: {v0} {v}" assert np.allclose(v0, v) # todo: add a better check of the lake concentrations @@ -293,7 +294,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_buy_lak02.py b/autotest/test_gwf_buy_lak02.py index 8554c886970..86a8a094e64 100644 --- a/autotest/test_gwf_buy_lak02.py +++ b/autotest/test_gwf_buy_lak02.py @@ -12,9 +12,10 @@ # 4. lak has concentration of 35., aquifer is 0. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -88,12 +89,12 @@ def build_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -167,7 +168,7 @@ def build_model(idx, dir): ] # note: for specifying lake number, use fortran indexing! - fname = "{}.lak.obs.csv".format(gwfname) + fname = f"{gwfname}.lak.obs.csv" lak_obs = { fname: [ ("lakestage", "stage", 1), @@ -193,8 +194,8 @@ def build_model(idx, dir): print_input=True, print_flows=True, print_stage=True, - stage_filerecord="{}.lak.bin".format(gwfname), - budget_filerecord="{}.lak.bud".format(gwfname), + stage_filerecord=f"{gwfname}.lak.bin", + budget_filerecord=f"{gwfname}.lak.bud", nlakes=len(pak_data), ntables=0, packagedata=pak_data, @@ -208,8 +209,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -229,12 +230,12 @@ def build_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -289,8 +290,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -306,7 +307,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -356,8 +357,8 @@ def eval_results(sim): vl0 = (2.25 - 2.0) * 2 + (2.25 - 1.0) m0 += vl0 * lak_conc_list[sim.idxsim] v0 += vl0 - print("initial volume of water in model = {}".format(v0)) - print("initial mass of solute in model = {}".format(m0)) + print(f"initial volume of water in model = {v0}") + print(f"initial mass of solute in model = {m0}") # calculate ending water volume in model head = np.where(head > 1e10, -1e10, head) @@ -379,15 +380,15 @@ def eval_results(sim): vl = (s - 2.0) * 2 + (s - 1.0) v = v + vl m += vl * clak[0] - print("final volume of water in model = {}".format(v)) - print("final mass of solute in model = {}".format(m)) + print(f"final volume of water in model = {v}") + print(f"final mass of solute in model = {m}") # check to make sure starting water volume same as equalized final volume - errmsg = "initial and final water volume not equal: {} {}".format(v0, v) + errmsg = f"initial and final water volume not equal: {v0} {v}" assert np.allclose(v0, v), errmsg # check to make sure starting starting solute mass same as equalized solute mass - errmsg = "initial and final solute mass not equal: {} {}".format(m0, m) + errmsg = f"initial and final solute mass not equal: {m0} {m}" assert np.allclose(m0, m), errmsg # todo: add a better check of the lake concentrations @@ -425,7 +426,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_buy_maw01.py b/autotest/test_gwf_buy_maw01.py index 8bd38153767..72887e337d7 100644 --- a/autotest/test_gwf_buy_maw01.py +++ b/autotest/test_gwf_buy_maw01.py @@ -10,9 +10,10 @@ # 3. Buoyancy package with maw and aquifer density = 1024.5 import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -93,7 +94,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -155,8 +156,8 @@ def build_model(idx, dir): print_head=True, print_flows=True, save_flows=True, - head_filerecord="{}.maw.bin".format(gwfname), - budget_filerecord="{}.maw.bud".format(gwfname), + head_filerecord=f"{gwfname}.maw.bin", + budget_filerecord=f"{gwfname}.maw.bud", packagedata=mawpackagedata, connectiondata=mawconnectiondata, perioddata=mawperioddata, @@ -167,8 +168,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -234,9 +235,7 @@ def eval_results(sim): vgwf += 0.3 * max(0.0, dz) vmaw = stage[kstp] * np.pi * 0.1**2 vnow = vmaw + vgwf - errmsg = "kstp {}: current volume ({}) not equal initial volume ({})".format( - kstp, v0, vnow - ) + errmsg = f"kstp {kstp}: current volume ({v0}) not equal initial volume ({vnow})" assert np.allclose(v0, vnow), errmsg # compare the maw-gwf flows in maw budget file with the gwf-maw flows in @@ -259,9 +258,7 @@ def eval_results(sim): for i in range(ra_maw.shape[0]): qmaw = ra_maw[i]["q"] qgwf = ra_gwf[i]["q"] - msg = "step {} record {} comparing qmaw with qgwf: {} {}".format( - istp, i, qmaw, qgwf - ) + msg = f"step {istp} record {i} comparing qmaw with qgwf: {qmaw} {qgwf}" print(msg) assert np.allclose(qmaw, -qgwf), msg @@ -297,7 +294,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_buy_sfr01.py b/autotest/test_gwf_buy_sfr01.py index f447ffefb42..73749476ff3 100644 --- a/autotest/test_gwf_buy_sfr01.py +++ b/autotest/test_gwf_buy_sfr01.py @@ -2,9 +2,10 @@ # one-d sfr network. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -74,7 +75,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -137,7 +138,7 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # wel files @@ -152,7 +153,7 @@ def build_model(idx, dir): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # pak_data = [ [] []] @@ -230,8 +231,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -242,7 +243,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -259,7 +260,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -279,18 +280,18 @@ def build_model(idx, dir): ic = flopy.mf6.ModflowGwtic( gwt, strt=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - filename="{}.ic".format(gwtname), + filename=f"{gwtname}.ic", ) # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 1.0 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -298,7 +299,7 @@ def build_model(idx, dir): ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # cnc files @@ -315,15 +316,14 @@ def build_model(idx, dir): sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [(0, "STATUS", "CONSTANT"), (0, "CONCENTRATION", 100.0)] sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -362,8 +362,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -377,7 +377,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -433,7 +433,7 @@ def eval_results(sim): b = bobj.get_data(text="AUXILIARY") b = b[-1] b = b["CONCENTRATION"] - errmsg = "SFR aux conc not equal to SFT sim conc\n{}\n{}".format(b, csft) + errmsg = f"SFR aux conc not equal to SFT sim conc\n{b}\n{csft}" assert np.allclose(b, csft), errmsg # load the sfr stage file @@ -466,7 +466,7 @@ def eval_results(sim): # print('reach {} flow {} not equal {}'.format(n, qcalc, qsim)) assert np.allclose( qcalc, qsim - ), "reach {} flow {} not equal {}".format(n, qcalc, qsim) + ), f"reach {n} flow {qcalc} not equal {qsim}" # uncomment when testing # assert False @@ -503,7 +503,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_chd01.py b/autotest/test_gwf_chd01.py index 3a9e71e06d6..8f3bbf79a40 100644 --- a/autotest/test_gwf_chd01.py +++ b/autotest/test_gwf_chd01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -104,13 +105,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -130,8 +129,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -146,12 +145,12 @@ def eval_model(sim): name = ex[sim.idxsim] gwfname = "gwf_" + name - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_data().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. hres = np.linspace(1, 0, 100) @@ -194,7 +193,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_db01_nr.py b/autotest/test_gwf_csub_db01_nr.py index 5e5aa7832d6..1e19d128f54 100644 --- a/autotest/test_gwf_csub_db01_nr.py +++ b/autotest/test_gwf_csub_db01_nr.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ( @@ -171,7 +172,7 @@ def build_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration=imsla, scaling_method="NONE", reordering_method="NONE", @@ -237,7 +238,7 @@ def build_model(idx, dir): ) # create chd time series - chnam = "{}.ch.ts".format(name) + chnam = f"{name}.ch.ts" chd_ts = [ (0.0, strt), (tsp0, strt), @@ -276,7 +277,7 @@ def build_model(idx, dir): obsarr = [] for iobs, cobs in enumerate(obstype): for jobs, otup in enumerate(obspos): - otag = "{}{}".format(obstag[iobs], jobs + 1) + otag = f"{obstag[iobs]}{jobs + 1}" obsarr.append((otag, cobs, otup)) obsloc = [ (0, 0), @@ -338,8 +339,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -355,12 +356,10 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -372,9 +371,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -394,41 +391,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -479,7 +476,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_dbgeo01.py b/autotest/test_gwf_csub_dbgeo01.py index 368e457c6da..c0e0dd9678b 100644 --- a/autotest/test_gwf_csub_dbgeo01.py +++ b/autotest/test_gwf_csub_dbgeo01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -10,7 +11,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_dbgeo01a"] @@ -261,13 +262,11 @@ def build_model(idx, dir): delc=delc, top=top, botm=bots, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt[idx], filename="{}.ic".format(name) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt[idx], filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -290,9 +289,9 @@ def build_model(idx, dir): ) # csub files - opth = "{}.csub.obs".format(name) - ibcsv = "{}.ib.strain.csv".format(name) - skcsv = "{}.sk.strain.csv".format(name) + opth = f"{name}.csub.obs" + ibcsv = f"{name}.ib.strain.csv" + skcsv = f"{name}.sk.strain.csv" csub = flopy.mf6.ModflowGwfcsub( gwf, print_input=True, @@ -323,8 +322,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -343,7 +342,7 @@ def eval_sub(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # set comparison data tc0 = compdata[sim.idxsim] @@ -352,29 +351,29 @@ def eval_sub(sim): diff = tc["TCOMP"] - tc0[:] diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0[i]) - line += " {:15g}".format(tc["TCOMP"][i]) - line += " {:15g}".format(tc0[i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0[i]:15g}" + line += f" {tc['TCOMP'][i]:15g}" + line += f" {tc0[i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -426,7 +425,7 @@ def main(): # use python testmf6_csub_sub01.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_inelastic.py b/autotest/test_gwf_csub_inelastic.py index 9d48f9adca6..c83b33fae4a 100644 --- a/autotest/test_gwf_csub_inelastic.py +++ b/autotest/test_gwf_csub_inelastic.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "csub" @@ -140,11 +141,11 @@ def build_mf6(idx, ws, update=None): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt6, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt6, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -165,7 +166,7 @@ def build_mf6(idx, ws, update=None): gwf, maxbound=len(c6), stress_period_data=cd6, save_flows=False ) # initialize time series - chnam = "{}.ch.ts".format(name) + chnam = f"{name}.ch.ts" chd.ts.initialize( filename=chnam, timeseries=chd_ts, @@ -174,7 +175,7 @@ def build_mf6(idx, ws, update=None): ) # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, print_input=True, @@ -203,8 +204,8 @@ def build_mf6(idx, ws, update=None): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("BUDGET", "ALL")], @@ -251,29 +252,29 @@ def eval_void(sim): diff = v - v2 diffmax = np.abs(diff).max() dtol = 0.002 - msg = "maximum absolute void ratio difference ({}) ".format(diffmax) + msg = f"maximum absolute void ratio difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("VOID") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'VOID':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(cd["time"][i]) - line += " {:15g}".format(v[i]) - line += " {:15g}".format(v[i]) - line += " {:15g}".format(diff[i]) + line = f"{cd['time'][i]:15g}" + line += f" {v[i]:15g}" + line += f" {v[i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -322,7 +323,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_ndb01_nr.py b/autotest/test_gwf_csub_ndb01_nr.py index e477fb35d84..9155a1d0260 100644 --- a/autotest/test_gwf_csub_ndb01_nr.py +++ b/autotest/test_gwf_csub_ndb01_nr.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ( @@ -171,7 +172,7 @@ def build_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration=imsla, scaling_method="NONE", reordering_method="NONE", @@ -233,7 +234,7 @@ def build_model(idx, dir): ) # create chd time series - chnam = "{}.ch.ts".format(name) + chnam = f"{name}.ch.ts" chd_ts = [ (0.0, strt), (tsp0, strt), @@ -266,7 +267,7 @@ def build_model(idx, dir): obsarr = [] for iobs, cobs in enumerate(obstype): for jobs, otup in enumerate(obspos): - otag = "{}{}".format(obstag[iobs], jobs + 1) + otag = f"{obstag[iobs]}{jobs + 1}" obsarr.append((otag, cobs, otup)) # csub files @@ -310,8 +311,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -327,12 +328,10 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -344,9 +343,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -366,41 +363,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -453,7 +450,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sk01.py b/autotest/test_gwf_csub_sk01.py index 20de193d0f2..168e941d93b 100644 --- a/autotest/test_gwf_csub_sk01.py +++ b/autotest/test_gwf_csub_sk01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_sk01a", "csub_sk01b", "csub_sk01c"] @@ -202,11 +203,11 @@ def get_model(idx, ws): delc=delc, top=tops[idx], botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -248,7 +249,7 @@ def get_model(idx, ws): gwf, maxbound=maxchd, stress_period_data=cd6, save_flows=False ) # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, head_based=True, @@ -264,7 +265,7 @@ def get_model(idx, ws): obsarr = [] for iobs, cobs in enumerate(obstype): for jobs, otup in enumerate(obspos): - otag = "{}{}".format(obstag[iobs], jobs + 1) + otag = f"{obstag[iobs]}{jobs + 1}" obsarr.append((otag, cobs, otup)) obsarr2 = [] @@ -285,7 +286,7 @@ def get_model(idx, ws): iobs = 0 for cobs in obstype2: iobs += 1 - otag = "obs{:03d}".format(iobs) + otag = f"obs{iobs:03d}" obsarr2.append((otag, cobs, (0,))) obstype3 = [ @@ -299,7 +300,7 @@ def get_model(idx, ws): ] for cobs in obstype3: iobs += 1 - otag = "obs{:03d}".format(iobs) + otag = f"obs{iobs:03d}" obsarr2.append((otag, cobs, (0,), (0,))) obsarr3 = [] @@ -320,7 +321,7 @@ def get_model(idx, ws): ] for cobs in obstype4: iobs += 1 - otag = "obs{:03d}".format(iobs) + otag = f"obs{iobs:03d}" obsarr3.append((otag, cobs, obspos[-1])) orecarray = {} @@ -335,8 +336,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -364,7 +365,7 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # regression compaction results cpth = cmppths[sim.idxsim] @@ -372,38 +373,36 @@ def eval_comp(sim): try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP3"] - tc0["TCOMP3"] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): - line = "{:10.2g}".format(tc0["time"][i]) - line += "{:10.2g}".format(tc["TCOMP3"][i]) - line += "{:10.2g}".format(tc0["TCOMP3"][i]) - line += "{:10.2g}".format(diff[i]) + line = f"{tc0['time'][i]:10.2g}" + line += f"{tc['TCOMP3'][i]:10.2g}" + line += f"{tc0['TCOMP3'][i]:10.2g}" + line += f"{diff[i]:10.2g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True print(" " + msg) # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -415,9 +414,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -437,41 +434,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -534,7 +531,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sk02.py b/autotest/test_gwf_csub_sk02.py index fb55a033219..d87765feed8 100644 --- a/autotest/test_gwf_csub_sk02.py +++ b/autotest/test_gwf_csub_sk02.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_sk02a", "csub_sk02b", "csub_sk02c", "csub_sk02d"] @@ -266,11 +267,11 @@ def get_model(idx, ws): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -311,7 +312,7 @@ def get_model(idx, ws): gwf, maxbound=maxchd, stress_period_data=cd6, save_flows=False ) # ibc files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, update_material_properties=ump[idx], @@ -339,8 +340,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -371,7 +372,7 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # comparision total compaction results cpth = cmppths[sim.idxsim] @@ -379,38 +380,36 @@ def eval_comp(sim): try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP3"] - tc0["TCOMP3"] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): - line = "{:10.2g}".format(tc0["time"][i]) - line += "{:10.2g}".format(tc["TCOMP3"][i]) - line += "{:10.2g}".format(tc0["TCOMP3"][i]) - line += "{:10.2g}".format(diff[i]) + line = f"{tc0['time'][i]:10.2g}" + line += f"{tc['TCOMP3'][i]:10.2g}" + line += f"{tc0['TCOMP3'][i]:10.2g}" + line += f"{diff[i]:10.2g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True print(" " + msg) # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -422,9 +421,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -444,41 +441,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -548,7 +545,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sk03.py b/autotest/test_gwf_csub_sk03.py index 8176fe5237d..ce7e9e7685c 100644 --- a/autotest/test_gwf_csub_sk03.py +++ b/autotest/test_gwf_csub_sk03.py @@ -1,7 +1,8 @@ +import datetime import os -import pytest + import numpy as np -import datetime +import pytest try: import pymake @@ -19,7 +20,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_sk03a"] @@ -132,7 +133,7 @@ tsnames = [] sig0 = [] for i in range(nrow): - tsname = "TLR{:02d}".format(i + 1) + tsname = f"TLR{i + 1:02d}" tsnames.append(tsname) sig0.append([(0, i, 0), tsname]) tsname = "FR" @@ -314,7 +315,7 @@ def get_model(idx, ws): ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -361,7 +362,7 @@ def get_model(idx, ws): ) # create chd time series - chnam = "{}.ch.ts".format(name) + chnam = f"{name}.ch.ts" chd_ts = [(0.0, strt), (1.0, strt), (perlen.sum(), finish)] # chd files @@ -378,100 +379,100 @@ def get_model(idx, ws): # create load time series file with load csub_ts = [] - csubnam = "{}.load.ts".format(name) + csubnam = f"{name}.load.ts" fopth = os.path.join(ws, "ts.csv") fo = open(fopth, "w") line2 = "TIME" for tsname in tsnames: - line2 += ",{}".format(tsname) - fo.write("{}\n".format(line2)) + line2 += f",{tsname}" + fo.write(f"{line2}\n") d = [0.0] - line = " {:12.6e}".format(0.0) + line = f" {0.0:12.6e}" dateon = datestart + datetime.timedelta(seconds=0) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for tsname in tsnames: d.append(0.0) line2 += ",0.0000" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") ton = 1.0 d = [ton] dateon = datestart + datetime.timedelta(seconds=ton) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for tsname in tsnames: d.append(0.0) line2 += ",0.0000" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") for i in range(tsv.shape[0]): ton = tstime[i] d = [ton] dateon = datestart + datetime.timedelta(seconds=ton) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for j in range(tsv.shape[1]): d.append(tsv[i, j]) - line2 += ",{:6.4f}".format(tsv[i, j]) + line2 += f",{tsv[i, j]:6.4f}" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") ton += 1 d = [ton] dateon = datestart + datetime.timedelta(seconds=ton) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for tsname in tsnames: if tsname == "FR": d.append(fcar1) - line2 += ",{:6.4f}".format(fcar1) + line2 += f",{fcar1:6.4f}" else: d.append(0.0) line2 += ",0.0000" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") ton += (i + 1.0) * 86400.0 d = [ton] dateon = datestart + datetime.timedelta(minutes=29) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for tsname in tsnames: if tsname == "FR": d.append(fcar1) - line2 += ",{:6.4f}".format(fcar1) + line2 += f",{fcar1:6.4f}" else: d.append(0.0) line2 += ",0.0000" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") ton = 100.0 * sec2day d = [ton] dateon = datestart + datetime.timedelta(minutes=30) datestr = dateon.strftime("%m/%d/%Y %H:%M:%S") - line2 = "{}".format(datestr) + line2 = f"{datestr}" for tsname in tsnames: if tsname == "FR": d.append(fcar1) - line2 += ",{:6.4f}".format(fcar1) + line2 += f",{fcar1:6.4f}" else: d.append(fcar1) line2 += ",0.0000" csub_ts.append(tuple(d)) - fo.write("{}\n".format(line2)) + fo.write(f"{line2}\n") # close ts,csv fo.close() # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, print_input=True, @@ -519,8 +520,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -552,12 +553,10 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -569,9 +568,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -591,41 +588,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -694,7 +691,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sk04_nr.py b/autotest/test_gwf_csub_sk04_nr.py index 760a348d874..5ba5545ee75 100644 --- a/autotest/test_gwf_csub_sk04_nr.py +++ b/autotest/test_gwf_csub_sk04_nr.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ( @@ -141,7 +142,7 @@ def build_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration=imsla, scaling_method="NONE", reordering_method="NONE", @@ -203,7 +204,7 @@ def build_model(idx, dir): ) # create chd time series - chnam = "{}.ch.ts".format(name) + chnam = f"{name}.ch.ts" chd_ts = [ (0.0, strt), (tsp0, strt), @@ -236,11 +237,11 @@ def build_model(idx, dir): obsarr = [] for iobs, cobs in enumerate(obstype): for jobs, otup in enumerate(obspos): - otag = "{}{}".format(obstag[iobs], jobs + 1) + otag = f"{obstag[iobs]}{jobs + 1}" obsarr.append((otag, cobs, otup)) # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, observations={"csub_obs.csv": obsarr}, @@ -258,8 +259,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -275,12 +276,10 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -292,9 +291,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -314,41 +311,41 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -401,7 +398,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub01.py b/autotest/test_gwf_csub_sub01.py index 93bf1d9b38b..5302a6ae736 100644 --- a/autotest/test_gwf_csub_sub01.py +++ b/autotest/test_gwf_csub_sub01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "csub" @@ -147,11 +148,11 @@ def get_model(idx, ws): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -208,8 +209,8 @@ def get_model(idx, ws): ] ] - opth = "{}.csub.obs".format(name) - cnvgpth = "{}.csub.cnvg.csv".format(name) + opth = f"{name}.csub.obs" + cnvgpth = f"{name}.csub.cnvg.csv" csub = flopy.mf6.ModflowGwfcsub( gwf, head_based=True, @@ -236,8 +237,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -267,42 +268,42 @@ def eval_sub(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # comparison total compaction results fpth = os.path.join(sim.simpath, "mf6-regression", "csub_obs.csv") try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP"] - tc0["TCOMP"] diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0["time"][i]) - line += " {:15g}".format(tc["TCOMP"][i]) - line += " {:15g}".format(tc0["TCOMP"][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0['time'][i]:15g}" + line += f" {tc['TCOMP'][i]:15g}" + line += f" {tc0['TCOMP'][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -317,9 +318,7 @@ def eval_sub(sim): # compare cbc and lst budgets def cbc_compare(sim): # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -332,13 +331,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -372,41 +369,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "diffmax {} exceeds tolerance {}".format(diffmax, budtol) + msg += f"diffmax {diffmax} exceeds tolerance {budtol}" assert diffmax < budtol, msg else: sim.success = True @@ -455,7 +452,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub01_adjmat.py b/autotest/test_gwf_csub_sub01_adjmat.py index eaeaf049135..de5c09ca06b 100644 --- a/autotest/test_gwf_csub_sub01_adjmat.py +++ b/autotest/test_gwf_csub_sub01_adjmat.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "csub" @@ -152,7 +153,7 @@ def get_model(idx, dir, adjustmat=False): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="bicgstab", scaling_method="NONE", reordering_method="NONE", @@ -169,11 +170,11 @@ def get_model(idx, dir, adjustmat=False): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -196,7 +197,7 @@ def get_model(idx, dir, adjustmat=False): ) # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, head_based=True, @@ -220,7 +221,7 @@ def get_model(idx, dir, adjustmat=False): ["delay-compaction", "delay-thickness", "delay-theta"] ): for n in range(ndcell[idx]): - tag = "{}{:02d}".format(tags[jdx], n + 1) + tag = f"{tags[jdx]}{n + 1:02d}" obs.append((tag, otype, (0, n))) orecarray = {} orecarray["csub_obs.csv"] = obs @@ -232,8 +233,8 @@ def get_model(idx, dir, adjustmat=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -259,42 +260,42 @@ def eval_sub(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 base compaction results fpth = os.path.join(sim.simpath, compdir, "csub_obs.csv") try: tcb = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP"] - tcb["TCOMP"] diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) - line += " {:15g}".format(tc["TCOMP"][i]) - line += " {:15g}".format(tcb["TCOMP"][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc['time'][i]:15g}" + line += f" {tc['TCOMP'][i]:15g}" + line += f" {tcb['TCOMP'][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {:15.7g}".format(dtol) + msg += f"exceeds {dtol:15.7g}" assert diffmax < dtol, msg else: sim.success = True @@ -312,12 +313,13 @@ def eval_sub(sim): for key in calc.dtype.names: diff = calc[key] - ovalsi[key] diffmax = np.abs(diff).max() - msg = "maximum absolute interbed {} ".format( - key - ) + "difference ({:15.7g}) ".format(diffmax) + msg = ( + "maximum absolute interbed {} ".format(key) + + f"difference ({diffmax:15.7g}) " + ) if diffmax > dtol: sim.success = False - msg += "exceeds {:15.7g}".format(dtol) + msg += f"exceeds {dtol:15.7g}" assert diffmax < dtol, msg else: sim.success = True @@ -327,9 +329,9 @@ def eval_sub(sim): calci = np.zeros((comp.shape[0]), dtype=dtype) thickini = 1.0 / ndcell[sim.idxsim] for n in range(ndcell[sim.idxsim]): - tagc = "DBCOMP{:02d}".format(n + 1) - tagb = "DBTHICK{:02d}".format(n + 1) - tagp = "DBPORO{:02d}".format(n + 1) + tagc = f"DBCOMP{n + 1:02d}" + tagb = f"DBTHICK{n + 1:02d}" + tagp = f"DBPORO{n + 1:02d}" comp = tc[tagc] ovals = np.zeros((comp.shape[0]), dtype=dtype) ovals["THICK"] = tc[tagb] @@ -341,12 +343,13 @@ def eval_sub(sim): for key in calc.dtype.names: diff = calc[key] - ovals[key] diffmax = np.abs(diff).max() - msg = "maximum absolute {}({}) difference ".format( - key, n + 1 - ) + "({:15.7g}) ".format(diffmax) + msg = ( + "maximum absolute {}({}) difference ".format(key, n + 1) + + f"({diffmax:15.7g}) " + ) if diffmax > dtol: sim.success = False - msg += "exceeds {:15.7g}".format(dtol) + msg += f"exceeds {dtol:15.7g}" assert diffmax < dtol, msg else: sim.success = True @@ -359,13 +362,14 @@ def eval_sub(sim): for key in calci.dtype.names: diff = calci[key] - ovalsi[key] diffmax = np.abs(diff).max() - msg = "maximum absolute interbed {} difference ".format( - key - ) + "({:15.7g}) ".format(diffmax) + msg = ( + "maximum absolute interbed {} difference ".format(key) + + f"({diffmax:15.7g}) " + ) msg += "calculated from individual interbed cell values " if diffmax > dtol: sim.success = False - msg += "exceeds {:15.7g}".format(dtol) + msg += f"exceeds {dtol:15.7g}" assert diffmax < dtol, msg else: sim.success = True @@ -380,9 +384,7 @@ def eval_sub(sim): # compare cbc and lst budgets def cbc_compare(sim): # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -395,13 +397,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -435,41 +435,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -522,7 +522,7 @@ def main(): # use python testmf6_csub_sub01.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub01_elastic.py b/autotest/test_gwf_csub_sub01_elastic.py index a5fa0ec40f6..baec5b1bfe5 100644 --- a/autotest/test_gwf_csub_sub01_elastic.py +++ b/autotest/test_gwf_csub_sub01_elastic.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation cmppth = "mf6" @@ -147,11 +148,11 @@ def build_mf6(idx, ws, newton=None): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -174,7 +175,7 @@ def build_mf6(idx, ws, newton=None): ) # csub files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, head_based=True, @@ -195,8 +196,8 @@ def build_mf6(idx, ws, newton=None): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -222,14 +223,14 @@ def eval_sub(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 with newton-raphson fpth = os.path.join(sim.simpath, cmppth, "csub_obs.csv") try: tci = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' diffmax = -1e20 tagmax = None @@ -240,33 +241,31 @@ def eval_sub(sim): diffmax = diffmaxt tagmax = tag - msg = "maximum compaction difference " + "({}) in tag: {}".format( - diffmax, tagmax - ) + msg = "maximum compaction difference " + f"({diffmax}) in tag: {tagmax}" # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") + line = f"{'TOTIM':>15s}" for tag in tc.dtype.names[1:]: - line += " {:>15s}".format("{}_SK".format(tag)) - line += " {:>15s}".format("{}_SKIB".format(tag)) - line += " {:>15s}".format("{}_DIFF".format(tag)) + line += f" {f'{tag}_SK':>15s}" + line += f" {f'{tag}_SKIB':>15s}" + line += f" {f'{tag}_DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) + line = f"{tc['time'][i]:15g}" for tag in tc.dtype.names[1:]: - line += " {:15g}".format(tc[tag][i]) - line += " {:15g}".format(tci[tag][i]) - line += " {:15g}".format(tc[tag][i] - tci[tag][i]) + line += f" {tc[tag][i]:15g}" + line += f" {tci[tag][i]:15g}" + line += f" {tc[tag][i] - tci[tag][i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -281,9 +280,7 @@ def eval_sub(sim): # compare cbc and lst budgets def cbc_compare(sim): # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -296,13 +293,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -336,41 +331,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -420,7 +415,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub01_pch.py b/autotest/test_gwf_csub_sub01_pch.py index 1de8a4fcb48..73632cf0efb 100644 --- a/autotest/test_gwf_csub_sub01_pch.py +++ b/autotest/test_gwf_csub_sub01_pch.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "csub" @@ -136,7 +137,7 @@ def get_model(idx, dir, pch=None): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="bicgstab", scaling_method="NONE", reordering_method="NONE", @@ -153,11 +154,11 @@ def get_model(idx, dir, pch=None): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -213,7 +214,7 @@ def get_model(idx, dir, pch=None): ] ] - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, initial_preconsolidation_head=pch, @@ -241,8 +242,8 @@ def get_model(idx, dir, pch=None): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -259,42 +260,42 @@ def eval_sub(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 base compaction results fpth = os.path.join(sim.simpath, compdir, "csub_obs.csv") try: tcb = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP"] - tcb["TCOMP"] diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) - line += " {:15g}".format(tc["TCOMP"][i]) - line += " {:15g}".format(tcb["TCOMP"][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc['time'][i]:15g}" + line += f" {tc['TCOMP'][i]:15g}" + line += f" {tcb['TCOMP'][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {:15.7g}".format(dtol) + msg += f"exceeds {dtol:15.7g}" assert diffmax < dtol, msg else: sim.success = True @@ -309,9 +310,7 @@ def eval_sub(sim): # compare cbc and lst budgets def cbc_compare(sim): # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -324,13 +323,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -364,41 +361,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -448,7 +445,7 @@ def main(): # use python testmf6_csub_sub01.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub02.py b/autotest/test_gwf_csub_sub02.py index cea635fabc5..858bfb6d241 100644 --- a/autotest/test_gwf_csub_sub02.py +++ b/autotest/test_gwf_csub_sub02.py @@ -1,4 +1,5 @@ import os + import pytest try: @@ -17,7 +18,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = [ @@ -158,7 +159,7 @@ def get_model(idx, ws): # create gwf model gwf = flopy.mf6.ModflowGwf( - sim, modelname=name, model_nam_file="{}.nam".format(name) + sim, modelname=name, model_nam_file=f"{name}.nam" ) dis = flopy.mf6.ModflowGwfdis( @@ -170,11 +171,11 @@ def get_model(idx, ws): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -217,8 +218,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -278,7 +279,7 @@ def main(): # use python test_gwf_csub_sub02.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_sub03.py b/autotest/test_gwf_csub_sub03.py index a8b7701370f..67b3ab36e5b 100644 --- a/autotest/test_gwf_csub_sub03.py +++ b/autotest/test_gwf_csub_sub03.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_sub03a", "csub_sub03b"] @@ -160,7 +161,7 @@ nz = [1, 1] dstart = [] for k in ldnd: - pth = os.path.join(ddir, "ibc03_dstart{}.ref".format(k + 1)) + pth = os.path.join(ddir, f"ibc03_dstart{k + 1}.ref") v = np.genfromtxt(pth) dstart.append(v.copy()) @@ -181,7 +182,7 @@ def get_model(idx, ws): # skip constant head cells if k == 0 and i == nrow - 1 and j in ccol: continue - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" # create nodelay entry # no delay beds b = thicknd0[kdx] @@ -213,7 +214,7 @@ def get_model(idx, ws): # skip constant head cells if k == 0 and i == nrow - 1 and j in ccol: continue - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" # create nodelay entry d = [ ibcno, @@ -281,11 +282,11 @@ def get_model(idx, ws): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -327,10 +328,10 @@ def get_model(idx, ws): gwf, maxbound=maxchd, stress_period_data=cd6, save_flows=False ) # csub files - opth = "{}.csub.obs".format(name) - ibcsv = "{}.ib.strain.csv".format(name) - skcsv = "{}.sk.strain.csv".format(name) - copth = "{}.compaction.gridbin".format(name) + opth = f"{name}.csub.obs" + ibcsv = f"{name}.ib.strain.csv" + skcsv = f"{name}.sk.strain.csv" + copth = f"{name}.compaction.gridbin" csub = flopy.mf6.ModflowGwfcsub( gwf, print_input=True, @@ -361,8 +362,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -389,32 +390,30 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Comparision total compaction results fpth = os.path.join(sim.simpath, cmppth, "csub_obs.csv") try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP3"] - tc0["TCOMP3"] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True print(" " + msg) # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -426,9 +425,7 @@ def eval_comp(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -445,20 +442,20 @@ def eval_comp(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -519,7 +516,7 @@ def main(): # use python test_gwf_csub_sub03.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_subwt01.py b/autotest/test_gwf_csub_subwt01.py index 3f2f730fa13..b4fb615e35c 100644 --- a/autotest/test_gwf_csub_subwt01.py +++ b/autotest/test_gwf_csub_subwt01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,7 +20,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_subwt01a", "csub_subwt01b", "csub_subwt01c", "csub_subwt01d"] @@ -128,7 +129,7 @@ if j == 1: iactive = 1 if iactive > 0: - tag = "{:02d}_{:02d}_{:02d}".format(1, i + 1, j + 1) + tag = f"{1:02d}_{i + 1:02d}_{j + 1:02d}" d = [ ibcno, (0, i, j), @@ -192,11 +193,11 @@ def get_model(idx, ws): top=top, botm=botm, idomain=ib, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -224,9 +225,9 @@ def get_model(idx, ws): for j in range(ncol): gg.append([(0, i, j), gs0[idx]]) sig0 = {0: gg} - opth = "{}.csub.obs".format(name) - fcgstrain = "{}.csub.strain.cg.csv".format(name) - fibstrain = "{}.csub.strain.ib.csv".format(name) + opth = f"{name}.csub.obs" + fcgstrain = f"{name}.csub.strain.cg.csv" + fibstrain = f"{name}.csub.strain.ib.csv" csub = flopy.mf6.ModflowGwfcsub( gwf, straincg_filerecord=fcgstrain, @@ -258,8 +259,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -288,7 +289,7 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Comparision total compaction results cpth = cmppth @@ -296,35 +297,35 @@ def eval_comp(sim): try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error loctag = "W1L1" diff = tc[loctag] - tc0[loctag] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0["time"][i]) - line += " {:15g}".format(tc[loctag][i]) - line += " {:15g}".format(tc0[loctag][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0['time'][i]:15g}" + line += f" {tc[loctag][i]:15g}" + line += f" {tc0[loctag][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -340,9 +341,7 @@ def eval_comp(sim): def cbc_compare(sim): print("evaluating cbc and budget...") # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -355,13 +354,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -395,41 +392,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -495,7 +492,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_subwt02.py b/autotest/test_gwf_csub_subwt02.py index c11663c0447..399390f0bdb 100644 --- a/autotest/test_gwf_csub_subwt02.py +++ b/autotest/test_gwf_csub_subwt02.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_subwt02a", "csub_subwt02b", "csub_subwt02c", "csub_subwt02d"] @@ -223,7 +224,7 @@ if i == 19 and (j == 7 or j == 8): iactive = 0 if iactive > 0: - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" d = [ ibcno, (k, i, j), @@ -284,11 +285,11 @@ def get_model(idx, ws): top=top, botm=botm, idomain=ib, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -344,7 +345,7 @@ def get_model(idx, ws): if ib0[i, j] > 0: gg.append([(0, i, j), sig0v]) sig0 = {0: gg} - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, # print_input=True, @@ -365,7 +366,7 @@ def get_model(idx, ws): stress_period_data=sig0, ) if timeseries[idx]: - fname = "{}.csub.ts".format(name) + fname = f"{name}.csub.ts" csub.ts.initialize( filename=fname, timeseries=ts_data, @@ -424,8 +425,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -454,7 +455,7 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # comparision total compaction results cpth = cmppth @@ -462,35 +463,35 @@ def eval_comp(sim): try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error loctag = "W2L4" diff = tc[loctag] - tc0[loctag] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0["time"][i]) - line += " {:15g}".format(tc[loctag][i]) - line += " {:15g}".format(tc0[loctag][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0['time'][i]:15g}" + line += f" {tc[loctag][i]:15g}" + line += f" {tc0[loctag][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -506,9 +507,7 @@ def eval_comp(sim): def cbc_compare(sim): print("evaluating cbc and budget...") # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -521,13 +520,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -561,41 +558,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -661,7 +658,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_subwt03.py b/autotest/test_gwf_csub_subwt03.py index 62d98a333c4..85649fa11fa 100644 --- a/autotest/test_gwf_csub_subwt03.py +++ b/autotest/test_gwf_csub_subwt03.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,7 +20,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_subwt03a", "csub_subwt03b", "csub_subwt03c", "csub_subwt03d"] @@ -209,7 +210,7 @@ def get_interbed(headbased=False, delay=False): if i == 19 and (j == 7 or j == 8): iactive = 0 if iactive > 0: - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" d = [ csubno, (k, i, j), @@ -283,11 +284,11 @@ def build_mf6(idx, ws, interbed=False): top=top, botm=botm, idomain=ib, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -342,7 +343,7 @@ def build_mf6(idx, ws, interbed=False): cg_ske_cr = [cr for k in range(nlay)] if interbed: cg_ske_cr[2] = 0 - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, print_input=True, @@ -371,8 +372,8 @@ def build_mf6(idx, ws, interbed=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -388,14 +389,14 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 with interbeds fpth = os.path.join(sim.simpath, cmppth, "csub_obs.csv") try: tci = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' diffmax = 0.0 tagmax = None @@ -406,33 +407,31 @@ def eval_comp(sim): diffmax = diffmaxt tagmax = tag - msg = "maximum compaction difference " + "({}) in tag: {}".format( - diffmax, tagmax - ) + msg = "maximum compaction difference " + f"({diffmax}) in tag: {tagmax}" # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") + line = f"{'TOTIM':>15s}" for tag in tc.dtype.names[1:]: - line += " {:>15s}".format("{}_SK".format(tag)) - line += " {:>15s}".format("{}_SKIB".format(tag)) - line += " {:>15s}".format("{}_DIFF".format(tag)) + line += f" {f'{tag}_SK':>15s}" + line += f" {f'{tag}_SKIB':>15s}" + line += f" {f'{tag}_DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) + line = f"{tc['time'][i]:15g}" for tag in tc.dtype.names[1:]: - line += " {:15g}".format(tc[tag][i]) - line += " {:15g}".format(tci[tag][i]) - line += " {:15g}".format(tc[tag][i] - tci[tag][i]) + line += f" {tc[tag][i]:15g}" + line += f" {tci[tag][i]:15g}" + line += f" {tc[tag][i] - tci[tag][i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -448,9 +447,7 @@ def eval_comp(sim): def cbc_compare(sim): print("evaluating cbc and budget...") # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -463,13 +460,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -503,41 +498,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -600,7 +595,7 @@ def main(): # use python testmf6_csub_subwt03.py if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_wc01.py b/autotest/test_gwf_csub_wc01.py index 31a14b9043d..de266afaade 100644 --- a/autotest/test_gwf_csub_wc01.py +++ b/autotest/test_gwf_csub_wc01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,7 +20,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_wc01a", "csub_wc02b"] @@ -158,7 +159,7 @@ if i == 19 and (j == 7 or j == 8): iactive = 0 if iactive > 0: - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" d = [ csubno, (k, i, j), @@ -292,11 +293,11 @@ def build_mf6(idx, ws, interbed=False): top=top, botm=botm, idomain=ib, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -335,7 +336,7 @@ def build_mf6(idx, ws, interbed=False): else: sswt6 = None ninterbeds = 0 - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, # interbed_stress_offset=True, @@ -362,8 +363,8 @@ def build_mf6(idx, ws, interbed=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -379,14 +380,14 @@ def eval_wcomp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 with interbeds water compressibility fpth = os.path.join(sim.simpath, cmppth, "csub_obs.csv") try: tci = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' diffmax = 0.0 tagmax = None @@ -399,32 +400,32 @@ def eval_wcomp(sim): msg = ( "maximum absolute water compressibility difference " - + "({}) in tag: {}".format(diffmax, tagmax) + + f"({diffmax}) in tag: {tagmax}" ) # write summary fpth = os.path.join( - sim.simpath, "{}.wcomp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.wcomp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") + line = f"{'TOTIM':>15s}" for tag in tc.dtype.names[1:]: - line += " {:>15s}".format("{}_SK".format(tag)) - line += " {:>15s}".format("{}_SKIB".format(tag)) - line += " {:>15s}".format("{}_DIFF".format(tag)) + line += f" {f'{tag}_SK':>15s}" + line += f" {f'{tag}_SKIB':>15s}" + line += f" {f'{tag}_DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) + line = f"{tc['time'][i]:15g}" for tag in tc.dtype.names[1:]: - line += " {:15g}".format(tc[tag][i]) - line += " {:15g}".format(tci[tag][i]) - line += " {:15g}".format(tc[tag][i] - tci[tag][i]) + line += f" {tc[tag][i]:15g}" + line += f" {tci[tag][i]:15g}" + line += f" {tc[tag][i] - tci[tag][i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -438,9 +439,7 @@ def eval_wcomp(sim): def cbc_compare(sim): print("evaluating cbc and budget...") # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -453,13 +452,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -493,41 +490,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -578,7 +575,7 @@ def main(): # main if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_wtgeo.py b/autotest/test_gwf_csub_wtgeo.py index b7c62e5a631..be59a6d0535 100644 --- a/autotest/test_gwf_csub_wtgeo.py +++ b/autotest/test_gwf_csub_wtgeo.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = [ @@ -402,11 +403,11 @@ def get_model(idx, ws): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -447,7 +448,7 @@ def get_model(idx, ws): gwf, maxbound=maxchd, stress_period_data=cd6, save_flows=False ) # ibc files - opth = "{}.csub.obs".format(name) + opth = f"{name}.csub.obs" csub = flopy.mf6.ModflowGwfcsub( gwf, specified_initial_interbed_state=True, @@ -477,7 +478,7 @@ def get_model(idx, ws): obsarr = [] for iobs, cobs in enumerate(obstype): for jobs, otup in enumerate(obspos): - otag = "{}{}".format(obstag[iobs], jobs + 1) + otag = f"{obstag[iobs]}{jobs + 1}" obsarr.append((otag, cobs, otup)) orecarray = {} @@ -489,8 +490,8 @@ def get_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -521,43 +522,41 @@ def eval_comp(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # comparision total compaction results fpth = os.path.join(sim.simpath, cmppth, "csub_obs.csv") try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP3"] - tc0["TCOMP3"] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format( - diffmax - ) + msg = f"maximum absolute total-compaction difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.comp.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.comp.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("CSUB") - line += " {:>15s}".format("MF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'CSUB':>15s}" + line += f" {'MF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0["time"][i]) - line += " {:15g}".format(tc["TCOMP3"][i]) - line += " {:15g}".format(tc0["TCOMP3"][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0['time'][i]:15g}" + line += f" {tc['TCOMP3'][i]:15g}" + line += f" {tc0['TCOMP3'][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -573,9 +572,7 @@ def eval_comp(sim): def cbc_compare(sim): print("evaluating cbc and budget...") # open cbc file - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") # build list of cbc data to retrieve @@ -588,13 +585,11 @@ def cbc_compare(sim): t = t.strip() if paktest in t.lower(): cbc_bud.append(t) - bud_lst.append("{}_IN".format(t)) - bud_lst.append("{}_OUT".format(t)) + bud_lst.append(f"{t}_IN") + bud_lst.append(f"{t}_OUT") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -628,41 +623,41 @@ def cbc_compare(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -732,7 +727,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_csub_zdisp01.py b/autotest/test_gwf_csub_zdisp01.py index 76dc6d91e3c..d5ac7645d3b 100644 --- a/autotest/test_gwf_csub_zdisp01.py +++ b/autotest/test_gwf_csub_zdisp01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -18,7 +19,7 @@ msg += " pip install https://github.com/modflowpy/pymake/zipball/master" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["csub_zdisp01"] @@ -184,7 +185,7 @@ # skip constant head cells if idomain[k, i, j] == 0: continue - tag = "{:02d}_{:02d}_{:02d}".format(k + 1, i + 1, j + 1) + tag = f"{k + 1:02d}_{i + 1:02d}_{j + 1:02d}" # create nodelay entry # no delay beds b = thicknd0[kdx] @@ -268,11 +269,11 @@ def get_model(idx, dir): top=top, botm=botm, idomain=idomain, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -291,11 +292,11 @@ def get_model(idx, dir): ) # csub files - opth = "{}.csub.obs".format(name) - ibcsv = "{}.ib.strain.csv".format(name) - skcsv = "{}.sk.strain.csv".format(name) - copth = "{}.compaction.gridbin".format(name) - zopth = "{}.zdisplacement.gridbin".format(name) + opth = f"{name}.csub.obs" + ibcsv = f"{name}.ib.strain.csv" + skcsv = f"{name}.sk.strain.csv" + copth = f"{name}.compaction.gridbin" + zopth = f"{name}.zdisplacement.gridbin" csub = flopy.mf6.ModflowGwfcsub( gwf, boundnames=True, @@ -313,7 +314,7 @@ def get_model(idx, dir): packagedata=sub6, ) orecarray = {} - tag = "{:02d}_{:02d}_{:02d}".format(3, wrp[0] + 1, wcp[0] + 1) + tag = f"{3:02d}_{wrp[0] + 1:02d}_{wcp[0] + 1:02d}" oloc = (2, wrp[0], wcp[0]) orecarray["csub_obs.csv"] = [ ("tcomp3", "interbed-compaction", tag), @@ -347,8 +348,8 @@ def get_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -439,34 +440,32 @@ def eval_zdisplacement(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW-2005 total compaction results - fn = "{}.total_comp.hds".format(os.path.basename(sim.name)) + fn = f"{os.path.basename(sim.name)}.total_comp.hds" fpth = os.path.join(sim.simpath, "mfnwt", fn) try: sobj = flopy.utils.HeadFile(fpth, text="LAYER COMPACTION") tc0 = sobj.get_ts((2, wrp[0], wcp[0])) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["TCOMP3"] - tc0[:, 1] diffmax = np.abs(diff).max() - msg = "maximum absolute total-compaction difference ({}) ".format(diffmax) + msg = f"maximum absolute total-compaction difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True print(" " + msg) # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -485,9 +484,7 @@ def eval_zdisplacement(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -512,41 +509,41 @@ def eval_zdisplacement(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -555,14 +552,14 @@ def eval_zdisplacement(sim): # compare z-displacement data fpth1 = os.path.join( sim.simpath, - "{}.zdisplacement.gridbin".format(os.path.basename(sim.name)), + f"{os.path.basename(sim.name)}.zdisplacement.gridbin", ) fpth2 = os.path.join(sim.simpath, cmppth, "csub_zdisp01.vert_disp.hds") text1 = "CSUB-ZDISPLACE" text2 = "Z DISPLACEMENT" fout = os.path.join( sim.simpath, - "{}.z-displacement.bin.out".format(os.path.basename(sim.name)), + f"{os.path.basename(sim.name)}.z-displacement.bin.out", ) success_tst = pymake.compare_heads( None, @@ -576,7 +573,7 @@ def eval_zdisplacement(sim): verbose=True, exarr=iex, ) - msg = "z-displacement comparison success = {}".format(success_tst) + msg = f"z-displacement comparison success = {success_tst}" if success_tst: sim.success = True print(msg) @@ -643,7 +640,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_disu01.py b/autotest/test_gwf_disu01.py index 622c767d939..6adc1d59f77 100644 --- a/autotest/test_gwf_disu01.py +++ b/autotest/test_gwf_disu01.py @@ -7,6 +7,7 @@ import os import shutil import subprocess + import numpy as np try: @@ -37,7 +38,7 @@ def run_mf6(argv, ws): if result is not None: c = result.decode("utf-8") c = c.rstrip("\r\n") - print("{}".format(c)) + print(f"{c}") buff.append(c) return proc.returncode, buff @@ -103,8 +104,8 @@ def test_disu_idomain_simple(): chd = flopy.mf6.modflow.ModflowGwfchd(gwf, stress_period_data=spd) oc = flopy.mf6.modflow.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.bud", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) sim.write_simulation() @@ -141,7 +142,7 @@ def test_disu_idomain_simple(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") test_disu_simple() test_disu_idomain_simple() diff --git a/autotest/test_gwf_disv_uzf.py b/autotest/test_gwf_disv_uzf.py new file mode 100644 index 00000000000..a4dcd4d8be1 --- /dev/null +++ b/autotest/test_gwf_disv_uzf.py @@ -0,0 +1,508 @@ +""" +MODFLOW 6 Autotest +A test of DISV with UZF. Originally created due to a possible bug in the +ASCII output file generated by UZF. Uses quadrilateral cells. The cells +are created from a numpy grid with cells that are 1m x 1m. Althought a DISV +grid, arrangement mimics that of a 10 row x 10 col x 5 layer DIS grid. +Inflow from infiltration on the top of the grid, flow exits via GHB +boundary on the right-hand side of the model. +""" + +import os +import pytest +import sys +import numpy as np + +try: + import flopy + import flopy.utils.cvfdutil +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + + +from framework import testing_framework +from simulation import Simulation + + +ex = ["disv_with_uzf"] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +nlay = 5 +nper = 5 +perlen = [10] * 5 +nstp = [5] * 5 +tsmult = len(perlen) * [1.0] +botm = [20.0, 15.0, 10.0, 5.0, 0.0] +strt = 20 + +nouter, ninner = 100, 300 +hclose, rclose, relax = 1e-9, 1e-3, 0.97 + +ghb_ids = [] + + +def create_disv_mesh(): + # Create a grid of verts + nx, ny = (11, 11) + x = np.linspace(0, 10, nx) + y = np.linspace(0, 10, ny) + xv, yv = np.meshgrid(x, y) + yv = np.flipud(yv) + + verts = [] + vid = 0 + vert_lkup = {} + for i in yv[:, 0]: + for j in xv[0, :]: + vert_lkup.update({(float(j), float(i)): vid}) + verts.append([int(vid), float(j), float(i)]) + vid += 1 + + ivert = [] + ivid = 0 + xyverts = [] + xc, yc = [], [] # for storing the cell center location + for i in yv[:-1, 0]: + for j in xv[0, :-1]: + xlst, ylst = [], [] + vid_lst = [] + # Start with upper-left corner and go clockwise + for ct in [0, 1, 2, 3]: + if ct == 0: + iadj = 0.0 + jadj = 0.0 + elif ct == 1: + iadj = 0.0 + jadj = 1.0 + elif ct == 2: + iadj = -1.0 + jadj = 1.0 + elif ct == 3: + iadj = -1.0 + jadj = 0.0 + + vid = vert_lkup[(float(j + jadj), float(i + iadj))] + vid_lst.append(vid) + + xlst.append(float(j + jadj)) + ylst.append(float(i + iadj)) + + xc.append(np.mean(xlst)) + yc.append(np.mean(ylst)) + xyverts.append(list(zip(xlst, ylst))) + + rec = [ivid] + vid_lst + ivert.append(rec) + + # if ivert part of right boundary, store id + if j == 9.0: + ghb_ids.append(ivid) + + ivid += 1 + + # finally, create a cell2d record + cell2d = [] + for ix, iv in enumerate(ivert): + xvt, yvt = np.array(xyverts[ix]).T + if flopy.utils.geometry.is_clockwise(xvt, yvt): + rec = [iv[0], xc[ix], yc[ix], len(iv[1:])] + iv[1:] + else: + iiv = iv[1:][::-1] + rec = [iv[0], xc[ix], yc[ix], len(iiv)] + iiv + + cell2d.append(rec) + + return verts, cell2d + + +verts, cell2d = create_disv_mesh() + +# Work up UZF data +iuzno = 0 +cellid = 0 +uzf_pkdat = [] +vks = 10.0 +thtr = 0.05 +thts = 0.30 +thti = 0.15 +eps = 3.5 + +for k in np.arange(nlay): + for i in np.arange(0, len(cell2d), 1): + if k == 0: + landflg = 1 + surfdp = 0.25 + else: + landflg = 0 + surfdp = 1e-6 + + if k == nlay - 1: + ivertcon = -1 + else: + ivertcon = iuzno + len(cell2d) + + bndnm = "uzf" + "{0:03d}".format(int(i + 1)) + uzf_pkdat.append( + # iuzno cellid landflag ivertcn surfdp vks thtr thts thti eps [bndnm] + [ + iuzno, + (k, i), + landflg, + ivertcon, + surfdp, + vks, + thtr, + thts, + thti, + eps, + bndnm, + ] + ) + + iuzno += 1 + + +extdp = 14.0 +extwc = 0.055 +pet = 0.001 +zero = 0.0 +uzf_spd = {} +for t in np.arange(0, nper, 1): + spd = [] + iuzno = 0 + for k in np.arange(nlay): + for i in np.arange(0, len(cell2d), 1): + if k == 0: + if t == 0: + finf = 0.15 + if t == 1: + finf = 0.15 + if t == 2: + finf = 0.15 + if t == 3: + finf = 0.15 + if t == 4: + finf = 0.15 + + spd.append([iuzno, finf, pet, extdp, extwc, zero, zero, zero]) + iuzno += 1 + + uzf_spd.update({t: spd}) + + +# Work up the GHB boundary +ghb_spd = [] +cond = 1e4 +for k in np.arange(3, 5, 1): + for i in ghb_ids: + ghb_spd.append([(k, i), 14.0, cond]) + + +def build_model(idx, dir): + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + + # time discretization + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwf = flopy.mf6.ModflowGwf( + sim, modelname=name, newtonoptions="NEWTON", save_flows=True + ) + + # create iterative model solution and register the gwf model with it + ims = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + complexity="MODERATE", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="DBD", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + ) + sim.register_ims_package(ims, [gwf.name]) + + ncpl = len(cell2d) + nvert = len(verts) + disv = flopy.mf6.ModflowGwfdisv( + gwf, + nlay=nlay, + ncpl=ncpl, + nvert=nvert, + top=25.0, + botm=botm, + vertices=verts, + cell2d=cell2d, + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt) + + # node property flow + npf = flopy.mf6.ModflowGwfnpf( + gwf, save_flows=True, icelltype=1, k=0.1, k33=1 + ) + + # aquifer storage + sto = flopy.mf6.ModflowGwfsto( + gwf, iconvert=1, ss=1e-5, sy=0.2, transient=True + ) + + # general-head boundary + ghb = flopy.mf6.ModflowGwfghb( + gwf, print_flows=True, stress_period_data=ghb_spd + ) + + # unsaturated-zone flow + etobs = [] + i = 4 + # Seems as though these are 1-based and not 0-based, like the rest of flopy + for j in list(np.arange(40, 50, 1)) + list(np.arange(140, 150, 1)): + etobs.append(("uzet_" + str(j + 1), "uzet", (j,))) + etobs.append(("uzf-gwet_" + str(j + 1), "uzf-gwet", (j,))) + + uzf_obs = {"{}.uzfobs".format(name): etobs} + + uzf = flopy.mf6.ModflowGwfuzf( + gwf, + print_flows=True, + save_flows=True, + simulate_et=True, + simulate_gwseep=True, + linear_gwet=True, + observations=uzf_obs, + boundnames=True, + ntrailwaves=15, + nwavesets=40, + nuzfcells=len(uzf_pkdat), + packagedata=uzf_pkdat, + perioddata=uzf_spd, + budget_filerecord="{}.uzf.bud".format(name), + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord="{}.cbc".format(name), + head_filerecord="{}.hds".format(name), + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + filename="{}.oc".format(name), + ) + + # Print human-readable heads + obs_lst = [] + for k in np.arange(0, 1, 1): + for i in np.arange(40, 50, 1): + obs_lst.append(["obs_" + str(i + 1), "head", (k, i)]) + + obs_dict = {f"{name}.obs.csv": obs_lst} + obs = flopy.mf6.ModflowUtlobs( + gwf, pname="head_obs", digits=20, continuous=obs_dict + ) + + return sim, None + + +def eval_model(sim): + print("evaluating model...") + + idx = sim.idxsim + name = ex[idx] + ws = os.path.join("temp", name) + + # Next, get the binary printed heads + fpth = os.path.join(ws, name + ".hds") + hobj = flopy.utils.HeadFile(fpth, precision="double") + hds = hobj.get_alldata() + hds = hds.reshape((np.sum(nstp), 5, 10, 10)) + + # Get the MF6 cell-by-cell fluxes + bpth = os.path.join(ws, name + ".cbc") + bobj = flopy.utils.CellBudgetFile(bpth, precision="double") + bobj.get_unique_record_names() + # ' STO-SS' + # ' STO-SY' + # ' FLOW-JA-FACE' + # ' GHB' + # ' UZF-GWRCH' + # ' UZF-GWD' + # ' UZF-GWET' + + gwet = bobj.get_data(text="UZF-GWET") + gwet = np.array(gwet) + gwetl = gwet.ravel().tolist() + gwetv = np.array([itm[2] for i, itm in enumerate(gwetl)]) + gwet = gwetv.reshape((np.sum(nstp), 5, 10, 10)) + + # Also retrieve the binary UZET output + uzpth = os.path.join(ws, name + ".uzf.bud") + uzobj = flopy.utils.CellBudgetFile(uzpth, precision="double") + uzobj.get_unique_record_names() + # b' FLOW-JA-FACE', + # b' GWF', + # b' INFILTRATION', + # b' REJ-INF', + # b' UZET', + # b' STORAGE' + uzet = uzobj.get_data(text="UZET") + uzet = np.array(uzet) + uzetl = uzet.ravel().tolist() + uzetv = np.array([itm[2] for i, itm in enumerate(uzetl)]) + uzet = uzetv.reshape((np.sum(nstp), 5, 10, 10)) + + # Confirm that the groundwater gradient dips to the right + for tm in np.arange(hds.shape[0]): + arr = hds[tm] + for ly in np.arange(hds.shape[1]): + hdlayer = arr[ly] + for rw in np.arange(arr.shape[0]): + fullrw = hdlayer[rw] + assert np.all( + np.diff(fullrw) < 0 + ), "GW heads not decreasing to the right" + + # After confirming heads drop off to the right, + # complete checks that ET totals & character (UZET vs GWET) + # make sense + # + # Need a 4D array boolean array of whether or not the water table is + # present + hds_flg = np.zeros_like(hds) + for t in np.arange(hds.shape[0]): + for k in np.arange(hds.shape[1]): + for i in np.arange(hds.shape[2]): + for j in np.arange(hds.shape[3]): + if hds[t, k, i, j] > botm[k]: + hds_flg[t, k, i, j] = 1 + + # Given that heads dip to the right, the GWET should also drop off to the + # right + gwetf = gwet.sum(axis=1) + for tm in np.arange(gwetf.shape[0]): + arr = gwetf[tm] + for rw in np.arange(arr.shape[0]): + fullrw = arr[rw] + for cl in np.arange(len(fullrw) - 1): + assert abs(fullrw[cl]) >= abs(fullrw[cl + 1]), ( + "gwet not decreasing to the right as expected. Stress Period: " + + str(tm + 1) + + "; Row: " + + str(rw + 1) + + "; Col: " + + str(cl + 1) + ) + + # Given the spatial uniformity of the model setup, wherever the water + # table is below the bottom of layer 1, the UZET should be equal + # (within a very tight tolerance). + for tm in np.arange(hds_flg.shape[0]): + flg = False + for i in np.arange(hds_flg.shape[2]): + for j in np.arange(hds_flg.shape[3]): + if hds_flg[tm, 0, i, j] == 0: + if not flg: + uzet_val2chk = uzet[tm, 0, i, j] + flg = not flg + else: + assert np.isclose( + [uzet_val2chk], [uzet[tm, 0, i, j]], atol=1e-6 + ), "UZET in layer 1 is not uniform, but should be" + + # Also because the groundwater heads dip to the right, that means the + # UZ thickness increases to the right. As a result, the summed UZET + # should increase to the right (the opposite of the GWET) + uzets = uzet.sum(axis=0) + for tm in np.arange(uzets.shape[0]): + arr = uzets[tm] + for rw in np.arange(arr.shape[0]): + fullrw = arr[rw] + for cl in np.arange(len(fullrw) - 1): + assert abs(fullrw[cl]) <= abs(fullrw[cl + 1]), ( + "gwet not decreasing to the right as expected. Stress Period: " + + str(tm + 1) + + "; Row: " + + str(rw + 1) + + "; Col: " + + str(cl + 1) + + f"{fullrw[cl]} should be less than or equal to {abs(fullrw[cl + 1])}" + ) + + # Confirm that total simulated ET does not exceed potential ET. + # Sum UZET and GWET + total_et = abs(uzet) + abs(gwet) + # Sum ET from across layers + total_et = total_et.sum(axis=1) + for tm in np.arange(total_et.shape[0]): + for rw in np.arange(total_et.shape[1]): + for cl in np.arange(total_et.shape[2]): + assert total_et[tm, rw, cl] <= pet, ( + "simulated ET exceeds user-specified potential ET. Stress Period: " + + str(tm + 1) + + "; Row: " + + str(rw + 1) + + "; Col: " + + str(cl + 1) + ) + + print("Finished running checks") + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_model, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_model, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print("standalone run of {}".format(os.path.basename(__file__))) + + # run main routine + main() diff --git a/autotest/test_gwf_drn_ddrn01.py b/autotest/test_gwf_drn_ddrn01.py index 193a99f5041..11a7ec66fa3 100644 --- a/autotest/test_gwf_drn_ddrn01.py +++ b/autotest/test_gwf_drn_ddrn01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "drn" @@ -74,7 +75,7 @@ def initial_conditions(): def get_model(idxsim, ws, name): strt = initial_conditions() - hdsfile = "{}.hds".format(name) + hdsfile = f"{name}.hds" if newton[idxsim]: newtonoptions = "NEWTON" else: @@ -118,7 +119,7 @@ def get_model(idxsim, ws, name): print_input=True, ) drn.obs.initialize( - filename="{}.drn.obs".format(name), + filename=f"{name}.drn.obs", digits=20, print_input=True, continuous=drn_obs, @@ -155,14 +156,14 @@ def eval_disch(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 head results fpth = os.path.join(sim.simpath, "head_obs.csv") try: th0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate the drain flux analytically xdiff = th0["H1_1_100"] - delev @@ -173,29 +174,29 @@ def eval_disch(sim): diff = tc["D1_1_100"] - tc0 diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute discharge difference ({}) ".format(diffmax) + msg = f"maximum absolute discharge difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.disc.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.disc.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("DRN") - line += " {:>15s}".format("UZF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'DRN':>15s}" + line += f" {'UZF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc["time"][i]) - line += " {:15g}".format(tc["D1_1_100"][i]) - line += " {:15g}".format(tc0[i]) - line += " {:15g}".format(diff[i]) + line = f"{tc['time'][i]:15g}" + line += f" {tc['D1_1_100'][i]:15g}" + line += f" {tc0[i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -264,7 +265,7 @@ def main(): # use python testmf6_drn_ddrn01.py if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_drn_ddrn02.py b/autotest/test_gwf_drn_ddrn02.py index c1e6a73c65b..1e1c61f9f01 100644 --- a/autotest/test_gwf_drn_ddrn02.py +++ b/autotest/test_gwf_drn_ddrn02.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -18,7 +19,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation paktest = "drn" @@ -65,7 +66,7 @@ def get_model(ws, name, uzf=False): - hdsfile = "{}.hds".format(name) + hdsfile = f"{name}.hds" # build the model sim = flopy.mf6.MFSimulation(sim_name=name, exe_name="mf6", sim_ws=ws) @@ -104,7 +105,7 @@ def get_model(ws, name, uzf=False): gwf, simulate_gwseep=True, packagedata=uzf_pd, print_input=True ) uzf.obs.initialize( - filename="{}.uzf.obs".format(name), + filename=f"{name}.uzf.obs", digits=20, print_input=True, continuous=uzf_obs, @@ -118,7 +119,7 @@ def get_model(ws, name, uzf=False): print_input=True, ) drn.obs.initialize( - filename="{}.drn.obs".format(name), + filename=f"{name}.drn.obs", digits=20, print_input=True, continuous=drn_obs, @@ -156,42 +157,42 @@ def eval_disch(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 uzf discharge results fpth = os.path.join(sim.simpath, "mf6", "uzf_obs.csv") try: tc0 = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculate maximum absolute error diff = tc["D1_1_1"] - tc0["D1_1_1"] diffmax = np.abs(diff).max() dtol = 1e-6 - msg = "maximum absolute discharge difference ({}) ".format(diffmax) + msg = f"maximum absolute discharge difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.disc.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.disc.cmp.out" ) f = open(fpth, "w") - line = "{:>15s}".format("TOTIM") - line += " {:>15s}".format("DRN") - line += " {:>15s}".format("UZF") - line += " {:>15s}".format("DIFF") + line = f"{'TOTIM':>15s}" + line += f" {'DRN':>15s}" + line += f" {'UZF':>15s}" + line += f" {'DIFF':>15s}" f.write(line + "\n") for i in range(diff.shape[0]): - line = "{:15g}".format(tc0["time"][i]) - line += " {:15g}".format(tc["D1_1_1"][i]) - line += " {:15g}".format(tc0["D1_1_1"][i]) - line += " {:15g}".format(diff[i]) + line = f"{tc0['time'][i]:15g}" + line += f" {tc['D1_1_1'][i]:15g}" + line += f" {tc0['D1_1_1'][i]:15g}" + line += f" {diff[i]:15g}" f.write(line + "\n") f.close() if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -247,7 +248,7 @@ def main(): # use python testmf6_drn_ddrn01.py if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_errors.py b/autotest/test_gwf_errors.py index 49da624f5df..fe688406f16 100644 --- a/autotest/test_gwf_errors.py +++ b/autotest/test_gwf_errors.py @@ -7,10 +7,11 @@ """ import os -import pytest import shutil import subprocess + import numpy as np +import pytest try: import flopy @@ -41,7 +42,7 @@ def run_mf6(argv, ws): if result is not None: c = result.decode("utf-8") c = c.rstrip("\r\n") - print("{}".format(c)) + print(f"{c}") buff.append(c) return proc.returncode, buff @@ -61,9 +62,7 @@ def run_mf6_error(ws, err_str_list): raise RuntimeError(msg) else: msg += " but did not print correct error message." - msg += ' Correct message should have been "{}"'.format( - err_str - ) + msg += f' Correct message should have been "{err_str}"' raise ValueError(msg) @@ -139,7 +138,7 @@ def test_simple_model_success(): assert returncode == 0, "mf6 failed for simple model." final_message = "Normal termination of simulation." - failure_message = 'mf6 did not terminate with "{}"'.format(final_message) + failure_message = f'mf6 did not terminate with "{final_message}"' assert final_message in buff[-1], failure_message if teardown_test: shutil.rmtree(ws, ignore_errors=True) @@ -244,11 +243,11 @@ def test_fail_continue_success(): assert returncode == 0, "mf6 failed for simple model." final_message = "Simulation convergence failure occurred 10 time(s)." - failure_message = 'mf6 did not terminate with "{}"'.format(final_message) + failure_message = f'mf6 did not terminate with "{final_message}"' assert final_message in buff[0], failure_message final_message = "Normal termination of simulation." - failure_message = 'mf6 did not terminate with "{}"'.format(final_message) + failure_message = f'mf6 did not terminate with "{final_message}"' assert final_message in buff[0], failure_message if teardown_test: @@ -259,7 +258,7 @@ def test_fail_continue_success(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") test_empty_folder() test_simple_model_success() diff --git a/autotest/test_gwf_evt01.py b/autotest/test_gwf_evt01.py index b2cc946de9e..0c435b49146 100644 --- a/autotest/test_gwf_evt01.py +++ b/autotest/test_gwf_evt01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -128,12 +129,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -192,7 +193,7 @@ def eval_model(sim): h, 0.001, 95.0, 90, [1.0, 0.0, 1.0], [0.25, 0.5, 0.75], petm0=0.1 ) - msg = "{} {} {} {}".format(kper, h, sim_evt_rate, cal_evt_rate) + msg = f"{kper} {h} {sim_evt_rate} {cal_evt_rate}" assert np.allclose(sim_evt_rate, cal_evt_rate), msg return @@ -227,7 +228,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_evt02.py b/autotest/test_gwf_evt02.py new file mode 100644 index 00000000000..65d013c5e4c --- /dev/null +++ b/autotest/test_gwf_evt02.py @@ -0,0 +1,216 @@ +import os +import sys + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = ["evt02"] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + + +def build_model(idx, dir): + + nlay, nrow, ncol = 1, 1, 3 + chdheads = list(np.linspace(1, 100)) + nper = len(chdheads) + perlen = nper * [1.0] + nstp = nper * [1] + tsmult = nper * [1.0] + + delr = delc = 1.0 + strt = chdheads[0] + + nouter, ninner = 100, 300 + hclose, rclose, relax = 1e-9, 1e-3, 0.97 + + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwf = flopy.mf6.ModflowGwf(sim, modelname=name, save_flows=True) + + # create iterative model solution and register the gwf model with it + ims = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="DBD", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + ) + sim.register_ims_package(ims, [gwf.name]) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=100.0, + botm=0.0, + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt) + + # node property flow + npf = flopy.mf6.ModflowGwfnpf(gwf, save_flows=True, icelltype=1, k=1.0) + + # chd files + chdspd = {} + for kper, chdval in enumerate(chdheads): + chdspd[kper] = [[(0, 0, 0), chdval], [(0, 0, ncol - 1), chdval]] + chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chdspd) + + nseg = 1 + surf_rate_specified = True + evtspd = [[(0, 0, 1), 95.0, 0.001, 90.0, 0.1]] + + # nseg = 4 + # surf_rate_specified = False + # evtspd = [((0, 0, 1), 95., 0.001, 90., 0.25, 0.5, 0.75, 1., 0., 1.)] + + # nseg = 1 + # surf_rate_specified = False + # evtspd = [[(0, 0, 1), 95., 0.001, 90.]] + + evt = flopy.mf6.ModflowGwfevt( + gwf, + print_flows=True, + surf_rate_specified=surf_rate_specified, + maxbound=1, + nseg=nseg, + stress_period_data=evtspd, + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + filename=f"{name}.oc", + ) + + return sim, None + + +def etfunc(h, qmax, surf, exdp, petm, pxdp, petm0=1.0): + nseg = len(petm) + 1 + d = surf - h + if h >= surf: + hcof = 0.0 + rhs = qmax * petm0 + elif d >= exdp: + hcof = 0.0 + rhs = 0.0 + else: + if nseg > 1: + pxdp1 = 0.0 + petm1 = petm0 + for iseg in range(nseg): + if iseg < nseg - 1: + pxdp2 = pxdp[iseg] + petm2 = petm[iseg] + else: + pxdp2 = 1.0 + petm2 = 0.0 + if d <= pxdp2 * exdp: + break + pxdp1 = pxdp2 + petm1 = petm2 + hcof = -(petm1 - petm2) * qmax / ((pxdp2 - pxdp1) * exdp) + rhs = hcof * (surf - pxdp1 * exdp) + petm1 * qmax + else: + hcof = -qmax / exdp + rhs = qmax - qmax * surf / exdp + q = h * hcof - rhs + return q, hcof, rhs + + +def eval_model(sim): + print("evaluating model...") + + # The nature of the bug is that the model crashes with nseg=1 + fpth = os.path.join(sim.simpath, "evt02.cbc") + assert os.path.isfile(fpth), "model did not run with nseg=1 in EVT input" + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_model, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_model, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_henry_nr.py b/autotest/test_gwf_henry_nr.py index b4d2827f46d..ec9ffaacbe2 100644 --- a/autotest/test_gwf_henry_nr.py +++ b/autotest/test_gwf_henry_nr.py @@ -6,8 +6,9 @@ # the effects of tides on the aquifer. import os -import pytest + import numpy as np +import pytest try: import flopy @@ -228,14 +229,14 @@ def build_model(idx, dir): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(name), + filename=f"{name}.wel", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -246,9 +247,9 @@ def build_model(idx, dir): def set_make_comparison(): version = get_mf6_version() - print("MODFLOW version='{}'".format(version)) + print(f"MODFLOW version='{version}'") version = get_mf6_version(version="mf6-regression") - print("MODFLOW regression version='{}'".format(version)) + print(f"MODFLOW regression version='{version}'") if version in ("6.2.1",): make_comparison = False else: @@ -301,7 +302,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_buy.py b/autotest/test_gwf_ifmod_buy.py index 980905b5a7b..9b1714944db 100644 --- a/autotest/test_gwf_ifmod_buy.py +++ b/autotest/test_gwf_ifmod_buy.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -126,7 +127,7 @@ def get_model(idx, dir): rcloserecord=rclose, linear_acceleration="BICGSTAB", relaxation_factor=relax, - filename="{}.ims".format("gwf"), + filename="gwf.ims", ) # the full gwf model as a reference @@ -147,12 +148,12 @@ def get_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format("gwt"), + filename="gwt.ims", ) gwt = add_gwtrefmodel(sim) @@ -168,21 +169,21 @@ def get_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=mname_ref, exgmnameb=mname_gwtref, - filename="{}.gwfgwt".format("reference"), + filename="reference.gwfgwt", ) gwfgwt_left = flopy.mf6.ModflowGwfgwt( sim, exgtype="GWF6-GWT6", exgmnamea=mname_left, exgmnameb=mname_gwtleft, - filename="{}.gwfgwt".format("left"), + filename="left.gwfgwt", ) gwfgwt_right = flopy.mf6.ModflowGwfgwt( sim, exgtype="GWF6-GWT6", exgmnamea=mname_right, exgmnameb=mname_gwtright, - filename="{}.gwfgwt".format("right"), + filename="right.gwfgwt", ) return sim @@ -231,8 +232,8 @@ def add_refmodel(sim): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_ref), - budget_filerecord="{}.cbc".format(mname_ref), + head_filerecord=f"{mname_ref}.hds", + budget_filerecord=f"{mname_ref}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -273,8 +274,8 @@ def add_leftmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_left), - budget_filerecord="{}.cbc".format(mname_left), + head_filerecord=f"{mname_left}.hds", + budget_filerecord=f"{mname_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -317,8 +318,8 @@ def add_rightmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_right), - budget_filerecord="{}.cbc".format(mname_right), + head_filerecord=f"{mname_right}.hds", + budget_filerecord=f"{mname_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -388,8 +389,8 @@ def add_gwtrefmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtref), - concentration_filerecord="{}.ucn".format(mname_gwtref), + budget_filerecord=f"{mname_gwtref}.cbc", + concentration_filerecord=f"{mname_gwtref}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -435,8 +436,8 @@ def add_gwtleftmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtleft), - concentration_filerecord="{}.ucn".format(mname_gwtleft), + budget_filerecord=f"{mname_gwtleft}.cbc", + concentration_filerecord=f"{mname_gwtleft}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -484,8 +485,8 @@ def add_gwtrightmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtright), - concentration_filerecord="{}.ucn".format(mname_gwtright), + budget_filerecord=f"{mname_gwtright}.cbc", + concentration_filerecord=f"{mname_gwtright}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -556,24 +557,24 @@ def qxqyqz(fname, nlay, nrow, ncol): def compare_to_ref(sim): print("comparing heads and spec. discharge to single model reference...") - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.cbc") nlay, nrow, ncol = heads.shape qxb, qyb, qzb = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.hds") hds = flopy.utils.HeadFile(fpth) heads_left = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.cbc") nlay, nrow, ncol = heads_left.shape qxb_left, qyb_left, qzb_left = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.hds") hds = flopy.utils.HeadFile(fpth) heads_right = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.cbc") nlay, nrow, ncol = heads_right.shape qxb_right, qyb_right, qzb_right = qxqyqz(fpth, nlay, nrow, ncol) @@ -644,7 +645,7 @@ def compare_to_ref(sim): # check budget error from .lst file for mname in [mname_ref, mname_left, mname_right]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -688,7 +689,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_mult_exg.py b/autotest/test_gwf_ifmod_mult_exg.py index a5226bca908..56731552a41 100644 --- a/autotest/test_gwf_ifmod_mult_exg.py +++ b/autotest/test_gwf_ifmod_mult_exg.py @@ -22,10 +22,11 @@ """ import os + import numpy as np -from modflowapi import ModflowApi -from flopy.utils.lgrutil import Lgr import pytest +from flopy.utils.lgrutil import Lgr +from modflowapi import ModflowApi try: import flopy @@ -163,8 +164,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_parent), - budget_filerecord="{}.cbc".format(name_parent), + head_filerecord=f"{name_parent}.hds", + budget_filerecord=f"{name_parent}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -197,8 +198,8 @@ def get_model(idx, dir): ) oc = flopy.mf6.ModflowGwfoc( gwfc, - head_filerecord="{}.hds".format(name_child), - budget_filerecord="{}.cbc".format(name_child), + head_filerecord=f"{name_child}.hds", + budget_filerecord=f"{name_child}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -276,19 +277,19 @@ def build_model(idx, exdir): def eval_heads(sim): name = ex[sim.idxsim] - fpth = os.path.join(sim.simpath, "{}.hds".format(name_parent)) + fpth = os.path.join(sim.simpath, f"{name_parent}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.hds".format(name_child)) + fpth = os.path.join(sim.simpath, f"{name_child}.hds") hds_c = flopy.utils.HeadFile(fpth) heads_c = hds_c.get_data() - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(name_parent)) + fpth = os.path.join(sim.simpath, f"{name_parent}.dis.grb") grb = flopy.mf6.utils.MfGrdFile(fpth) mg = grb.modelgrid - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(name_child)) + fpth = os.path.join(sim.simpath, f"{name_child}.dis.grb") grb_c = flopy.mf6.utils.MfGrdFile(fpth) mg_c = grb_c.modelgrid @@ -377,7 +378,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_rewet.py b/autotest/test_gwf_ifmod_rewet.py index f06c08f71b9..c7821aa69ba 100644 --- a/autotest/test_gwf_ifmod_rewet.py +++ b/autotest/test_gwf_ifmod_rewet.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -155,7 +156,7 @@ def get_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format("gwf"), + filename="gwf.ims", ) # the full gwf model as a reference @@ -216,8 +217,8 @@ def add_refmodel(sim): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_ref), - budget_filerecord="{}.cbc".format(mname_ref), + head_filerecord=f"{mname_ref}.hds", + budget_filerecord=f"{mname_ref}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -262,8 +263,8 @@ def add_leftmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_left), - budget_filerecord="{}.cbc".format(mname_left), + head_filerecord=f"{mname_left}.hds", + budget_filerecord=f"{mname_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -311,8 +312,8 @@ def add_rightmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_right), - budget_filerecord="{}.cbc".format(mname_right), + head_filerecord=f"{mname_right}.hds", + budget_filerecord=f"{mname_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -363,15 +364,15 @@ def compare_to_ref(sim): print("comparing heads to single model reference...") for iper in range(nper): - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data(idx=iper) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.hds") hds = flopy.utils.HeadFile(fpth) heads_left = hds.get_data(idx=iper) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.hds") hds = flopy.utils.HeadFile(fpth) heads_right = hds.get_data(idx=iper) @@ -388,7 +389,7 @@ def compare_to_ref(sim): # check budget error from .lst file for mname in [mname_ref, mname_left, mname_right]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -432,7 +433,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_vert.py b/autotest/test_gwf_ifmod_vert.py index 47c12ca9efa..bc2ae206849 100644 --- a/autotest/test_gwf_ifmod_vert.py +++ b/autotest/test_gwf_ifmod_vert.py @@ -31,6 +31,7 @@ """ import os + import numpy as np import pytest @@ -43,6 +44,7 @@ raise Exception(msg) from flopy.utils.lgrutil import Lgr + from framework import testing_framework from simulation import Simulation @@ -166,8 +168,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(parent_name), - budget_filerecord="{}.cbc".format(parent_name), + head_filerecord=f"{parent_name}.hds", + budget_filerecord=f"{parent_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -198,8 +200,8 @@ def get_model(idx, dir): ) oc = flopy.mf6.ModflowGwfoc( gwfc, - head_filerecord="{}.hds".format(child_name), - budget_filerecord="{}.cbc".format(child_name), + head_filerecord=f"{child_name}.hds", + budget_filerecord=f"{child_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -252,11 +254,11 @@ def build_model(idx, exdir): def eval_heads(sim): print("comparing heads for child model to analytical result...") - fpth = os.path.join(sim.simpath, "{}.hds".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.hds") hds_c = flopy.utils.HeadFile(fpth) heads_c = hds_c.get_data() - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.dis.grb") grb_c = flopy.mf6.utils.MfGrdFile(fpth) # (note that without XT3D on the exchange, the 'error' @@ -276,7 +278,7 @@ def eval_heads(sim): grb = flopy.mf6.utils.MfGrdFile(fpth) ia = grb._datadict["IA"] - 1 - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.cbc") assert os.path.isfile(fpth) cbb = flopy.utils.CellBudgetFile(fpth, precision="double") flow_ja_face = cbb.get_data(idx=0) @@ -287,9 +289,7 @@ def eval_heads(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg return @@ -325,7 +325,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_xt3d01.py b/autotest/test_gwf_ifmod_xt3d01.py index 17855d8855b..a34da82307c 100644 --- a/autotest/test_gwf_ifmod_xt3d01.py +++ b/autotest/test_gwf_ifmod_xt3d01.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -11,6 +12,7 @@ raise Exception(msg) from flopy.utils.lgrutil import Lgr + from framework import testing_framework from simulation import Simulation @@ -80,7 +82,7 @@ def get_model(idx, dir): row_s, row_e = 3, 5 col_s, col_e = 3, 5 - ref_fct = 3 + ref_fct = 5 nrowc = ref_fct * ((row_e - row_s) + 1) ncolc = ref_fct * ((col_e - col_s) + 1) @@ -172,8 +174,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(parent_name), - budget_filerecord="{}.cbc".format(parent_name), + head_filerecord=f"{parent_name}.hds", + budget_filerecord=f"{parent_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -204,8 +206,8 @@ def get_model(idx, dir): ) oc = flopy.mf6.ModflowGwfoc( gwfc, - head_filerecord="{}.hds".format(child_name), - budget_filerecord="{}.cbc".format(child_name), + head_filerecord=f"{child_name}.hds", + budget_filerecord=f"{child_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -314,27 +316,27 @@ def eval_heads(sim): name = ex[sim.idxsim] - fpth = os.path.join(sim.simpath, "{}.hds".format(parent_name)) + fpth = os.path.join(sim.simpath, f"{parent_name}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(parent_name)) + fpth = os.path.join(sim.simpath, f"{parent_name}.cbc") nlay, nrow, ncol = heads.shape qxb, qyb, qzb = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.hds") hds_c = flopy.utils.HeadFile(fpth) heads_c = hds_c.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.cbc") nlay, nrow, ncol = heads_c.shape qxb_c, qyb_c, qzb_c = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(parent_name)) + fpth = os.path.join(sim.simpath, f"{parent_name}.dis.grb") grb = flopy.mf6.utils.MfGrdFile(fpth) mg = grb.modelgrid - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.dis.grb") grb_c = flopy.mf6.utils.MfGrdFile(fpth) mg_c = grb_c.modelgrid @@ -418,7 +420,7 @@ def exact(x): # todo: mflistbudget # check cumulative balance error from .lst file for mname in [parent_name, child_name]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -431,7 +433,7 @@ def exact(x): # Check on residual, which is stored in diagonal position of # flow-ja-face. Residual should be less than convergence tolerance, # or this means the residual term is not added correctly. - fpth = os.path.join(sim.simpath, "{}.cbc".format(parent_name)) + fpth = os.path.join(sim.simpath, f"{parent_name}.cbc") cbb = flopy.utils.CellBudgetFile(fpth) flow_ja_face = cbb.get_data(idx=0) assert ( @@ -441,9 +443,7 @@ def exact(x): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg # Read gwf-gwf observations values @@ -454,7 +454,7 @@ def exact(x): obsvalues = [float(v) for v in lines[1].strip().split(",")[1:]] # Extract the gwf-gwf flows stored in parent budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(parent_name)) + fpth = os.path.join(sim.simpath, f"{parent_name}.cbc") cbb = flopy.utils.CellBudgetFile(fpth, precision="double") parent_exchange_flows = cbb.get_data( kstpkper=(0, 0), text="FLOW-JA-FACE", paknam="GWF-GWF_1" @@ -462,7 +462,7 @@ def exact(x): parent_exchange_flows = parent_exchange_flows["q"] # Extract the gwf-gwf flows stored in child budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.cbc") cbb = flopy.utils.CellBudgetFile(fpth, precision="double") child_exchange_flows = cbb.get_data( kstpkper=(0, 0), text="FLOW-JA-FACE", paknam="GWF-GWF_1" @@ -521,7 +521,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ifmod_xt3d02.py b/autotest/test_gwf_ifmod_xt3d02.py index bedf6409988..b1e9146fdec 100644 --- a/autotest/test_gwf_ifmod_xt3d02.py +++ b/autotest/test_gwf_ifmod_xt3d02.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -11,6 +12,7 @@ raise Exception(msg) from flopy.utils.lgrutil import Lgr + from framework import testing_framework from simulation import Simulation @@ -176,8 +178,8 @@ def get_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_ref), - budget_filerecord="{}.cbc".format(mname_ref), + head_filerecord=f"{mname_ref}.hds", + budget_filerecord=f"{mname_ref}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -214,8 +216,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_left), - budget_filerecord="{}.cbc".format(mname_left), + head_filerecord=f"{mname_left}.hds", + budget_filerecord=f"{mname_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -259,8 +261,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_right), - budget_filerecord="{}.cbc".format(mname_right), + head_filerecord=f"{mname_right}.hds", + budget_filerecord=f"{mname_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -323,24 +325,24 @@ def qxqyqz(fname, nlay, nrow, ncol): def compare_to_ref(sim): print("comparing heads and spec. discharge to single model reference...") - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.cbc") nlay, nrow, ncol = heads.shape qxb, qyb, qzb = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.hds") hds = flopy.utils.HeadFile(fpth) heads_left = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.cbc") nlay, nrow, ncol = heads_left.shape qxb_left, qyb_left, qzb_left = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.hds") hds = flopy.utils.HeadFile(fpth) heads_right = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.cbc") nlay, nrow, ncol = heads_right.shape qxb_right, qyb_right, qzb_right = qxqyqz(fpth, nlay, nrow, ncol) @@ -411,7 +413,7 @@ def compare_to_ref(sim): # check budget error from .lst file for mname in [mname_ref, mname_left, mname_right]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -455,7 +457,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ims_rcm_reorder.py b/autotest/test_gwf_ims_rcm_reorder.py index 3dff3f4022c..c4eca177504 100644 --- a/autotest/test_gwf_ims_rcm_reorder.py +++ b/autotest/test_gwf_ims_rcm_reorder.py @@ -1,5 +1,7 @@ import os + import pytest + from budget_file_compare import eval_bud_diff try: @@ -195,7 +197,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_lakobs01.py b/autotest/test_gwf_lakobs01.py index afdb8b97ca4..8ff09c449c9 100644 --- a/autotest/test_gwf_lakobs01.py +++ b/autotest/test_gwf_lakobs01.py @@ -7,10 +7,10 @@ import os import shutil - -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -20,9 +20,9 @@ msg += " pip install flopy" raise Exception(msg) +import targets from framework import testing_framework from simulation import Simulation -import targets mf6_exe = os.path.abspath(targets.target_dict["mf6"]) @@ -102,7 +102,7 @@ def build_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) # number of columns to be a lake for layer 1, 2, , ... len(lakend) @@ -170,7 +170,7 @@ def build_model(): ] # note: for specifying lake number, use fortran indexing! - fname = "{}.lak.obs.csv".format(gwfname) + fname = f"{gwfname}.lak.obs.csv" lak_obs = { fname: [ ("lakestage", "stage", 1), @@ -187,8 +187,8 @@ def build_model(): print_input=True, print_flows=True, print_stage=True, - stage_filerecord="{}.lak.bin".format(gwfname), - budget_filerecord="{}.lak.bud".format(gwfname), + stage_filerecord=f"{gwfname}.lak.bin", + budget_filerecord=f"{gwfname}.lak.bud", nlakes=len(pak_data), ntables=0, packagedata=pak_data, @@ -210,8 +210,8 @@ def build_model(): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -336,7 +336,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_evt01.py b/autotest/test_gwf_libmf6_evt01.py index 39d61ac416f..7bf1f6349d0 100644 --- a/autotest/test_gwf_libmf6_evt01.py +++ b/autotest/test_gwf_libmf6_evt01.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -138,7 +139,7 @@ def get_model(ws, name, bmi=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -206,6 +207,16 @@ def api_func(exe, idx, model_ws=None): well_tag = mf6.get_var_address("BOUND", name, "WEL_0") well = mf6.get_value(well_tag) + # check NPF type + package_type_tag = mf6.get_var_address("PACKAGE_TYPE", name, "NPF") + package_type = mf6.get_value(package_type_tag)[0] + assert package_type == "NPF", f"{package_type} /= NPF" + + # check wel type + package_type_tag = mf6.get_var_address("PACKAGE_TYPE", name, "WEL_0") + package_type = mf6.get_value(package_type_tag)[0] + assert package_type == "WEL", f"{package_type} /= WEL" + twell = np.zeros(ncol, dtype=np.float64) # model time loop @@ -233,8 +244,8 @@ def api_func(exe, idx, model_ws=None): if has_converged: msg = ( - "Component {}".format(1) - + " converged in {}".format(kiter) + f"Component {1}" + + f" converged in {kiter}" + " outer iterations" ) print(msg) @@ -295,7 +306,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_ghb01.py b/autotest/test_gwf_libmf6_ghb01.py index cd560bfaea1..6cb729387ee 100644 --- a/autotest/test_gwf_libmf6_ghb01.py +++ b/autotest/test_gwf_libmf6_ghb01.py @@ -7,8 +7,9 @@ possible solution to https://github.com/MODFLOW-USGS/modflow6/issues/724 """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -173,7 +174,7 @@ def get_model(ws, name, api=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -271,7 +272,7 @@ def api_func(exe, idx, model_ws=None): kiter += 1 if has_converged: - msg = "Converged in {}".format(kiter) + " outer iterations" + msg = f"Converged in {kiter}" + " outer iterations" print(msg) break @@ -330,7 +331,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_ifmod01.py b/autotest/test_gwf_libmf6_ifmod01.py index 9d03f67b947..3f138e5dc20 100644 --- a/autotest/test_gwf_libmf6_ifmod01.py +++ b/autotest/test_gwf_libmf6_ifmod01.py @@ -13,9 +13,10 @@ """ import os + import numpy as np -from modflowapi import ModflowApi import pytest +from modflowapi import ModflowApi try: import pymake @@ -140,8 +141,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_left), - budget_filerecord="{}.cbc".format(name_left), + head_filerecord=f"{name_left}.hds", + budget_filerecord=f"{name_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -179,8 +180,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_right), - budget_filerecord="{}.cbc".format(name_right), + head_filerecord=f"{name_right}.hds", + budget_filerecord=f"{name_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -283,7 +284,7 @@ def check_interface_models(mf6): ixt3d = mf6.get_value_ptr(mem_addr)[0] assert ( ixt3d == 1 - ), "Interface model for {} should have XT3D enabled".format(name_left) + ), f"Interface model for {name_left} should have XT3D enabled" # check if n2 > n1, then cell 1 is below 2 mem_addr = mf6.get_var_address("TOP", ifm_name_left, "DIS") @@ -293,9 +294,7 @@ def check_interface_models(mf6): zc = (bot + top) / 2 assert all( [zc[i] >= zc[i + 1] for i in range(len(zc) - 1)] - ), "Interface model for {} contains incorrectly numbered cells".format( - name_left - ) + ), f"Interface model for {name_left} contains incorrectly numbered cells" # confirm some properties for the 'left' interface # model, looping over the models that contribute: @@ -362,7 +361,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_ifmod02.py b/autotest/test_gwf_libmf6_ifmod02.py index a19bf961f62..d81a0946460 100644 --- a/autotest/test_gwf_libmf6_ifmod02.py +++ b/autotest/test_gwf_libmf6_ifmod02.py @@ -37,9 +37,10 @@ """ import os + import numpy as np -from modflowapi import ModflowApi import pytest +from modflowapi import ModflowApi try: import pymake @@ -174,8 +175,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_tl), - budget_filerecord="{}.cbc".format(name_tl), + head_filerecord=f"{name_tl}.hds", + budget_filerecord=f"{name_tl}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -208,8 +209,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_bl), - budget_filerecord="{}.cbc".format(name_bl), + head_filerecord=f"{name_bl}.hds", + budget_filerecord=f"{name_bl}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -242,8 +243,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_tr), - budget_filerecord="{}.cbc".format(name_tr), + head_filerecord=f"{name_tr}.hds", + budget_filerecord=f"{name_tr}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -454,7 +455,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_ifmod03.py b/autotest/test_gwf_libmf6_ifmod03.py index 9903a992d21..003a03b2d8f 100644 --- a/autotest/test_gwf_libmf6_ifmod03.py +++ b/autotest/test_gwf_libmf6_ifmod03.py @@ -27,9 +27,10 @@ """ import os + import numpy as np -from modflowapi import ModflowApi import pytest +from modflowapi import ModflowApi try: import pymake @@ -156,8 +157,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_left), - budget_filerecord="{}.cbc".format(name_left), + head_filerecord=f"{name_left}.hds", + budget_filerecord=f"{name_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -190,8 +191,8 @@ def get_model(dir, name): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name_right), - budget_filerecord="{}.cbc".format(name_right), + head_filerecord=f"{name_right}.hds", + budget_filerecord=f"{name_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -339,7 +340,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_rch01.py b/autotest/test_gwf_libmf6_rch01.py index d1b80dbf26a..07592d15a94 100644 --- a/autotest/test_gwf_libmf6_rch01.py +++ b/autotest/test_gwf_libmf6_rch01.py @@ -9,8 +9,9 @@ """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -145,7 +146,7 @@ def get_model(ws, name, rech): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -220,8 +221,8 @@ def api_func(exe, idx, model_ws=None): if has_converged: msg = ( - "Component {}".format(1) - + " converged in {}".format(kiter) + f"Component {1}" + + f" converged in {kiter}" + " outer iterations" ) print(msg) @@ -283,7 +284,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_rch02.py b/autotest/test_gwf_libmf6_rch02.py index e37e99a19d3..3ed421c2254 100644 --- a/autotest/test_gwf_libmf6_rch02.py +++ b/autotest/test_gwf_libmf6_rch02.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -149,7 +150,7 @@ def get_model(ws, name, rech=rch_spd): rch = flopy.mf6.ModflowGwfrcha(gwf, recharge=rech, pname=rch_pname) # gwf observations - onam = "{}.head.obs".format(name) + onam = f"{name}.head.obs" cnam = onam + ".csv" obs_recarray = {cnam: [("h1_6_6", "HEAD", (0, 5, 5))]} gwfobs = flopy.mf6.ModflowUtlobs( @@ -163,7 +164,7 @@ def get_model(ws, name, rech=rch_spd): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -210,7 +211,7 @@ def api_func(exe, idx, model_ws=None): os.chdir(model_ws) # get the observations from the standard run - fpth = os.path.join("..", "{}.head.obs.csv".format(ex[idx])) + fpth = os.path.join("..", f"{ex[idx]}.head.obs.csv") hobs = np.genfromtxt(fpth, delimiter=",", names=True)["H1_6_6"] try: @@ -284,11 +285,11 @@ def api_func(exe, idx, model_ws=None): # evaluate if the estimation iterations need to continue if abs(r0) < 1e-5: msg = ( - "Estimation for time {:5.1f}".format(current_time) - + " converged in {:3d}".format(est_iter) + f"Estimation for time {current_time:5.1f}" + + f" converged in {est_iter:3d}" + " iterations" - + " -- final recharge={:10.5f}".format(rch) - + " residual={:10.2g}".format(rch - rch_rates[idx]) + + f" -- final recharge={rch:10.5f}" + + f" residual={rch - rch_rates[idx]:10.2g}" ) print(msg) break @@ -358,7 +359,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_riv01.py b/autotest/test_gwf_libmf6_riv01.py index cf4f033bcba..7a753137e86 100644 --- a/autotest/test_gwf_libmf6_riv01.py +++ b/autotest/test_gwf_libmf6_riv01.py @@ -4,8 +4,9 @@ the same values as they are in the non-bmi simulation. """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -140,7 +141,7 @@ def get_model(ws, name, riv_spd): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -231,8 +232,8 @@ def api_func(exe, idx, model_ws=None): if has_converged: msg = ( - "Component {}".format(1) - + " converged in {}".format(kiter) + f"Component {1}" + + f" converged in {kiter}" + " outer iterations" ) print(msg) @@ -294,7 +295,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_riv02.py b/autotest/test_gwf_libmf6_riv02.py index f27a555b43a..67d7f04fd20 100644 --- a/autotest/test_gwf_libmf6_riv02.py +++ b/autotest/test_gwf_libmf6_riv02.py @@ -4,8 +4,9 @@ package in the non-api simulation. """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -143,7 +144,7 @@ def get_model(ws, name, riv_spd, api=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -265,7 +266,7 @@ def api_func(exe, idx, model_ws=None): kiter += 1 if has_converged: - msg = "Converged in {}".format(kiter) + " outer iterations" + msg = f"Converged in {kiter}" + " outer iterations" print(msg) break @@ -324,7 +325,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_libmf6_sto01.py b/autotest/test_gwf_libmf6_sto01.py index 1279a3bb1cb..80e4365cd59 100644 --- a/autotest/test_gwf_libmf6_sto01.py +++ b/autotest/test_gwf_libmf6_sto01.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest from modflowapi import ModflowApi try: @@ -148,7 +149,7 @@ def get_model(ws, name, sy): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -259,7 +260,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw01.py b/autotest/test_gwf_maw01.py index 43d570e3bdc..425388bf22f 100644 --- a/autotest/test_gwf_maw01.py +++ b/autotest/test_gwf_maw01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -68,7 +69,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) gwf.name_file.newtonoptions = newtonoptions[idx] @@ -99,11 +100,11 @@ def build_model(idx, dir): top=100.0, botm=0.0, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -112,7 +113,7 @@ def build_model(idx, dir): icelltype=1, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # storage sto = flopy.mf6.ModflowGwfsto( @@ -123,7 +124,7 @@ def build_model(idx, dir): sy=0.1, steady_state={0: True}, # transient={1: False}, - filename="{}.sto".format(name), + filename=f"{name}.sto", ) # chd files @@ -140,7 +141,7 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # wel files @@ -149,7 +150,7 @@ def build_model(idx, dir): # periodrecarray=wd6, # save_flows=False) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" wellbottom = 50.0 wellrecarray = [[0, 0.1, wellbottom, 100.0, "THIEM", 1]] wellconnectionsrecarray = [[0, 0, (0, 0, 1), 100.0, wellbottom, 1.0, 0.1]] @@ -158,7 +159,7 @@ def build_model(idx, dir): mawo_dict["maw_obs.csv"] = [("mh1", "head", 1)] maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(name), + filename=f"{name}.maw", print_input=True, print_head=True, print_flows=True, @@ -172,12 +173,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -191,7 +192,7 @@ def eval_maw(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # create known results array tc0 = np.array([100.0, 25.0, 100.0]) @@ -200,11 +201,11 @@ def eval_maw(sim): diff = tc["MH1"] - tc0 diffmax = np.abs(diff).max() dtol = 1e-9 - msg = "maximum absolute maw head difference ({}) ".format(diffmax) + msg = f"maximum absolute maw head difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -245,7 +246,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw02.py b/autotest/test_gwf_maw02.py index d15c13b1a5f..745264a71cd 100644 --- a/autotest/test_gwf_maw02.py +++ b/autotest/test_gwf_maw02.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -76,7 +77,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) # create iterative model solution and register the gwf model with it @@ -106,11 +107,11 @@ def build_model(idx, dir): top=100.0, botm=0.0, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -119,7 +120,7 @@ def build_model(idx, dir): icelltype=1, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # storage sto = flopy.mf6.ModflowGwfsto( @@ -130,7 +131,7 @@ def build_model(idx, dir): sy=0.1, steady_state={0: True}, # transient={1: False}, - filename="{}.sto".format(name), + filename=f"{name}.sto", ) # chd files @@ -147,11 +148,11 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" wellbottom = 0.0 wellrecarray = [ [0, 0.1, wellbottom, 100.0, "THIEM", 1], @@ -183,8 +184,8 @@ def build_model(idx, dir): mawo_dict["maw_obs.csv"] = [("mh1", "head", 1)] maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(name), - budget_filerecord="{}.maw.cbc".format(name), + filename=f"{name}.maw", + budget_filerecord=f"{name}.maw.cbc", print_input=True, print_head=True, print_flows=True, @@ -199,12 +200,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -214,9 +215,7 @@ def eval_maw(sim): print("evaluating MAW budgets...") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget( fpth, budgetkey="MAW-1 BUDGET FOR ENTIRE MODEL AT END OF TIME STEP" ) @@ -230,9 +229,7 @@ def eval_maw(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.maw.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.maw.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -262,9 +259,9 @@ def eval_maw(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout maw_vals = [ @@ -281,39 +278,39 @@ def eval_maw(sim): for ov, sv in zip(ovs, svs): diffv.append(ov - sv) diffv = np.abs(np.array(diffv)).max() - msg = "\nmaximum absolute maw rate difference ({})\n".format(diffv) + msg = f"\nmaximum absolute maw rate difference ({diffv})\n" # calculate difference between water budget items in the lst and cbc files diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg += "maximum absolute total-budget difference ({}) ".format(diffmax) + msg += f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol or diffv > budtol: sim.success = False - msg += "\n...exceeds {}".format(budtol) + msg += f"\n...exceeds {budtol}" assert diffmax < budtol, msg else: sim.success = True @@ -354,7 +351,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw03.py b/autotest/test_gwf_maw03.py index 264a3f42176..0ef3963d939 100644 --- a/autotest/test_gwf_maw03.py +++ b/autotest/test_gwf_maw03.py @@ -7,9 +7,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -80,7 +81,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) # create iterative model solution and register the gwf model with it @@ -110,11 +111,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -123,7 +124,7 @@ def build_model(idx, dir): icelltype=1, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # storage @@ -135,23 +136,23 @@ def build_model(idx, dir): sy=0.1, steady_state={0: False}, transient={0: True}, - filename="{}.sto".format(name), + filename=f"{name}.sto", ) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" wellbottom = -1000 wellrecarray = [[0, 0.15, wellbottom, 0.0, "THIEM", 1]] wellconnectionsrecarray = [[0, 0, (0, 50, 50), 0.0, wellbottom, 0.0, 0.0]] wellperiodrecarray = mawsettings[idx] mawo_dict = {} - mawo_dict["{}.maw.obs.csv".format(name)] = [ + mawo_dict[f"{name}.maw.obs.csv"] = [ ("m1head", "head", (0,)), ("m1rate", "rate", (0,)), ] # is this index one-based? Not if in a tuple maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(name), + filename=f"{name}.maw", print_input=True, print_head=True, print_flows=True, @@ -165,23 +166,23 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) # head observations obs_data0 = [("head_well_cell", "HEAD", (0, 0, 0))] - obs_recarray = {"{}.obs.csv".format(name): obs_data0} + obs_recarray = {f"{name}.obs.csv": obs_data0} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", - filename="{}.obs".format(name), + filename=f"{name}.obs", digits=15, print_input=True, continuous=obs_recarray, @@ -196,11 +197,11 @@ def eval_maw(sim): # MODFLOW 6 maw results idx = sim.idxsim name = ex[idx] - fpth = os.path.join(sim.simpath, "{}.maw.obs.csv".format(name)) + fpth = os.path.join(sim.simpath, f"{name}.maw.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' if idx == 0: @@ -231,7 +232,7 @@ def eval_maw(sim): else: - assert False, "Test error. idx {} not being tested.".format(idx) + assert False, f"Test error. idx {idx} not being tested." return @@ -268,7 +269,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw04.py b/autotest/test_gwf_maw04.py index f7078e9519a..403fc8905e4 100644 --- a/autotest/test_gwf_maw04.py +++ b/autotest/test_gwf_maw04.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,7 +20,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = [ @@ -186,8 +187,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], ) # build MODFLOW-2005 files @@ -292,7 +293,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw05.py b/autotest/test_gwf_maw05.py index d2862d1abb3..d5df0743915 100644 --- a/autotest/test_gwf_maw05.py +++ b/autotest/test_gwf_maw05.py @@ -4,9 +4,10 @@ # maw_05c - well starts at or below 3.0; not working yet import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -87,7 +88,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -140,16 +141,16 @@ def build_model(idx, dir): print_head=True, print_flows=True, save_flows=True, - head_filerecord="{}.maw.bin".format(gwfname), - budget_filerecord="{}.maw.bud".format(gwfname), + head_filerecord=f"{gwfname}.maw.bin", + budget_filerecord=f"{gwfname}.maw.bud", packagedata=mawpackagedata, connectiondata=mawconnectiondata, perioddata=mawperioddata, pname="MAW-1", ) - opth = "{}.maw.obs".format(gwfname) + opth = f"{gwfname}.maw.obs" obsdata = { - "{}.maw.obs.csv".format(gwfname): [ + f"{gwfname}.maw.obs.csv": [ ("whead", "head", (0,)), ] } @@ -160,8 +161,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -217,9 +218,9 @@ def eval_results(sim): print( "Initial volumes\n" - + " Groundwater: {}\n".format(v0gwf) - + " Well: {}\n".format(v0maw) - + " Total: {}".format(v0) + + f" Groundwater: {v0gwf}\n" + + f" Well: {v0maw}\n" + + f" Total: {v0}" ) # calculate current volume of water in well and aquifer and compare with @@ -235,20 +236,20 @@ def eval_results(sim): vmaw = stage[kstp] * np.pi * 0.1**2 vnow = vmaw + vgwf errmsg = ( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) assert np.allclose(v0, vnow), errmsg print( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) return @@ -283,7 +284,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw06.py b/autotest/test_gwf_maw06.py index de1e2d2700a..3043636e360 100644 --- a/autotest/test_gwf_maw06.py +++ b/autotest/test_gwf_maw06.py @@ -3,8 +3,9 @@ # maw_06b - well starts at 2, aquifer starts at .25 import os -import pytest + import numpy as np +import pytest try: import flopy @@ -103,12 +104,12 @@ def build_model(idx, dir): under_relaxation_gamma=0.98, inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -150,8 +151,8 @@ def build_model(idx, dir): ] # mawperioddata = [[0, "STATUS", "ACTIVE"]] - mbin = "{}.maw.bin".format(gwfname) - mbud = "{}.maw.bud".format(gwfname) + mbin = f"{gwfname}.maw.bin" + mbud = f"{gwfname}.maw.bud" maw = flopy.mf6.ModflowGwfmaw( gwf, print_input=True, @@ -166,9 +167,9 @@ def build_model(idx, dir): perioddata=mawperioddata, pname="MAW-1", ) - opth = "{}.maw.obs".format(gwfname) + opth = f"{gwfname}.maw.obs" obsdata = { - "{}.maw.obs.csv".format(gwfname): [ + f"{gwfname}.maw.obs.csv": [ ("whead", "head", (0,)), ] } @@ -179,8 +180,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -232,9 +233,9 @@ def eval_results(sim): print( "Initial volumes\n" - + " Groundwater: {}\n".format(v0gwf) - + " Well: {}\n".format(v0maw) - + " Total: {}".format(v0) + + f" Groundwater: {v0gwf}\n" + + f" Well: {v0maw}\n" + + f" Total: {v0}" ) # calculate current volume of water in well and aquifer and compare with @@ -249,20 +250,20 @@ def eval_results(sim): vmaw = (stage[kstp] - bot) * mawarea vnow = vmaw + vgwf errmsg = ( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) assert np.allclose(v0, vnow), errmsg print( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) # compare the maw-gwf flows with the gwf-maw flows @@ -284,9 +285,7 @@ def eval_results(sim): for i in range(ra_maw.shape[0]): qmaw = ra_maw[i]["q"] qgwf = ra_gwf[i]["q"] - msg = "step {} record {} comparing qmaw with qgwf: {} {}".format( - istp, i, qmaw, qgwf - ) + msg = f"step {istp} record {i} comparing qmaw with qgwf: {qmaw} {qgwf}" print(msg) assert np.allclose(qmaw, -qgwf), msg @@ -322,7 +321,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw07.py b/autotest/test_gwf_maw07.py index ed01389ef9d..94eb6993177 100644 --- a/autotest/test_gwf_maw07.py +++ b/autotest/test_gwf_maw07.py @@ -3,8 +3,9 @@ # in the gwf and maw budget files are zero for this first period. import os -import pytest + import numpy as np +import pytest try: import flopy @@ -103,12 +104,12 @@ def build_model(idx, dir): under_relaxation_gamma=0.98, inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -152,8 +153,8 @@ def build_model(idx, dir): mawperioddata = {} mawperioddata[0] = [[0, "STATUS", "INACTIVE"]] mawperioddata[1] = [[0, "STATUS", "ACTIVE"]] - mbin = "{}.maw.bin".format(gwfname) - mbud = "{}.maw.bud".format(gwfname) + mbin = f"{gwfname}.maw.bin" + mbud = f"{gwfname}.maw.bud" maw = flopy.mf6.ModflowGwfmaw( gwf, print_input=True, @@ -168,9 +169,9 @@ def build_model(idx, dir): perioddata=mawperioddata, pname="MAW-1", ) - opth = "{}.maw.obs".format(gwfname) + opth = f"{gwfname}.maw.obs" obsdata = { - "{}.maw.obs.csv".format(gwfname): [ + f"{gwfname}.maw.obs.csv": [ ("whead", "head", (0,)), ] } @@ -181,8 +182,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -234,9 +235,9 @@ def eval_results(sim): print( "Initial volumes\n" - + " Groundwater: {}\n".format(v0gwf) - + " Well: {}\n".format(v0maw) - + " Total: {}".format(v0) + + f" Groundwater: {v0gwf}\n" + + f" Well: {v0maw}\n" + + f" Total: {v0}" ) # calculate current volume of water in well and aquifer and compare with @@ -251,20 +252,20 @@ def eval_results(sim): vmaw = (stage[kstp] - bot) * mawarea vnow = vmaw + vgwf errmsg = ( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) assert np.allclose(v0, vnow), errmsg print( - "kstp {}: \n".format(kstp + 1) - + " Groundwater: {}\n".format(vgwf) - + " Well: {}\n".format(vmaw) - + " Total: {}\n".format(vnow) - + " Initial Total: {}".format(v0) + f"kstp {kstp + 1}: \n" + + f" Groundwater: {vgwf}\n" + + f" Well: {vmaw}\n" + + f" Total: {vnow}\n" + + f" Initial Total: {v0}" ) # compare the maw-gwf flows with the gwf-maw flows @@ -290,9 +291,7 @@ def eval_results(sim): assert np.allclose( qmaw, 0.0 ), "inactive well, flow should be 0." - msg = "step {} record {} comparing qmaw with qgwf: {} {}".format( - istp, i, qmaw, qgwf - ) + msg = f"step {istp} record {i} comparing qmaw with qgwf: {qmaw} {qgwf}" print(msg) assert np.allclose(qmaw, -qgwf), msg @@ -328,7 +327,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw08.py b/autotest/test_gwf_maw08.py index 3425e9563f9..a1e1a2b9a34 100644 --- a/autotest/test_gwf_maw08.py +++ b/autotest/test_gwf_maw08.py @@ -2,8 +2,9 @@ # dry multi-aquifer well problem. Developed to address issue #546 import os -import pytest + import numpy as np +import pytest try: import flopy @@ -75,7 +76,7 @@ def build_model(idx, dir): complexity="complex", outer_dvclose=dvclose, inner_dvclose=dvclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", relaxation_factor=relax, ) @@ -150,8 +151,8 @@ def build_model(idx, dir): mawconnectiondata["hk_skin"] = -999 mawconnectiondata["radius_skin"] = -999 - mbin = "{}.maw.bin".format(gwfname) - mbud = "{}.maw.bud".format(gwfname) + mbin = f"{gwfname}.maw.bin" + mbud = f"{gwfname}.maw.bud" maw = flopy.mf6.ModflowGwfmaw( gwf, print_input=True, @@ -163,9 +164,9 @@ def build_model(idx, dir): packagedata=mawpackagedata, connectiondata=mawconnectiondata, ) - opth = "{}.maw.obs".format(gwfname) + opth = f"{gwfname}.maw.obs" obsdata = { - "{}.maw.obs.csv".format(gwfname): [ + f"{gwfname}.maw.obs.csv": [ ("whead", "head", (0,)), ] } @@ -176,8 +177,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -218,7 +219,7 @@ def eval_results(sim): well_head = bobj.get_data().flatten() assert np.allclose( well_head, 10.0 - ), "simulated maw head ({}) does not equal 10.".format(well_head[0]) + ), f"simulated maw head ({well_head[0]}) does not equal 10." fname = gwfname + ".hds" fname = os.path.join(sim.simpath, fname) @@ -245,9 +246,7 @@ def eval_results(sim): for i in range(ra_maw.shape[0]): qmaw = ra_maw[i]["q"] qgwf = ra_gwf[i]["q"] - msg = "step {} record {} comparing qmaw with qgwf: {} {}".format( - istp, i, qmaw, qgwf - ) + msg = f"step {istp} record {i} comparing qmaw with qgwf: {qmaw} {qgwf}" print(msg) assert np.allclose(qmaw, -qgwf), msg @@ -283,7 +282,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw09.py b/autotest/test_gwf_maw09.py index 5bfcc5df336..4513ab1659c 100644 --- a/autotest/test_gwf_maw09.py +++ b/autotest/test_gwf_maw09.py @@ -2,8 +2,9 @@ # dry multi-aquifer well problem. Developed to address issue #546 import os -import pytest + import numpy as np +import pytest try: import flopy @@ -79,7 +80,7 @@ def build_model(idx, dir): complexity="complex", outer_dvclose=dvclose, inner_dvclose=dvclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", relaxation_factor=relax, ) @@ -145,8 +146,8 @@ def build_model(idx, dir): k33=Kv, ) # gwf observations - opth = "{}.gwf.obs".format(gwfname) - obsdata = {"{}.gwf.obs.csv".format(gwfname): gwf_obs} + opth = f"{gwfname}.gwf.obs" + obsdata = {f"{gwfname}.gwf.obs.csv": gwf_obs} flopy.mf6.ModflowUtlobs( gwf, filename=opth, digits=20, print_input=True, continuous=obsdata ) @@ -175,8 +176,8 @@ def build_model(idx, dir): mawconnectiondata["hk_skin"] = 1.0 mawconnectiondata["radius_skin"] = -999 - mbin = "{}.maw.bin".format(gwfname) - mbud = "{}.maw.bud".format(gwfname) + mbin = f"{gwfname}.maw.bin" + mbud = f"{gwfname}.maw.bud" maw = flopy.mf6.ModflowGwfmaw( gwf, print_input=True, @@ -189,9 +190,9 @@ def build_model(idx, dir): packagedata=mawpackagedata, connectiondata=mawconnectiondata, ) - opth = "{}.maw.obs".format(gwfname) + opth = f"{gwfname}.maw.obs" obsdata = { - "{}.maw.obs.csv".format(gwfname): [ + f"{gwfname}.maw.obs.csv": [ ("whead", "head", (0,)), ] } @@ -202,8 +203,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -237,13 +238,13 @@ def eval_results(sim): gwfname = "gwf_" + name # get well observations - fname = "{}.gwf.obs.csv".format(gwfname) + fname = f"{gwfname}.gwf.obs.csv" fname = os.path.join(sim.simpath, fname) assert os.path.isfile(fname) gobs = np.genfromtxt(fname, delimiter=",", names=True) # get well observations - fname = "{}.maw.obs.csv".format(gwfname) + fname = f"{gwfname}.maw.obs.csv" fname = os.path.join(sim.simpath, fname) assert os.path.isfile(fname) wobs = np.genfromtxt(fname, delimiter=",", names=True)["WHEAD"] @@ -269,21 +270,21 @@ def eval_results(sim): vt = vw + vg # write a message - msg = "{}\n well volume: {} ".format(idx, vw) - msg += "\n groundwater volume: {}".format(vg) - msg += "\n total volume: {}".format(vt) + msg = f"{idx}\n well volume: {vw} " + msg += f"\n groundwater volume: {vg}" + msg += f"\n total volume: {vt}" print(msg) # evaluate results - msg = "total volume {} not equal to initial volume {}".format(vt, v0) - msg += "\nwell volume: {}\ngroundwater volume: {}".format(vw, vg) + msg = f"total volume {vt} not equal to initial volume {v0}" + msg += f"\nwell volume: {vw}\ngroundwater volume: {vg}" assert np.allclose(vt, v0), msg # Check final well head well_head = wobs[-1] assert np.allclose( well_head, 17.25 - ), "final simulated maw head ({}) does not equal 17.25.".format(well_head) + ), f"final simulated maw head ({well_head}) does not equal 17.25." fname = gwfname + ".hds" fname = os.path.join(sim.simpath, fname) @@ -310,9 +311,7 @@ def eval_results(sim): for i in range(ra_maw.shape[0]): qmaw = ra_maw[i]["q"] qgwf = ra_gwf[i]["q"] - msg = "step {} record {} comparing qmaw with qgwf: {} {}".format( - istp, i, qmaw, qgwf - ) + msg = f"step {istp} record {i} comparing qmaw with qgwf: {qmaw} {qgwf}" print(msg) assert np.allclose(qmaw, -qgwf), msg @@ -348,7 +347,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_maw10.py b/autotest/test_gwf_maw10.py new file mode 100644 index 00000000000..9d84281c7bd --- /dev/null +++ b/autotest/test_gwf_maw10.py @@ -0,0 +1,327 @@ +""" +MODFLOW 6 Autotest +Test to confirm that the sum of rate-actual and maw-reduction observations +is equal to the specified MAW extraction or injection pumping rate when +reported using the MAW_FLOW_REDUCE_CSV option. Injection and extraction +are tested for both MAW HEAD_LIMIT and RATE_SCALING options to reduce MAW +flow rates from the specified input (requested) values. +""" + +import os +import sys + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = ["maw10a", "maw10b", "maw10c", "maw10d"] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# maw settings for runs a, b, c and d +mawsetting_a = { + 0: [ + [0, "rate", -2000.0], + [0, "head_limit", -0.4], + ], + 1: [ + [0, "status", "inactive"], + ], +} +mawsetting_b = { + 0: [ + [0, "rate", -2000.0], + [0, "rate_scaling", -1.4, 1.0], + ], + 1: [ + [0, "status", "inactive"], + ], +} +mawsetting_c = { + 0: [ + [0, "rate", 2000.0], + [0, "head_limit", 0.4], + ], + 1: [ + [0, "status", "inactive"], + ], +} +mawsetting_d = { + 0: [ + [0, "rate", 2000.0], + [0, "rate_scaling", 0.0, 1.0], + ], + 1: [ + [0, "status", "inactive"], + ], +} + +# simple single stress period without going inactive in 2nd stress period +# mawsetting_a = [(0, "rate", -2000.0), (0, "head_limit", -0.4)] +# mawsetting_b = [[(0, "rate", -2000.0), (0, "rate_scaling", -1.4, 1.0)], ["status", "inactive"]] +# mawsetting_c = [[(0, "rate", 2000.0), (0, "head_limit", 0.4)], ["status", "inactive"]] +# mawsetting_d = [[(0, "rate", 2000.0), (0, "rate_scaling", 0.0, 1.0)], ["status", "inactive"]] +mawsettings = [mawsetting_a, mawsetting_b, mawsetting_c, mawsetting_d] + + +def build_model(idx, dir): + + nlay, nrow, ncol = 1, 101, 101 + nper = 2 + perlen = [500.0, 500.0] + nstp = [50, 50] + tsmult = [1.2, 1.2] + delr = delc = 142.0 + top = 0.0 + botm = [-1000.0] + strt = 0.0 + hk = 10.0 + + nouter, ninner = 100, 100 + hclose, rclose, relax = 1e-6, 1e-6, 1.0 + + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation(sim_name=name, sim_ws=ws) + + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwf = flopy.mf6.MFModel( + sim, + model_type="gwf6", + modelname=name, + model_nam_file=f"{name}.nam", + ) + + # create iterative model solution and register the gwf model with it + ims = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + ) + sim.register_ims_package(ims, [gwf.name]) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=1, + filename=f"{name}.dis", + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") + + # node property flow + npf = flopy.mf6.ModflowGwfnpf( + gwf, + save_flows=True, + icelltype=1, + k=hk, + k33=hk, + filename=f"{name}.npf", + ) + + # storage + sto = flopy.mf6.ModflowGwfsto( + gwf, + save_flows=True, + iconvert=0, + ss=1.0e-5, + sy=0.1, + steady_state={0: False}, + transient={0: True}, + filename=f"{name}.sto", + ) + + # MAW + opth = f"{name}.maw.obs" + wellbottom = -1000 + wellrecarray = [[0, 0.15, wellbottom, 0.0, "THIEM", 1]] + wellconnectionsrecarray = [[0, 0, (0, 50, 50), 0.0, wellbottom, 0.0, 0.0]] + wellperiodrecarray = mawsettings[idx] + mawo_dict = {} + mawo_dict[f"{name}.maw.obs.csv"] = [ + ("m1head", "head", (0,)), + ("m1rate", "rate", (0,)), + ] # is this index one-based? Not if in a tuple + maw = flopy.mf6.ModflowGwfmaw( + gwf, + filename=f"{name}.maw", + print_input=True, + print_head=True, + print_flows=True, + save_flows=True, + observations=mawo_dict, + packagedata=wellrecarray, + connectiondata=wellconnectionsrecarray, + perioddata=wellperiodrecarray, + mfrcsv_filerecord=f"{name}.maw-reduction.csv", + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", + headprintrecord=[ + ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("HEAD", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + filename=f"{name}.oc", + ) + + # head observations + obs_data0 = [("head_well_cell", "HEAD", (0, 0, 0))] + obs_recarray = {f"{name}.obs.csv": obs_data0} + obs = flopy.mf6.ModflowUtlobs( + gwf, + pname="head_obs", + filename=f"{name}.obs", + digits=15, + print_input=True, + continuous=obs_recarray, + ) + + return sim, None + + +# 2 tests to perform here: +# 1. within the .maw-reduction.csv file, do values of actual + reduction = requested? +# 2. do the values in .maw-reduction.csv file match with the .maw.obs.csv file at each time +# (and all are reduction times present in the obs file)? +def eval_mawred(sim): + print("evaluating MAW flow reduction outputs...") + + # MODFLOW 6 maw results + idx = sim.idxsim + name = ex[idx] + fpthobs = os.path.join(sim.simpath, f"{name}.maw.obs.csv") + fpthmfr = os.path.join(sim.simpath, f"{name}.maw-reduction.csv") + try: + tcobs = np.genfromtxt(fpthobs, names=True, delimiter=",") + except: + assert False, f'could not load data from "{fpthobs}"' + try: + tcmfr = np.genfromtxt( + fpthmfr, names=True, delimiter=",", deletechars="" + ) + except: + assert False, f'could not load data from "{fpthmfr}"' + + # test 1: does rate-requested = rate-actual + maw-reduction at each time in the .maw.reduced.csv? + for rowmfr in tcmfr: + v1 = rowmfr["rate-requested"] + v2 = rowmfr["rate-actual"] + rowmfr["maw-reduction"] + errmsg = f"MAW flow reduction output: requested rate must equal actual rate plus reduced rate.\n" + errmsg += f"{v1} /= {v2}" + assert np.allclose(v1, v2), errmsg + + # test 2: do values of rate-actual in .maw.reduced.csv equal those flow values reported in .maw.obs.csv? + # (and are there matching times?) + for rowmfr in tcmfr: + timevalmfr = rowmfr["time"] + actvalmfr = rowmfr["rate-actual"] + msgtime = ( + "There should be a matching time in the maw.obs.csv file for each " + "time in the maw.reduce.csv file, but no match was found for " + "time = {} in the maw.obs.csv file".format(timevalmfr) + ) + blnFoundTimeMatch = False + for rowobs in tcobs: + timevalobs = rowobs["time"] + if np.isclose(timevalmfr, timevalobs): + blnFoundTimeMatch = True + actvalobs = rowobs["M1RATE"] + msgval = ( + "The maw.obs.csv file rate-actual value of {} should have " + "matched the maw.reduce.csv file rate-actual value of {} " + "at time {}".format(actvalobs, actvalmfr, timevalobs) + ) + break + assert blnFoundTimeMatch, msgtime + assert np.isclose(actvalmfr, actvalobs), msgval + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the models + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_mawred, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # build the models + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_mawred, idxsim=idx) + test.run_mf6(sim) + + return + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_maw_obs.py b/autotest/test_gwf_maw_obs.py index 6a3ed238a86..21ee3503b39 100644 --- a/autotest/test_gwf_maw_obs.py +++ b/autotest/test_gwf_maw_obs.py @@ -8,8 +8,8 @@ import os import shutil -import pytest import numpy as np +import pytest try: import pymake @@ -77,7 +77,7 @@ def build_model(): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) gwf.name_file.newtonoptions = newtonoptions[0] @@ -108,11 +108,11 @@ def build_model(): top=100.0, botm=0.0, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -121,7 +121,7 @@ def build_model(): icelltype=1, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # storage sto = flopy.mf6.ModflowGwfsto( @@ -132,7 +132,7 @@ def build_model(): sy=0.1, steady_state={0: True}, # transient={1: False}, - filename="{}.sto".format(name), + filename=f"{name}.sto", ) # chd files @@ -149,7 +149,7 @@ def build_model(): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # wel files @@ -158,7 +158,7 @@ def build_model(): # periodrecarray=wd6, # save_flows=False) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" wellbottom = 50.0 wellrecarray = [[0, 0.1, wellbottom, 100.0, "THIEM", 1]] wellconnectionsrecarray = [[0, 0, (0, 0, 1), 100.0, wellbottom, 1.0, 0.1]] @@ -167,7 +167,7 @@ def build_model(): mawo_dict["maw_obs.csv"] = [("mh1", "head", 1), ("mawgw", "maw", 1)] maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(name), + filename=f"{name}.maw", print_input=True, print_head=True, print_flows=True, @@ -181,12 +181,12 @@ def build_model(): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim @@ -253,7 +253,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_multimvr.py b/autotest/test_gwf_multimvr.py index 394f1486b8b..59bcef3a48e 100644 --- a/autotest/test_gwf_multimvr.py +++ b/autotest/test_gwf_multimvr.py @@ -1,8 +1,10 @@ +import math import os -import pytest -import numpy as np import shutil -import math + +import numpy as np +import pytest + import targets try: @@ -603,7 +605,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): modelname=gwfname, save_flows=True, newtonoptions="NEWTON", - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # Create iterative model solution and register the gwf model with it @@ -620,7 +622,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -635,14 +637,12 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): top=topp, botm=botmp, idomain=idomainp, - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # Instantiate initial conditions package strt = [topp - 0.25, topp - 0.25, topp - 0.25] - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # Instantiate node property flow package npf = flopy.mf6.ModflowGwfnpf( @@ -653,7 +653,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): k=hk, k33=k33, save_specific_discharge=False, - filename="{}.npf".format(gwfname), + filename=f"{gwfname}.npf", ) # output control @@ -687,7 +687,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): stress_period_data=chdspd, save_flows=False, pname="CHD-1", - filename="{}.chd1.chd".format(gwfname), + filename=f"{gwfname}.chd1.chd", ) chdspd = {0: chdspd_right} chd2 = flopy.mf6.modflow.mfgwfchd.ModflowGwfchd( @@ -696,7 +696,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): stress_period_data=chdspd, save_flows=False, pname="CHD-2", - filename="{}.chd2.chd".format(gwfname), + filename=f"{gwfname}.chd2.chd", ) welspd_mf6 = [] @@ -715,7 +715,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): boundnames=False, save_flows=True, pname="WEL-1", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # --------------------------- @@ -750,7 +750,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): modelname=gwfnamec, save_flows=True, newtonoptions="NEWTON", - model_nam_file="{}.nam".format(gwfnamec), + model_nam_file=f"{gwfnamec}.nam", ) # Instantiate the discretization package @@ -770,7 +770,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): idomain=idomainc, xorigin=xorigin, yorigin=yorigin, - filename="{}.dis".format(gwfnamec), + filename=f"{gwfnamec}.dis", ) # Instantiate initial conditions package @@ -782,9 +782,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): topc - 0.25, topc - 0.25, ] - icc = flopy.mf6.ModflowGwfic( - gwfc, strt=strtc, filename="{}.ic".format(gwfnamec) - ) + icc = flopy.mf6.ModflowGwfic(gwfc, strt=strtc, filename=f"{gwfnamec}.ic") # Instantiate node property flow package icelltypec = [1, 0, 0, 0, 0, 0] @@ -796,7 +794,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): k=hk, k33=k33, save_specific_discharge=False, - filename="{}.npf".format(gwfnamec), + filename=f"{gwfnamec}.npf", ) # output control @@ -822,7 +820,7 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): boundnames=False, save_flows=True, pname="WEL-2", - filename="{}.wel".format(gwfnamec), + filename=f"{gwfnamec}.wel", ) # exchange data @@ -838,9 +836,8 @@ def instantiate_base_simulation(sim_ws, gwfname, gwfnamec): exgmnameb=gwfnamec, nexg=len(exchange_data), exchangedata=exchange_data, - mvr_filerecord="{}.mvr".format(name), pname="EXG-1", - filename="{}.exg".format(name), + filename=f"{name}.exg", ) return sim, gwf, gwfc @@ -862,7 +859,7 @@ def add_parent_sfr(gwf, gwfname, conns): packagedata=pkdat, connectiondata=conns, perioddata=sfrspd, - filename="{}.sfr".format(gwfname), + filename=f"{gwfname}.sfr", ) @@ -882,7 +879,7 @@ def add_child_sfr(gwfc, gwfnamec): packagedata=pkdatc, connectiondata=connsc, perioddata=sfrspd, - filename="{}.sfr".format(gwfnamec), + filename=f"{gwfnamec}.sfr", ) @@ -896,7 +893,7 @@ def add_parent_mvr(gwf, gwfname, frac): maxpackages=maxpackages, packages=mvrpack, perioddata=mvrspd, - filename="{}.mvr".format(gwfname), + filename=f"{gwfname}.mvr", ) @@ -908,7 +905,7 @@ def add_child_mvr(gwfc, gwfnamec): maxpackages=maxpackagesc, packages=mvrpackc, perioddata=mvrspdc, - filename="{}.mvr".format(gwfnamec), + filename=f"{gwfnamec}.mvr", ) @@ -977,15 +974,15 @@ def add_sim_mvr(sim, gwfname, gwfnamec, remaining_frac=None): mvrspd = {0: sim_mvr_perioddata} maxmvr = 3 - mvr = flopy.mf6.ModflowMvr( - sim, + gwfgwf = sim.get_exchange_file("gwf.exg") + gwfgwf.mvr.initialize( modelnames=True, maxmvr=maxmvr, print_flows=True, maxpackages=maxpackages, packages=mvrpack_sim, perioddata=mvrspd, - filename="{}.mvr".format(name), + filename=f"{name}.mvr", ) @@ -1174,7 +1171,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_mvr01.py b/autotest/test_gwf_mvr01.py index 8e0a1e3a3f3..d971945a7c7 100644 --- a/autotest/test_gwf_mvr01.py +++ b/autotest/test_gwf_mvr01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -61,8 +62,8 @@ def build_model(idx, dir): ) # create iterative model solution and register the gwf model with it - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" ims = flopy.mf6.ModflowIms( sim, csv_outer_output_filerecord=csv0, @@ -204,7 +205,7 @@ def build_model(idx, dir): [3, "status", "active"], [4, "status", "active"], ] - cnvgpth = "{}.sfr.cnvg.csv".format(name) + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, mover=True, @@ -285,7 +286,7 @@ def build_model(idx, dir): (2, "rate", 0.0), ] perioddata = lakeperioddata + outletperioddata - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, mover=True, @@ -323,7 +324,7 @@ def build_model(idx, dir): [7, 1.0e-8, 0, 0, 0, 0, 0, 0], [8, 1.0e-8, 0, 0, 0, 0, 0, 0], ] - cnvgpth = "{}.uzf.cnvg.csv".format(name) + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, mover=True, @@ -360,7 +361,7 @@ def build_model(idx, dir): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -370,8 +371,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -484,7 +485,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_newton01.py b/autotest/test_gwf_newton01.py index 012bee60f48..ca733eba833 100644 --- a/autotest/test_gwf_newton01.py +++ b/autotest/test_gwf_newton01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -103,8 +104,8 @@ def build_model(idx, ws): # output control flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -118,10 +119,10 @@ def eval_head(sim): fpth = os.path.join(sim.simpath, oname) v = np.genfromtxt(fpth, delimiter=",", names=True) - msg = "head in layer 1 != 8. ({})".format(v["H1"]) + msg = f"head in layer 1 != 8. ({v['H1']})" assert np.allclose(v["H1"], 8.0), msg - msg = "head in layer 2 != 7. ({})".format(v["H2"]) + msg = f"head in layer 2 != 7. ({v['H2']})" assert np.allclose(v["H2"], 7.0), msg return @@ -157,7 +158,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_noptc01.py b/autotest/test_gwf_noptc01.py index 99b2abe383c..2addf94f33e 100644 --- a/autotest/test_gwf_noptc01.py +++ b/autotest/test_gwf_noptc01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -10,7 +11,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["gwf_noptc01", "gwf_noptc02", "gwf_noptc03"] @@ -134,8 +135,8 @@ def get_model(idx, dir, no_ptcrecord): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -197,7 +198,7 @@ def main(): # use python testmf6_csub_sub03.py --mf2005 mf2005devdbl if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf01_75x75.py b/autotest/test_gwf_npf01_75x75.py index ca03ce5e012..74ca2cb494d 100644 --- a/autotest/test_gwf_npf01_75x75.py +++ b/autotest/test_gwf_npf01_75x75.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -83,7 +84,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) # create iterative model solution and register the gwf model with it @@ -113,11 +114,11 @@ def build_model(idx, dir): top=top[idx], botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -152,8 +153,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -232,7 +233,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf02_rewet.py b/autotest/test_gwf_npf02_rewet.py index d6620420842..353b85bd9cb 100644 --- a/autotest/test_gwf_npf02_rewet.py +++ b/autotest/test_gwf_npf02_rewet.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -57,7 +58,7 @@ def get_local_data(idx): nmodels = len(ncolst) mnames = [] for jdx in range(nmodels): - mname = "gwf{}".format(jdx) + mname = f"gwf{jdx}" mnames.append(mname) return ncolst, nmodels, mnames @@ -101,8 +102,8 @@ def build_model(idx, dir): sim, time_units="DAYS", nper=nper, perioddata=tdis_rc ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -154,7 +155,7 @@ def build_model(idx, dir): mname = mnames[jdx] gwf = flopy.mf6.ModflowGwf( - sim, modelname=mname, model_nam_file="{}.nam".format(mname) + sim, modelname=mname, model_nam_file=f"{mname}.nam" ) dis = flopy.mf6.ModflowGwfdis( @@ -166,13 +167,11 @@ def build_model(idx, dir): delc=delc, top=top, botm=botm, - filename="{}.dis".format(mname), + filename=f"{mname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(mname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{mname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -186,7 +185,7 @@ def build_model(idx, dir): # chd files if jdx == 0: - fn = "{}.chd1.chd".format(mname) + fn = f"{mname}.chd1.chd" chd1 = flopy.mf6.modflow.ModflowGwfchd( gwf, stress_period_data=cd6left, @@ -196,7 +195,7 @@ def build_model(idx, dir): print_input=True, ) if jdx == nmodels - 1: - fn = "{}.chd2.chd".format(mname) + fn = f"{mname}.chd2.chd" chd2 = flopy.mf6.modflow.ModflowGwfchd( gwf, stress_period_data=cd6right, @@ -209,8 +208,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(mname), - head_filerecord="{}.hds".format(mname), + budget_filerecord=f"{mname}.cbc", + head_filerecord=f"{mname}.hds", headprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -309,7 +308,7 @@ def eval_hds(sim): imid = int(nrow / 2) for j in range(nmodels): - fn = os.path.join(sim.simpath, "{}.hds".format(mnames[j])) + fn = os.path.join(sim.simpath, f"{mnames[j]}.hds") hobj = flopy.utils.HeadFile(fn) times = hobj.get_times() ioff = 0 @@ -340,11 +339,11 @@ def eval_hds(sim): diff = hval - h0 diffmax = np.abs(diff).max() dtol = 1e-9 - msg = "maximum absolute maw head difference ({}) ".format(diffmax) + msg = f"maximum absolute maw head difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -385,7 +384,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf03_sfr.py b/autotest/test_gwf_npf03_sfr.py index 7caa83f5ba8..ce3cc623fb1 100644 --- a/autotest/test_gwf_npf03_sfr.py +++ b/autotest/test_gwf_npf03_sfr.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -11,7 +12,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["npf03_sfra", "npf03_sfrb"] @@ -67,7 +68,7 @@ def get_local_data(idx): nmodels = len(ncolst) mnames = [] for jdx in range(nmodels): - mname = "gwf{}".format(jdx + 1) + mname = f"gwf{jdx + 1}" mnames.append(mname) return ncolst, nmodels, mnames @@ -104,8 +105,8 @@ def build_model(idx, dir): ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -129,7 +130,7 @@ def build_model(idx, dir): # create mover and exchange file, if needed if nmodels > 1: # mover file and package name - fnmvr = "{}.mvr".format(name) + fnmvr = f"{name}.mvr" pmvr = "simmvr" # exchange data @@ -147,7 +148,6 @@ def build_model(idx, dir): excf = flopy.mf6.ModflowGwfgwf( sim, exgtype="GWF6-GWF6", - mvr_filerecord=fnmvr, nexg=len(exchd), exgmnamea=mnames[0], exgmnameb=mnames[1], @@ -160,7 +160,7 @@ def build_model(idx, dir): packages = [] for jdx in range(nmodels): mname = mnames[jdx] - pname = "sfr{}".format(jdx + 1) + pname = f"sfr{jdx + 1}" packages.append([mname, pname]) id = 0 if jdx == 0: @@ -179,7 +179,7 @@ def build_model(idx, dir): ) # create mvr package mmvr = flopy.mf6.ModflowMvr( - sim, + excf, print_input=True, modelnames=True, maxmvr=len(mvrpd), @@ -200,7 +200,7 @@ def build_model(idx, dir): hkt = hk[:, i0:i1] gwf = flopy.mf6.ModflowGwf( - sim, modelname=mname, model_nam_file="{}.nam".format(mname) + sim, modelname=mname, model_nam_file=f"{mname}.nam" ) dis = flopy.mf6.ModflowGwfdis( @@ -212,13 +212,11 @@ def build_model(idx, dir): delc=delc, top=top, botm=bot, - filename="{}.dis".format(mname), + filename=f"{mname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(mname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{mname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -227,7 +225,7 @@ def build_model(idx, dir): # chd files if jdx == 0: - fn = "{}.chd1.chd".format(mname) + fn = f"{mname}.chd1.chd" chd1 = flopy.mf6.modflow.ModflowGwfchd( gwf, boundnames=True, @@ -238,7 +236,7 @@ def build_model(idx, dir): print_input=True, ) if jdx == nmodels - 1: - fn = "{}.chd2.chd".format(mname) + fn = f"{mname}.chd2.chd" chd2 = flopy.mf6.modflow.ModflowGwfchd( gwf, boundnames=True, @@ -285,9 +283,9 @@ def build_model(idx, dir): if jdx == 0: perioddata = [[0, "inflow", 5.0]] - pname = "sfr{}".format(jdx + 1) - fn = "{}.{}.sfr".format(mname, pname) - cnvgpth = "{}.sfr.cnvg.csv".format(mname) + pname = f"sfr{jdx + 1}" + fn = f"{mname}.{pname}.sfr" + cnvgpth = f"{mname}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, @@ -328,7 +326,7 @@ def build_model(idx, dir): if nmodels == 1: packages = [(pname,), ("maw",)] mpd = [("maw", 0, pname, sfrdst, "FACTOR", 1.0)] - fn = "{}.mvr".format(mname) + fn = f"{mname}.mvr" # create mvr package mvr = flopy.mf6.ModflowGwfmvr( gwf, @@ -343,8 +341,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(mname), - head_filerecord="{}.hds".format(mname), + budget_filerecord=f"{mname}.cbc", + head_filerecord=f"{mname}.hds", headprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -5775,7 +5773,7 @@ def eval_hds(sim): i0 = 0 for j in range(nmodels): - fn = os.path.join(sim.simpath, "{}.hds".format(mnames[j])) + fn = os.path.join(sim.simpath, f"{mnames[j]}.hds") hobj = flopy.utils.HeadFile(fn) h = hobj.get_data() i1 = i0 + h.shape[2] @@ -5786,11 +5784,11 @@ def eval_hds(sim): diff = hval - hdata diffmax = np.abs(diff).max() dtol = 1e-8 - msg = "maximum absolute maw head difference ({}) ".format(diffmax) + msg = f"maximum absolute maw head difference ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -5836,7 +5834,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf04_spdis.py b/autotest/test_gwf_npf04_spdis.py index a80d9ff311b..34e4e2a9ceb 100644 --- a/autotest/test_gwf_npf04_spdis.py +++ b/autotest/test_gwf_npf04_spdis.py @@ -9,9 +9,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -110,8 +111,8 @@ def build_model(idx, dir): oc = flopy.mf6.ModflowGwfoc( gwf, pname="oc", - budget_filerecord="{}.cbc".format(namea), - head_filerecord="{}.hds".format(namea), + budget_filerecord=f"{namea}.cbc", + head_filerecord=f"{namea}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -144,8 +145,8 @@ def build_model(idx, dir): oc = flopy.mf6.ModflowGwfoc( cgwf, pname="oc", - budget_filerecord="{}.cbc".format(nameb), - head_filerecord="{}.hds".format(nameb), + budget_filerecord=f"{nameb}.cbc", + head_filerecord=f"{nameb}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -191,28 +192,28 @@ def eval_mf6(sim): print("evaluating head and qx in parent and child models...") # make sure parent head is same as child head in same column - fname = os.path.join(sim.simpath, "{}.hds".format(namea)) + fname = os.path.join(sim.simpath, f"{namea}.hds") hdobj = flopy.utils.HeadFile(fname) ha = hdobj.get_data() - fname = os.path.join(sim.simpath, "{}.hds".format(nameb)) + fname = os.path.join(sim.simpath, f"{nameb}.hds") hdobj = flopy.utils.HeadFile(fname) hb = hdobj.get_data() - msg = "Heads should be the same {} {}".format(ha[0, 1, 2], hb[0, 0, 0]) + msg = f"Heads should be the same {ha[0, 1, 2]} {hb[0, 0, 0]}" assert np.allclose(ha[0, 1, 2], hb[0, 0, 0]), msg # make sure specific discharge is calculated correctly for child and # parent models (even though child model has same resolution as parent - fname = os.path.join(sim.simpath, "{}.cbc".format(namea)) + fname = os.path.join(sim.simpath, f"{namea}.cbc") nlaya, nrowa, ncola = ha.shape qxa, qya, qza = qxqyqz(fname, nlaya, nrowa, ncola) - fname = os.path.join(sim.simpath, "{}.cbc".format(nameb)) + fname = os.path.join(sim.simpath, f"{nameb}.cbc") nlayb, nrowb, ncolb = hb.shape qxb, qyb, qzb = qxqyqz(fname, nlayb, nrowb, ncolb) - msg = "qx should be the same {} {}".format(qxa[0, 2, 1], qxb[0, 0, 0]) + msg = f"qx should be the same {qxa[0, 2, 1]} {qxb[0, 0, 0]}" assert np.allclose(qxa[0, 2, 1], qxb[0, 0, 0]), msg - cbcpth = os.path.join(sim.simpath, "{}.cbc".format(namea)) - grdpth = os.path.join(sim.simpath, "{}.dis.grb".format(namea)) + cbcpth = os.path.join(sim.simpath, f"{namea}.cbc") + grdpth = os.path.join(sim.simpath, f"{namea}.dis.grb") grb = flopy.mf6.utils.MfGrdFile(grdpth) cbb = flopy.utils.CellBudgetFile(cbcpth, precision="double") flow_ja_face = cbb.get_data(text="FLOW-JA-FACE") @@ -220,9 +221,7 @@ def eval_mf6(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg return @@ -260,7 +259,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf05_anisotropy.py b/autotest/test_gwf_npf05_anisotropy.py index aa42bb13b36..e9e9e0d4048 100644 --- a/autotest/test_gwf_npf05_anisotropy.py +++ b/autotest/test_gwf_npf05_anisotropy.py @@ -5,9 +5,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -133,12 +134,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -196,7 +197,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf_tvk01.py b/autotest/test_gwf_npf_tvk01.py index 38fbae31d42..53ca8c37a43 100644 --- a/autotest/test_gwf_npf_tvk01.py +++ b/autotest/test_gwf_npf_tvk01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -104,13 +105,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow tvk_filename = f"{gwfname}.npf.tvk" @@ -120,7 +119,6 @@ def build_model(idx, dir): icelltype=laytyp, k=hk, k33=hk, - tvk_filerecord=[tvk_filename], ) # tvk @@ -134,7 +132,7 @@ def build_model(idx, dir): spd.append([(k, i, j), "K", hydraulic_conductivity]) tvkspd[kper] = spd tvk = flopy.mf6.ModflowUtltvk( - gwf, print_input=True, perioddata=tvkspd, filename=tvk_filename + npf, print_input=True, perioddata=tvkspd, filename=tvk_filename ) # chd files @@ -154,8 +152,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -171,20 +169,20 @@ def eval_model(sim): gwfname = "gwf_" + name # head - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # budget - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.cbc") try: bobj = flopy.utils.CellBudgetFile(fpth, precision="double") bud_allspd = bobj.get_data(text="CHD") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. hk = time_varying_k[sim.idxsim] @@ -237,7 +235,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf_tvk02.py b/autotest/test_gwf_npf_tvk02.py index 0ecca127f9a..2cb79d6acca 100644 --- a/autotest/test_gwf_npf_tvk02.py +++ b/autotest/test_gwf_npf_tvk02.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = False @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -104,19 +105,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow tvk_filename = f"{gwfname}.npf.tvk" - npf = flopy.mf6.ModflowGwfnpf( - gwf, icelltype=laytyp, k=hk, k33=hk, tvk_filerecord=[tvk_filename] - ) + npf = flopy.mf6.ModflowGwfnpf(gwf, icelltype=laytyp, k=hk, k33=hk) # TVK tvkspd = {} @@ -157,7 +154,7 @@ def build_model(idx, dir): tvkspd[kper - 1] = spd tvk = flopy.mf6.ModflowUtltvk( - gwf, print_input=True, perioddata=tvkspd, filename=tvk_filename + npf, print_input=True, perioddata=tvkspd, filename=tvk_filename ) # chd files @@ -175,7 +172,7 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(gwfname), + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST")], @@ -191,12 +188,12 @@ def eval_model(sim): gwfname = "gwf_" + name # head - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check against manually calculated results expected_results = [] @@ -263,7 +260,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf_tvk03.py b/autotest/test_gwf_npf_tvk03.py index e1293f54c59..20d47db9c75 100644 --- a/autotest/test_gwf_npf_tvk03.py +++ b/autotest/test_gwf_npf_tvk03.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = False @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -104,19 +105,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow tvk_filename = f"{gwfname}.npf.tvk" - npf = flopy.mf6.ModflowGwfnpf( - gwf, icelltype=laytyp, k=hk, k33=hk, tvk_filerecord=[tvk_filename] - ) + npf = flopy.mf6.ModflowGwfnpf(gwf, icelltype=laytyp, k=hk, k33=hk) # TVK tvkspd = {} @@ -157,7 +154,7 @@ def build_model(idx, dir): tvkspd[kper - 1] = spd tvk = flopy.mf6.ModflowUtltvk( - gwf, print_input=True, perioddata=tvkspd, filename=tvk_filename + npf, print_input=True, perioddata=tvkspd, filename=tvk_filename ) # chd files @@ -175,7 +172,7 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(gwfname), + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST")], @@ -191,12 +188,12 @@ def eval_model(sim): gwfname = "gwf_" + name # head - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check against manually calculated results expected_results = [] @@ -263,7 +260,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_npf_tvk04.py b/autotest/test_gwf_npf_tvk04.py new file mode 100644 index 00000000000..eef8bff16f0 --- /dev/null +++ b/autotest/test_gwf_npf_tvk04.py @@ -0,0 +1,247 @@ +import os +import sys + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = [ + "tvk05", +] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) +ddir = "data" + +time_varying_k = [1.0, 10.0] + + +def build_model(idx, dir): + nlay, nrow, ncol = 3, 3, 3 + perlen = [100.0, 100.0] + nper = len(perlen) + nstp = nper * [1] + tsmult = nper * [1.0] + delr = 1.0 + delc = 1.0 + delz = 1.0 + top = 1.0 + laytyp = 0 + botm = [0.0, -1.0, -2.0] + strt = 1.0 + hk = 0.1 + + nouter, ninner = 100, 300 + hclose, rclose, relax = 1e-6, 1e-6, 1.0 + + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwfname = "gwf_" + name + gwf = flopy.mf6.MFModel( + sim, + model_type="gwf6", + modelname=gwfname, + model_nam_file=f"{gwfname}.nam", + ) + gwf.name_file.save_flows = True + + # create iterative model solution and register the gwf model with it + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + sim.register_ims_package(imsgwf, [gwf.name]) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=np.ones((nlay, nrow, ncol), dtype=int), + filename=f"{gwfname}.dis", + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") + + # node property flow + tvk_filename = f"{gwfname}.npf.tvk" + npf = flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=laytyp, + k=hk, + k22=hk, + ) + + # tvk + # k33 not originally specified in NPF, but specifying an + # alternate value in the 2nd stress period to test MF6 + tvkspd = {} + kper = 1 + hydraulic_conductivity = time_varying_k[kper] + spd = [] + for k in range(nlay): + for i in range(nrow): + for j in range(ncol): + spd.append([(k, i, j), "K33", hydraulic_conductivity]) + tvkspd[kper] = spd + + tvk = flopy.mf6.ModflowUtltvk( + npf, print_input=True, perioddata=tvkspd, filename=tvk_filename + ) + + # chd files + chdspd = [] + for i in range(nrow): + chdspd.append([(0, i, 0), top + 1]) + + chd = flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdspd, + save_flows=False, + print_flows=True, + pname="CHD-1", + ) + + # ghb files + ghbspd = [] + ghbcond = time_varying_k[1] * delz * delc / (0.5 * delr) + for i in range(nrow): + ghbspd.append([(nlay - 1, i, ncol - 1), top, ghbcond]) + + ghb = flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + save_flows=False, + print_flows=True, + pname="GHB-1", + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + ) + + return sim, None + + +def eval_model(sim): + print("evaluating model...") + + name = ex[sim.idxsim] + + # budget + try: + fname = f"gwf_{name}.lst" + ws = sim.simpath + fname = os.path.join(ws, fname) + lst = flopy.utils.Mf6ListBudget( + fname, budgetkey="VOLUME BUDGET FOR ENTIRE MODEL" + ) + lstra = lst.get_incremental() + except: + assert False, f'could not load data from "{fname}"' + + # This is the answer to this problem. + sp_x = [] + for kper, bud in enumerate(lstra): + sp_x.append(bud) + + # comment when done testing + print(f"Total outflow in stress period 1 is {str(sp_x[0][8])}") + print( + f"Total outflow in stress period 2 after increasing K33 is {str(sp_x[1][8])}" + ) + errmsg = f"Expect higher flow rate in period 2 compared to period 1, but found equal or higher flow rate in period 1" + assert 2.0 * sp_x[0][8] < sp_x[1][8], errmsg + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_model, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_model, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() \ No newline at end of file diff --git a/autotest/test_gwf_npf_tvk05.py b/autotest/test_gwf_npf_tvk05.py new file mode 100644 index 00000000000..44b265f99d9 --- /dev/null +++ b/autotest/test_gwf_npf_tvk05.py @@ -0,0 +1,248 @@ +import os +import sys + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = [ + "tvk05", +] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) +ddir = "data" + +time_varying_k = [1.0, 10.0] + + +def build_model(idx, dir): + nlay, nrow, ncol = 1, 3, 3 + perlen = [100.0, 100.0] + nper = len(perlen) + nstp = nper * [1] + tsmult = nper * [1.0] + delr = 1.0 + delc = 1.0 + delz = 1.0 + top = 1.0 + laytyp = 0 + botm = [0.0] + strt = 1.0 + hk = 0.1 + + nouter, ninner = 100, 300 + hclose, rclose, relax = 1e-6, 1e-6, 1.0 + + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwfname = "gwf_" + name + gwf = flopy.mf6.MFModel( + sim, + model_type="gwf6", + modelname=gwfname, + model_nam_file=f"{gwfname}.nam", + ) + gwf.name_file.save_flows = True + + # create iterative model solution and register the gwf model with it + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + sim.register_ims_package(imsgwf, [gwf.name]) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=np.ones((nlay, nrow, ncol), dtype=int), + filename=f"{gwfname}.dis", + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") + + # node property flow + tvk_filename = f"{gwfname}.npf.tvk" + npf = flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=laytyp, + k=hk, + k22=hk, + ) + + # tvk + # k33 not originally specified in NPF; however, specifying + # it in tvk in this test should not change the solution to the + # problem + tvkspd = {} + kper = 1 + k33 = 1000.0 + spd = [] + for k in range(nlay): + for i in range(nrow): + for j in range(ncol): + spd.append([(k, i, j), "K33", k33]) + tvkspd[kper] = spd + + tvk = flopy.mf6.ModflowUtltvk( + npf, print_input=True, perioddata=tvkspd, filename=tvk_filename + ) + + # chd files + chdspd = [] + for i in range(nrow): + chdspd.append([(0, i, 0), top + 1]) + + chd = flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdspd, + save_flows=False, + print_flows=True, + pname="CHD-1", + ) + + # ghb files + ghbspd = [] + ghbcond = hk * delz * delc / (0.5 * delr) + for i in range(nrow): + ghbspd.append([(0, i, ncol - 1), top, ghbcond]) + + ghb = flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + save_flows=False, + print_flows=True, + pname="GHB-1", + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + ) + + return sim, None + + +def eval_model(sim): + print("evaluating model...") + + name = ex[sim.idxsim] + + # budget + try: + fname = f"gwf_{name}.lst" + ws = sim.simpath + fname = os.path.join(ws, fname) + lst = flopy.utils.Mf6ListBudget( + fname, budgetkey="VOLUME BUDGET FOR ENTIRE MODEL" + ) + lstra = lst.get_incremental() + except: + assert False, f'could not load data from "{fname}"' + + # This is the answer to this problem. + sp_x = [] + for kper, bud in enumerate(lstra): + sp_x.append(bud) + + # comment when done testing + print(f"Total outflow in stress period 1 is {str(sp_x[0][8])}") + print( + f"Total outflow in stress period 2 after increasing K33 should have no effect on final solution" + ) + errmsg = f"Period 2 budget should be exactly the same as period 1" + assert sp_x[0][8] == sp_x[1][8], errmsg + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_model, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_model, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() \ No newline at end of file diff --git a/autotest/test_gwf_obs01.py b/autotest/test_gwf_obs01.py index 6d6b975cd82..39256e24893 100644 --- a/autotest/test_gwf_obs01.py +++ b/autotest/test_gwf_obs01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -22,10 +23,7 @@ from simulation import Simulation cell_dimensions = (300,) -ex = [ - "gwf_obs01{}".format(chr(ord("a") + idx)) - for idx in range(len(cell_dimensions)) -] +ex = [f"gwf_obs01{chr(ord('a') + idx)}" for idx in range(len(cell_dimensions))] exdirs = [] for s in ex: exdirs.append(os.path.join("temp", s)) @@ -46,16 +44,16 @@ def get_obs(idx): for j in range(ncol): node = i * ncol + j + 1 obs_lst.append([node, "head", (0, i, j)]) - return {"{}.gwf.obs.csv".format(ex[idx]): obs_lst} + return {f"{ex[idx]}.gwf.obs.csv": obs_lst} def get_obs_out(sim): - fpth = os.path.join(sim.simpath, "{}.gwf.obs.csv".format(ex[sim.idxsim])) + fpth = os.path.join(sim.simpath, f"{ex[sim.idxsim]}.gwf.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") return tc.view((float, len(tc.dtype.names)))[1:] except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' def get_chd(idx): @@ -117,7 +115,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -201,7 +199,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_obs02.py b/autotest/test_gwf_obs02.py index 3663179ebc5..5e2cb0aff7b 100644 --- a/autotest/test_gwf_obs02.py +++ b/autotest/test_gwf_obs02.py @@ -3,8 +3,9 @@ correct. """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -87,7 +88,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -106,10 +107,8 @@ def build_model(idx, dir): # build list of obs csv files to create obsdict = {} for i in range(nrow): - obslst = [ - ("h_{}_{}".format(i, j), "head", (0, i, j)) for j in range(ncol) - ] - fname = "{}.{}.obs.csv".format(name, i) + obslst = [(f"h_{i}_{j}", "head", (0, i, j)) for j in range(ncol)] + fname = f"{name}.{i}.obs.csv" obsdict[fname] = obslst flopy.mf6.ModflowUtlobs( @@ -138,7 +137,7 @@ def build_model(idx, dir): # output control flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), + head_filerecord=f"{name}.hds", printrecord=[("BUDGET", "LAST"), ("HEAD", "LAST")], saverecord=[("HEAD", "LAST")], ) @@ -151,12 +150,12 @@ def eval_model(sim): name = ex[sim.idxsim] headcsv = np.empty((nlay, nrow, ncol), dtype=float) for i in range(nrow): - fname = "{}.{}.obs.csv".format(name, i) - print("Loading and testing {}".format(fname)) + fname = f"{name}.{i}.obs.csv" + print(f"Loading and testing {fname}") fname = os.path.join(sim.simpath, fname) rec = np.genfromtxt(fname, names=True, delimiter=",", deletechars="") for j in range(ncol): - obsname_true = "h_{}_{}".format(i, j).upper() + obsname_true = f"h_{i}_{j}".upper() obsname_found = rec.dtype.names[j + 1].upper() errmsg = ( 'obsname in {} is incorrect. Looking for "{}" but found "{}"' @@ -165,7 +164,7 @@ def eval_model(sim): assert obsname_true == obsname_found, errmsg headcsv[0, i, :] = np.array(rec.tolist()[1:]) - fn = os.path.join(sim.simpath, "{}.hds".format(name)) + fn = os.path.join(sim.simpath, f"{name}.hds") hobj = flopy.utils.HeadFile(fn) headbin = hobj.get_data() @@ -208,7 +207,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ptc01.py b/autotest/test_gwf_ptc01.py index 501cb57a004..af8197c9f7f 100644 --- a/autotest/test_gwf_ptc01.py +++ b/autotest/test_gwf_ptc01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -67,7 +68,7 @@ def build_mf6(idx, ws, storage=True): gwf = flopy.mf6.ModflowGwf( sim, modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", save_flows=True, newtonoptions="NEWTON", ) @@ -109,11 +110,11 @@ def build_mf6(idx, ws, storage=True): top=top, botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow flopy.mf6.ModflowGwfnpf(gwf, icelltype=1, k=hk) @@ -133,8 +134,8 @@ def build_mf6(idx, ws, storage=True): # output control flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -187,7 +188,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_rch01.py b/autotest/test_gwf_rch01.py index 39d85519907..f36d6465411 100644 --- a/autotest/test_gwf_rch01.py +++ b/autotest/test_gwf_rch01.py @@ -9,9 +9,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -72,8 +73,8 @@ def build_model(idx, dir): ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -129,12 +130,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -191,7 +192,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_rch02.py b/autotest/test_gwf_rch02.py index 675b6d9697d..69f0d2645cd 100644 --- a/autotest/test_gwf_rch02.py +++ b/autotest/test_gwf_rch02.py @@ -5,9 +5,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -64,8 +65,8 @@ def build_model(idx, dir): ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -118,12 +119,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -183,7 +184,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_rch03.py b/autotest/test_gwf_rch03.py index 1f31aeccfcd..b4ffea4e22d 100644 --- a/autotest/test_gwf_rch03.py +++ b/autotest/test_gwf_rch03.py @@ -5,9 +5,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -64,8 +65,8 @@ def build_model(idx, dir): ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -140,12 +141,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -209,7 +210,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_returncodes.py b/autotest/test_gwf_returncodes.py index aca2886e1b3..9201054d3df 100644 --- a/autotest/test_gwf_returncodes.py +++ b/autotest/test_gwf_returncodes.py @@ -1,8 +1,7 @@ import os -import pytest -import sys import shutil import subprocess +import sys import pytest @@ -20,7 +19,7 @@ name = "gwf_ret_codes01" base_ws = os.path.join("temp", name) if not os.path.isdir(base_ws): - os.makedirs(base_ws) + os.makedirs(base_ws, exist_ok=True) app = "mf6" if sys.platform.lower() == "win32": app += ".exe" @@ -35,7 +34,7 @@ def run_mf6(argv, ws): if result is not None: c = result.decode("utf-8") c = c.rstrip("\r\n") - print("{}".format(c)) + print(f"{c}") buff.append(c) return proc.returncode, buff @@ -132,8 +131,8 @@ def get_sim(ws, idomain, continue_flag=False, nouter=500): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -218,9 +217,9 @@ def idomain_runtime_error(): # run the simulation returncode, buff = run_mf6([mf6_exe], ws) - msg = "could not run {}".format(sim.name) + msg = f"could not run {sim.name}" if returncode != 0: - err_str = "IDOMAIN ARRAY HAS SOME VALUES GREATER THAN ZERO" + err_str = "Ensure IDOMAIN array has some" err = any(err_str in s for s in buff) if err: clean(ws) @@ -235,14 +234,14 @@ def unknown_keyword_error(): with pytest.raises(RuntimeError): returncode, buff = run_mf6([mf6_exe, "--unknown_keyword"], ws) - msg = "could not run {}".format("unknown_keyword") + msg = "could not run unknown_keyword" if returncode != 0: - err_str = "{}: illegal option".format(app) + err_str = f"{app}: illegal option" err = any(err_str in s for s in buff) if err: raise RuntimeError(msg) else: - msg += " but {} not returned".format(err_str) + msg += f" but {err_str} not returned" raise ValueError(msg) @@ -253,36 +252,34 @@ def run_argv(arg, return_str): if returncode == 0: found_str = any(return_str in s for s in buff) if not found_str: - msg = "{} keyword did not return {}".format(arg, return_str) + msg = f"{arg} keyword did not return {return_str}" raise ValueError(msg) else: - msg = "could not run with command line argument {}".format(arg) + msg = f"could not run with command line argument {arg}" raise RuntimeError(msg) def help_argv(): for arg in ["-h", "--help", "-?"]: - return_str = "{} [options] retrieve program information".format( - app - ) + return_str = f"{app} [options] retrieve program information" run_argv(arg, return_str) def version_argv(): for arg in ["-v", "--version"]: - return_str = "{}: 6".format(app) + return_str = f"{app}: 6" run_argv(arg, return_str) def develop_argv(): for arg in ["-dev", "--develop"]: - return_str = "{}: develop version".format(app) + return_str = f"{app}: develop version" run_argv(arg, return_str) def compiler_argv(): for arg in ["-c", "--compiler"]: - return_str = "{}: MODFLOW 6 compiled".format(app) + return_str = f"{app}: MODFLOW 6 compiled" run_argv(arg, return_str) @@ -310,7 +307,7 @@ def test_main(fn): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") idomain_runtime_error() unknown_keyword_error() diff --git a/autotest/test_gwf_sfr_badfactor.py b/autotest/test_gwf_sfr_badfactor.py index 794751f645f..86c4751f93a 100644 --- a/autotest/test_gwf_sfr_badfactor.py +++ b/autotest/test_gwf_sfr_badfactor.py @@ -1,9 +1,10 @@ import os -import pytest -import sys -import numpy as np import shutil import subprocess +import sys + +import numpy as np +import pytest try: import flopy @@ -13,11 +14,10 @@ msg += " pip install flopy" raise Exception(msg) +import targets from framework import testing_framework from simulation import Simulation -import targets - mf6_exe = os.path.abspath(targets.target_dict["mf6"]) paktest = "sfr" @@ -66,8 +66,8 @@ def build_model(timeseries=False): sim, time_units="DAYS", nper=nper, perioddata=tdis_rc ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -346,8 +346,8 @@ def build_model(timeseries=False): perioddata.append([0, "inflow", inflow]) perioddata.append([2, "diversion", 1, divflow]) - budpth = "{}.{}.cbc".format(name, paktest) - cnvgpth = "{}.sfr.cnvg.csv".format(name) + budpth = f"{name}.{paktest}.cbc" + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, print_stage=True, @@ -366,7 +366,7 @@ def build_model(timeseries=False): pname="sfr-1", ) if timeseries: - fname = "{}.sfr.ts".format(name) + fname = f"{name}.sfr.ts" sfr.ts.initialize( filename=fname, timeseries=ts_data, @@ -434,7 +434,7 @@ def build_model(timeseries=False): (0, "slope", "1.000000000000e-003"), (0, "rough", "1.000000000000e-001"), ] - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, mover=True, @@ -472,7 +472,7 @@ def build_model(timeseries=False): [7, 1.0e-8, 0, 0, 0, 0, 0, 0], [8, 1.0e-8, 0, 0, 0, 0, 0, 0], ] - cnvgpth = "{}.uzf.cnvg.csv".format(name) + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, mover=True, @@ -510,7 +510,7 @@ def build_model(timeseries=False): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -520,8 +520,8 @@ def build_model(timeseries=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST"), ("HEAD", "LAST")], ) @@ -582,7 +582,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sfr_npoint01.py b/autotest/test_gwf_sfr_npoint01.py index e4554c113e3..a63b85f88fb 100644 --- a/autotest/test_gwf_sfr_npoint01.py +++ b/autotest/test_gwf_sfr_npoint01.py @@ -1,5 +1,6 @@ import os import sys + import numpy as np import pytest @@ -370,7 +371,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sfr_npoint02.py b/autotest/test_gwf_sfr_npoint02.py index fd401299b66..d54d404009f 100644 --- a/autotest/test_gwf_sfr_npoint02.py +++ b/autotest/test_gwf_sfr_npoint02.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -281,7 +282,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sfr_npoint03.py b/autotest/test_gwf_sfr_npoint03.py index ff4b2c40844..b69e4d88a81 100644 --- a/autotest/test_gwf_sfr_npoint03.py +++ b/autotest/test_gwf_sfr_npoint03.py @@ -1,5 +1,6 @@ import os import sys + import numpy as np import pytest @@ -17,7 +18,6 @@ sys.path.append("scripts") from cross_section_functions import calculate_rectchan_mannings_discharge - paktest = "sfr" ex = [ @@ -343,7 +343,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sfr_reorder.py b/autotest/test_gwf_sfr_reorder.py index 604b2e19263..71fdfb352f6 100644 --- a/autotest/test_gwf_sfr_reorder.py +++ b/autotest/test_gwf_sfr_reorder.py @@ -1,5 +1,6 @@ import os import sys + import numpy as np import pytest @@ -300,7 +301,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sto01.py b/autotest/test_gwf_sto01.py index ba63245bfdd..08144c20bfe 100644 --- a/autotest/test_gwf_sto01.py +++ b/autotest/test_gwf_sto01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -10,7 +11,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = ["gwf_sto01"] @@ -164,11 +165,11 @@ def build_model(idx, dir): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -212,8 +213,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -281,9 +282,7 @@ def eval_sto(sim): print("evaluating storage...") # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -295,9 +294,7 @@ def eval_sto(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -322,41 +319,41 @@ def eval_sto(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -417,7 +414,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sto02.py b/autotest/test_gwf_sto02.py index 839537a985a..f4c471afb8f 100644 --- a/autotest/test_gwf_sto02.py +++ b/autotest/test_gwf_sto02.py @@ -4,8 +4,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -99,7 +100,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -148,8 +149,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -168,7 +169,7 @@ def eval_flow(sim): gwfname = "gwf_" + name # This will fail if budget numbers cannot be read - fpth = os.path.join(sim.simpath, "{}.lst".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.lst") mflist = flopy.utils.Mf6ListBudget(fpth) names = mflist.get_record_names() print(names) @@ -208,7 +209,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sto03.py b/autotest/test_gwf_sto03.py index 9bbebfc880e..c90844c6070 100644 --- a/autotest/test_gwf_sto03.py +++ b/autotest/test_gwf_sto03.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -10,7 +11,7 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI +from framework import running_on_CI, testing_framework from simulation import Simulation ex = [ @@ -148,7 +149,7 @@ def get_model(name, ws, newton_bool, offset=0.0): flopy.mf6.ModflowUtlobs( gwf, - filename="{}.obs".format(name), + filename=f"{name}.obs", digits=10, print_input=True, continuous={"head.obs.csv": [(obsname, "HEAD", (0, 0, 0))]}, @@ -184,7 +185,7 @@ def get_model(name, ws, newton_bool, offset=0.0): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), + budget_filerecord=f"{name}.cbc", saverecord=[("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], ) @@ -216,9 +217,10 @@ def eval_hmax(fpth): for idx, t in enumerate(ctimes): sv[idx] = b.get_data(totim=t)[obsname] - msg = "maximum heads in {} exceed tolerance ".format( - fpth - ) + "- maximum difference {}".format((bv - sv).max()) + msg = ( + "maximum heads in {} exceed tolerance ".format(fpth) + + f"- maximum difference {(bv - sv).max()}" + ) assert np.allclose(bv, sv), msg return @@ -234,7 +236,7 @@ def eval_sto(sim): msg = ( "head differences exceed tolerance when offset removed " - + "- maximum difference {}".format((base_obs - offset_obs).max()) + + f"- maximum difference {(base_obs - offset_obs).max()}" ) assert np.allclose(base_obs, offset_obs, atol=1e-6), msg @@ -255,15 +257,15 @@ def eval_sto(sim): msg = ( "maximum heads exceed tolerance when offset removed " - + "- maximum difference {}".format((base_cmp - offset_cmp).max()) + + f"- maximum difference {(base_cmp - offset_cmp).max()}" ) assert np.allclose(base_cmp, offset_cmp), msg print("evaluating storage...") name = ex[sim.idxsim] - fpth = os.path.join(sim.simpath, "{}.cbc".format(name)) + fpth = os.path.join(sim.simpath, f"{name}.cbc") base_cbc = flopy.utils.CellBudgetFile(fpth, precision="double") - fpth = os.path.join(sim.simpath, cmppth, "{}.cbc".format(name)) + fpth = os.path.join(sim.simpath, cmppth, f"{name}.cbc") offset_cbc = flopy.utils.CellBudgetFile(fpth, precision="double") # get results from cbc file @@ -335,7 +337,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_sto_tvs01.py b/autotest/test_gwf_sto_tvs01.py index cca647fd579..5f169bc6219 100644 --- a/autotest/test_gwf_sto_tvs01.py +++ b/autotest/test_gwf_sto_tvs01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -77,7 +78,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = False gwf.name_file.newtonoptions = "NEWTON UNDER_RELAXATION" @@ -104,7 +105,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -118,13 +119,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf(gwf, icelltype=laytyp, k=hk, k33=hk) @@ -138,7 +137,6 @@ def build_model(idx, dir): ss=ss, sy=sy, transient=transient, - tvs_filerecord=[tvs_filename], ) # TVS @@ -172,13 +170,13 @@ def build_model(idx, dir): tvsspd[kper - 1] = spd tvs = flopy.mf6.ModflowUtltvs( - gwf, print_input=True, perioddata=tvsspd, filename=tvs_filename + sto, print_input=True, perioddata=tvsspd, filename=tvs_filename ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(gwfname), + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST")], @@ -194,12 +192,12 @@ def eval_model(sim): gwfname = "gwf_" + name # head - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check against manually calculated results expected_results = [] @@ -262,7 +260,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ts_lak01.py b/autotest/test_gwf_ts_lak01.py index bb6e93fb302..e9fea2f9c8d 100644 --- a/autotest/test_gwf_ts_lak01.py +++ b/autotest/test_gwf_ts_lak01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -255,7 +256,7 @@ def get_model(ws, name, timeseries=False): - hdsfile = "{}.hds".format(name) + hdsfile = f"{name}.hds" # build the model sim = flopy.mf6.MFSimulation(sim_name=name, exe_name="mf6", sim_ws=ws) @@ -312,13 +313,13 @@ def get_model(ws, name, timeseries=False): pname="lak-1", ) lak.obs.initialize( - filename="{}.lak.obs".format(name), + filename=f"{name}.lak.obs", digits=20, print_input=True, continuous=lak_obs, ) if timeseries: - fname = "{}.lak.ts".format(name) + fname = f"{name}.lak.ts" lak.ts.initialize( filename=fname, timeseries=ts_data, @@ -329,8 +330,8 @@ def get_model(ws, name, timeseries=False): ic = flopy.mf6.ModflowGwfic(gwf, strt=strt) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(name), - budget_filerecord="{}.cbc".format(name), + head_filerecord=f"{name}.hds", + budget_filerecord=f"{name}.cbc", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST")], ) @@ -357,12 +358,12 @@ def eval_budget(sim): from budget_file_compare import eval_bud_diff # get ia/ja from binary grid file - fname = "{}.dis.grb".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.dis.grb" fpth = os.path.join(sim.simpath, fname) grbobj = flopy.mf6.utils.MfGrdFile(fpth) ia = grbobj._datadict["IA"] - 1 - fname = "{}.cbc".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc" # open first cbc file fpth = os.path.join(sim.simpath, fname) @@ -373,7 +374,7 @@ def eval_budget(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.cbc.cmp.out".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1, ia, dtol=0.1) @@ -414,7 +415,7 @@ def main(): # use python testmf6_drn_ddrn01.py if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ts_maw01.py b/autotest/test_gwf_ts_maw01.py index b4a487c9e8c..0eb277a98af 100644 --- a/autotest/test_gwf_ts_maw01.py +++ b/autotest/test_gwf_ts_maw01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -14,7 +15,7 @@ from simulation import Simulation paktest = "maw" -ex = ["ts_{}01".format(paktest)] +ex = [f"ts_{paktest}01"] exdirs = [] for s in ex: exdirs.append(os.path.join("temp", s)) @@ -215,7 +216,7 @@ def get_model(ws, name, timeseries=False): [3, "status", "active"], [4, "status", "active"], ] - cnvgpth = "{}.sfr.cnvg.csv".format(name) + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, print_input=True, @@ -254,7 +255,7 @@ def get_model(ws, name, timeseries=False): perioddata.append([0, "AUXILIARY", "conc", conc]) perioddata.append([0, "AUXILIARY", "temp", temp]) - budpth = "{}.{}.cbc".format(name, paktest) + budpth = f"{name}.{paktest}.cbc" maw = flopy.mf6.ModflowGwfmaw( gwf, print_head=True, @@ -270,7 +271,7 @@ def get_model(ws, name, timeseries=False): pname="maw-1", ) if timeseries: - fname = "{}.{}.ts".format(name, paktest) + fname = f"{name}.{paktest}.ts" maw.ts.initialize( filename=fname, timeseries=ts_data, @@ -318,7 +319,7 @@ def get_model(ws, name, timeseries=False): (0, "slope", "1.0e-003"), (0, "rough", "1.0e-001"), ] - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, print_input=True, @@ -358,7 +359,7 @@ def get_model(ws, name, timeseries=False): [8, 1.0e-8, 0, 0, 0, 0, 0, 0], ] - cnvgpth = "{}.uzf.cnvg.csv".format(name) + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, print_input=True, @@ -395,7 +396,7 @@ def get_model(ws, name, timeseries=False): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -405,8 +406,8 @@ def get_model(ws, name, timeseries=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST")], ) @@ -433,12 +434,12 @@ def eval_model(sim): from budget_file_compare import eval_bud_diff # get ia/ja from binary grid file - fname = "{}.dis.grb".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.dis.grb" fpth = os.path.join(sim.simpath, fname) grbobj = flopy.mf6.utils.MfGrdFile(fpth) ia = grbobj._datadict["IA"] - 1 - fname = "{}.cbc".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc" # open first gwf cbc file fpth = os.path.join(sim.simpath, fname) @@ -449,12 +450,12 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.cbc.cmp.out".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1, ia) # evaluate the sfr package budget file - fname = "{}.{}.cbc".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc" # open first sfr cbc file fpth = os.path.join(sim.simpath, fname) cobj0 = flopy.utils.CellBudgetFile(fpth, precision="double") @@ -464,7 +465,7 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.{}.cbc.cmp.out".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1) @@ -504,7 +505,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ts_sfr01.py b/autotest/test_gwf_ts_sfr01.py index bac548cac2c..faa6b60b334 100644 --- a/autotest/test_gwf_ts_sfr01.py +++ b/autotest/test_gwf_ts_sfr01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -67,8 +68,8 @@ def get_model(ws, name, timeseries=False): sim, time_units="DAYS", nper=nper, perioddata=tdis_rc ) # set ims csv files - csv0 = "{}.outer.ims.csv".format(name) - csv1 = "{}.inner.ims.csv".format(name) + csv0 = f"{name}.outer.ims.csv" + csv1 = f"{name}.inner.ims.csv" # create iterative model solution and register the gwf model with it ims = flopy.mf6.ModflowIms( @@ -346,8 +347,8 @@ def get_model(ws, name, timeseries=False): perioddata.append([0, "inflow", inflow]) perioddata.append([2, "diversion", 1, divflow]) - budpth = "{}.{}.cbc".format(name, paktest) - cnvgpth = "{}.sfr.cnvg.csv".format(name) + budpth = f"{name}.{paktest}.cbc" + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, print_stage=True, @@ -366,7 +367,7 @@ def get_model(ws, name, timeseries=False): pname="sfr-1", ) if timeseries: - fname = "{}.sfr.ts".format(name) + fname = f"{name}.sfr.ts" sfr.ts.initialize( filename=fname, timeseries=ts_data, @@ -434,7 +435,7 @@ def get_model(ws, name, timeseries=False): (0, "slope", "1.000000000000e-003"), (0, "rough", "1.000000000000e-001"), ] - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, mover=True, @@ -472,7 +473,7 @@ def get_model(ws, name, timeseries=False): [7, 1.0e-8, 0, 0, 0, 0, 0, 0], [8, 1.0e-8, 0, 0, 0, 0, 0, 0], ] - cnvgpth = "{}.uzf.cnvg.csv".format(name) + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, mover=True, @@ -510,7 +511,7 @@ def get_model(ws, name, timeseries=False): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -520,8 +521,8 @@ def get_model(ws, name, timeseries=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST"), ("HEAD", "LAST")], ) @@ -548,12 +549,12 @@ def eval_model(sim): from budget_file_compare import eval_bud_diff # get ia/ja from binary grid file - fname = "{}.dis.grb".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.dis.grb" fpth = os.path.join(sim.simpath, fname) grbobj = flopy.mf6.utils.MfGrdFile(fpth) ia = grbobj._datadict["IA"] - 1 - fname = "{}.cbc".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc" # open first gwf cbc file fpth = os.path.join(sim.simpath, fname) @@ -564,12 +565,12 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.cbc.cmp.out".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1, ia) # evaluate the sfr package budget file - fname = "{}.{}.cbc".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc" # open first sfr cbc file fpth = os.path.join(sim.simpath, fname) cobj0 = flopy.utils.CellBudgetFile(fpth, precision="double") @@ -579,7 +580,7 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.{}.cbc.cmp.out".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1) @@ -645,7 +646,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ts_sfr02.py b/autotest/test_gwf_ts_sfr02.py index 3c7d5dbddd0..6cf9220424a 100644 --- a/autotest/test_gwf_ts_sfr02.py +++ b/autotest/test_gwf_ts_sfr02.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -339,8 +340,8 @@ def get_model(ws, name, timeseries=False): perioddata.append([0, "inflow", inflow]) perioddata.append([2, "diversion", 1, divflow]) - budpth = "{}.{}.cbc".format(name, paktest) - cnvgpth = "{}.sfr.cnvg.csv".format(name) + budpth = f"{name}.{paktest}.cbc" + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, maximum_picard_iterations=5, @@ -358,7 +359,7 @@ def get_model(ws, name, timeseries=False): pname="sfr-1", ) if timeseries: - fname = "{}.sfr.ts".format(name) + fname = f"{name}.sfr.ts" sfr.ts.initialize( filename=fname, timeseries=ts_data, @@ -425,7 +426,7 @@ def get_model(ws, name, timeseries=False): (0, "slope", "1.000000000000e-003"), (0, "rough", "1.000000000000e-001"), ] - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, mover=True, @@ -463,7 +464,7 @@ def get_model(ws, name, timeseries=False): [7, 1.0e-8, 0, 0, 0, 0, 0, 0], [8, 1.0e-8, 0, 0, 0, 0, 0, 0], ] - cnvgpth = "{}.uzf.cnvg.csv".format(name) + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, mover=True, @@ -501,7 +502,7 @@ def get_model(ws, name, timeseries=False): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -511,8 +512,8 @@ def get_model(ws, name, timeseries=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST")], ) @@ -539,12 +540,12 @@ def eval_model(sim): from budget_file_compare import eval_bud_diff # get ia/ja from binary grid file - fname = "{}.dis.grb".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.dis.grb" fpth = os.path.join(sim.simpath, fname) grbobj = flopy.mf6.utils.MfGrdFile(fpth) ia = grbobj._datadict["IA"] - 1 - fname = "{}.cbc".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc" # open first gwf cbc file fpth = os.path.join(sim.simpath, fname) @@ -555,12 +556,12 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.cbc.cmp.out".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1, ia) # evaluate the sfr package budget file - fname = "{}.{}.cbc".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc" # open first sfr cbc file fpth = os.path.join(sim.simpath, fname) cobj0 = flopy.utils.CellBudgetFile(fpth, precision="double") @@ -570,7 +571,7 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.{}.cbc.cmp.out".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1) @@ -651,7 +652,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_ts_uzf01.py b/autotest/test_gwf_ts_uzf01.py index fd11812fe0d..6714a31f637 100644 --- a/autotest/test_gwf_ts_uzf01.py +++ b/autotest/test_gwf_ts_uzf01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -325,7 +326,7 @@ def get_model(ws, name, timeseries=False): [2, "diversion", 1, divflow], ] - cnvgpth = "{}.sfr.cnvg.csv".format(name) + cnvgpth = f"{name}.sfr.cnvg.csv" sfr = flopy.mf6.ModflowGwfsfr( gwf, auxiliary=auxnames, @@ -401,7 +402,7 @@ def get_model(ws, name, timeseries=False): (0, "slope", "1.000000000000e-003"), (0, "rough", "1.000000000000e-001"), ] - cnvgpth = "{}.lak.cnvg.csv".format(name) + cnvgpth = f"{name}.lak.cnvg.csv" lak = flopy.mf6.ModflowGwflak( gwf, mover=True, @@ -575,8 +576,8 @@ def get_model(ws, name, timeseries=False): [8, finf, pet, extdp, extwc, ha, hroot, rootact, temp, conc], ] - budpth = "{}.{}.cbc".format(name, paktest) - cnvgpth = "{}.uzf.cnvg.csv".format(name) + budpth = f"{name}.{paktest}.cbc" + cnvgpth = f"{name}.uzf.cnvg.csv" uzf = flopy.mf6.ModflowGwfuzf( gwf, print_input=True, @@ -595,7 +596,7 @@ def get_model(ws, name, timeseries=False): pname="uzf-1", ) if timeseries: - fname = "{}.{}.ts".format(name, paktest) + fname = f"{name}.{paktest}.ts" uzf.ts.initialize( filename=fname, timeseries=ts_data, @@ -628,7 +629,7 @@ def get_model(ws, name, timeseries=False): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -638,8 +639,8 @@ def get_model(ws, name, timeseries=False): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("BUDGET", "LAST")], ) @@ -666,12 +667,12 @@ def eval_model(sim): from budget_file_compare import eval_bud_diff # get ia/ja from binary grid file - fname = "{}.dis.grb".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.dis.grb" fpth = os.path.join(sim.simpath, fname) grbobj = flopy.mf6.utils.MfGrdFile(fpth) ia = grbobj._datadict["IA"] - 1 - fname = "{}.cbc".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc" # open first gwf cbc file fpth = os.path.join(sim.simpath, fname) @@ -682,12 +683,12 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.cbc.cmp.out".format(os.path.basename(sim.name)) + fname = f"{os.path.basename(sim.name)}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1, ia) # evaluate the sfr package budget file - fname = "{}.{}.cbc".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc" # open first sfr cbc file fpth = os.path.join(sim.simpath, fname) cobj0 = flopy.utils.CellBudgetFile(fpth, precision="double") @@ -697,7 +698,7 @@ def eval_model(sim): cobj1 = flopy.utils.CellBudgetFile(fpth, precision="double") # define file path and evaluate difference - fname = "{}.{}.cbc.cmp.out".format(os.path.basename(sim.name), paktest) + fname = f"{os.path.basename(sim.name)}.{paktest}.cbc.cmp.out" fpth = os.path.join(sim.simpath, fname) eval_bud_diff(fpth, cobj0, cobj1) @@ -737,7 +738,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl01_binaryinput.py b/autotest/test_gwf_utl01_binaryinput.py index 79b239f4a82..0bf84dd7db6 100644 --- a/autotest/test_gwf_utl01_binaryinput.py +++ b/autotest/test_gwf_utl01_binaryinput.py @@ -3,8 +3,9 @@ # 2. Have binary data in a single record for all layers import os -import pytest + import numpy as np +import pytest try: import flopy @@ -63,7 +64,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) # create iterative model solution and register the gwf model with it @@ -120,8 +121,8 @@ def build_model(idx, dir): if idx == 0: botarr = [] for k in range(nlay): - text = "BOTM_L{}".format(k + 1) - fname = "botm.l{:02d}.bin".format(k + 1) + text = f"BOTM_L{k + 1}" + fname = f"botm.l{k + 1:02d}.bin" pth = os.path.join(exdirs[idx], fname) f = open(pth, "wb") header = flopy.utils.BinaryHeader.create( @@ -186,8 +187,8 @@ def build_model(idx, dir): if idx == 0: idomain = [] for k in range(nlay): - text = "IDOMAIN_L{}".format(k + 1) - fname = "idomain.l{:02d}.bin".format(k + 1) + text = f"IDOMAIN_L{k + 1}" + fname = f"idomain.l{k + 1:02d}.bin" pth = os.path.join(exdirs[idx], fname) f = open(pth, "wb") header = flopy.utils.BinaryHeader.create( @@ -259,7 +260,7 @@ def build_model(idx, dir): top=top, botm=botarr, idomain=idomain, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions @@ -267,8 +268,8 @@ def build_model(idx, dir): if idx == 0: strt = [] for k in range(nlay): - text = "IC_L{}".format(k + 1) - fname = "ic.strt_l{:02d}.bin".format(k + 1) + text = f"IC_L{k + 1}" + fname = f"ic.strt_l{k + 1:02d}.bin" pth = os.path.join(exdirs[idx], fname) f = open(pth, "wb") header = flopy.utils.BinaryHeader.create( @@ -330,14 +331,14 @@ def build_model(idx, dir): "iprn": 1, } - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow # write icelltype to binary file if idx == 0: icelltype = [] for k in range(nlay): - fname = "npf.icelltype.l{}.bin".format(k + 1) + fname = f"npf.icelltype.l{k + 1}.bin" pth = os.path.join(exdirs[idx], fname) f = open(pth, "wb") header = flopy.utils.BinaryHeader.create( @@ -408,7 +409,7 @@ def build_model(idx, dir): icelltype=icelltype, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # chd files @@ -421,18 +422,18 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -470,7 +471,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl02_timeseries.py b/autotest/test_gwf_utl02_timeseries.py index 1828071afe5..573c2989f0e 100644 --- a/autotest/test_gwf_utl02_timeseries.py +++ b/autotest/test_gwf_utl02_timeseries.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -57,7 +58,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", ) # create iterative model solution and register the gwf model with it @@ -87,11 +88,11 @@ def build_model(idx, dir): top=0.0, botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=0.0, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=0.0, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -100,7 +101,7 @@ def build_model(idx, dir): icelltype=0, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # chd files @@ -113,7 +114,7 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # wel files @@ -151,12 +152,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -194,7 +195,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl03_obs01.py b/autotest/test_gwf_utl03_obs01.py index d15e729ab37..4f5944833a6 100644 --- a/autotest/test_gwf_utl03_obs01.py +++ b/autotest/test_gwf_utl03_obs01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -52,12 +53,8 @@ cd6 = {0: c60, 1: c61} # gwf obs -obs_data0 = [ - ("h{:04d}".format(i + 1), "HEAD", (0, 10, 10)) for i in range(1000) -] -obs_data1 = [ - ("h{:04d}".format(i + 1001), "HEAD", (0, 1, 1)) for i in range(737) -] +obs_data0 = [(f"h{i + 1:04d}", "HEAD", (0, 10, 10)) for i in range(1000)] +obs_data1 = [(f"h{i + 1001:04d}", "HEAD", (0, 1, 1)) for i in range(737)] # solver data nouter, ninner = 100, 300 @@ -80,7 +77,7 @@ def build_mf6(idx, ws, binaryobs=True): gwf = flopy.mf6.ModflowGwf( sim, modelname=name, - model_nam_file="{}.nam".format(name), + model_nam_file=f"{name}.nam", save_flows=True, ) @@ -113,11 +110,11 @@ def build_mf6(idx, ws, binaryobs=True): top=top, botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow flopy.mf6.ModflowGwfnpf(gwf, icelltype=1, k=hk) @@ -131,7 +128,7 @@ def build_mf6(idx, ws, binaryobs=True): o = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", - filename="{}.obs".format(name), + filename=f"{name}.obs", digits=10, print_input=True, continuous=obs_recarray, @@ -143,8 +140,8 @@ def build_mf6(idx, ws, binaryobs=True): # output control flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -186,7 +183,7 @@ def hack_binary_obs(idx, dir): line = line.rstrip() if "BEGIN continuous FILEOUT" in line: line += " BINARY" - f.write("{}\n".format(line)) + f.write(f"{line}\n") f.close() return @@ -205,24 +202,24 @@ def eval_obs(sim): names0 = d0.dtype.names names1 = d1.dtype.names msg = ( - "The number of columns ({}) ".format(len(names0)) - + "in {} ".format(pth0) + f"The number of columns ({len(names0)}) " + + f"in {pth0} " + "is not equal to " - + "the number of columns ({}) ".format(len(names1)) - + "in {}.".format(pth1) + + f"the number of columns ({len(names1)}) " + + f"in {pth1}." ) assert len(names0) == len(names1), msg msg = ( - "The number of rows ({}) ".format(d0.shape[0]) - + "in {} ".format(pth0) + f"The number of rows ({d0.shape[0]}) " + + f"in {pth0} " + "is not equal to " - + "the number of rows ({}) ".format(d1.shape[0]) - + "in {}.".format(pth1) + + f"the number of rows ({d1.shape[0]}) " + + f"in {pth1}." ) assert d0.shape[0] == d1.shape[0], msg for name in names0: msg = ( - "The values for column '{}' ".format(name) + f"The values for column '{name}' " + "are not within 1e-5 of each other" ) assert np.allclose(d0[name], d1[name], rtol=1e-5), msg @@ -261,7 +258,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl04_auxmult.py b/autotest/test_gwf_utl04_auxmult.py index 969b5b9ff1b..9c925f36336 100644 --- a/autotest/test_gwf_utl04_auxmult.py +++ b/autotest/test_gwf_utl04_auxmult.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -87,11 +88,11 @@ def build_model(idx, dir): top=0.0, botm=botm, idomain=1, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=0.0, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=0.0, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -100,7 +101,7 @@ def build_model(idx, dir): icelltype=0, k=hk, k33=hk, - filename="{}.npf".format(name), + filename=f"{name}.npf", ) # chd files @@ -112,7 +113,7 @@ def build_model(idx, dir): gwf, stress_period_data=chdspdict, save_flows=False, - filename="{}.chd".format(name), + filename=f"{name}.chd", ) # wel files @@ -160,12 +161,12 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.bud", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -185,7 +186,7 @@ def eval_model(sim): qlist = np.array(qlist) answer = np.array(7 * [1.0, 0.0])[:-1] - msg = "err {} /= {}".format(qlist, answer) + msg = f"err {qlist} /= {answer}" assert np.allclose(qlist, answer), msg # assert False @@ -222,7 +223,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl05_budparse.py b/autotest/test_gwf_utl05_budparse.py index 9a63ef77db7..d62d7f74ed2 100644 --- a/autotest/test_gwf_utl05_budparse.py +++ b/autotest/test_gwf_utl05_budparse.py @@ -4,8 +4,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -93,7 +94,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -147,8 +148,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -167,7 +168,7 @@ def eval_flow(sim): gwfname = "gwf_" + name # This will fail if budget numbers cannot be read - fpth = os.path.join(sim.simpath, "{}.lst".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.lst") mflist = flopy.utils.Mf6ListBudget(fpth) names = mflist.get_record_names() print(names) @@ -208,7 +209,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_utl06_tas.py b/autotest/test_gwf_utl06_tas.py index 37d9482bb97..0f5b3bd8e05 100644 --- a/autotest/test_gwf_utl06_tas.py +++ b/autotest/test_gwf_utl06_tas.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -95,7 +96,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -190,8 +191,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -207,22 +208,22 @@ def eval_transport(sim): idx = sim.idxsim # load concentration file - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # load gwf budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.cbc") try: bobj = flopy.utils.CellBudgetFile( fpth, precision="double", ) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' rchbudall = bobj.get_data(text="RCH") times = bobj.get_times() @@ -409,7 +410,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf01.py b/autotest/test_gwf_uzf01.py index 02654b43f0d..1fcbc24890c 100644 --- a/autotest/test_gwf_uzf01.py +++ b/autotest/test_gwf_uzf01.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -205,16 +206,17 @@ def build_model(idx, exdir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), + budget_filerecord=f"{name}.uzf.bud", + budgetcsv_filerecord=f"{name}.uzf.bud.csv", observations=uzf_obs, - filename="{}.uzf".format(name), + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.bud", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -261,9 +263,7 @@ def eval_flow(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg # Open the uzf observation file @@ -315,7 +315,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf02.py b/autotest/test_gwf_uzf02.py index 03b9cb38679..0e0eed7dc40 100644 --- a/autotest/test_gwf_uzf02.py +++ b/autotest/test_gwf_uzf02.py @@ -4,8 +4,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -105,7 +106,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -155,7 +156,7 @@ def build_model(idx, dir): uzf_obs = { name + ".uzf.obs.csv": [ - ("wc{}".format(k + 1), "water-content", 1, depth) + (f"wc{k + 1}", "water-content", 1, depth) for k, depth in enumerate(np.linspace(1, 20, 15)) ] } @@ -187,7 +188,7 @@ def build_model(idx, dir): thts, thti, brooks_corey_epsilon, - "uzf0{}".format(k + 1), + f"uzf0{k + 1}", ] for k in range(1, nlay) ] @@ -219,16 +220,16 @@ def build_model(idx, dir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), + budget_filerecord=f"{name}.uzf.bud", observations=uzf_obs, - filename="{}.uzf".format(name), + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -236,7 +237,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -265,7 +266,7 @@ def make_plot(sim, obsvals): depth = np.arange(1, 20, 2.0) depth = np.linspace(1, 20, 15) for row in obsvals: - label = "time {}".format(row[0]) + label = f"time {row[0]}" ax.plot(row[1:], depth, label=label, marker="o") ax.set_ylim(0.0, 20.0) ax.set_xlim(0.15, 0.4) @@ -311,9 +312,7 @@ def eval_flow(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg bpth = os.path.join(ws, name + ".uzf.bud") @@ -328,7 +327,7 @@ def eval_flow(sim): try: obsvals = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' if False: make_plot(sim, obsvals) return @@ -365,7 +364,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf03.py b/autotest/test_gwf_uzf03.py index 928d1193db0..cbcad1e6dbf 100644 --- a/autotest/test_gwf_uzf03.py +++ b/autotest/test_gwf_uzf03.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -106,7 +107,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -156,7 +157,7 @@ def build_model(idx, dir): uzf_obs = { name + ".uzf.obs.csv": [ - ("wc{}".format(k + 1), "water-content", k + 1, 0.5 * delv) + (f"wc{k + 1}", "water-content", k + 1, 0.5 * delv) for k in range(nlay) ] } @@ -188,7 +189,7 @@ def build_model(idx, dir): thts, thti, brooks_corey_epsilon, - "uzf0{}".format(k + 1), + f"uzf0{k + 1}", ] for k in range(1, nlay) ] @@ -220,16 +221,16 @@ def build_model(idx, dir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), + budget_filerecord=f"{name}.uzf.bud", observations=uzf_obs, - filename="{}.uzf".format(name), + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -238,7 +239,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) obs_lst.append(["obs2", "head", (1, 0, 0)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -266,7 +267,7 @@ def make_plot(sim, obsvals): ax = fig.add_subplot(1, 1, 1) depth = np.arange(1, 31, 2.0) for row in obsvals: - label = "time {}".format(row[0]) + label = f"time {row[0]}" ax.plot(row[1:], depth, label=label, marker="o") ax.set_ylim(0.0, 20.0) ax.set_xlim(0.15, 0.4) @@ -312,9 +313,7 @@ def eval_flow(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg bpth = os.path.join(ws, name + ".uzf.bud") @@ -329,7 +328,7 @@ def eval_flow(sim): try: obsvals = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' if False: make_plot(sim, obsvals) return @@ -366,7 +365,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf04.py b/autotest/test_gwf_uzf04.py index 24ea2a18927..05ea7f8025d 100644 --- a/autotest/test_gwf_uzf04.py +++ b/autotest/test_gwf_uzf04.py @@ -10,8 +10,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -111,7 +112,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -161,7 +162,7 @@ def build_model(idx, dir): uzf_obs = { name + ".uzf.obs.csv": [ - ("wc{}".format(k + 1), "water-content", 1, depth) + (f"wc{k + 1}", "water-content", 1, depth) for k, depth in enumerate(np.linspace(1, 20, 15)) ] } @@ -209,17 +210,17 @@ def build_model(idx, dir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), - wc_filerecord="{}.uzf.bin".format(name), + budget_filerecord=f"{name}.uzf.bud", + wc_filerecord=f"{name}.uzf.bin", observations=uzf_obs, - filename="{}.uzf".format(name), + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -227,7 +228,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -241,11 +242,11 @@ def eval_flow(sim): name = ex[sim.idxsim] ws = exdirs[sim.idxsim] - fname = os.path.join(ws, "{}.uzf.bin".format(name)) + fname = os.path.join(ws, f"{name}.uzf.bin") wobj = flopy.utils.HeadFile(fname, text="WATER-CONTENT") wc = wobj.get_alldata() - fname = os.path.join(ws, "{}.hds".format(name)) + fname = os.path.join(ws, f"{name}.hds") wobj = flopy.utils.HeadFile(fname) head = wobj.get_alldata() @@ -310,7 +311,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf05.py b/autotest/test_gwf_uzf05.py new file mode 100644 index 00000000000..7258a5a03cf --- /dev/null +++ b/autotest/test_gwf_uzf05.py @@ -0,0 +1,298 @@ +""" +Test uzf for case where uzf is only in top cell. There was a +bug with this in the past in which case UZF would not send +water to water table unless there was a uzf in each cell. + +""" + +import os + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = ["gwf_uzf05a"] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) +ddir = "data" +nlay, nrow, ncol = 3, 1, 1 + +thts = 0.30 # saturated water content +thtr = 0.05 # residual water content +thti = 0.10 # initial water content +strt = 15.0 + + +def build_model(idx, dir): + + perlen = [1.0] + nper = len(perlen) + nstp = [1] + tsmult = nper * [1.0] + delr = 1.0 + delc = 1.0 + delv = 30.0 + top = 90.0 + botm = [top - (k + 1) * delv for k in range(nlay)] + laytyp = 1 + ss = 1.0e-5 + sy = 0.3 + + # unsat props + hk = 10.0 + infiltration_rate = 10. + evapotranspiration_rate = 0.0 + evt_extinction_depth = 2.0 + brooks_corey_epsilon = 3.5 # brooks corey exponent + + tdis_rc = [] + for id in range(nper): + tdis_rc.append((perlen[id], nstp[id], tsmult[id])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwfname = name + newtonoptions = "NEWTON UNDER_RELAXATION" + gwf = flopy.mf6.ModflowGwf( + sim, + modelname=gwfname, + newtonoptions=newtonoptions, + save_flows=True, + ) + + # create iterative model solution and register the gwf model with it + nouter, ninner = 100, 10 + hclose, rclose, relax = 1.5e-6, 1e-6, 0.97 + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="DBD", + under_relaxation_theta=0.7, + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + sim.register_ims_package(imsgwf, [gwf.name]) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=np.ones((nlay, nrow, ncol), dtype=int), + ) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt) + + # node property flow + npf = flopy.mf6.ModflowGwfnpf( + gwf, save_flows=False, icelltype=laytyp, k=hk + ) + # storage + sto = flopy.mf6.ModflowGwfsto( + gwf, + save_flows=False, + iconvert=laytyp, + ss=ss, + sy=sy, + steady_state={0: False}, + transient={0: True}, + ) + + # ghb + ghbspdict = { + 0: [[(nlay - 1, 0, 0), 15.0, hk / (0.5 * delv)]], + } + ghb = flopy.mf6.ModflowGwfghb( + gwf, + print_input=True, + print_flows=True, + stress_period_data=ghbspdict, + save_flows=False, + ) + + # note: for specifying uzf number, use fortran indexing! + uzf_obs = { + name + + ".uzf.obs.csv": [ + (f"wc{k + 1}", "water-content", 1, depth) + for k, depth in enumerate(np.linspace(1, 20, 15)) + ] + } + + surfdep = 1.0e-5 + uzf_pkdat = [ + [ + 0, + (0, 0, 0), + 1, + -1, + surfdep, + hk, + thtr, + thts, + thti, + brooks_corey_epsilon, + "uzf01", + ], + ] + uzf_spd = { + 0: [ + [ + 0, + infiltration_rate, + evapotranspiration_rate, + evt_extinction_depth, + thtr, + 0.0, + 0.0, + 0.0, + ], + ] + } + uzf = flopy.mf6.ModflowGwfuzf( + gwf, + print_input=True, + print_flows=True, + save_flows=True, + boundnames=True, + simulate_et=False, + unsat_etwc=True, + simulate_gwseep=True, + ntrailwaves=15, + nwavesets=40, + nuzfcells=len(uzf_pkdat), + packagedata=uzf_pkdat, + perioddata=uzf_spd, + budget_filerecord=f"{name}.uzf.bud", + wc_filerecord=f"{name}.uzf.bin", + observations=uzf_obs, + pname="uzf-1", + filename=f"{name}1.uzf", + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], + ) + + obs_lst = [] + obs_lst.append(["obs1", "head", (0, 0, 0)]) + obs_dict = {f"{gwfname}.obs.csv": obs_lst} + obs = flopy.mf6.ModflowUtlobs( + gwf, pname="head_obs", digits=20, continuous=obs_dict + ) + + return sim, None + + +def eval_flow(sim): + print("evaluating flow...") + + name = ex[sim.idxsim] + ws = exdirs[sim.idxsim] + + fname = os.path.join(ws, f"{name}.uzf.bin") + wobj = flopy.utils.HeadFile(fname, text="WATER-CONTENT") + wc = wobj.get_alldata() + + fname = os.path.join(ws, f"{name}.hds") + wobj = flopy.utils.HeadFile(fname) + head = wobj.get_alldata() + + bpth = os.path.join(ws, name + ".uzf.bud") + bobj = flopy.utils.CellBudgetFile(bpth, precision="double") + flowtogwf = bobj.get_data(text="GWF")[0] + + print("Checking to make sure UZF cell 1 sends water to GWF cell 1") + node, node2, q, flow_area = flowtogwf[0] + assert node == 1, "uzf node should be 1" + assert node2 == 1, "GWF node should be 1" + assert np.isclose(q, -4.), "Flow from UZF to node 1 should be -4." + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_flow, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_flow, idxsim=idx) + test.run_mf6(sim) + + return + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_uzf_gwet.py b/autotest/test_gwf_uzf_gwet.py index cef5d1100f3..171d984a903 100644 --- a/autotest/test_gwf_uzf_gwet.py +++ b/autotest/test_gwf_uzf_gwet.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -258,19 +259,19 @@ def build_model(idx, dir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), - filename="{}.uzf".format(name), + budget_filerecord=f"{name}.uzf.bud", + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim, None @@ -419,7 +420,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf_surfdep.py b/autotest/test_gwf_uzf_surfdep.py index 6f29f6f00cc..b9d101fd682 100644 --- a/autotest/test_gwf_uzf_surfdep.py +++ b/autotest/test_gwf_uzf_surfdep.py @@ -1,9 +1,10 @@ import os -import pytest -import sys -import numpy as np import shutil import subprocess +import sys + +import numpy as np +import pytest try: import pymake @@ -194,19 +195,19 @@ def build_model(): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), - filename="{}.uzf".format(name), + budget_filerecord=f"{name}.uzf.bud", + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim @@ -248,7 +249,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_uzf_wc_output.py b/autotest/test_gwf_uzf_wc_output.py index a1d86fec101..1404ca4b21f 100644 --- a/autotest/test_gwf_uzf_wc_output.py +++ b/autotest/test_gwf_uzf_wc_output.py @@ -1,6 +1,7 @@ -import pytest import os + import numpy as np +import pytest try: import pymake @@ -311,7 +312,7 @@ def build_mf6_model(idx, ws): # transient uzf info uzf_obs = { - "{}.uzfobs".format(name): [ + f"{name}.uzfobs": [ ("uzf01_dpth=0.5", "water-content", "uzf01", 0.5), ( "uzf01_dpth=1.5", @@ -341,19 +342,19 @@ def build_mf6_model(idx, ws): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(name), - filename="{}.uzf".format(name), + budget_filerecord=f"{name}.uzf.bud", + filename=f"{name}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], - filename="{}.oc".format(name), + filename=f"{name}.oc", ) return sim @@ -591,7 +592,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_vsc01.py b/autotest/test_gwf_vsc01.py new file mode 100644 index 00000000000..0c547db2e77 --- /dev/null +++ b/autotest/test_gwf_vsc01.py @@ -0,0 +1,359 @@ +# ## Test problem for VSC +# +# Uses constant head and general-head boundaries on the left and right +# sides of the model domain, respectively, to drive flow from left to +# right. Tests that head-dependent boundary conditions are properly +# accounting for viscosity when VSC is active. +# + +# Imports + +import os +import sys + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +hyd_cond = [1205.49396942506, 864.0] # Hydraulic conductivity (m/d) +ex = ["no-vsc01-bnd", "vsc01-bnd", "no-vsc01-k"] +viscosity_on = [False, True, False] +hydraulic_conductivity = [hyd_cond[0], hyd_cond[1], hyd_cond[1]] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# Model units + +length_units = "cm" +time_units = "seconds" + +# Table of model parameters + +nper = 1 # Number of periods +nstp = 500 # Number of time steps +perlen = 0.5 # Simulation time length ($d$) +nlay = 1 # Number of layers +nrow = 10 # Number of rows +ncol = 80 # Number of columns +system_length = 2.0 # Length of system ($m$) +delr = 1.0 # Column width ($m$) +delc = 1.0 # Row width ($m$) +delv = 1.0 # Layer thickness +top = 1.0 # Top of the model ($m$) +initial_temperature = 35.0 # Initial temperature (unitless) +porosity = 0.26 # porosity (unitless) +K_therm = 2.0 # Thermal conductivity # ($W/m/C$) +rho_water = 1000 # Density of water ($kg/m^3$) +rho_solids = 2650 # Density of the aquifer material ($kg/m^3$) +C_p_w = 4180 # Heat Capacity of water ($J/kg/C$) +C_s = 880 # Heat capacity of the solids ($J/kg/C$) +D_m = K_therm / (porosity * rho_water * C_p_w) +rhob = (1 - porosity) * rho_solids # Bulk density ($kg/m^3$) +K_d = C_s / (rho_water * C_p_w) # Partitioning coefficient ($m^3/kg$) +inflow = 5.7024 # ($m^3/d$) + +botm = [top - k * delv for k in range(1, nlay + 1)] + +nouter, ninner = 100, 300 +hclose, rclose, relax = 1e-10, 1e-6, 0.97 + +# +# MODFLOW 6 flopy GWF simulation object (sim) is returned +# + + +def build_model(idx, dir): + # Base simulation and model name and workspace + ws = dir + name = ex[idx] + + print("Building model...{}".format(name)) + + # generate names for each model + gwfname = "gwf-" + name + gwtname = "gwt-" + name + + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + + # Instantiating time discretization + tdis_ds = ((perlen, nstp, 1.0),) + flopy.mf6.ModflowTdis( + sim, nper=nper, perioddata=tdis_ds, time_units=time_units + ) + gwf = flopy.mf6.ModflowGwf(sim, modelname=gwfname, save_flows=True) + + # Instantiating solver + ims = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwfname), + ) + sim.register_ims_package(ims, [gwfname]) + + # Instantiating DIS + flopy.mf6.ModflowGwfdis( + gwf, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating NPF + flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=0, + k=hydraulic_conductivity[idx], + ) + flopy.mf6.ModflowGwfic(gwf, strt=0.0) + + # Instantiating VSC + if viscosity_on[idx]: + # Instantiate viscosity (VSC) package + vsc_filerecord = "{}.vsc.bin".format(gwfname) + vsc_pd = [(0, 0.0, 20.0, gwtname, "temperature")] + flopy.mf6.ModflowGwfvsc( + gwf, + viscref=8.904e-4, + viscosity_filerecord=vsc_filerecord, + thermal_formulation="nonlinear", + thermal_a2=10.0, + thermal_a3=248.37, + thermal_a4=133.16, + nviscspecies=len(vsc_pd), + packagedata=vsc_pd, + pname="vsc", + filename="{}.vsc".format(gwfname), + ) + + # Instantiating GHB + ghbcond = hydraulic_conductivity[idx] * delv * delc / (0.5 * delr) + ghbspd = [ + [(0, i, ncol - 1), top, ghbcond, initial_temperature] + for i in range(nrow) + ] + flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + pname="GHB-1", + auxiliary="temperature", + ) + + # Instantiating CHD + chdspd = [[(0, i, 0), 2.0, initial_temperature] for i in range(nrow)] + flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdspd, + pname="CHD-1", + auxiliary="temperature", + ) + + # Instatiating OC + head_filerecord = "{}.hds".format(gwfname) + budget_filerecord = "{}.bud".format(gwfname) + flopy.mf6.ModflowGwfoc( + gwf, + head_filerecord=head_filerecord, + budget_filerecord=budget_filerecord, + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + # Setup the GWT model for simulating heat transport + # ------------------------------------------------- + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # Instantiating solver for GWT + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwtname), + ) + sim.register_ims_package(imsgwt, [gwtname]) + + # Instantiating DIS for GWT + flopy.mf6.ModflowGwtdis( + gwt, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating MST for GWT + flopy.mf6.ModflowGwtmst( + gwt, + porosity=porosity, + sorption="linear", + bulk_density=rhob, + distcoef=K_d, + pname="MST-1", + filename="{}.mst".format(gwtname), + ) + + # Instantiating IC for GWT + flopy.mf6.ModflowGwtic(gwt, strt=initial_temperature) + + # Instantiating ADV for GWT + flopy.mf6.ModflowGwtadv(gwt, scheme="UPSTREAM") + + # Instantiating DSP for GWT + flopy.mf6.ModflowGwtdsp(gwt, xt3d_off=True, diffc=D_m) + + # Instantiating SSM for GWT + sourcerecarray = [ + ("CHD-1", "AUX", "TEMPERATURE"), + ("GHB-1", "AUX", "TEMPERATURE"), + ] + flopy.mf6.ModflowGwtssm(gwt, sources=sourcerecarray) + + # Instantiating OC for GWT + flopy.mf6.ModflowGwtoc( + gwt, + concentration_filerecord="{}.ucn".format(gwtname), + saverecord=[("CONCENTRATION", "ALL")], + printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")], + ) + + # Instantiating GWF/GWT Exchange + flopy.mf6.ModflowGwfgwt( + sim, exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname + ) + + return sim, None + + +def eval_results(sim): + print("evaluating results...") + + # read flow results from model + name = ex[sim.idxsim] + gwfname = "gwf-" + name + + fname = gwfname + ".bud" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + budobj = flopy.utils.CellBudgetFile(fname, precision="double") + outbud = budobj.get_data(text=" GHB") + + # Establish known answer: + stored_ans = -151.63446156218242 + + if sim.idxsim == 0: + no_vsc_bud_last = np.array(outbud[-1].tolist()) + sim_val_1 = no_vsc_bud_last[:, 2].sum() + + # Ensure latest simulated value hasn't changed from stored answer + assert np.allclose( + sim_val_1, stored_ans, atol=1e-4 + ), "Flow in the " + exdirs[ + 0 + ] + " test problem (doesn't simulate " "viscosity) has changed,\n should be " + str( + stored_ans + ) + " but instead is " + str( + sim_val_1 + ) + + elif sim.idxsim == 1: + with_vsc_bud_last = np.array(outbud[-1].tolist()) + sim_val_2 = with_vsc_bud_last[:, 2].sum() + + # Ensure latest simulated value hasn't changed from stored answer + assert np.allclose( + sim_val_2, stored_ans, atol=1e-4 + ), "Flow in the " + exdirs[ + 1 + ] + " test problem (simulates " "viscosity) has changed,\n should be " + str( + stored_ans + ) + " but instead is " + str( + sim_val_2 + ) + + elif sim.idxsim == 2: + no_vsc_low_k_bud_last = np.array(outbud[-1].tolist()) + sim_val_3 = no_vsc_low_k_bud_last[:, 2].sum() + + # Ensure the flow leaving model 3 is less than what leaves model 2 + assert abs(stored_ans) > abs(sim_val_3), ( + "Exit flow from model " + + exdirs[1] + + " should be greater than flow exiting " + + exdirs[2] + + ", but it is not." + ) + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_vsc02.py b/autotest/test_gwf_vsc02.py new file mode 100644 index 00000000000..2e6039d5116 --- /dev/null +++ b/autotest/test_gwf_vsc02.py @@ -0,0 +1,363 @@ +# ## Test problem for VSC +# +# Uses general-head and drain boundaries on the left and right +# sides of the model domain, respectively, to drive flow from left to +# right. Tests that head-dependent boundary conditions are properly +# accounting for viscosity when VSC is active. Similar to gwf-vsc01-bnd +# but employs head-dependent boundary on the left and right side of the +# model + +# Imports + +import os +import sys + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +# Import common functionality +from framework import testing_framework +from simulation import Simulation + +# Setup scenario input +hyd_cond = [1205.49396942506, 864.0] # Hydraulic conductivity (m/d) +ex = ["no-vsc02-bnd", "vsc02-bnd", "no-vsc02-k"] +viscosity_on = [False, True, False] +hydraulic_conductivity = [hyd_cond[0], hyd_cond[1], hyd_cond[1]] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# Model units + +length_units = "cm" +time_units = "seconds" + +# Table of model parameters + +nper = 1 # Number of periods +nstp = 500 # Number of time steps +perlen = 0.5 # Simulation time length ($d$) +nlay = 1 # Number of layers +nrow = 10 # Number of rows +ncol = 80 # Number of columns +system_length = 2.0 # Length of system ($m$) +delr = 1.0 # Column width ($m$) +delc = 1.0 # Row width ($m$) +delv = 1.0 # Layer thickness +top = 1.0 # Top of the model ($m$) +initial_temperature = 35.0 # Initial temperature (unitless) +porosity = 0.26 # porosity (unitless) +K_therm = 2.0 # Thermal conductivity # ($W/m/C$) +rho_water = 1000 # Density of water ($kg/m^3$) +rho_solids = 2650 # Density of the aquifer material ($kg/m^3$) +C_p_w = 4180 # Heat Capacity of water ($J/kg/C$) +C_s = 880 # Heat capacity of the solids ($J/kg/C$) +D_m = K_therm / (porosity * rho_water * C_p_w) +rhob = (1 - porosity) * rho_solids # Bulk density ($kg/m^3$) +K_d = C_s / (rho_water * C_p_w) # Partitioning coefficient ($m^3/kg$) +inflow = 5.7024 # ($m^3/d$) + +botm = [top - k * delv for k in range(1, nlay + 1)] + +nouter, ninner = 100, 300 +hclose, rclose, relax = 1e-10, 1e-6, 0.97 + +# +# MODFLOW 6 flopy GWF simulation object (sim) is returned +# + + +def build_model(idx, dir): + # Base simulation and model name and workspace + ws = dir + name = ex[idx] + + print("Building model...{}".format(name)) + + # generate names for each model + gwfname = "gwf-" + name + gwtname = "gwt-" + name + + sim = flopy.mf6.MFSimulation( + sim_name=name, sim_ws=ws, exe_name="mf6", version="mf6" + ) + + # Instantiating time discretization + tdis_ds = ((perlen, nstp, 1.0),) + flopy.mf6.ModflowTdis( + sim, nper=nper, perioddata=tdis_ds, time_units=time_units + ) + gwf = flopy.mf6.ModflowGwf(sim, modelname=gwfname, save_flows=True) + + # Instantiating solver + ims = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwfname), + ) + sim.register_ims_package(ims, [gwfname]) + + # Instantiating DIS + flopy.mf6.ModflowGwfdis( + gwf, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating NPF + flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=0, + k=hydraulic_conductivity[idx], + ) + flopy.mf6.ModflowGwfic(gwf, strt=0.0) + + # Instantiating VSC + if viscosity_on[idx]: + # Instantiate viscosity (VSC) package + vsc_filerecord = "{}.vsc.bin".format(gwfname) + vsc_pd = [(0, 0.0, 20.0, gwtname, "temperature")] + flopy.mf6.ModflowGwfvsc( + gwf, + viscref=8.904e-4, + viscosity_filerecord=vsc_filerecord, + thermal_formulation="nonlinear", + thermal_a2=10.0, + thermal_a3=248.37, + thermal_a4=133.16, + nviscspecies=len(vsc_pd), + packagedata=vsc_pd, + pname="vsc", + filename="{}.vsc".format(gwfname), + ) + + # Instantiating GHB + ghbcond = hydraulic_conductivity[idx] * delv * delc / (0.5 * delr) + ghbspd = [ + [(0, i, 0), top + 3, ghbcond, initial_temperature] for i in range(nrow) + ] + flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + pname="GHB-1", + auxiliary="temperature", + ) + + # Instantiating DRN + drnspd = [ + [(0, i, ncol - 1), top, 1.2 * ghbcond, initial_temperature] + for i in range(nrow) + ] + flopy.mf6.ModflowGwfdrn( + gwf, + stress_period_data=drnspd, + pname="DRN-1", + auxiliary="temperature", + ) + + # Instatiatingi OC + head_filerecord = "{}.hds".format(gwfname) + budget_filerecord = "{}.bud".format(gwfname) + flopy.mf6.ModflowGwfoc( + gwf, + head_filerecord=head_filerecord, + budget_filerecord=budget_filerecord, + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + # Setup the GWT model for simulating heat transport + # ------------------------------------------------- + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # Instantiating solver for GWT + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwtname), + ) + sim.register_ims_package(imsgwt, [gwtname]) + + # Instantiating DIS for GWT + flopy.mf6.ModflowGwtdis( + gwt, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating MST for GWT + flopy.mf6.ModflowGwtmst( + gwt, + porosity=porosity, + sorption="linear", + bulk_density=rhob, + distcoef=K_d, + pname="MST-1", + filename="{}.mst".format(gwtname), + ) + + # Instantiating IC for GWT + flopy.mf6.ModflowGwtic(gwt, strt=initial_temperature) + + # Instantiating ADV for GWT + flopy.mf6.ModflowGwtadv(gwt, scheme="UPSTREAM") + + # Instantiating DSP for GWT + flopy.mf6.ModflowGwtdsp(gwt, xt3d_off=True, diffc=D_m) + + # Instantiating SSM for GWT + sourcerecarray = [ + ("GHB-1", "AUX", "TEMPERATURE"), + ("DRN-1", "AUX", "TEMPERATURE"), + ] + flopy.mf6.ModflowGwtssm(gwt, sources=sourcerecarray) + + # Instantiating OC for GWT + flopy.mf6.ModflowGwtoc( + gwt, + concentration_filerecord="{}.ucn".format(gwtname), + saverecord=[("CONCENTRATION", "ALL")], + printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")], + ) + + # Instantiating GWF/GWT Exchange + flopy.mf6.ModflowGwfgwt( + sim, exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname + ) + return sim, None + + +def eval_results(sim): + print("evaluating results...") + + # read flow results from model + name = ex[sim.idxsim] + gwfname = "gwf-" + name + + fname = gwfname + ".bud" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + budobj = flopy.utils.CellBudgetFile(fname, precision="double") + outbud = budobj.get_data(text=" GHB") + + # Establish known answer: + stored_ans = 452.5316256451224 + + if sim.idxsim == 0: + no_vsc_bud_last = np.array(outbud[-1].tolist()) + sim_val_1 = no_vsc_bud_last[:, 2].sum() + + # Ensure latest simulated value hasn't changed from stored answer + assert np.allclose( + sim_val_1, stored_ans, atol=1e-4 + ), "Flow in the " + exdirs[ + 0 + ] + " test problem (doesn't simulate " "viscosity) has changed,\n should be " + str( + stored_ans + ) + " but instead is " + str( + sim_val_1 + ) + + elif sim.idxsim == 1: + with_vsc_bud_last = np.array(outbud[-1].tolist()) + sim_val_2 = with_vsc_bud_last[:, 2].sum() + + # Ensure latest simulated value hasn't changed from stored answer + assert np.allclose( + sim_val_2, stored_ans, atol=1e-4 + ), "Flow in the " + exdirs[ + 1 + ] + " test problem (simulates " "viscosity) has changed,\n should be " + str( + stored_ans + ) + " but instead is " + str( + sim_val_2 + ) + + elif sim.idxsim == 2: + no_vsc_low_k_bud_last = np.array(outbud[-1].tolist()) + sim_val_3 = no_vsc_low_k_bud_last[:, 2].sum() + + # Ensure the flow leaving model 3 is less than what leaves model 2 + assert abs(stored_ans) > abs(sim_val_3), ( + "Exit flow from model " + + exdirs[1] + + " should be greater than flow existing " + + exdirs[2] + + ", but it is not." + ) + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_vsc03_sfr.py b/autotest/test_gwf_vsc03_sfr.py new file mode 100644 index 00000000000..a3c79f0620b --- /dev/null +++ b/autotest/test_gwf_vsc03_sfr.py @@ -0,0 +1,576 @@ +# Scenario envisioned by this test is a river running through a V-shaped +# valley that loses water to the aquifer at the upper end until it goes +# dry, then begins to gain flow again in the lower reaches. River water +# enters the simulation at 8 deg C. Aquifer water starts out at 35 deg C. +# Reference viscosity temperature is 20 deg C. With the VSC package active, +# the simulation should predict less loss of river water to the aquifer +# and more discharge of gw to the stream, compared to the same simulation +# with the VSC package inactive. + +# Imports + +import os +import sys + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = ["no-vsc-sfr01", "vsc-sfr01"] +viscosity_on = [False, True] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# Equation for determining land surface elevation with a stream running down the middle +def topElev_sfrCentered(x, y): + return ((-0.003 * x) + 260.0) + ( + ((-2e-9 * (x - 5000.0)) + 1e-5) * (y + 1500.0) ** 2 + ) + + +# Model units +length_units = "m" +time_units = "days" + +# model domain and grid definition +Lx = 10000.0 +Ly = 3000.0 +nrow = 60 +ncol = 200 +nlay = 1 +delr = Lx / ncol +delc = Ly / nrow +xmax = ncol * delr +ymax = nrow * delc +X, Y = np.meshgrid( + np.linspace(delr / 2, xmax - delr / 2, ncol), + np.linspace(ymax - delc / 2, 0 + delc / 2, nrow), +) +ibound = np.ones((nlay, nrow, ncol)) +# Because eqn uses negative values in the Y direction, need to do a little manipulation +Y_m = -1 * np.flipud(Y) +top = topElev_sfrCentered(X, Y_m) +botm = np.zeros(top.shape) +strthd = top - 10.0 + +# NPF parameters +k11 = 1 +ss = 0.00001 +sy = 0.20 +hani = 1 +laytyp = 1 + +# Package boundary conditions +viscref = 8.904e-4 + +# time params +steady = {0: True, 1: False} +transient = {0: False, 1: True} +nstp = [1, 20] +tsmult = [1, 1] +perlen = [1, 20] + +nouter, ninner = 1000, 300 +hclose, rclose, relax = 1e-3, 1e-4, 0.97 + +# Transport related parameters +initial_temperature = 35.0 # Initial temperature (unitless) +porosity = 0.20 # porosity (unitless) +K_therm = 2.0 # Thermal conductivity # ($W/m/C$) +rho_water = 1000 # Density of water ($kg/m^3$) +rho_solids = 2650 # Density of the aquifer material ($kg/m^3$) +C_p_w = 4180 # Heat Capacity of water ($J/kg/C$) +C_s = 880 # Heat capacity of the solids ($J/kg/C$) +D_m = K_therm / (porosity * rho_water * C_p_w) +rhob = (1 - porosity) * rho_solids # Bulk density ($kg/m^3$) +K_d = C_s / (rho_water * C_p_w) # Partitioning coefficient ($m^3/kg$) + +# +# MODFLOW 6 flopy GWF & GWT simulation object (sim) is returned +# + + +def build_model(idx, dir): + # Base simulation and model name and workspace + ws = dir + name = ex[idx] + + print("Building model...{}".format(name)) + + # generate names for each model + gwfname = "gwf-" + name + gwtname = "gwt-" + name + + sim = flopy.mf6.MFSimulation( + sim_name=name, sim_ws=ws, exe_name="mf6", version="mf6" + ) + + # Instantiating time discretization + tdis_rc = [] + for i in range(len(nstp)): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + flopy.mf6.ModflowTdis( + sim, nper=len(nstp), perioddata=tdis_rc, time_units=time_units + ) + + gwf = flopy.mf6.ModflowGwf( + sim, modelname=gwfname, save_flows=True, newtonoptions="newton" + ) + + # Instantiating solver + ims = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="cooley", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwfname), + ) + sim.register_ims_package(ims, [gwfname]) + + # Instantiate discretization package + flopy.mf6.ModflowGwfdis( + gwf, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiate node property flow package + flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=1, # >0 means saturated thickness varies with computed head + k=k11, + ) + + # Instantiate storage package + flopy.mf6.ModflowGwfsto( + gwf, + save_flows=False, + iconvert=laytyp, + ss=ss, + sy=sy, + steady_state=steady, + transient=transient, + ) + + # Instantiate initial conditions package + flopy.mf6.ModflowGwfic(gwf, strt=strthd) + + # Instantiate viscosity package + if viscosity_on[idx]: + vsc_filerecord = "{}.vsc.bin".format(gwfname) + vsc_pd = [(0, 0.0, 20.0, gwtname, "TEMPERATURE")] + flopy.mf6.ModflowGwfvsc( + gwf, + viscref=viscref, + viscosity_filerecord=vsc_filerecord, + thermal_formulation="nonlinear", + thermal_a2=10.0, + thermal_a3=248.37, + thermal_a4=133.16, + nviscspecies=len(vsc_pd), + packagedata=vsc_pd, + pname="vsc", + filename="{}.vsc".format(gwfname), + ) + + # Instantiate output control package + flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "LAST")], + ) + + # Instantiate recharge package + # total inflow 2000.0 on each side (4,000 total) + rech = np.zeros_like(top) + rech_rate_lo = 0.001 + rech_rate_hi = 0.015 + for i in np.arange(ncol): + rech[0, i] = rech_rate_lo + (rech_rate_hi - rech_rate_lo) / ncol * i + + rech[-1, :] = rech[0, :] + irch = np.zeros_like(rech) + irch = irch.astype(int) + temperature_array = np.ones_like(irch) * 15.0 + aux = {0: [temperature_array]} + flopy.mf6.ModflowGwfrcha( + gwf, + print_flows=True, + recharge=rech, + irch=irch, + auxiliary=["TEMPERATURE"], + aux=aux, + pname="RCHA-1", + filename="{}.rcha".format(gwfname), + ) + + # Instantiate evapotranspiration package + # ET rate is 0.003 everywhere in the model + evtr_lo = 0.0001 + evtr_hi = 0.012 + extdp_hi = 30 + extdp_lo = 10 + evtspd = [] + for i in np.arange(nrow): + for j in np.arange(ncol): + evtr = evtr_hi - (evtr_hi - evtr_lo) / ncol * j + extdp = extdp_hi - (extdp_hi - extdp_lo) / ncol * j + # cellid, surface, rate, depth, [pxdp], [petm], [petm0], [aux] + evtspd.append([(0, i, j), top[i, j], evtr, extdp, 1.0, 0.0]) + surf_rate_specified = True + flopy.mf6.ModflowGwfevt( + gwf, + print_flows=False, + surf_rate_specified=surf_rate_specified, + maxbound=nrow * ncol, + nseg=1, + stress_period_data=evtspd, + auxiliary="TEMPERATURE", + pname="EVT-1", + filename="{}.evt".format(gwfname), + ) + + # Instantiate streamflow routing package + + # Determine the middle row and store in rMid (account for 0-base) + rMid = nrow // 2 - 1 + # sfr data + nreaches = ncol + rlen = delr + rwid = 7.0 + roughness = 0.035 + rbth = 1.0 + rhk = 1.0 + strm_up = 254.899750 + strm_dn = 225.150250 + slope = (strm_up - strm_dn) / ((ncol - 1) * delr) + ustrf = 1.0 + ndv = 0 + strm_incision = 10 + viscaux = 1.111111111 + temperatureaux = 8.0 + + packagedata = [] + for irch in range(nreaches): + nconn = 1 + if 0 < irch < nreaches - 1: + nconn += 1 + rp = [ + irch, + (0, rMid, irch), + rlen, + rwid, + slope, + top[rMid, irch] - strm_incision, + rbth, + rhk, + roughness, + nconn, + ustrf, + ndv, + viscaux, + temperatureaux, + ] + packagedata.append(rp) + + connectiondata = [] + for irch in range(nreaches): + rc = [irch] + if irch > 0: + rc.append(irch - 1) + if irch < nreaches - 1: + rc.append(-(irch + 1)) + connectiondata.append(rc) + + inflow_loc = 0 + sfr_perioddata = [ + [inflow_loc, "inflow", 25000.0], + ] + sfr_perioddata = {0: sfr_perioddata} + + budpth = f"{gwfname}.sfr.cbc" + flopy.mf6.ModflowGwfsfr( + gwf, + save_flows=True, + print_stage=True, + print_flows=True, + print_input=False, + auxiliary=["VDUMMY", "TEMPERATURE"], + unit_conversion=1.486 * 86400, + budget_filerecord=budpth, + mover=False, + nreaches=nreaches, + packagedata=packagedata, + connectiondata=connectiondata, + perioddata=sfr_perioddata, + pname="SFR-1", + filename="{}.sfr".format(gwfname), + ) + + # Setup the GWT model for simulating heat transport + # ------------------------------------------------- + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # Instantiating solver for GWT + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwtname), + ) + sim.register_ims_package(imsgwt, [gwtname]) + + # Instantiating DIS for GWT + flopy.mf6.ModflowGwtdis( + gwt, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiate Mobile Storage and Transfer package + flopy.mf6.ModflowGwtmst( + gwt, + porosity=porosity, + sorption="linear", + bulk_density=rhob, + distcoef=K_d, + pname="MST-1", + filename="{}.mst".format(gwtname), + ) + + # Instantiate Transport Initial Conditions package + flopy.mf6.ModflowGwtic(gwt, strt=initial_temperature) + + # Instantiate Advection package + flopy.mf6.ModflowGwtadv(gwt, scheme="UPSTREAM") + + # Instantiate Dispersion package (also handles conduction) + flopy.mf6.ModflowGwtdsp(gwt, xt3d_off=True, diffc=D_m) + + # Instantiate Source/Sink Mixing package + sourcerecarray = [ + ("RCHA-1", "AUX", "TEMPERATURE"), + ("EVT-1", "AUX", "TEMPERATURE"), + ] + flopy.mf6.ModflowGwtssm(gwt, sources=sourcerecarray) + + # Instantiate Streamflow Transport package + sftpackagedata = [] + for irno in range(ncol): + t = (irno, 0.0) + sftpackagedata.append(t) + + sftperioddata = [(0, "STATUS", "CONSTANT"), (0, "CONCENTRATION", 8.0)] + + flopy.mf6.modflow.ModflowGwtsft( + gwt, + boundnames=False, + save_flows=True, + print_input=False, + print_flows=True, + print_concentration=True, + concentration_filerecord=gwtname + ".sft.bin", + budget_filerecord=gwtname + ".sft.bud", + packagedata=sftpackagedata, + reachperioddata=sftperioddata, + flow_package_auxiliary_name="TEMPERATURE", + flow_package_name="SFR-1", + pname="SFT-1", + filename="{}.sft".format(gwtname), + ) + + # Instantiate Output Control package for transport + flopy.mf6.ModflowGwtoc( + gwt, + concentration_filerecord="{}.ucn".format(gwtname), + saverecord=[("CONCENTRATION", "ALL")], + printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")], + filename="{}.oc".format(gwtname), + ) + + # Instantiate Gwf-Gwt Exchange package + flopy.mf6.ModflowGwfgwt( + sim, + exgtype="GWF6-GWT6", + exgmnamea=gwfname, + exgmnameb=gwtname, + filename="{}.gwfgwt".format(gwtname), + ) + + return sim, None + + +def eval_results(sim): + print("evaluating results...") + + # read flow results from model + name = ex[sim.idxsim] + gwfname = "gwf-" + name + + fname = gwfname + ".sfr.cbc" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + budobj = flopy.utils.CellBudgetFile(fname, precision="double") + outbud = budobj.get_data(text=" GWF") + + # Establish known answer: + stored_ans_up = np.array( + [ + -381.07448455, + -380.78732368, + -380.49858508, + -380.20823421, + -379.91623521, + -379.62255085, + -379.32714247, + -379.02996987, + -378.73099123, + -378.43016302, + ] + ) + + stored_ans_dn = np.array( + [ + 87.34154005, + 92.49173569, + 98.11443969, + 104.34176415, + 111.36392723, + 119.46886139, + 129.12349417, + 141.16795665, + 157.38797791, + 182.65575269, + ] + ) + + if sim.idxsim == 0: + # convert np.array to list + no_vsc_bud_last = np.array(outbud[-1].tolist()) + + # sum up total losses and total gains in the first 10 reaches + # and the last 10 reaches + for i in np.arange(10): + # upper reaches + assert np.allclose( + abs(no_vsc_bud_last[i, 2]), abs(stored_ans_up[i]), atol=1e-4 + ), ( + "GW/SW not as expected in upper reaches of viscosity test " + "problem that uses SFR. This test keeps viscosity inactive " + "prior to activating VSC Package in next variant of this test " + "problem." + ) + + # lower reaches + assert np.allclose( + abs(no_vsc_bud_last[-(i + 1), 2]), + abs(stored_ans_dn[-(i + 1)]), + atol=1e-4, + ), ( + "GW/SW not as expected in lower reaches of viscosity test " + "problem that uses SFR. This test keeps viscosity inactive " + "prior to activating VSC Package in next variant of this test " + " problem." + ) + + elif sim.idxsim == 1: + with_vsc_bud_last = np.array(outbud[-1].tolist()) + + # sum up total losses and total gains in the first 10 reaches + # and the last 10 reaches + for i in np.arange(10): + # upper reaches + assert abs(stored_ans_up[i]) > abs(with_vsc_bud_last[i, 2]), ( + "GW/SW not as expected in upper reaches of viscosity test " + "problem that uses SFR. This test activates the VSC package that " + "should elicit a known relative change in the GW/SW exchange" + ) + + # lower reaches + assert abs(stored_ans_dn[-(i + 1)]) < abs( + with_vsc_bud_last[-(i + 1), 2] + ), ( + "GW/SW not as expected in lower reaches of viscosity test " + "problem that uses SFR. This test activates the VSC package that " + "should elicit a known relative change in the GW/SW exchange" + ) + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_vsc04_lak.py b/autotest/test_gwf_vsc04_lak.py new file mode 100644 index 00000000000..54757eca6e5 --- /dev/null +++ b/autotest/test_gwf_vsc04_lak.py @@ -0,0 +1,822 @@ +# Simple single lake model. Lake cut into top two layers of a 5 layer +# model. Model is loosely based on the first example problem in +# Merritt and Konikow (2000) which also is one of the MT3D-USGS test +# problems. This test developed to isolate lake-aquifer interaction; +# no SFR or other advanced packages. Problem set up to have groundwater +# pass through the lake: gw inflow on the left side, gw outflow on the +# right side of the lake. Uses constant stage boundary in the lake to +# ensure desired flow conditions for testing budget changes with and +# without VSC active. +# +# starting groundwater temperature: 30.0 +# left chd boundary inflow temperature: 30.0 +# starting lake temperature: 4.0 +# + +import os +import sys + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +ex = ["no-vsc04-lak", "vsc04-lak"] +viscosity_on = [False, True] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# Model units +length_units = "m" +time_units = "days" + +# model domain and grid definition +delr = [ + 76.2, + 304.8, + 304.8, + 304.8, + 304.8, + 304.8, + 152.4, + 152.4, + 152.4, + 152.4, + 152.4, + 304.8, + 304.8, + 304.8, + 304.8, + 304.8, + 76.2, +] + +delc = [ + 76.2, + 304.8, + 304.8, + 304.8, + 304.8, + 304.8, + 152.4, + 152.4, + 152.4, + 152.4, + 152.4, + 304.8, + 304.8, + 304.8, + 304.8, + 304.8, + 76.2, +] + +fixedstrthds = [ + 35.052, + 34.9267, + 34.7216, + 34.5062, + 34.2755, + 34.0237, + 33.8143, + 33.6657, + 33.5077, + 33.3394, + 33.1599, + 32.8728, + 32.4431, + 31.9632, + 31.4353, + 30.8627, + 30.48, +] + +nrow = len(delc) +ncol = len(delr) +top = np.ones((nrow, ncol)) * 35.6616 +bot1 = np.ones_like(top) * 32.6136 +bot2 = np.ones_like(top) * 29.5656 +bot3 = np.ones_like(top) * 26.5176 +bot4 = np.ones_like(top) * 23.4696 +bot5 = np.ones_like(top) * 20.4216 +botm = np.array([bot1, bot2, bot3, bot4, bot5]) +nlay = botm.shape[0] +ibound = np.ones_like(botm) + +# deactive gw cells where lake cells are active +ibound[0, 6:11, 6:11] = 0 # layer 1 +ibound[1, 7:10, 7:10] = 0 # layer 2 + +strthd = np.zeros_like(ibound) +for j in np.arange(ncol): + strthd[:, :, j] = fixedstrthds[j] + +# setup lake array +lakibnd = np.zeros_like(ibound) +lakibnd[0] = 1 - ibound[0] # layer 1 +lakibnd[1] = 1 - ibound[1] # layer 2 + +# NPF parameters +k11 = 9.144 # = 30 ft/day +k33 = 0.9144 # = 30 ft/day +ss = 3e-4 +sy = 0.20 +hani = 1 +laytyp = 1 + +# Package boundary conditions +chdl = 35.052 +chdr = 30.48 +viscref = 8.904e-4 + +# time params +transient = {0: True} +nstp = [100] +tsmult = [1.02] +perlen = [5000] + +# solver params +nouter, ninner = 1000, 300 +hclose, rclose, relax = 1e-3, 1e-4, 0.97 + +# Transport related parameters +al = 1 # longitudinal dispersivity ($m$) +ath1 = al # horizontal transverse dispersivity +atv = al # vertical transverse dispersivity +mixelm = 0 # Upstream vs TVD (Upstream selected) +initial_temperature = 35.0 # Initial temperature (unitless) +porosity = 0.20 # porosity (unitless) +K_therm = 2.0 # Thermal conductivity # ($W/m/C$) +rho_water = 1000 # Density of water ($kg/m^3$) +rho_solids = 2650 # Density of the aquifer material ($kg/m^3$) +C_p_w = 4180 # Heat Capacity of water ($J/kg/C$) +C_s = 880 # Heat capacity of the solids ($J/kg/C$) +D_m = K_therm / (porosity * rho_water * C_p_w) +rhob = (1 - porosity) * rho_solids # Bulk density ($kg/m^3$) +K_d = C_s / (rho_water * C_p_w) # Partitioning coefficient ($m^3/kg$) +leftTemp = 30.0 # Temperature of inflow from left constant head ($C$) + +# Viscosity related parameters +tviscref = 20.0 + +# +# MODFLOW 6 flopy GWF & GWT simulation object (sim) is returned +# + + +def build_model(idx, dir): + global lak_lkup_dict + + # Base simulation and model name and workspace + ws = dir + name = ex[idx] + + print("Building model...{}".format(name)) + + # generate names for each model + gwfname = "gwf-" + name + gwtname = "gwt-" + name + + sim = flopy.mf6.MFSimulation( + sim_name=name, sim_ws=ws, exe_name="mf6", version="mf6" + ) + + tdis_rc = [] + for i in range(len(nstp)): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + flopy.mf6.ModflowTdis( + sim, nper=len(nstp), perioddata=tdis_rc, time_units=time_units + ) + + gwf = flopy.mf6.ModflowGwf( + sim, modelname=gwfname, save_flows=True, newtonoptions="newton" + ) + + # Instantiating solver + ims = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="cooley", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwfname), + ) + sim.register_ims_package(ims, [gwfname]) + + # Instantiate discretization package + flopy.mf6.ModflowGwfdis( + gwf, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=ibound, + filename="{}.dis".format(gwfname), + ) + + # Instantiate node property flow package + flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=1, # >0 means saturated thickness varies with computed head + k=k11, + k33=k33, + ) + + # Instantiate storage package + flopy.mf6.ModflowGwfsto( + gwf, + save_flows=False, + iconvert=laytyp, + ss=ss, + sy=sy, + transient=transient, + ) + + # Instantiate initial conditions package + flopy.mf6.ModflowGwfic(gwf, strt=strthd) + + # Instantiate viscosity package + if viscosity_on[idx]: + vsc_filerecord = "{}.vsc.bin".format(gwfname) + vsc_pd = [(0, 0.0, tviscref, gwtname, "TEMPERATURE")] + flopy.mf6.ModflowGwfvsc( + gwf, + viscref=viscref, + viscosity_filerecord=vsc_filerecord, + thermal_formulation="nonlinear", + thermal_a2=10.0, + thermal_a3=248.37, + thermal_a4=133.16, + nviscspecies=len(vsc_pd), + packagedata=vsc_pd, + pname="vsc", + filename="{}.vsc".format(gwfname), + ) + + # Instantiate output control package + flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 17, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "LAST")], + ) + + # Instantiate constant head package + # (for driving gw flow from left to right) + chdlistl = [] + chdlistr = [] + for k in np.arange(nlay): + for i in np.arange(nrow): + # left side + if botm[k, i, 0] <= chdl: + chdlistl.append([(k, i, 0), chdl, leftTemp]) + # right side + if botm[k, i, -1] <= chdr: + chdlistr.append([(k, i, ncol - 1), chdr, 10.0]) + + flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdlistl, + print_input=True, + print_flows=True, + save_flows=False, + pname="CHD-L", + auxiliary="TEMPERATURE", + filename=f"{gwfname}.left.chd", + ) + + flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdlistr, + print_input=True, + print_flows=True, + save_flows=False, + pname="CHD-R", + auxiliary="TEMPERATURE", + filename=f"{gwfname}.right.chd", + ) + + # Instantiate lake package + lakeconnectiondata = [] + nlakecon = [0] # Expand this to [0, 0, ...] for each additional lake + ilakconn = -1 + lak_leakance = 0.1 + lak_lkup_dict = {} + for k in [0, 1]: + for i in range(nrow): + for j in range(ncol): + if lakibnd[k, i, j] == 0: + continue + else: + ilak = int(lakibnd[k, i, j] - 1) + # back + if i > 0: + if ( + lakibnd[k, i - 1, j] == 0 + and ibound[k, i - 1, j] == 1 + ): + ilakconn += 1 + # by setting belev==telev, MF6 will automatically + # re-assign elevations based on cell dimensions + h = [ + ilak, # + ilakconn, # + (k, i - 1, j), # + "horizontal", # + lak_leakance, # + 0.0, # + 0.0, # + delc[i] / 2.0, # + delr[j], # + ] + lakeconnectiondata.append(h) + lak_lkup_dict.update({ilakconn: (k, i, j)}) + + # left + if j > 0: + if ( + lakibnd[k, i, j - 1] == 0 + and ibound[k, i, j - 1] == 1 + ): + ilakconn += 1 + h = [ + ilak, + ilakconn, + (k, i, j - 1), + "horizontal", + lak_leakance, + 0.0, + 0.0, + delr[j] / 2.0, + delc[i], + ] + lakeconnectiondata.append(h) + lak_lkup_dict.update({ilakconn: (k, i, j)}) + + # right + if j < ncol - 1: + if ( + lakibnd[k, i, j + 1] == 0 + and ibound[k, i, j + 1] == 1 + ): + ilakconn += 1 + h = [ + ilak, + ilakconn, + (k, i, j + 1), + "horizontal", + lak_leakance, + 0.0, + 0.0, + delr[j] / 2.0, + delc[i], + ] + lakeconnectiondata.append(h) + lak_lkup_dict.update({ilakconn: (k, i, j)}) + + # front + if i < nrow - 1: + if ( + lakibnd[k, i + 1, j] == 0 + and ibound[k, i + 1, j] == 1 + ): + ilakconn += 1 + h = [ + ilak, + ilakconn, + (k, i + 1, j), + "horizontal", + lak_leakance, + 0.0, + 0.0, + delc[i] / 2.0, + delr[j], + ] + lakeconnectiondata.append(h) + lak_lkup_dict.update({ilakconn: (k, i, j)}) + + # vertical + if lakibnd[k, i, j] == 1 and ibound[k + 1, i, j] == 1: + ilakconn += 1 + v = [ + ilak, + ilakconn, + (k + 1, i, j), + "vertical", + lak_leakance, + 0.0, + 0.0, + 0.0, + 0.0, + ] + lakeconnectiondata.append(v) + lak_lkup_dict.update({ilakconn: (k, i, j)}) + + strtStg = 33.75 + lakpackagedata = [[0, strtStg, len(lakeconnectiondata), 4.0, "lake1"]] + lak_pkdat_dict = {"filename": "lak_pakdata.in", "data": lakpackagedata} + + lakeperioddata = { + 0: [ + (0, "STATUS", "CONSTANT"), # RAINFALL 0.005 & 0.00504739035 + (0, "STAGE", 33.5), + ] + } + + lak_obs = { + "{}.lakeobs".format(gwfname): [ + ("lakestage", "stage", "lake1"), + ("gwexchng", "lak", "lake1"), + ] + } + lak = flopy.mf6.ModflowGwflak( + gwf, + auxiliary="TEMPERATURE", + time_conversion=86400.0, + print_stage=True, + print_flows=True, + budget_filerecord=gwfname + ".lak.bud", + length_conversion=1.0, + mover=False, + pname="LAK-1", + boundnames=True, + nlakes=len(lakpackagedata), + noutlets=0, + packagedata=lak_pkdat_dict, + connectiondata=lakeconnectiondata, + perioddata=lakeperioddata, + observations=lak_obs, + filename="{}.lak".format(gwfname), + ) + + # pull in the tabfile defining the lake stage, vol, & surface area + fname = os.path.join("data", "vsc04-laktab", "stg-vol-surfarea.dat") + tabinput = [] + with open(fname, "r") as f: + # peel off the hdr line + hdr = next(f) + for line in f: + m_arr = line.strip().split(",") + # , , , + tabinput.append([float(m_arr[0]), m_arr[1], m_arr[2]]) + + tab6_filename = "{}.laktab".format(gwfname) + flopy.mf6.ModflowUtllaktab( + gwf, + nrow=len(tabinput), + ncol=3, + table=tabinput, + filename=tab6_filename, + pname="LAK_tab", + parent_file=lak, + ) + + # create gwt model + # ---------------- + gwt = flopy.mf6.ModflowGwt( + sim, modelname=gwtname, model_nam_file="{}.nam".format(gwtname) + ) + gwt.name_file.save_flows = True + + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwtname}.ims", + ) + sim.register_ims_package(imsgwt, [gwt.name]) + + # Instantiating MODFLOW 6 transport discretization package + flopy.mf6.ModflowGwtdis( + gwt, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=ibound, + filename="{}.dis".format(gwtname), + ) + + # Instantiating MODFLOW 6 transport initial concentrations + strtconc = leftTemp + flopy.mf6.ModflowGwtic( + gwt, strt=strtconc, filename="{}.ic".format(gwtname) + ) + + # Instantiate mobile storage and transfer package + sto = flopy.mf6.ModflowGwtmst( + gwt, porosity=porosity, filename=f"{gwtname}.sto" + ) + + # Instantiating MODFLOW 6 transport advection package + if mixelm == 0: + scheme = "UPSTREAM" + elif mixelm == -1: + scheme = "TVD" + else: + raise Exception() + + # Instantiate advection package + flopy.mf6.ModflowGwtadv( + gwt, scheme=scheme, filename="{}.adv".format(gwtname) + ) + + # Instantiate dispersion package + flopy.mf6.ModflowGwtdsp( + gwt, alh=al, ath1=ath1, atv=atv, filename="{}.dsp".format(gwtname) + ) + + # Instantiate source/sink mixing package + sourcerecarray = [ + ("CHD-L", "AUX", "TEMPERATURE"), + ("CHD-R", "AUX", "TEMPERATURE"), + ] + flopy.mf6.ModflowGwtssm( + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" + ) + + # Instantiating MODFLOW 6 transport output control package + flopy.mf6.ModflowGwtoc( + gwt, + budget_filerecord="{}.cbc".format(gwtname), + concentration_filerecord="{}.ucn".format(gwtname), + concentrationprintrecord=[ + ("COLUMNS", 17, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + printrecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + filename="{}.oc".format(gwtname), + ) + + # Instantiating MODFLOW 6 lake transport (lkt) package + lktpackagedata = [(0, 4.0, "lake1")] + + lktperioddata = {0: [(0, "STATUS", "CONSTANT"), (0, "CONCENTRATION", 4.0)]} + + # note: for specifying lake number, use fortran indexing! + lkt_obs = { + "{}.lakobs".format(gwtname): [ + ("resTemp", "concentration", 1), + ("resGwMassExchng", "lkt", "lake1"), + ] + } + + flopy.mf6.ModflowGwtlkt( + gwt, # Set time_conversion for use with Manning's eqn. + flow_package_name="LAK-1", + flow_package_auxiliary_name="TEMPERATURE", + budget_filerecord=gwtname + ".lkt.bud", + boundnames=True, + save_flows=True, + print_input=True, + print_flows=False, + print_concentration=True, + packagedata=lktpackagedata, + lakeperioddata=lktperioddata, + observations=lkt_obs, + pname="LKT-1", + filename="{}.lkt".format(gwtname), + ) + + # GWF-GWT exchange + flopy.mf6.ModflowGwfgwt( + sim, + exgtype="GWF6-GWT6", + exgmnamea=gwfname, + exgmnameb=gwtname, + filename=f"{name}.gwfgwt", + ) + + return sim, None + + +def eval_results(sim): + print("evaluating results...") + + # read flow results from model + name = ex[sim.idxsim] + gwfname = "gwf-" + name + + fname = gwfname + ".lak.bud" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + budobj = flopy.utils.CellBudgetFile(fname, precision="double") + outbud = budobj.get_data(text=" GWF") + + # Establish known answer: + stored_ans = np.array( + [ + [1.0, 9.20e1, 7.34424130e-01, 1.15181189e06], + [1.0, 1.08e2, 2.44117249e00, 1.15181189e06], + [1.0, 3.98e2, 2.19216490e01, 1.15181189e06], + [1.0, 9.30e1, -6.78268488e-02, 1.15181189e06], + [1.0, 3.99e2, 3.17042406e-01, 1.15181189e06], + [1.0, 9.40e1, -7.47709994e-01, 1.15181189e06], + [1.0, 4.00e2, -6.88938281e00, 1.15181189e06], + [1.0, 9.50e1, -1.51336530e00, 1.15181189e06], + [1.0, 4.01e2, -1.57614834e01, 1.15181189e06], + [1.0, 9.60e1, -2.54095715e00, 1.15181189e06], + [1.0, 1.14e2, -3.95961161e00, 1.15181189e06], + [1.0, 4.02e2, -5.60853100e01, 1.15181189e06], + [1.0, 1.25e2, 2.35138538e00, 1.15181189e06], + [1.0, 4.15e2, 1.69275311e01, 1.15181189e06], + [1.0, 1.31e2, -3.66648779e00, 1.15181189e06], + [1.0, 4.19e2, -3.45225854e01, 1.15181189e06], + [1.0, 1.42e2, 2.32550672e00, 1.15181189e06], + [1.0, 4.32e2, 1.65405908e01, 1.15181189e06], + [1.0, 1.48e2, -3.58087615e00, 1.15181189e06], + [1.0, 4.36e2, -3.27154545e01, 1.15181189e06], + [1.0, 1.59e2, 2.35138505e00, 1.15181189e06], + [1.0, 4.49e2, 1.69275277e01, 1.15181189e06], + [1.0, 1.65e2, -3.66648777e00, 1.15181189e06], + [1.0, 4.53e2, -3.45225840e01, 1.15181189e06], + [1.0, 1.76e2, 2.44117266e00, 1.15181189e06], + [1.0, 1.94e2, 7.34424819e-01, 1.15181189e06], + [1.0, 4.66e2, 2.19216459e01, 1.15181189e06], + [1.0, 1.95e2, -6.78264346e-02, 1.15181189e06], + [1.0, 4.67e2, 3.17038149e-01, 1.15181189e06], + [1.0, 1.96e2, -7.47709250e-01, 1.15181189e06], + [1.0, 4.68e2, -6.88938656e00, 1.15181189e06], + [1.0, 1.97e2, -1.51336458e00, 1.15181189e06], + [1.0, 4.69e2, -1.57614826e01, 1.15181189e06], + [1.0, 1.82e2, -3.95961151e00, 1.15181189e06], + [1.0, 1.98e2, -2.54095654e00, 1.15181189e06], + [1.0, 4.70e2, -5.60853022e01, 1.15181189e06], + [1.0, 3.99e2, 4.03508517e-03, 1.15181189e06], + [1.0, 4.15e2, 2.15441304e-01, 1.15181189e06], + [1.0, 7.05e2, 8.25215117e-01, 1.15181189e06], + [1.0, 4.00e2, -8.76830539e-02, 1.15181189e06], + [1.0, 7.06e2, -3.90793309e-01, 1.15181189e06], + [1.0, 4.01e2, -2.00600698e-01, 1.15181189e06], + [1.0, 4.19e2, -4.39378360e-01, 1.15181189e06], + [1.0, 7.07e2, -2.43955302e00, 1.15181189e06], + [1.0, 4.32e2, 2.10516610e-01, 1.15181189e06], + [1.0, 7.22e2, 8.37390920e-01, 1.15181189e06], + [1.0, 7.23e2, -6.85716153e-02, 1.15181189e06], + [1.0, 4.36e2, -4.16378511e-01, 1.15181189e06], + [1.0, 7.24e2, -1.73090130e00, 1.15181189e06], + [1.0, 4.49e2, 2.15441262e-01, 1.15181189e06], + [1.0, 4.67e2, 4.03503099e-03, 1.15181189e06], + [1.0, 7.39e2, 8.25212943e-01, 1.15181189e06], + [1.0, 4.68e2, -8.76831016e-02, 1.15181189e06], + [1.0, 7.40e2, -3.90795105e-01, 1.15181189e06], + [1.0, 4.53e2, -4.39378341e-01, 1.15181189e06], + [1.0, 4.69e2, -2.00600688e-01, 1.15181189e06], + [1.0, 7.41e2, -2.43955388e00, 1.15181189e06], + ] + ) + + # talley some flows on the left and right sides of the lake for comparison + # test + left_chk_ans = [] + right_chk_ans = [] + left_chk_no_vsc = [] + right_chk_no_vsc = [] + left_chk_with_vsc = [] + right_chk_with_vsc = [] + + if sim.idxsim == 0: + no_vsc_bud_last = np.array(outbud[-1].tolist()) + no_vsc_bud_np = np.array(no_vsc_bud_last.tolist()) + + for idx in np.arange(stored_ans.shape[0]): + k, i, j = lak_lkup_dict[idx] + + # left side of lake + if j < 7: + if no_vsc_bud_np[idx, 2] > 0 and stored_ans[idx, 2] > 0: + left_chk_no_vsc.append(no_vsc_bud_np[idx, 2]) + left_chk_ans.append(stored_ans[idx, 2]) + + # right side of lake + if j > 9: + if no_vsc_bud_np[idx, 2] < 0 and stored_ans[idx, 2] < 0: + right_chk_no_vsc.append(no_vsc_bud_np[idx, 2]) + right_chk_ans.append(stored_ans[idx, 2]) + + # Check that all the flows entering the lak in the 'with vsc' model are greater + # than their 'no vsc' counterpart + assert np.allclose( + np.array(left_chk_ans), np.array(left_chk_no_vsc), atol=1e-3 + ), ( + "Lake inflow in no-VSC LAK simulation do not match established " + "solution." + ) + + # Check that all the flows leaving the lak in the 'with vsc' model are less + # than their 'no vsc' counterpart (keep in mind values are negative, which + # affects how the comparison is made) + assert np.allclose( + np.array(right_chk_ans), np.array(right_chk_no_vsc), atol=1e-3 + ), ( + "Lake outflow in no-VSC LAK simulation do not match established " + "solution." + ) + + elif sim.idxsim == 1: + with_vsc_bud_last = np.array(outbud[-1].tolist()) + with_vsc_bud_np = np.array(with_vsc_bud_last.tolist()) + + for idx in np.arange(stored_ans.shape[0]): + k, i, j = lak_lkup_dict[idx] + + # left side of lake + if j < 7: + if stored_ans[idx, 2] > 0 and with_vsc_bud_np[idx, 2] > 0: + left_chk_no_vsc.append(stored_ans[idx, 2]) + left_chk_with_vsc.append(with_vsc_bud_np[idx, 2]) + + # right side of lake + if j > 9: + if stored_ans[idx, 2] < 0 and with_vsc_bud_np[idx, 2] < 0: + right_chk_no_vsc.append(stored_ans[idx, 2]) + right_chk_with_vsc.append(with_vsc_bud_np[idx, 2]) + + # Check that all the flows entering the lak in the 'with vsc' model are greater + # than their 'no vsc' counterpart + assert np.greater( + np.array(left_chk_with_vsc), np.array(left_chk_no_vsc) + ).all(), ( + "Lake inflow did no increase with VSC turned on and should have." + ) + + # Check that all the flows leaving the lak in the 'with vsc' model are less + # than their 'no vsc' counterpart (keep in mind values are negative, which + # affects how the comparison is made) + assert np.greater( + np.array(right_chk_with_vsc), np.array(right_chk_no_vsc) + ).all(), ( + "Lake outflow did no decrease with VSC turned on and should have." + ) + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_vsc05_hfb.py b/autotest/test_gwf_vsc05_hfb.py new file mode 100644 index 00000000000..6846226fd78 --- /dev/null +++ b/autotest/test_gwf_vsc05_hfb.py @@ -0,0 +1,415 @@ +# ## Test problem for VSC and HFB +# +# Uses constant head and general-head boundaries on the left and right +# sides of a 10 row by 10 column by 1 layer model to drive flow from left to +# right. Tests that a horizontal flow barrier accounts for changes in +# viscosity when temperature is simulated. Barrier is between middle two +# columns, but only cuts across the bottom 5 rows. +# Model 1: VSC inactive, uses a higher speified K that matches what the VSC +# package will come up with +# Model 2: VSC active, uses a lower K so that when VSC is applied, resulting +# K's match model 1 and should result in the same flows across the +# model domain +# Model 3: VSC inactive, uses the lower K of model 2 and checks that flows +# in model 3 are indeed lower than in model 2 when turning VSC off. +# Model simulates hot groundwater with lower viscosity resulting in +# more gw flow through the model domain.Flows that are checked are +# the row-wise flows between columns 5 and 6 (e.g., cell 5 to 6, 15 +# to 16, etc.) +# + +# Imports + +import os +import sys + +import numpy as np +import pytest + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from framework import testing_framework +from simulation import Simulation + +hyd_cond = [1205.49396942506, 864.0] # Hydraulic conductivity (m/d) +ex = ["no-vsc05-hfb", "vsc05-hfb", "no-vsc05-k"] +viscosity_on = [False, True, False] +hydraulic_conductivity = [hyd_cond[0], hyd_cond[1], hyd_cond[1]] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) + +# Model units + +length_units = "cm" +time_units = "seconds" + +# Table of model parameters + +nper = 1 # Number of periods +nstp = 10 # Number of time steps +perlen = 10 # Simulation time length ($d$) +nlay = 1 # Number of layers +nrow = 10 # Number of rows +ncol = 10 # Number of columns +delr = 1.0 # Column width ($m$) +delc = 1.0 # Row width ($m$) +delv = 1.0 # Layer thickness +top = 1.0 # Top of the model ($m$) +initial_temperature = 35.0 # Initial temperature (unitless) +porosity = 0.26 # porosity (unitless) +K_therm = 2.0 # Thermal conductivity # ($W/m/C$) +rho_water = 1000 # Density of water ($kg/m^3$) +rho_solids = 2650 # Density of the aquifer material ($kg/m^3$) +C_p_w = 4180 # Heat Capacity of water ($J/kg/C$) +C_s = 880 # Heat capacity of the solids ($J/kg/C$) +D_m = K_therm / (porosity * rho_water * C_p_w) +rhob = (1 - porosity) * rho_solids # Bulk density ($kg/m^3$) +K_d = C_s / (rho_water * C_p_w) # Partitioning coefficient ($m^3/kg$) +inflow = 5.7024 # ($m^3/d$) + +botm = [top - k * delv for k in range(1, nlay + 1)] + +nouter, ninner = 100, 300 +hclose, rclose, relax = 1e-10, 1e-6, 0.97 + +# +# MODFLOW 6 flopy GWF simulation object (sim) is returned +# + + +def build_model(idx, dir): + # Base simulation and model name and workspace + ws = dir + name = ex[idx] + + print("Building model...{}".format(name)) + + # generate names for each model + gwfname = "gwf-" + name + gwtname = "gwt-" + name + + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + + # Instantiating time discretization + tdis_ds = ((perlen, nstp, 1.0),) + flopy.mf6.ModflowTdis( + sim, nper=nper, perioddata=tdis_ds, time_units=time_units + ) + gwf = flopy.mf6.ModflowGwf(sim, modelname=gwfname, save_flows=True) + + # Instantiating solver + ims = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwfname), + ) + sim.register_ims_package(ims, [gwfname]) + + # Instantiating DIS + flopy.mf6.ModflowGwfdis( + gwf, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating NPF + flopy.mf6.ModflowGwfnpf( + gwf, + save_specific_discharge=True, + icelltype=0, + k=hydraulic_conductivity[idx], + ) + flopy.mf6.ModflowGwfic(gwf, strt=0.0) + + # Instantiating VSC + if viscosity_on[idx]: + # Instantiate viscosity (VSC) package + vsc_filerecord = "{}.vsc.bin".format(gwfname) + vsc_pd = [(0, 0.0, 20.0, gwtname, "temperature")] + flopy.mf6.ModflowGwfvsc( + gwf, + viscref=8.904e-4, + viscosity_filerecord=vsc_filerecord, + thermal_formulation="nonlinear", + thermal_a2=10.0, + thermal_a3=248.37, + thermal_a4=133.16, + nviscspecies=len(vsc_pd), + packagedata=vsc_pd, + pname="vsc", + filename="{}.vsc".format(gwfname), + ) + + # Instantiating CHD (leftside, "inflow" boundary) + chdspd = [[(0, i, 0), 2.0, initial_temperature] for i in range(nrow)] + flopy.mf6.ModflowGwfchd( + gwf, + stress_period_data=chdspd, + pname="CHD-1", + auxiliary="temperature", + ) + + # Instantiating GHB (rightside, "outflow" boundary) + ghbcond = hydraulic_conductivity[idx] * delv * delc / (0.5 * delr) + ghbspd = [ + [(0, i, ncol - 1), top, ghbcond, initial_temperature] + for i in range(nrow) + ] + flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=ghbspd, + pname="GHB-1", + auxiliary="temperature", + ) + + # Instantiate Horizontal Flow-Barrier (HFB) package + # Barrier present between middle two columns of the model domain, but only + # in rows 6-10. Remember that the hydraulic characteristic is the barrier + # hydraulic conductivity divided by the width of the horizontal-flow + # barrier. Assuming a barrier width of 10 cm (0.1 m) and desire to have + # the barrier's K be 1/10th of the aquifer hydraulic conductivity. + hfbspd = [] + K = 0.1 * hydraulic_conductivity[idx] + for i in np.arange(5, 10, 1): + hfbspd.append(((0, i, 4), (0, i, 5), K)) + flopy.mf6.ModflowGwfhfb( + gwf, + print_input=True, + maxhfb=len(hfbspd), + stress_period_data=hfbspd, + pname="HFB-1", + ) + + # Instatiating OC + head_filerecord = "{}.hds".format(gwfname) + budget_filerecord = "{}.bud".format(gwfname) + flopy.mf6.ModflowGwfoc( + gwf, + head_filerecord=head_filerecord, + budget_filerecord=budget_filerecord, + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + # Setup the GWT model for simulating heat transport + # ------------------------------------------------- + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # Instantiating solver for GWT + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename="{}.ims".format(gwtname), + ) + sim.register_ims_package(imsgwt, [gwtname]) + + # Instantiating DIS for GWT + flopy.mf6.ModflowGwtdis( + gwt, + length_units=length_units, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + # Instantiating MST for GWT + flopy.mf6.ModflowGwtmst( + gwt, + porosity=porosity, + sorption="linear", + bulk_density=rhob, + distcoef=K_d, + pname="MST-1", + filename="{}.mst".format(gwtname), + ) + + # Instantiating IC for GWT + flopy.mf6.ModflowGwtic(gwt, strt=initial_temperature) + + # Instantiating ADV for GWT + flopy.mf6.ModflowGwtadv(gwt, scheme="UPSTREAM") + + # Instantiating DSP for GWT + flopy.mf6.ModflowGwtdsp(gwt, xt3d_off=True, diffc=D_m) + + # Instantiating SSM for GWT + sourcerecarray = [ + ("CHD-1", "AUX", "TEMPERATURE"), + ("GHB-1", "AUX", "TEMPERATURE"), + ] + flopy.mf6.ModflowGwtssm(gwt, sources=sourcerecarray) + + # Instantiating OC for GWT + flopy.mf6.ModflowGwtoc( + gwt, + concentration_filerecord="{}.ucn".format(gwtname), + saverecord=[("CONCENTRATION", "ALL")], + printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")], + ) + + # Instantiating GWF/GWT Exchange + flopy.mf6.ModflowGwfgwt( + sim, exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname + ) + + return sim, None + + +def eval_results(sim): + print("evaluating results...") + + # read flow results from model + name = ex[sim.idxsim] + gwfname = "gwf-" + name + sim1 = flopy.mf6.MFSimulation.load(sim_ws=sim.simpath, load_only=["dis"]) + gwf = sim1.get_model(gwfname) + + # Get grid data + grdname = gwfname + ".dis.grb" + bgf = flopy.mf6.utils.MfGrdFile(os.path.join(sim.simpath, grdname)) + ia, ja = bgf.ia, bgf.ja + + fname = gwfname + ".bud" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + budobj = flopy.utils.CellBudgetFile(fname, precision="double") + outbud = budobj.get_data(text=" FLOW-JA-FACE")[-1].squeeze() + + # Establish known answer for the "with viscosity" variant: + stored_ans = np.array( + [ + [4, 5, 131.03196884892344], + [14, 15, 133.1834658429856], + [24, 25, 139.31716925610493], + [34, 35, 156.14497435040056], + [44, 45, 209.1055337693415], + [54, 55, 36.91267872240113], + [64, 65, 46.16474722642168], + [74, 75, 51.2708505192076], + [84, 85, 54.04369740428511], + [94, 95, 55.27469944201896], + ] + ) + + # Look at flow entering the left face for the cells in the 6th (1-based) column + cells = [gwf.modelgrid.get_node([(0, i, 5)])[0] for i in np.arange(nrow)] + + vals_to_store = [] # Will always have 10 vals, 1 per row + + # Note that the layer, row, column indices will be zero-based + for celln in cells: + for ipos in range(ia[celln] + 1, ia[celln + 1]): + cellm = ja[ipos] + if cellm == celln - 1: + vals_to_store.append([cellm, celln, outbud[ipos]]) + + if sim.idxsim == 0: + no_vsc_bud_last = np.array(vals_to_store) + + # Ensure with and without VSC simulations give nearly identical flow results + # for each cell-to-cell exchange between columns 5 and 6 + assert np.allclose( + no_vsc_bud_last[:, 2], stored_ans[:, 2], atol=1e-3 + ), ( + "Flow in models " + + exdirs[0] + + " and the established answer should be approximately " + "equal, but are not." + ) + + elif sim.idxsim == 1: + with_vsc_bud_last = np.array(vals_to_store) + + assert np.allclose( + with_vsc_bud_last[:, 2], stored_ans[:, 2], atol=1e-3 + ), ( + "Flow in models " + + exdirs[1] + + " and the established answer should be approximately " + "equal, but are not." + ) + + elif sim.idxsim == 2: + no_vsc_low_k_bud_last = np.array(vals_to_store) + + # Ensure the cell-to-cell flow between columns 5 and 6 in model + # 3 is less than what's in the "with viscosity" model + assert np.less(no_vsc_low_k_bud_last[:, 2], stored_ans[:, 2]).all(), ( + "Exit flow from model the established answer " + "should be greater than flow existing " + + exdirs[2] + + ", but it is not." + ) + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwf_wel01.py b/autotest/test_gwf_wel01.py index eedf8ceff98..c6923112ccc 100644 --- a/autotest/test_gwf_wel01.py +++ b/autotest/test_gwf_wel01.py @@ -4,8 +4,9 @@ specified. """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -167,7 +168,7 @@ def eval_obs(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' qtot = tc["Q"] + tc["QRED"] @@ -175,11 +176,11 @@ def eval_obs(sim): diff = qtot + wellq diffmax = np.abs(diff).max() dtol = 1e-9 - msg = "maximum absolute well rates ({}) ".format(diffmax) + msg = f"maximum absolute well rates ({diffmax}) " if diffmax > dtol: sim.success = False - msg += "exceeds {}".format(dtol) + msg += f"exceeds {dtol}" assert diffmax < dtol, msg else: sim.success = True @@ -192,7 +193,7 @@ def eval_obs(sim): fpth, names=True, delimiter=",", deletechars="" ) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' a1 = afroutput["rate-requested"] a2 = afroutput["rate-actual"] + afroutput["wel-reduction"] @@ -232,7 +233,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwf_zb01.py b/autotest/test_gwf_zb01.py index 26214b21a18..36fa5c8ca83 100644 --- a/autotest/test_gwf_zb01.py +++ b/autotest/test_gwf_zb01.py @@ -1,6 +1,7 @@ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -10,10 +11,9 @@ msg += " pip install flopy" raise Exception(msg) -from framework import testing_framework, running_on_CI -from simulation import Simulation - import targets +from framework import running_on_CI, testing_framework +from simulation import Simulation ex = ["zbud6_zb01"] exdirs = [] @@ -180,11 +180,11 @@ def build_model(idx, dir): delc=delc, top=top, botm=botm, - filename="{}.dis".format(name), + filename=f"{name}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename="{}.ic".format(name)) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{name}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -228,8 +228,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(name), - head_filerecord="{}.hds".format(name), + budget_filerecord=f"{name}.cbc", + head_filerecord=f"{name}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -248,23 +248,21 @@ def eval_zb6(sim): fpth = os.path.join(sim.simpath, "zonebudget.nam") f = open(fpth, "w") f.write("BEGIN ZONEBUDGET\n") - f.write(" BUD {}.cbc\n".format(os.path.basename(sim.name))) - f.write(" ZON {}.zon\n".format(os.path.basename(sim.name))) - f.write(" GRB {}.dis.grb\n".format(os.path.basename(sim.name))) + f.write(f" BUD {os.path.basename(sim.name)}.cbc\n") + f.write(f" ZON {os.path.basename(sim.name)}.zon\n") + f.write(f" GRB {os.path.basename(sim.name)}.dis.grb\n") f.write("END ZONEBUDGET\n") f.close() - fpth = os.path.join( - sim.simpath, "{}.zon".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.zon") f = open(fpth, "w") f.write("BEGIN DIMENSIONS\n") - f.write(" NCELLS {}\n".format(size3d)) + f.write(f" NCELLS {size3d}\n") f.write("END DIMENSIONS\n\n") f.write("BEGIN GRIDDATA\n") f.write(" IZONE LAYERED\n") for k in range(nlay): - f.write(" CONSTANT {:>10d}\n".format(zones[k])) + f.write(f" CONSTANT {zones[k]:>10d}\n") f.write("END GRIDDATA\n") f.close() @@ -278,11 +276,11 @@ def eval_zb6(sim): report=True, ) if success: - print("successfully ran...{}".format(os.path.basename(zbexe))) + print(f"successfully ran...{os.path.basename(zbexe)}") sim.success = True else: sim.success = False - msg = "could not run...{}".format(zbexe) + msg = f"could not run...{zbexe}" assert success, msg # read data from csv file @@ -309,9 +307,7 @@ def eval_zb6(sim): ion = 0 # get results from listing file - fpth = os.path.join( - sim.simpath, "{}.lst".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.lst") budl = flopy.utils.Mf6ListBudget(fpth) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] @@ -323,9 +319,7 @@ def eval_zb6(sim): d = np.recarray(nbud, dtype=dtype) for key in bud_lst: d[key] = 0.0 - fpth = os.path.join( - sim.simpath, "{}.cbc".format(os.path.basename(sim.name)) - ) + fpth = os.path.join(sim.simpath, f"{os.path.basename(sim.name)}.cbc") cobj = flopy.utils.CellBudgetFile(fpth, precision="double") kk = cobj.get_kstpkper() times = cobj.get_times() @@ -350,35 +344,35 @@ def eval_zb6(sim): d["totim"][idx] = t d["time_step"][idx] = k[0] d["stress_period"] = k[1] - key = "{}_IN".format(text) + key = f"{text}_IN" d[key][idx] = qin - key = "{}_OUT".format(text) + key = f"{text}_OUT" d[key][idx] = qout diff = np.zeros((nbud, len(bud_lst)), dtype=float) for idx, key in enumerate(bud_lst): diff[:, idx] = d0[key] - d[key] diffmax = np.abs(diff).max() - msg = "maximum absolute total-budget difference ({}) ".format(diffmax) + msg = f"maximum absolute total-budget difference ({diffmax}) " # write summary fpth = os.path.join( - sim.simpath, "{}.bud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.bud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_LST") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_LST':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, key in enumerate(bud_lst): - line += "{:25g}".format(d0[key][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diff[i, idx]) + line += f"{d0[key][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diff[i, idx]:25g}" f.write(line + "\n") f.close() @@ -388,35 +382,33 @@ def eval_zb6(sim): diffzb[:, idx] = zbsum[key0] - d[key] diffzbmax = np.abs(diffzb).max() msg += ( - "\nmaximum absolute zonebudget-cell by cell difference ({}) ".format( - diffzbmax - ) + f"\nmaximum absolute zonebudget-cell by cell difference ({diffzbmax}) " ) # write summary fpth = os.path.join( - sim.simpath, "{}.zbud.cmp.out".format(os.path.basename(sim.name)) + sim.simpath, f"{os.path.basename(sim.name)}.zbud.cmp.out" ) f = open(fpth, "w") for i in range(diff.shape[0]): if i == 0: - line = "{:>10s}".format("TIME") + line = f"{'TIME':>10s}" for idx, key in enumerate(bud_lst): - line += "{:>25s}".format(key + "_ZBUD") - line += "{:>25s}".format(key + "_CBC") - line += "{:>25s}".format(key + "_DIF") + line += f"{key + '_ZBUD':>25s}" + line += f"{key + '_CBC':>25s}" + line += f"{key + '_DIF':>25s}" f.write(line + "\n") - line = "{:10g}".format(d["totim"][i]) + line = f"{d['totim'][i]:10g}" for idx, (key0, key) in enumerate(zip(zone_lst, bud_lst)): - line += "{:25g}".format(zbsum[key0][i]) - line += "{:25g}".format(d[key][i]) - line += "{:25g}".format(diffzb[i, idx]) + line += f"{zbsum[key0][i]:25g}" + line += f"{d[key][i]:25g}" + line += f"{diffzb[i, idx]:25g}" f.write(line + "\n") f.close() if diffmax > budtol or diffzbmax > budtol: sim.success = False - msg += "\n...exceeds {}".format(budtol) + msg += f"\n...exceeds {budtol}" assert diffmax < budtol and diffzbmax < budtol, msg else: sim.success = True @@ -477,7 +469,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwfgwf_lgr.py b/autotest/test_gwfgwf_lgr.py index 53217d0a253..a457d1581d5 100644 --- a/autotest/test_gwfgwf_lgr.py +++ b/autotest/test_gwfgwf_lgr.py @@ -31,6 +31,7 @@ """ import os + import numpy as np import pytest @@ -43,6 +44,7 @@ raise Exception(msg) from flopy.utils.lgrutil import Lgr + from framework import testing_framework from simulation import Simulation @@ -171,8 +173,8 @@ def get_model(idx, dir): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(parent_name), - budget_filerecord="{}.cbc".format(parent_name), + head_filerecord=f"{parent_name}.hds", + budget_filerecord=f"{parent_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -203,8 +205,8 @@ def get_model(idx, dir): ) oc = flopy.mf6.ModflowGwfoc( gwfc, - head_filerecord="{}.hds".format(child_name), - budget_filerecord="{}.cbc".format(child_name), + head_filerecord=f"{child_name}.hds", + budget_filerecord=f"{child_name}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -256,11 +258,11 @@ def build_model(idx, exdir): def eval_heads(sim): print("comparing heads for child model to analytical result...") - fpth = os.path.join(sim.simpath, "{}.hds".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.hds") hds_c = flopy.utils.HeadFile(fpth) heads_c = hds_c.get_data() - fpth = os.path.join(sim.simpath, "{}.dis.grb".format(child_name)) + fpth = os.path.join(sim.simpath, f"{child_name}.dis.grb") grb_c = flopy.mf6.utils.MfGrdFile(fpth) # check flowja residual @@ -271,7 +273,7 @@ def eval_heads(sim): grb = flopy.mf6.utils.MfGrdFile(fpth) ia = grb._datadict["IA"] - 1 - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.cbc") assert os.path.isfile(fpth) cbb = flopy.utils.CellBudgetFile(fpth, precision="double") flow_ja_face = cbb.get_data(idx=0) @@ -282,9 +284,7 @@ def eval_heads(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg return @@ -320,7 +320,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv01.py b/autotest/test_gwt_adv01.py index 073df00ef55..3afcf22e605 100644 --- a/autotest/test_gwt_adv01.py +++ b/autotest/test_gwt_adv01.py @@ -6,9 +6,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -89,7 +90,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -103,13 +104,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -145,8 +144,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -158,7 +157,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -176,7 +175,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -190,17 +189,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -209,14 +206,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -239,7 +236,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -251,7 +248,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -263,14 +260,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -639,7 +636,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv01_fmi.py b/autotest/test_gwt_adv01_fmi.py index 3ef70eea1b8..98a08712210 100644 --- a/autotest/test_gwt_adv01_fmi.py +++ b/autotest/test_gwt_adv01_fmi.py @@ -6,9 +6,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -18,9 +19,9 @@ msg += " pip install flopy" raise Exception(msg) +from binary_file_writer import uniform_flow_field, write_budget, write_head from framework import testing_framework from simulation import Simulation -from binary_file_writer import write_head, write_budget, uniform_flow_field ex = ["adv01a_fmi", "adv01b_fmi", "adv01c_fmi"] scheme = ["upstream", "central", "tvd"] @@ -70,7 +71,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -88,7 +89,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -102,17 +103,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -121,7 +120,7 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # create a heads file with head equal top @@ -197,8 +196,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -221,7 +220,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -236,14 +235,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -612,7 +611,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv01_gwtgwt.py b/autotest/test_gwt_adv01_gwtgwt.py index 59118d178d4..dd4a067d4bd 100644 --- a/autotest/test_gwt_adv01_gwtgwt.py +++ b/autotest/test_gwt_adv01_gwtgwt.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest from matplotlib import pyplot as plt try: @@ -99,8 +100,8 @@ def get_gwf_model(sim, gwfname, gwfpath, modelshape, chdspd=None, welspd=None): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -156,8 +157,8 @@ def get_gwt_model( # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -302,7 +303,7 @@ def build_model(idx, dir): exgtype="GWT6-GWT6", gwfmodelname1=gwf1.name, gwfmodelname2=gwf2.name, - advscheme=scheme[idx], + adv_scheme=scheme[idx], nexg=len(gwfgwf_data), exgmnamea=gwt1.name, exgmnameb=gwt2.name, @@ -707,7 +708,7 @@ def eval_transport(sim): # check budget for mname in ["transport1", "transport2"]: - fpth = os.path.join(sim.simpath, mname, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, mname, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -719,21 +720,21 @@ def eval_transport(sim): # get grid data (from GWF) gwfname = "flow1" if mname == "transport1" else "flow2" - fpth = os.path.join(sim.simpath, gwfname, "{}.dis.grb".format(gwfname)) + fpth = os.path.join(sim.simpath, gwfname, f"{gwfname}.dis.grb") grb = flopy.mf6.utils.MfGrdFile(fpth) # Check on residual, which is stored in diagonal position of # flow-ja-face. Residual should be less than convergence tolerance, # or this means the residual term is not added correctly. - fpth = os.path.join(sim.simpath, mname, "{}.cbc".format(mname)) + fpth = os.path.join(sim.simpath, mname, f"{mname}.cbc") cbb = flopy.utils.CellBudgetFile(fpth) flow_ja_face = cbb.get_data(text="FLOW-JA-FACE") ia = grb._datadict["IA"] - 1 for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max flowja residual too large {} {}".format( - res.min(), res.max() + errmsg = ( + f"min or max flowja residual too large {res.min()} {res.max()}" ) # TODO: this is not implemented yet: # assert np.allclose(res, 0.0, atol=1.0e-6), errmsg @@ -773,7 +774,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv02.py b/autotest/test_gwt_adv02.py index 2683f532ce5..39942b02189 100644 --- a/autotest/test_gwt_adv02.py +++ b/autotest/test_gwt_adv02.py @@ -8,9 +8,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -58,7 +59,7 @@ def grid_triangulator(itri, delr, delc): vertdict[icell] = [vs[0], vs[1], vs[2], vs[0]] icell += 1 else: - raise Exception("Unknown itri value: {}".format(itri[i, j])) + raise Exception(f"Unknown itri value: {itri[i, j]}") verts, iverts = flopy.utils.cvfdutil.to_cvfd(vertdict) return verts, iverts @@ -117,7 +118,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -134,7 +135,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -157,7 +158,7 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwfname), + filename=f"{gwfname}.disv", ) # dis = flopy.mf6.ModflowGwfdis(gwf, nlay=nlay, nrow=nrow, ncol=ncol, @@ -167,9 +168,7 @@ def build_model(idx, dir): # filename='{}.dis'.format(gwfname)) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -205,8 +204,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -218,7 +217,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -236,7 +235,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -249,17 +248,15 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwtname), + filename=f"{gwtname}.disv", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -268,14 +265,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -298,7 +295,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -310,7 +307,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -322,14 +319,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -992,7 +989,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv03.py b/autotest/test_gwt_adv03.py index d3e680419e8..db6014f586d 100644 --- a/autotest/test_gwt_adv03.py +++ b/autotest/test_gwt_adv03.py @@ -8,9 +8,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -58,7 +59,7 @@ def grid_triangulator(itri, delr, delc): vertdict[icell] = [vs[0], vs[1], vs[2], vs[0]] icell += 1 else: - raise Exception("Unknown itri value: {}".format(itri[i, j])) + raise Exception(f"Unknown itri value: {itri[i, j]}") verts, iverts = flopy.utils.cvfdutil.to_cvfd(vertdict) return verts, iverts @@ -123,7 +124,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -140,7 +141,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -187,7 +188,7 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwfname), + filename=f"{gwfname}.disv", ) # dis = flopy.mf6.ModflowGwfdis(gwf, nlay=nlay, nrow=nrow, ncol=ncol, @@ -197,9 +198,7 @@ def build_model(idx, dir): # filename='{}.dis'.format(gwfname)) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -236,8 +235,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -249,7 +248,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -267,7 +266,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -280,17 +279,15 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwtname), + filename=f"{gwtname}.disv", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -299,14 +296,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -329,7 +326,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -341,7 +338,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -353,7 +350,7 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -362,7 +359,7 @@ def eval_transport(sim): tdistplot = times[int(len(times) / 5)] conc = cobj.get_data(totim=tdistplot) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # the time eqaul to 1/5 of perlen. @@ -544,7 +541,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_adv04.py b/autotest/test_gwt_adv04.py index 3dea91c183c..9bb743fe91d 100644 --- a/autotest/test_gwt_adv04.py +++ b/autotest/test_gwt_adv04.py @@ -7,9 +7,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -93,7 +94,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -110,7 +111,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -124,13 +125,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -162,8 +161,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -175,7 +174,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -192,7 +191,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -206,17 +205,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -225,14 +222,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -246,7 +243,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -258,14 +255,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check to make sure that the concentrations are symmetric in both the # up-down and left-right directions @@ -317,7 +314,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_buy_solute_heat.py b/autotest/test_gwt_buy_solute_heat.py index 5c03154048d..b1a7f0b818a 100644 --- a/autotest/test_gwt_buy_solute_heat.py +++ b/autotest/test_gwt_buy_solute_heat.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -78,7 +79,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwfname]) @@ -114,7 +115,7 @@ def build_model(idx, dir): (0, 0.7, 0.0, gwtsname, "SALINITY"), (1, -0.375, 25.0, gwthname, "TEMPERATURE"), ] - fname = "{}.buy.bin".format(gwfname) + fname = f"{gwfname}.buy.bin" buy = flopy.mf6.ModflowGwfbuy( gwf, density_filerecord=fname, nrhospecies=len(pd), packagedata=pd ) @@ -168,8 +169,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -193,7 +194,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtsname), + filename=f"{gwtsname}.ims", ) sim.register_ims_package(imsgwt, [gwts.name]) @@ -231,8 +232,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwts, - budget_filerecord="{}.cbc".format(gwtsname), - concentration_filerecord="{}.ucn".format(gwtsname), + budget_filerecord=f"{gwtsname}.cbc", + concentration_filerecord=f"{gwtsname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -246,7 +247,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtsname, - filename="{}-s.gwfgwt".format(name), + filename=f"{name}-s.gwfgwt", ) # create gwt model @@ -267,7 +268,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwthname), + filename=f"{gwthname}.ims", ) sim.register_ims_package(imsgwt, [gwth.name]) @@ -318,8 +319,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwth, - budget_filerecord="{}.cbc".format(gwthname), - concentration_filerecord="{}.ucn".format(gwthname), + budget_filerecord=f"{gwthname}.cbc", + concentration_filerecord=f"{gwthname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -333,7 +334,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwthname, - filename="{}-h.gwfgwt".format(name), + filename=f"{name}-h.gwfgwt", ) return sim, None @@ -509,7 +510,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_disu01.py b/autotest/test_gwt_disu01.py new file mode 100644 index 00000000000..45e33a5602e --- /dev/null +++ b/autotest/test_gwt_disu01.py @@ -0,0 +1,315 @@ +""" +MODFLOW 6 Autotest +Two-dimensional injection of solute into the middle of a square grid. The test will pass +if the results are symmetric. Based on test_gwt_adv04, this tests the disu package, which +represents a regular MODFLOW grid. + +""" + +import os +import sys + +import numpy as np +import pytest + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + +from disu_util import get_disu_kwargs +from framework import testing_framework +from simulation import Simulation + +ex = [ + "disu01a", +] +exdirs = [] +for s in ex: + exdirs.append(os.path.join("temp", s)) +ddir = "data" + + +def build_model(idx, dir): + nlay, nrow, ncol = 1, 21, 21 + nper = 1 + perlen = [5.0] + nstp = [200] + tsmult = [1.0] + steady = [True] + delr = np.ones(ncol, dtype=float) + delc = np.ones(nrow, dtype=float) + botm = [0.0] + strt = 1.0 + hnoflo = 1e30 + hdry = -1e30 + hk = 1.0 + + top = 1.0 + laytyp = 0 + + def get_nn(k, i, j): + return k * nrow * ncol + i * ncol + j + + # put constant heads all around the box + chdlist = [] + ib = np.ones((nlay, nrow, ncol), dtype=int) + ib[:, 1 : nrow - 1, 1 : ncol - 1] = 0 + idloc = np.where(ib > 0) + for k, i, j in zip(idloc[0], idloc[1], idloc[2]): + chdlist.append([(get_nn(k, i, j),), 0.0]) + chdspdict = {0: chdlist} + + # injection well with rate and concentration of 1. + k, i, j = (0, int(nrow / 2), int(ncol / 2)) + w = {0: [[(get_nn(k, i, j),), 1.0, 1.0]]} + + nouter, ninner = 100, 300 + hclose, rclose, relax = 1e-6, 1e-6, 1.0 + + tdis_rc = [] + for i in range(nper): + tdis_rc.append((perlen[i], nstp[i], tsmult[i])) + + name = ex[idx] + + # build MODFLOW 6 files + ws = dir + sim = flopy.mf6.MFSimulation( + sim_name=name, version="mf6", exe_name="mf6", sim_ws=ws + ) + # create tdis package + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + # create gwf model + gwfname = "gwf_" + name + gwf = flopy.mf6.MFModel( + sim, + model_type="gwf6", + modelname=gwfname, + model_nam_file=f"{gwfname}.nam", + ) + + # create iterative model solution and register the gwf model with it + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + sim.register_ims_package(imsgwf, [gwf.name]) + + # use utility to make a disu version of a regular grid + disu_kwargs = get_disu_kwargs(nlay, nrow, ncol, delr, delc, top, botm) + disu = flopy.mf6.ModflowGwfdisu(gwf, **disu_kwargs) + + # initial conditions + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") + + # node property flow + npf = flopy.mf6.ModflowGwfnpf( + gwf, save_flows=False, icelltype=laytyp, k=hk, k33=hk + ) + + # chd files + chd = flopy.mf6.ModflowGwfchd( + gwf, stress_period_data=chdspdict, save_flows=False, pname="CHD-1" + ) + + # wel files + wel = flopy.mf6.ModflowGwfwel( + gwf, + print_input=True, + print_flows=True, + stress_period_data=w, + save_flows=False, + auxiliary="CONCENTRATION", + pname="WEL-1", + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "LAST")], + printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + ) + + # create gwt model + gwtname = "gwt_" + name + gwt = flopy.mf6.MFModel( + sim, + model_type="gwt6", + modelname=gwtname, + model_nam_file=f"{gwtname}.nam", + ) + + # create iterative model solution and register the gwt model with it + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="SUMMARY", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwtname}.ims", + ) + sim.register_ims_package(imsgwt, [gwt.name]) + + # use utility to make a disu version of a regular grid + disu_kwargs = get_disu_kwargs(nlay, nrow, ncol, delr, delc, top, botm) + disu = flopy.mf6.ModflowGwtdisu(gwt, **disu_kwargs) + + # initial conditions + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") + + # advection + adv = flopy.mf6.ModflowGwtadv( + gwt, scheme="upstream", filename=f"{gwtname}.adv" + ) + + # dispersion must be off as disu package does not have ANGLDEGX specified + # dsp = flopy.mf6.ModflowGwtdsp( + # gwt, + # xt3d_off=True, + # diffc=100.0, + # alh=0.0, + # alv=0.0, + # ath1=0.0, + # atv=0.0, + # filename="{}.dsp".format(gwtname), + # ) + + # mass storage and transfer + mst = flopy.mf6.ModflowGwtmst(gwt, porosity=0.1) + + # sources + sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] + ssm = flopy.mf6.ModflowGwtssm( + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" + ) + + # output control + oc = flopy.mf6.ModflowGwtoc( + gwt, + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", + concentrationprintrecord=[ + ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("CONCENTRATION", "LAST")], + printrecord=[("CONCENTRATION", "LAST"), ("BUDGET", "LAST")], + ) + + # GWF GWT exchange + gwfgwt = flopy.mf6.ModflowGwfgwt( + sim, + exgtype="GWF6-GWT6", + exgmnamea=gwfname, + exgmnameb=gwtname, + filename=f"{name}.gwfgwt", + ) + + return sim, None + + +def eval_transport(sim): + print("evaluating transport...") + + name = ex[sim.idxsim] + gwtname = "gwt_" + name + + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") + try: + cobj = flopy.utils.HeadFile( + fpth, precision="double", text="CONCENTRATION" + ) + conc = cobj.get_data() + except: + assert False, f'could not load data from "{fpth}"' + + # Check to make sure that the concentrations are symmetric in both the + # up-down and left-right directions + conc = conc.reshape((21, 21)) + concud = np.flipud(conc) + assert np.allclose(concud, conc), ( + "simulated concentrations are not " "symmetric in up-down direction." + ) + + conclr = np.fliplr(conc) + assert np.allclose(conclr, conc), ( + "simulated concentrations are not " + "symmetric in left-right direction." + ) + + return + + +# - No need to change any code below + + +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the models + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_transport, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # build the models + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_transport, idxsim=idx) + test.run_mf6(sim) + + return + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwt_dsp01.py b/autotest/test_gwt_dsp01.py index ca95da108e4..ad11fc51c19 100644 --- a/autotest/test_gwt_dsp01.py +++ b/autotest/test_gwt_dsp01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -76,7 +77,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -94,7 +95,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -108,13 +109,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -134,8 +133,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -147,7 +146,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -165,7 +164,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -179,17 +178,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # dispersion @@ -202,7 +199,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -225,14 +222,14 @@ def build_model(idx, dir): # sources ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], print_flows=True, filename="{}.ssm".format(gwtname) + gwt, sources=[[]], print_flows=True, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -242,11 +239,11 @@ def build_model(idx, dir): # observations obs_data0 = [("flow1", "flow-ja-face", (0, 0, 0), (0, 0, 1))] - obs_recarray = {"{}.obs.csv".format(gwtname): obs_data0} + obs_recarray = {f"{gwtname}.obs.csv": obs_data0} obs = flopy.mf6.ModflowUtlobs( gwt, pname="gwt_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=15, print_input=True, continuous=obs_recarray, @@ -258,7 +255,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -270,14 +267,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -403,7 +400,7 @@ def eval_transport(sim): cncobs = np.genfromtxt(fname, names=True, delimiter=",", deletechars="") # ensure flow right face for first cell is equal to cnc flows - errmsg = "observations not equal:\n{}\n{}".format(gwtobs, cncobs) + errmsg = f"observations not equal:\n{gwtobs}\n{cncobs}" assert np.allclose(gwtobs["FLOW1"], -cncobs["CNC000"]), errmsg # comment when done testing @@ -444,7 +441,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp01_fmi.py b/autotest/test_gwt_dsp01_fmi.py index 019513dc500..10a7e5c5189 100644 --- a/autotest/test_gwt_dsp01_fmi.py +++ b/autotest/test_gwt_dsp01_fmi.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,9 +20,9 @@ msg += " pip install flopy" raise Exception(msg) +from binary_file_writer import write_budget, write_head from framework import testing_framework from simulation import Simulation -from binary_file_writer import write_head, write_budget ex = ["dsp01a_fmi", "dsp01b_fmi"] xt3d = [False, True] @@ -77,7 +78,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -95,7 +96,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -109,13 +110,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # dispersion xt3d_off = not xt3d[idx] @@ -127,7 +126,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -201,8 +200,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -219,14 +218,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -376,7 +375,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp01_gwtgwt.py b/autotest/test_gwt_dsp01_gwtgwt.py index 0f617bbc1e8..5fdba73aaf5 100644 --- a/autotest/test_gwt_dsp01_gwtgwt.py +++ b/autotest/test_gwt_dsp01_gwtgwt.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest from matplotlib import pyplot as plt try: @@ -74,8 +75,8 @@ def get_gwf_model(sim, gwfname, gwfpath, modelshape): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -130,7 +131,7 @@ def get_gwt_model(sim, gwtname, gwtpath, modelshape): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer @@ -139,8 +140,8 @@ def get_gwt_model(sim, gwtname, gwtpath, modelshape): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -284,24 +285,24 @@ def build_model(idx, dir): def eval_transport(sim): gwtname = "transport1" - fpth = os.path.join(sim.simpath, "transport1", "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, "transport1", f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc1 = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' gwtname = "transport2" - fpth = os.path.join(sim.simpath, "transport2", "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, "transport2", f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc2 = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # diffusion across both sub-models: assert np.all(conc1 > 0.0) @@ -345,7 +346,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp01_noadv.py b/autotest/test_gwt_dsp01_noadv.py index 98b7fc86968..230d3711752 100644 --- a/autotest/test_gwt_dsp01_noadv.py +++ b/autotest/test_gwt_dsp01_noadv.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -76,7 +77,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -94,7 +95,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -108,13 +109,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # dispersion xt3d_off = not xt3d[idx] @@ -126,7 +125,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -145,8 +144,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -163,14 +162,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -320,7 +319,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp02.py b/autotest/test_gwt_dsp02.py index e8bb02426f3..d2e0d7f0613 100644 --- a/autotest/test_gwt_dsp02.py +++ b/autotest/test_gwt_dsp02.py @@ -8,9 +8,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -58,7 +59,7 @@ def grid_triangulator(itri, delr, delc): vertdict[icell] = [vs[0], vs[1], vs[2], vs[0]] icell += 1 else: - raise Exception("Unknown itri value: {}".format(itri[i, j])) + raise Exception(f"Unknown itri value: {itri[i, j]}") verts, iverts = flopy.utils.cvfdutil.to_cvfd(vertdict) return verts, iverts @@ -117,7 +118,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -134,7 +135,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -157,13 +158,11 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwfname), + filename=f"{gwfname}.disv", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -187,8 +186,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -200,7 +199,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -218,7 +217,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -231,17 +230,15 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwtname), + filename=f"{gwtname}.disv", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="upstream", filename="{}.adv".format(gwtname) + gwt, scheme="upstream", filename=f"{gwtname}.adv" ) # dispersion @@ -254,7 +251,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer @@ -267,15 +264,13 @@ def build_model(idx, dir): ) # sources - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -289,7 +284,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -301,14 +296,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 200. @@ -765,7 +760,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp03.py b/autotest/test_gwt_dsp03.py index b730648d1dc..960de6fe324 100644 --- a/autotest/test_gwt_dsp03.py +++ b/autotest/test_gwt_dsp03.py @@ -8,9 +8,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -58,7 +59,7 @@ def grid_triangulator(itri, delr, delc): vertdict[icell] = [vs[0], vs[1], vs[2], vs[0]] icell += 1 else: - raise Exception("Unknown itri value: {}".format(itri[i, j])) + raise Exception(f"Unknown itri value: {itri[i, j]}") verts, iverts = flopy.utils.cvfdutil.to_cvfd(vertdict) return verts, iverts @@ -123,7 +124,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -140,7 +141,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -192,7 +193,7 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwfname), + filename=f"{gwfname}.disv", ) # dis = flopy.mf6.ModflowGwfdis(gwf, nlay=nlay, nrow=nrow, ncol=ncol, @@ -202,9 +203,7 @@ def build_model(idx, dir): # filename='{}.dis'.format(gwfname)) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -229,8 +228,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -242,7 +241,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -260,7 +259,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -273,17 +272,15 @@ def build_model(idx, dir): botm=botm, vertices=vertices, cell2d=cell2d, - filename="{}.disv".format(gwtname), + filename=f"{gwtname}.disv", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="upstream", filename="{}.adv".format(gwtname) + gwt, scheme="upstream", filename=f"{gwtname}.adv" ) # dispersion @@ -296,7 +293,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer @@ -308,15 +305,13 @@ def build_model(idx, dir): ) # sources - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -330,7 +325,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -342,7 +337,7 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -351,7 +346,7 @@ def eval_transport(sim): tdistplot = times[int(len(times) / 5)] conc = cobj.get_data(totim=tdistplot) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # the time equal to 1/5 of perlen. @@ -491,7 +486,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp04.py b/autotest/test_gwt_dsp04.py index 08a9e4304e9..85724e4856d 100644 --- a/autotest/test_gwt_dsp04.py +++ b/autotest/test_gwt_dsp04.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -83,7 +84,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -100,7 +101,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -114,13 +115,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -140,8 +139,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -153,7 +152,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -170,7 +169,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -184,17 +183,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # advection @@ -207,7 +204,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -220,15 +217,13 @@ def build_model(idx, dir): mst = flopy.mf6.ModflowGwtmst(gwt, porosity=0.1) # sources - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -242,7 +237,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -254,14 +249,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check to make sure that the concentrations are symmetric in both the # up-down and left-right directions @@ -313,7 +308,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_dsp05_noadv.py b/autotest/test_gwt_dsp05_noadv.py index 533af9b8b70..a5852b2132e 100644 --- a/autotest/test_gwt_dsp05_noadv.py +++ b/autotest/test_gwt_dsp05_noadv.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -73,7 +74,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -91,7 +92,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -105,13 +106,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # dispersion xt3d_off = not xt3d[idx] @@ -123,7 +122,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -142,8 +141,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -160,14 +159,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # The answer is a linear concentration gradient from 1 to zero x = np.array([1.0, -0.25, -0.75, -1.25, -1.75]) @@ -178,10 +177,7 @@ def eval_transport(sim): m = (c0 - ce) / (x0 - xe) b = c0 - m * x0 cres = m * x + b - msg = ( - "simulated concentrations do not match with known " - "solution. {} {}".format(conc, cres) - ) + msg = f"simulated concentrations do not match with known solution. {conc} {cres}" assert np.allclose(cres, conc.flatten()), msg return @@ -219,7 +215,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_fmi01.py b/autotest/test_gwt_fmi01.py index a021ace95d0..52d4c3680f6 100644 --- a/autotest/test_gwt_fmi01.py +++ b/autotest/test_gwt_fmi01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -19,9 +20,9 @@ msg += " pip install flopy" raise Exception(msg) +from binary_file_writer import uniform_flow_field, write_budget, write_head from framework import testing_framework from simulation import Simulation -from binary_file_writer import write_head, write_budget, uniform_flow_field ex = [ "fmi01a_fc", @@ -77,7 +78,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -95,7 +96,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -109,13 +110,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=10.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=10.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv(gwt) @@ -126,8 +125,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -202,20 +201,20 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. Concentration should not change cres = [[[10, 10, 10]]] cres = np.array(cres) errmsg = "simulated concentrations do not match with known solution.\n" - errmsg += "cres: {}\ncans:{}".format(cres, conc) + errmsg += f"cres: {cres}\ncans:{conc}" assert np.allclose(cres, conc), errmsg return @@ -253,7 +252,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_fmi02.py b/autotest/test_gwt_fmi02.py index 6712911f4db..032d47b309f 100644 --- a/autotest/test_gwt_fmi02.py +++ b/autotest/test_gwt_fmi02.py @@ -1,9 +1,10 @@ # tests to ability to run flow model first followed by transport model import os -import pytest import shutil + import numpy as np +import pytest try: import pymake @@ -119,7 +120,7 @@ def test_fmi(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run tests test_fmi() diff --git a/autotest/test_gwt_henry.py b/autotest/test_gwt_henry.py index d989b663573..6b7eae4478c 100644 --- a/autotest/test_gwt_henry.py +++ b/autotest/test_gwt_henry.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -77,7 +78,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwfname]) @@ -126,7 +127,7 @@ def chd_value(k): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) wellist1 = [] @@ -141,14 +142,14 @@ def chd_value(k): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -170,7 +171,7 @@ def chd_value(k): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -186,13 +187,11 @@ def chd_value(k): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=35.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=35.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # dispersion @@ -202,13 +201,13 @@ def chd_value(k): xt3d_off=True, diffc=diffc, # alh=0., alv=0., ath=0., atv=0., - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer porosity = 0.35 mst = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources @@ -217,14 +216,14 @@ def chd_value(k): ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -238,7 +237,7 @@ def chd_value(k): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -250,14 +249,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 500 and only for the bottom layer. @@ -336,7 +335,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_henry_nr.py b/autotest/test_gwt_henry_nr.py index f6c51d7b2f7..b410def2e20 100644 --- a/autotest/test_gwt_henry_nr.py +++ b/autotest/test_gwt_henry_nr.py @@ -6,9 +6,10 @@ # the effects of tides on the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -132,7 +133,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", no_ptcrecord=True, ) sim.register_ims_package(imsgwf, [gwfname]) @@ -236,14 +237,14 @@ def build_model(idx, dir): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -256,7 +257,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) imsgwt = flopy.mf6.ModflowIms( @@ -271,7 +272,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -333,8 +334,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -350,7 +351,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -358,8 +359,8 @@ def build_model(idx, dir): def get_patch_collection(modelgrid, head, conc, cmap="jet", zorder=None): # create patches for each cell - import matplotlib.patches import matplotlib.collections + import matplotlib.patches xv, yv, zv = modelgrid.xyzvertices botm = modelgrid.botm @@ -463,7 +464,7 @@ def make_plot(sim, headall, concall): if ifig == nplots - 1: ax.set_xlabel("DISTANCE, IN METERS", fontsize=6) ax.set_ylabel("ELEVATION, IN METERS", fontsize=6) - ttl = "TIME = {:.3f} days".format(simtime[itime]) + ttl = f"TIME = {simtime[itime]:.3f} days" ax.set_title(ttl, fontsize=6) ax.text(1.9, 1.025, figtxt[ifig], fontsize=6) @@ -528,10 +529,10 @@ def eval_transport(sim): ] ) - errmsg = "heads not right for cell (0, 0, 20):\n{}\n{}".format(hsim, hans) + errmsg = f"heads not right for cell (0, 0, 20):\n{hsim}\n{hans}" assert np.allclose(hsim, hans, atol=1.0e-3), errmsg - errmsg = "concs not right for cell (0, 0, 20):\n{}\n{}".format(csim, cans) + errmsg = f"concs not right for cell (0, 0, 20):\n{csim}\n{cans}" assert np.allclose(hsim, hans, atol=1.0e-3), errmsg makeplot = False @@ -574,7 +575,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_henry_openclose.py b/autotest/test_gwt_henry_openclose.py index ad772fff42b..596d9e84708 100644 --- a/autotest/test_gwt_henry_openclose.py +++ b/autotest/test_gwt_henry_openclose.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -77,7 +78,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwfname]) @@ -126,7 +127,7 @@ def chd_value(k): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) wellist1 = [] @@ -141,14 +142,14 @@ def chd_value(k): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -170,7 +171,7 @@ def chd_value(k): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -186,13 +187,11 @@ def chd_value(k): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=35.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=35.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # dispersion @@ -202,13 +201,13 @@ def chd_value(k): xt3d_off=True, diffc=diffc, # alh=0., alv=0., ath=0., atv=0., - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer porosity = 0.35 mst = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources @@ -217,14 +216,14 @@ def chd_value(k): ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -238,7 +237,7 @@ def chd_value(k): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) # set all the arrays to be open/close @@ -253,14 +252,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # time step 500 and only for the bottom layer. @@ -339,7 +338,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ims_issue655.py b/autotest/test_gwt_ims_issue655.py index 67c48c05316..07ef7b8bf6c 100644 --- a/autotest/test_gwt_ims_issue655.py +++ b/autotest/test_gwt_ims_issue655.py @@ -7,8 +7,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -107,7 +108,7 @@ def build_model(idx, ws): sim, modelname=gwfname, newtonoptions=newtonoptions, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -124,7 +125,7 @@ def build_model(idx, ws): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -138,13 +139,11 @@ def build_model(idx, ws): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -181,8 +180,8 @@ def build_model(idx, ws): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -194,7 +193,7 @@ def build_model(idx, ws): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -211,7 +210,7 @@ def build_model(idx, ws): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -225,17 +224,15 @@ def build_model(idx, ws): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="upstream", filename="{}.adv".format(gwtname) + gwt, scheme="upstream", filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -244,14 +241,14 @@ def build_model(idx, ws): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -265,7 +262,7 @@ def build_model(idx, ws): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -278,21 +275,21 @@ def eval_transport(sim): gwtname = "gwt_" + name gwfname = "gwf_" + name - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculations times = hobj.get_times() @@ -345,7 +342,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ist01.py b/autotest/test_gwt_ist01.py index 0963175f50d..b9ea2a9ea4e 100644 --- a/autotest/test_gwt_ist01.py +++ b/autotest/test_gwt_ist01.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -98,7 +99,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -149,8 +150,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -174,7 +175,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -188,7 +189,7 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions @@ -201,7 +202,7 @@ def build_model(idx, dir): mst = flopy.mf6.ModflowGwtmst(gwt, porosity=sy[idx]) # immobile storage and transfer - cim_filerecord = "{}.ist.ucn".format(gwtname) + cim_filerecord = f"{gwtname}.ist.ucn" ist = flopy.mf6.ModflowGwtist( gwt, save_flows=True, @@ -218,8 +219,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -233,7 +234,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -247,39 +248,39 @@ def eval_transport(sim): gwfname = "gwf_" + name # head - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # mobile concentration - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # immobile concentration - fpth = os.path.join(sim.simpath, "{}.ist.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ist.ucn") try: cobj = flopy.utils.HeadFile(fpth, precision="double", text="CIM") cim = cobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # budget - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.cbc") try: bobj = flopy.utils.CellBudgetFile(fpth, precision="double") print(bobj.get_unique_record_names()) immrate = bobj.get_data(text="IMMOBILE DOMAIN") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' times = cobj.get_times() for i, t in enumerate(times): @@ -290,7 +291,7 @@ def eval_transport(sim): (cim[i] - conc[i]) * zetaim[sim.idxsim] * saturation * volume ) print(t, conc[i], cim[i], rate_sim, rate_calc) - msg = "Rate: {} /= {} for time {}".format(rate_sim, rate_calc, t) + msg = f"Rate: {rate_sim} /= {rate_calc} for time {t}" assert np.allclose(rate_sim, rate_calc), msg return @@ -328,7 +329,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_lkt01.py b/autotest/test_gwt_lkt01.py index 30de95fa2c5..e3407bbafdb 100644 --- a/autotest/test_gwt_lkt01.py +++ b/autotest/test_gwt_lkt01.py @@ -4,9 +4,10 @@ # leaks into the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -75,7 +76,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -91,7 +92,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -134,7 +135,7 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) nlakeconn = 3 # note: this is the number of connectiosn for a lake, not total number of connections @@ -184,6 +185,7 @@ def build_model(idx, dir): print_stage=True, stage_filerecord="stage", budget_filerecord="lakebud", + budgetcsv_filerecord=f"{gwfname}.lak.bud.csv", nlakes=1, ntables=0, noutlets=1, @@ -199,8 +201,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -212,7 +214,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -229,7 +231,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -246,19 +248,17 @@ def build_model(idx, dir): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 0.30 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -266,7 +266,7 @@ def build_model(idx, dir): # ('WEL-1', 'AUX', 'CONCENTRATION'), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) lktpackagedata = [ @@ -321,8 +321,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -339,15 +339,40 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None +def get_mfsim(testsim): + ws = exdirs[testsim.idxsim] + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) + return sim + + +def eval_csv_information(testsim): + sim = get_mfsim(testsim) + name = ex[testsim.idxsim] + gwfname = "gwf_" + name + gwtname = "gwt_" + name + gwf = sim.get_model(gwfname) + gwt = sim.get_model(gwtname) + + lak_budget = gwf.lak.output.budgetcsv().data + result = lak_budget["PERCENT_DIFFERENCE"] + answer = np.zeros(result.shape) + assert np.allclose(result, answer), f"Lake package does not have zero mass balance error: {result}" + + return + + def eval_results(sim): print("evaluating results...") + # eval csv files + eval_csv_information(sim) + # ensure lake concentrations were saved name = ex[sim.idxsim] gwtname = "gwt_" + name @@ -359,7 +384,7 @@ def eval_results(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") clak = cobj.get_alldata().flatten() answer = np.ones(10) * 100.0 - assert np.allclose(clak, answer), "{} {}".format(clak, answer) + assert np.allclose(clak, answer), f"{clak} {answer}" # load the aquifer concentrations and make sure all values are correct fname = gwtname + ".ucn" @@ -369,52 +394,52 @@ def eval_results(sim): answer = np.array( [4.86242795, 27.24270616, 64.55536421, 27.24270616, 4.86242795] ) - assert np.allclose(caq[-1].flatten(), answer), "{} {}".format( + assert np.allclose( caq[-1].flatten(), answer - ) + ), f"{caq[-1].flatten()} {answer}" # lkt observation results fpth = os.path.join(sim.simpath, gwtname + ".lkt.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' res = tc["LKT1CONC"] answer = np.ones(10) * 100.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1EXTINFLOW"] answer = np.ones(10) * 0.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1RAIN"] answer = np.ones(10) * 2.5 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1ROFF"] answer = np.ones(10) * 2.5 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1EVAP"] answer = np.ones(10) * -5.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1WDRL"] answer = np.ones(10) * -10.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1STOR"] answer = np.ones(10) * 0.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1CONST"] answer = np.ones(10) * 236.3934 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1GWT2"] answer = np.ones(10) * -91.80328 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1GWT4"] answer = np.ones(10) * -32.78689 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1GWT3"] answer = np.ones(10) * -91.80328 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1MYLAKE"] answer = np.ones(10) * -216.3934 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" # uncomment when testing # assert False @@ -451,7 +476,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_lkt02.py b/autotest/test_gwt_lkt02.py index 1b04e050de3..412ebc19ae9 100644 --- a/autotest/test_gwt_lkt02.py +++ b/autotest/test_gwt_lkt02.py @@ -2,9 +2,10 @@ # move solute from one lake to another. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -73,7 +74,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -89,7 +90,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -132,7 +133,7 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # pak_data = [lakeno, strt, nlakeconn, CONC, dense, boundname] @@ -213,8 +214,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -226,7 +227,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -243,7 +244,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -263,18 +264,18 @@ def build_model(idx, dir): ic = flopy.mf6.ModflowGwtic( gwt, strt=[100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - filename="{}.ic".format(gwtname), + filename=f"{gwtname}.ic", ) # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 0.30 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -282,7 +283,7 @@ def build_model(idx, dir): # ('WEL-1', 'AUX', 'CONCENTRATION'), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) lktpackagedata = [ @@ -342,8 +343,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -357,7 +358,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -377,7 +378,7 @@ def eval_results(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") clak = cobj.get_data() answer = np.array([2.20913605e-01, 2.06598617e-03, 1.64112298e-05]) - assert np.allclose(clak, answer), "{} {}".format(clak, answer) + assert np.allclose(clak, answer), f"{clak} {answer}" # load the aquifer concentrations and make sure all values are correct fname = gwtname + ".ucn" @@ -395,14 +396,14 @@ def eval_results(sim): 7.33445279e-08, ] ) - assert np.allclose(caq, answer), "{} {}".format(caq.flatten(), answer) + assert np.allclose(caq, answer), f"{caq.flatten()} {answer}" # lkt observation results fpth = os.path.join(sim.simpath, gwtname + ".lkt.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' res = tc["LKT1CONC"] answer = [ 0.00418347, @@ -417,7 +418,7 @@ def eval_results(sim): 0.2209136, ] answer = np.array(answer) - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1STOR"] answer = [ -0.1988482, @@ -432,7 +433,7 @@ def eval_results(sim): -1.87034, ] answer = np.array(answer) - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1MYLAKE1"] answer = [ 0.1992666, @@ -447,22 +448,22 @@ def eval_results(sim): 1.892431, ] answer = np.array(answer) - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT1FJF"] answer = -tc["LKT2FJF"] - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT3FJF"] answer = -tc["LKT4FJF"] - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT5FJF"] answer = tc["LKT1FJF"] - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT6FJF"] answer = tc["LKT2FJF"] + tc["LKT3FJF"] - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["LKT7FJF"] answer = tc["LKT4FJF"] - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" # load the lake budget file fname = gwtname + ".lkt.bud" @@ -480,9 +481,7 @@ def eval_results(sim): dt = [("node", " + outlets = [(0, 0, -1, "SPECIFIED", 999.0, 999.0, 999.0, 999.0)] + outletperioddata = [(0, "RATE", -0.1)] + + # note: for specifying lake number, use fortran indexing! + lak_obs = { + ("lak_obs.csv"): [ + ("lakestage", "stage", 1), + ("lakevolume", "volume", 1), + ("lak1", "lak", 1, 1), + ("lak2", "lak", 1, 2), + ("lak3", "lak", 1, 3), + ] + } + + lak = flopy.mf6.modflow.ModflowGwflak( + gwf, + save_flows=True, + print_input=True, + print_flows=True, + print_stage=True, + stage_filerecord="stage", + budget_filerecord="lakebud", + budgetcsv_filerecord=f"{gwfname}.lak.bud.csv", + nlakes=1, + ntables=0, + noutlets=1, + packagedata=pak_data, + outlets=outlets, + pname="LAK-1", + connectiondata=con_data, + perioddata=p_data + outletperioddata, + observations=lak_obs, + auxiliary=["CONCENTRATION", "DENSITY"], + ) + + # output control + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], + ) + + # create gwt model + gwtname = "gwt_" + name + gwt = flopy.mf6.MFModel( + sim, + model_type="gwt6", + modelname=gwtname, + model_nam_file=f"{gwtname}.nam", + ) + + if not single_matrix: + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwtname}.ims", + ) + sim.register_ims_package(imsgwt, [gwt.name]) + + dis = flopy.mf6.ModflowGwtdis( + gwt, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + idomain=idomain, + ) + + # initial conditions + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") + + # advection + adv = flopy.mf6.ModflowGwtadv( + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" + ) + + # storage + porosity = 0.30 + sto = flopy.mf6.ModflowGwtmst( + gwt, porosity=porosity, filename=f"{gwtname}.sto" + ) + # sources + sourcerecarray = [ + ("CHD-1", "AUX", "CONCENTRATION"), + # ('WEL-1', 'AUX', 'CONCENTRATION'), + ] + ssm = flopy.mf6.ModflowGwtssm( + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" + ) + + lktpackagedata = [ + (0, 100.0, 99.0, 999.0, "mylake"), + ] + lktperioddata = [ + (0, "STATUS", "ACTIVE"), + (0, "RAINFALL", 25.0), + (0, "EVAPORATION", 0.0), + (0, "RUNOFF", 25.0), + ] + + lkt_obs = { + (gwtname + ".lkt.obs.csv",): [ + ("lkt-1-conc", "CONCENTRATION", 1), + ("lkt-1-extinflow", "EXT-INFLOW", 1), + ("lkt-1-rain", "RAINFALL", 1), + ("lkt-1-roff", "RUNOFF", 1), + ("lkt-1-evap", "EVAPORATION", 1), + ("lkt-1-wdrl", "WITHDRAWAL", 1), + ("lkt-1-stor", "STORAGE", 1), + ("lkt-1-const", "CONSTANT", 1), + ("lkt-1-gwt2", "LKT", 1, 1), + ("lkt-1-gwt4", "LKT", 1, 3), + ("lkt-1-gwt3", "LKT", 1, 2), + ("lkt-1-mylake", "LKT", "MYLAKE"), + ], + } + # append additional obs attributes to obs dictionary + lkt_obs["digits"] = 7 + lkt_obs["print_input"] = True + lkt_obs["filename"] = gwtname + ".lkt.obs" + + lkt = flopy.mf6.modflow.ModflowGwtlkt( + gwt, + boundnames=True, + save_flows=True, + print_input=True, + print_flows=True, + print_concentration=True, + concentration_filerecord=gwtname + ".lkt.bin", + budget_filerecord="gwtlak1.bud", + budgetcsv_filerecord=f"{gwtname}.lkt.bud.csv", + packagedata=lktpackagedata, + lakeperioddata=lktperioddata, + observations=lkt_obs, + flow_package_name="LAK-1", + flow_package_auxiliary_name="CONCENTRATION", + pname="LKT-1", + auxiliary=["aux1", "aux2"], + ) + # output control + oc = flopy.mf6.ModflowGwtoc( + gwt, + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", + concentrationprintrecord=[ + ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("CONCENTRATION", "ALL")], + printrecord=[ + ("CONCENTRATION", "ALL"), + ("BUDGET", "ALL"), + ], + ) + + # GWF GWT exchange + gwfgwt = flopy.mf6.ModflowGwfgwt( + sim, + exgtype="GWF6-GWT6", + exgmnamea=gwfname, + exgmnameb=gwtname, + filename=f"{name}.gwfgwt", + ) + + return sim, None + + +def get_mfsim(testsim): + ws = exdirs[testsim.idxsim] + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) + return sim + + +def eval_csv_information(testsim): + sim = get_mfsim(testsim) + name = ex[testsim.idxsim] + gwfname = "gwf_" + name + gwtname = "gwt_" + name + gwf = sim.get_model(gwfname) + gwt = sim.get_model(gwtname) + + success = True + atol = 0.002 + + # Lake budget checks + lak_budget = gwf.lak.output.budgetcsv().data + result = lak_budget["PERCENT_DIFFERENCE"] + for pd in result: + if abs(pd) > atol: + success = False + print(f"Lake package balance error ({pd}) > tolerance ({atol})") + + # Lake transport budget checks + lkt_budget = gwt.lkt.output.budgetcsv().data + result = lkt_budget["PERCENT_DIFFERENCE"] + for pd in result: + if abs(pd) > atol: + success = False + print( + f"Lake transport package balance error ({pd}) > tolerance ({atol})" + ) + + assert success, f"One or more errors encountered in budget checks" + + return + + +def eval_results(sim): + print("evaluating results...") + + # eval csv files + eval_csv_information(sim) + + # ensure lake concentrations were saved + name = ex[sim.idxsim] + gwtname = "gwt_" + name + fname = gwtname + ".lkt.bin" + fname = os.path.join(sim.simpath, fname) + assert os.path.isfile(fname) + + # load the lake concentrations and make sure all values are 100. + cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") + clak = cobj.get_alldata().flatten() + clak_answer = np.array( + [ + 99.6180852, + 99.23811519, + 98.86008004, + 98.48396992, + 98.10977501, + 97.73748558, + 97.36709191, + 96.99858435, + 96.63195329, + 96.26718919, + ] + ) + assert np.allclose(clak, clak_answer), f"{clak} {clak_answer}" + + # load the aquifer concentrations and make sure all values are correct + fname = gwtname + ".ucn" + fname = os.path.join(sim.simpath, fname) + cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") + caq = cobj.get_alldata() + answer = np.zeros(5) + assert np.allclose( + caq[-1].flatten(), answer + ), f"{caq[-1].flatten()} {answer}" + + # lkt observation results + fpth = os.path.join(sim.simpath, gwtname + ".lkt.obs.csv") + try: + tc = np.genfromtxt(fpth, names=True, delimiter=",") + except: + assert False, f'could not load data from "{fpth}"' + res = tc["LKT1CONC"] + answer = clak_answer + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1EXTINFLOW"] + answer = np.ones(10) * 0.0 + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1RAIN"] + answer = np.ones(10) * 2.5 + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1ROFF"] + answer = np.ones(10) * 2.5 + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1EVAP"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1WDRL"] + answer = clak_answer * -0.1 + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1STOR"] + answer = np.array( + [ + 14.92362, + 14.84762, + 14.77202, + 14.69679, + 14.62196, + 14.5475, + 14.47342, + 14.39972, + 14.32639, + 14.25344, + ] + ) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1CONST"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1GWT2"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1GWT4"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1GWT3"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + res = tc["LKT1MYLAKE"] + answer = np.zeros(10) + assert np.allclose(res, answer), f"{res} {answer}" + + # uncomment when testing + # assert False + + return + + +# - No need to change any code below +@pytest.mark.parametrize( + "idx, dir", + list(enumerate(exdirs)), +) +def test_mf6model(idx, dir): + # initialize testing framework + test = testing_framework() + + # build the model + test.build_mf6_models(build_model, idx, dir) + + # run the test model + test.run_mf6(Simulation(dir, exfunc=eval_results, idxsim=idx)) + + +def main(): + # initialize testing framework + test = testing_framework() + + # run the test model + for idx, dir in enumerate(exdirs): + test.build_mf6_models(build_model, idx, dir) + sim = Simulation(dir, exfunc=eval_results, idxsim=idx) + test.run_mf6(sim) + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run main routine + main() diff --git a/autotest/test_gwt_moc3d01.py b/autotest/test_gwt_moc3d01.py index 6f02490067e..6aa18374340 100644 --- a/autotest/test_gwt_moc3d01.py +++ b/autotest/test_gwt_moc3d01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -88,7 +89,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -105,7 +106,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -119,13 +120,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -164,8 +163,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -177,7 +176,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -194,7 +193,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -208,20 +207,16 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions strt = np.zeros((nlay, nrow, ncol)) strt[0, 0, 0] = 0.0 - ic = flopy.mf6.ModflowGwtic( - gwt, strt=strt, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=strt, filename=f"{gwtname}.ic") # advection - adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="tvd", filename="{}.adv".format(gwtname) - ) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="tvd", filename=f"{gwtname}.adv") # dispersion dsp = flopy.mf6.ModflowGwtdsp( @@ -231,7 +226,7 @@ def build_model(idx, dir): alv=alphal[idx], ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -270,14 +265,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -291,7 +286,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -303,7 +298,7 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -311,7 +306,7 @@ def eval_transport(sim): station = [(0, 0, 0), (0, 40, 0), (0, 110, 0)] tssim = cobj.get_ts(station)[::10] except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' tsresab = [ [5.00000000e-01, 2.83603277e-01, 1.98913375e-16, 4.55149741e-41], @@ -413,7 +408,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_moc3d01_zod.py b/autotest/test_gwt_moc3d01_zod.py index 1378b3b6e6c..30ad34d1b99 100644 --- a/autotest/test_gwt_moc3d01_zod.py +++ b/autotest/test_gwt_moc3d01_zod.py @@ -5,9 +5,10 @@ # where concentrations are zero. import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -93,7 +94,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -110,7 +111,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -124,13 +125,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -169,8 +168,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -182,7 +181,7 @@ def build_model(idx, dir): sim, modelname=gwtname, save_flows=True, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -199,7 +198,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -213,20 +212,16 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions strt = np.zeros((nlay, nrow, ncol)) strt[0, 0, 0] = 0.0 - ic = flopy.mf6.ModflowGwtic( - gwt, strt=strt, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=strt, filename=f"{gwtname}.ic") # advection - adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="tvd", filename="{}.adv".format(gwtname) - ) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="tvd", filename=f"{gwtname}.adv") # dispersion dsp = flopy.mf6.ModflowGwtdsp( @@ -236,7 +231,7 @@ def build_model(idx, dir): alv=alphal, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # storage @@ -271,7 +266,7 @@ def build_model(idx, dir): if ist_package[idx]: ist = flopy.mf6.ModflowGwtist( gwt, - cim_filerecord="{}.ist.ucn".format(gwtname), + cim_filerecord=f"{gwtname}.ist.ucn", sorption=sorption, zero_order_decay=True, cim=0.0, @@ -286,14 +281,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -307,7 +302,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -365,7 +360,7 @@ def make_plot_cd(cobj, fname=None): mec=mec[i], mfc="none", markersize="4", - label="t={} s".format(t), + label=f"t={t} s", ) ax.set_xlabel("Distance (cm)") @@ -384,7 +379,7 @@ def eval_transport(sim): gwtname = "gwt_" + name # get mobile domain concentration object - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -392,10 +387,10 @@ def eval_transport(sim): station = [(0, 0, 0), (0, 40, 0), (0, 110, 0)] tssim = cobj.get_ts(station) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # get mobile domain budget object - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.cbc") bobj = flopy.utils.CellBudgetFile(fpth, precision="double") # Check to make sure decay rates in budget file are correct. If there is @@ -419,13 +414,13 @@ def eval_transport(sim): # print(i, qdecay_budfile[i], conc[i]) # get immobile domain concentration object - fpth = os.path.join(sim.simpath, "{}.ist.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ist.ucn") cimobj = None if os.path.isfile(fpth): try: cimobj = flopy.utils.HeadFile(fpth, precision="double", text="CIM") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' records = bobj.get_data(text="immobile domain") qim_budfile = records[0]["q"] @@ -619,7 +614,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_moc3d02.py b/autotest/test_gwt_moc3d02.py index f9a1fc00296..7b349b471aa 100644 --- a/autotest/test_gwt_moc3d02.py +++ b/autotest/test_gwt_moc3d02.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -80,7 +81,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -97,7 +98,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -111,13 +112,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -161,8 +160,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -174,7 +173,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -191,7 +190,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -205,20 +204,16 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions strt = np.zeros((nlay, nrow, ncol)) strt[0, 0, 0] = 0.0 - ic = flopy.mf6.ModflowGwtic( - gwt, strt=strt, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=strt, filename=f"{gwtname}.ic") # advection - adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="TVD", filename="{}.adv".format(gwtname) - ) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="TVD", filename=f"{gwtname}.adv") # dispersion xt3d_off = not xt3d[idx] @@ -230,7 +225,7 @@ def build_model(idx, dir): alv=alphal, ath1=alphath, ath2=alphatv, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer @@ -239,14 +234,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -260,7 +255,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -272,7 +267,7 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -281,7 +276,7 @@ def eval_transport(sim): t = times[-1] csim = cobj.get_data(totim=t) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' cres = np.array( [ @@ -369,7 +364,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_moc3d03.py b/autotest/test_gwt_moc3d03.py index a3411397f26..866c2d9df1e 100644 --- a/autotest/test_gwt_moc3d03.py +++ b/autotest/test_gwt_moc3d03.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -79,7 +80,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -96,7 +97,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -110,13 +111,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -158,8 +157,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -171,7 +170,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -188,7 +187,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -202,19 +201,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions strt = np.zeros((nlay, nrow, ncol)) - ic = flopy.mf6.ModflowGwtic( - gwt, strt=strt, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=strt, filename=f"{gwtname}.ic") # advection - adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="TVD", filename="{}.adv".format(gwtname) - ) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="TVD", filename=f"{gwtname}.adv") # dispersion dsp = flopy.mf6.ModflowGwtdsp( @@ -224,7 +219,7 @@ def build_model(idx, dir): alv=alphal, ath1=alphath, atv=alphatv, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # mass storage and transfer @@ -233,14 +228,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -254,7 +249,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -266,7 +261,7 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" @@ -275,7 +270,7 @@ def eval_transport(sim): t = times[-1] csim = cobj.get_data(totim=t) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' cres = np.array( [ @@ -351,7 +346,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst01.py b/autotest/test_gwt_mst01.py index 4bbb2ab3d5c..e732c1c1ce7 100644 --- a/autotest/test_gwt_mst01.py +++ b/autotest/test_gwt_mst01.py @@ -1,7 +1,8 @@ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -73,7 +74,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -104,13 +105,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -148,8 +147,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -161,7 +160,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -178,7 +177,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -192,35 +191,33 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=1.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=1.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # mass storage and transfer mst = flopy.mf6.ModflowGwtmst( - gwt, porosity=sy[idx], filename="{}.mst".format(gwtname) + gwt, porosity=sy[idx], filename=f"{gwtname}.mst" ) # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -234,7 +231,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -246,14 +243,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc1 = cobj.get_data(totim=3.0) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # end of stress period 1 cres1 = np.ones((nlay, nrow, ncol), float) @@ -296,7 +293,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst02.py b/autotest/test_gwt_mst02.py index fe933751847..410ec71309d 100644 --- a/autotest/test_gwt_mst02.py +++ b/autotest/test_gwt_mst02.py @@ -3,9 +3,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -109,7 +110,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -126,7 +127,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -140,13 +141,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -162,8 +161,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -187,7 +186,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -201,13 +200,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # mass storage and transfer mst = flopy.mf6.ModflowGwtmst( @@ -225,15 +222,13 @@ def build_model(idx, dir): ) # sources - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.bud".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.bud", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -247,7 +242,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -260,14 +255,14 @@ def eval_transport(sim): name = ex[idx] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) ts = cobj.get_ts([(0, 0, 0), (0, 0, 1)]) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # Check concentrations assert np.allclose(ts, tsanswers[idx]), ( @@ -275,12 +270,12 @@ def eval_transport(sim): ) # Check budget file - fpth = os.path.join(sim.simpath, "{}.bud".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.bud") try: bobj = flopy.utils.CellBudgetFile(fpth, precision="double") ra = bobj.get_data(totim=1.0) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' return @@ -317,7 +312,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst03.py b/autotest/test_gwt_mst03.py index d6857de389f..7a4874e966c 100644 --- a/autotest/test_gwt_mst03.py +++ b/autotest/test_gwt_mst03.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -95,7 +96,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -144,8 +145,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -157,7 +158,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -174,7 +175,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -188,7 +189,7 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions @@ -196,25 +197,25 @@ def build_model(idx, dir): # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # mass storage and transfer mst = flopy.mf6.ModflowGwtmst( - gwt, porosity=sy[idx], filename="{}.mst".format(gwtname) + gwt, porosity=sy[idx], filename=f"{gwtname}.mst" ) # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -228,7 +229,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -241,21 +242,21 @@ def eval_transport(sim): gwtname = "gwt_" + name gwfname = "gwf_" + name - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculations times = hobj.get_times() @@ -308,7 +309,7 @@ def eval_transport(sim): print("concentration sim", conc) print("concentration calc", concentration_calc) canswer = np.array(concentration_calc) - errmsg = "{}\n{}".format(conc, canswer) + errmsg = f"{conc}\n{canswer}" assert np.allclose(conc, canswer, atol=1.0e-8), errmsg return @@ -346,7 +347,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst04_noadv.py b/autotest/test_gwt_mst04_noadv.py index dc09edb1374..d4fc01c690e 100644 --- a/autotest/test_gwt_mst04_noadv.py +++ b/autotest/test_gwt_mst04_noadv.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -104,13 +105,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # mass storage and transfer mst = flopy.mf6.ModflowGwtmst( @@ -120,8 +119,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -138,21 +137,18 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # The answer 1 cres = np.array([10.0]) - msg = ( - "simulated concentrations do not match with known " - "solution. {} {}".format(conc, cres) - ) + msg = f"simulated concentrations do not match with known solution. {conc} {cres}" assert np.allclose(cres, conc.flatten()), msg return @@ -190,7 +186,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst05.py b/autotest/test_gwt_mst05.py index 87b58c91cc1..4999f5a3c89 100644 --- a/autotest/test_gwt_mst05.py +++ b/autotest/test_gwt_mst05.py @@ -5,9 +5,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -17,9 +18,9 @@ msg += " pip install flopy" raise Exception(msg) +from binary_file_writer import uniform_flow_field, write_budget, write_head from framework import testing_framework from simulation import Simulation -from binary_file_writer import write_head, write_budget, uniform_flow_field ex = ["mst05a", "mst05b"] isotherm = ["freundlich", "langmuir"] @@ -77,7 +78,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -95,7 +96,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -251,8 +252,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -269,7 +270,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -284,24 +285,24 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' fpth = os.path.join(sim.simpath, "conc_obs.csv") try: obs = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' cnorm = obs["X008"] / 0.05 cnorm_max = [0.32842034, 0.875391418] - msg = "{} /= {}".format(cnorm_max[sim.idxsim], cnorm.max()) + msg = f"{cnorm_max[sim.idxsim]} /= {cnorm.max()}" assert np.allclose(cnorm_max[sim.idxsim], cnorm.max(), atol=0.001), msg savefig = False @@ -353,7 +354,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mst06_noadv.py b/autotest/test_gwt_mst06_noadv.py index b45cb0258ac..26710b34e9d 100644 --- a/autotest/test_gwt_mst06_noadv.py +++ b/autotest/test_gwt_mst06_noadv.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -73,7 +74,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -91,7 +92,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -105,13 +106,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=8.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=8.0, filename=f"{gwtname}.ic") # mass storage and transfer mst = flopy.mf6.ModflowGwtmst( @@ -130,8 +129,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.bud".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.bud", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -148,14 +147,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_ts((0, 0, 0)) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # The answer # print(conc[:, 1]) @@ -167,11 +166,11 @@ def eval_transport(sim): assert np.allclose(cres, conc[:, 1]), msg # Check budget file - fpth = os.path.join(sim.simpath, "{}.bud".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.bud") try: bobj = flopy.utils.CellBudgetFile(fpth, precision="double") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' decay_list = bobj.get_data(text="DECAY-AQUEOUS") decay_rate = [dr[0] for dr in decay_list] decay_rate_answer = [ @@ -227,7 +226,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mt3dms_p01.py b/autotest/test_gwt_mt3dms_p01.py index 244760be99d..43e8da72055 100644 --- a/autotest/test_gwt_mt3dms_p01.py +++ b/autotest/test_gwt_mt3dms_p01.py @@ -20,10 +20,11 @@ """ import os -import pytest import shutil import sys + import numpy as np +import pytest try: import pymake @@ -261,7 +262,7 @@ def p01mf6( sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -278,7 +279,7 @@ def p01mf6( scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -292,16 +293,14 @@ def p01mf6( top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions strt = np.zeros((nlay, nrow, ncol), dtype=float) h1 = q * Lx strt[0, 0, 0] = h1 - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -326,8 +325,8 @@ def p01mf6( # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -339,7 +338,7 @@ def p01mf6( sim, modelname=gwtname, save_flows=True, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -357,7 +356,7 @@ def p01mf6( scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -371,13 +370,11 @@ def p01mf6( top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection if mixelm == 0: @@ -387,7 +384,7 @@ def p01mf6( else: raise Exception() adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme, filename="{}.adv".format(gwtname) + gwt, scheme=scheme, filename=f"{gwtname}.adv" ) # dispersion @@ -426,9 +423,7 @@ def p01mf6( pname="CNC-1", ) - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") if zeta is not None: ist = flopy.mf6.ModflowGwtist( @@ -442,15 +437,15 @@ def p01mf6( decay_sorbed=decay_rate_sorbed, zetaim=zeta, thetaim=prsity2, - filename="{}.ist".format(gwtname), + filename=f"{gwtname}.ist", pname="IST-1", ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.bud".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.bud", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -464,7 +459,7 @@ def p01mf6( exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) sim.write_simulation() @@ -517,7 +512,7 @@ def test_mt3dmsp01a(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-4), msg # load transport budget @@ -525,12 +520,12 @@ def test_mt3dmsp01a(): # STORAGE-AQUEOUS, DECAY-AQUEOUS, STORAGE-SORBED, # DECAY-SORBED, FLOW-JA-FACE, SOURCE-SINK MIX, CONSTANT CONC gwtname = "gwt_p01" - fname = os.path.join(mf6_ws, "{}.bud".format(gwtname)) + fname = os.path.join(mf6_ws, f"{gwtname}.bud") try: bobj = flopy.utils.CellBudgetFile(fname, precision="double") budra = bobj.get_data(kstpkper=(9, 0), text="DECAY-AQUEOUS")[0] except: - assert False, 'could not load data from "{}"'.format(fname) + assert False, f'could not load data from "{fname}"' # ensure decay aqueous is zero decay_aqueous = bobj.get_data(kstpkper=(9, 0), text="DECAY-AQUEOUS")[0] @@ -543,7 +538,7 @@ def test_mt3dmsp01a(): # ensure storage sorbed is zero storage_sorbed = bobj.get_data(kstpkper=(9, 0), text="STORAGE-SORBED")[0] bobj.file.close() - assert np.allclose(0.0, storage_sorbed), "{}".format(storage_sorbed) + assert np.allclose(0.0, storage_sorbed), f"{storage_sorbed}" if remove_files: shutil.rmtree(mf6_ws) @@ -581,7 +576,7 @@ def test_mt3dmsp01b(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-4), msg if remove_files: shutil.rmtree(mf6_ws) @@ -619,7 +614,7 @@ def test_mt3dmsp01c(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-4), msg if remove_files: shutil.rmtree(mf6_ws) @@ -657,7 +652,7 @@ def test_mt3dmsp01d(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-4), msg if remove_files: shutil.rmtree(mf6_ws) @@ -695,7 +690,7 @@ def test_mt3dmsp01e(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-1), msg if remove_files: shutil.rmtree(mf6_ws) @@ -734,7 +729,7 @@ def test_mt3dmsp01f(): prsity2, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1e-1), msg if remove_files: shutil.rmtree(mf6_ws) @@ -775,7 +770,7 @@ def test_mt3dmsp01g(): zero_order_decay=True, ) - msg = "concentrations not equal {} {}".format(conc_mt3d, conc_mf6) + msg = f"concentrations not equal {conc_mt3d} {conc_mf6}" assert np.allclose(conc_mt3d, conc_mf6, atol=1.0e-4), msg if remove_files: shutil.rmtree(mf6_ws) @@ -784,7 +779,7 @@ def test_mt3dmsp01g(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") test_mt3dmsp01a() test_mt3dmsp01b() test_mt3dmsp01c() diff --git a/autotest/test_gwt_mvt01.py b/autotest/test_gwt_mvt01.py index 8759528637a..eb69289bf9e 100644 --- a/autotest/test_gwt_mvt01.py +++ b/autotest/test_gwt_mvt01.py @@ -5,9 +5,10 @@ # There is no flow between the stream and the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -76,7 +77,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -92,7 +93,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -134,7 +135,7 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # wel files @@ -149,7 +150,7 @@ def build_model(idx, dir): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) nlakeconn = 1 # note: this is the number of connectiosn for a lake, not total number of connections @@ -283,8 +284,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -301,7 +302,7 @@ def build_model(idx, dir): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -314,7 +315,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -331,7 +332,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -351,18 +352,18 @@ def build_model(idx, dir): ic = flopy.mf6.ModflowGwtic( gwt, strt=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - filename="{}.ic".format(gwtname), + filename=f"{gwtname}.ic", ) # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 1.0 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -370,7 +371,7 @@ def build_model(idx, dir): ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # lkt package @@ -421,7 +422,7 @@ def build_model(idx, dir): # sft sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [ @@ -430,8 +431,7 @@ def build_model(idx, dir): sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -472,8 +472,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -487,7 +487,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -513,20 +513,20 @@ def eval_results(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") caq = cobj.get_data().flatten() - assert np.allclose(csft, caq), "{} {}".format(csft, caq) + assert np.allclose(csft, caq), f"{csft} {caq}" # sft observation results fpth = os.path.join(sim.simpath, gwtname + ".sft.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # compare observation concs with binary file concs for i in range(7): - oname = "SFT{}CONC".format(i + 1) - assert np.allclose(tc[oname][-1], csft[i]), "{} {}".format( + oname = f"SFT{i + 1}CONC" + assert np.allclose( tc[oname][-1], csft[i] - ) + ), f"{tc[oname][-1]} {csft[i]}" # load the sft budget file fname = gwtname + ".sft.bud" @@ -550,8 +550,8 @@ def eval_results(sim): ) names = list(bud_lst) d0 = budl.get_budget(names=names)[0] - errmsg = "SFR-1_OUT NOT EQUAL LAK-1_IN\n{}\n{}".format( - d0["SFR-1_OUT"], d0["LAK-1_IN"] + errmsg = ( + f"SFR-1_OUT NOT EQUAL LAK-1_IN\n{d0['SFR-1_OUT']}\n{d0['LAK-1_IN']}" ) assert np.allclose(d0["SFR-1_OUT"], d0["LAK-1_IN"]) @@ -590,7 +590,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mvt02.py b/autotest/test_gwt_mvt02.py index 05e47a5eae2..573f4a098c2 100644 --- a/autotest/test_gwt_mvt02.py +++ b/autotest/test_gwt_mvt02.py @@ -5,9 +5,10 @@ # There is no flow between the stream and the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -78,7 +79,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -94,7 +95,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -230,8 +231,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -247,7 +248,7 @@ def build_model(idx, dir): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -263,7 +264,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -280,7 +281,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -297,32 +298,30 @@ def build_model(idx, dir): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=10.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=10.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 1.0 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # sft sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [ @@ -331,8 +330,7 @@ def build_model(idx, dir): sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -368,7 +366,7 @@ def build_model(idx, dir): ) # mover transport package - fname = "{}.mvt.bud".format(gwtname) + fname = f"{gwtname}.mvt.bud" mvt = flopy.mf6.modflow.ModflowGwtmvt( gwt, print_flows=True, budget_filerecord=fname ) @@ -392,7 +390,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -444,14 +442,14 @@ def eval_results(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # compare observation concs with binary file concs for i in range(7): - oname = "SFT{}CONC".format(i + 1) - assert np.allclose(tc[oname][-1], csft[i]), "{} {}".format( + oname = f"SFT{i + 1}CONC" + assert np.allclose( tc[oname][-1], csft[i] - ) + ), f"{tc[oname][-1]} {csft[i]}" simres = tc["SFT1CONC"] answer = [ @@ -467,7 +465,7 @@ def eval_results(sim): 71.6825866699, ] - assert np.allclose(simres, answer), "{} {}".format(simres, answer) + assert np.allclose(simres, answer), f"{simres} {answer}" # load the mvt budget file fname = gwtname + ".mvt.bud" @@ -523,7 +521,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mvt02fmi.py b/autotest/test_gwt_mvt02fmi.py index 0290416533f..3147d066fa6 100644 --- a/autotest/test_gwt_mvt02fmi.py +++ b/autotest/test_gwt_mvt02fmi.py @@ -6,6 +6,7 @@ import os import shutil + import numpy as np try: @@ -16,9 +17,8 @@ msg += " pip install flopy" raise Exception(msg) -from framework import set_teardown_test - import targets +from framework import set_teardown_test exe_name_mf6 = targets.target_dict["mf6"] exe_name_mf6 = os.path.abspath(exe_name_mf6) @@ -95,7 +95,7 @@ def run_flow_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -259,7 +259,7 @@ def run_flow_model(): sim.write_simulation() success, buff = sim.run_simulation(silent=False) - errmsg = "flow model did not terminate successfully\n{}".format(buff) + errmsg = f"flow model did not terminate successfully\n{buff}" assert success, errmsg return @@ -287,7 +287,7 @@ def run_transport_model(): gwt = flopy.mf6.ModflowGwt( sim, modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) imsgwt = flopy.mf6.ModflowIms( @@ -303,7 +303,7 @@ def run_transport_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) dis = flopy.mf6.ModflowGwtdis( @@ -319,32 +319,30 @@ def run_transport_model(): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=10.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=10.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 1.0 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # sft sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [ @@ -353,8 +351,7 @@ def run_transport_model(): sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -390,7 +387,7 @@ def run_transport_model(): ) # mover transport package - fname = "{}.mvt.bud".format(gwtname) + fname = f"{gwtname}.mvt.bud" mvt = flopy.mf6.modflow.ModflowGwtmvt( gwt, print_flows=True, budget_filerecord=fname ) @@ -418,7 +415,7 @@ def run_transport_model(): sim.write_simulation() success, buff = sim.run_simulation(silent=False) - errmsg = "transport model did not terminate successfully\n{}".format(buff) + errmsg = f"transport model did not terminate successfully\n{buff}" assert success, errmsg print("evaluating results...") @@ -457,14 +454,14 @@ def run_transport_model(): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # compare observation concs with binary file concs for i in range(7): oname = f"SFT{i+1}CONC" - assert np.allclose(tc[oname][-1], csft[i]), "{} {}".format( + assert np.allclose( tc[oname][-1], csft[i] - ) + ), f"{tc[oname][-1]} {csft[i]}" simres = tc["SFT1CONC"] answer = [ @@ -480,7 +477,7 @@ def run_transport_model(): 71.6825866699, ] - assert np.allclose(simres, answer), "{} {}".format(simres, answer) + assert np.allclose(simres, answer), f"{simres} {answer}" # load the mvt budget file mobj = mvt.output.budget() @@ -516,7 +513,7 @@ def test_mvt02fmi(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run tests test_mvt02fmi() diff --git a/autotest/test_gwt_mwt01.py b/autotest/test_gwt_mwt01.py index 26ec8b281f3..971aa819f63 100644 --- a/autotest/test_gwt_mwt01.py +++ b/autotest/test_gwt_mwt01.py @@ -4,9 +4,10 @@ # flows into the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -74,7 +75,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -90,7 +91,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -133,11 +134,11 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" wellbottom = -3.0 wellrecarray = [[0, 0.1, wellbottom, 0.0, "THIEM", 3]] wellconnectionsrecarray = [ @@ -148,7 +149,7 @@ def build_model(idx, dir): wellperiodrecarray = [[0, "rate", -1.0]] maw = flopy.mf6.ModflowGwfmaw( gwf, - filename="{}.maw".format(gwfname), + filename=f"{gwfname}.maw", print_input=True, print_head=True, print_flows=True, @@ -162,8 +163,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -175,7 +176,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -192,7 +193,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -209,19 +210,17 @@ def build_model(idx, dir): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 0.30 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -229,22 +228,46 @@ def build_model(idx, dir): # ('WEL-1', 'AUX', 'CONCENTRATION'), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) - mwt_obs = { - (gwtname + ".mwt.obs.csv",): [ - ("mwt-1-conc", "CONCENTRATION", 1), - ("mwt-1-rate", "RATE", 1), - ], - } + mwt_obs = {} + for obstype in [ + "CONCENTRATION", + "FROM-MVR", + "STORAGE", + "CONSTANT", + "RATE", + "FW-RATE", + "RATE-TO-MVR", + "FW-RATE-TO-MVR", + ]: + fname = f"{gwtname}.mwt.obs.{obstype.lower()}.csv" + ncv = 1 + obs1 = [(f"mwt{i + 1}", obstype, i + 1) for i in range(ncv)] + obs2 = [(f"bmwt{i + 1}", obstype, f"mymwt{i + 1}") for i in range(ncv)] + mwt_obs[fname] = obs1 + obs2 + + obstype = "MWT" + fname = f"{gwtname}.mwt.obs.{obstype.lower()}.csv" + ncv = 1 + nconn = 3 + obs1 = [] + for icv in range(ncv): + for iconn in range(nconn): + obs1.append( + (f"mwt{icv + 1}x{iconn + 1}", obstype, icv + 1, iconn + 1) + ) + obs2 = [(f"bmwt{i + 1}", obstype, f"mymwt{i + 1}") for i in range(ncv)] + mwt_obs[fname] = obs1 + obs2 + # append additional obs attributes to obs dictionary - mwt_obs["digits"] = 7 + mwt_obs["digits"] = 15 mwt_obs["print_input"] = True mwt_obs["filename"] = gwtname + ".mwt.obs" mwtpackagedata = [ - (0, 0.0, 99.0, 999.0, "mywel"), + (0, 0.0, 99.0, 999.0, "mymwt1"), ] mwtperioddata = [ (0, "STATUS", "ACTIVE"), @@ -271,8 +294,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -289,60 +312,98 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None +def check_obs(sim): + print("checking obs...") + name = ex[sim.idxsim] + ws = exdirs[sim.idxsim] + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) + gwfname = "gwf_" + name + gwtname = "gwt_" + name + gwf = sim.get_model(gwfname) + gwt = sim.get_model(gwtname) + + # extract mwt concentrations from binary output file + conc_mwt1 = gwt.mwt.output.concentration().get_alldata().flatten() + + # ensure mwt obs are the same whether specified by + # boundname or by reach + csvfiles = gwt.mwt.obs.output.obs_names + for csvfile in csvfiles: + if ".mwt.csv" in csvfile: + continue + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.mwt.obs.output.obs(f=csvfile).data + success = True + if ".concentration.csv" in csvfile: + print( + "Comparing binary concentrations with observed well concentrations." + ) + is_same = np.allclose(conc_ra[f"BMWT1"], conc_mwt1) + if not is_same: + success = False + print( + "Binary concentrations do not match with observation concentrations for mwt1" + ) + print(conc_ra[f"BMWT1"], conc_mwt1) + # check boundname observations with numeric ID observations + for icv in range(1): + # print(f" Checking reach {imwt + 1}") + is_same = np.allclose( + conc_ra[f"MWT{icv + 1}"], conc_ra[f"BMWT{icv + 1}"] + ) + if not is_same: + success = False + for t, x, y in zip( + conc_ra["totim"], + conc_ra[f"MWT{icv + 1}"], + conc_ra[f"BMWT{icv + 1}"], + ): + print(t, x, y) + + # Sum individual iconn mwt rates and compare with total rate + csvfile = f"{gwtname}.mwt.obs.mwt.csv" + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.mwt.obs.output.obs(f=csvfile).data + ntimes = conc_ra.shape[0] + for imwt in range(1): + connection_sum = np.zeros(ntimes) + for column_name in conc_ra.dtype.names: + if f"MWT{icv + 1}X" in column_name: + connection_sum += conc_ra[column_name] + is_same = np.allclose(connection_sum, conc_ra[f"BMWT{icv + 1}"]) + if not is_same: + success = False + diff = connection_sum - conc_ra[f"BMWT{icv + 1}"] + print( + f"Problem with MWT {icv + 1}; mindiff {diff.min()} and maxdiff {diff.max()}" + ) + + assert success, "One or more MWT obs checks did not pass" + return + + def eval_results(sim): print("evaluating results...") - # ensure lake concentrations were saved + # ensure mwt concentrations were saved name = ex[sim.idxsim] gwtname = "gwt_" + name fname = gwtname + ".mwt.bin" fname = os.path.join(sim.simpath, fname) assert os.path.isfile(fname) - # load and check the well concentrations + # ensure gwt concentrations were saved fname = gwtname + ".ucn" fname = os.path.join(sim.simpath, fname) - cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") - cmwt = cobj.get_alldata().flatten() - print(cmwt) - answer = np.ones(10) * 100.0 - # assert np.allclose(cmwt, answer), '{} {}'.format(cmwt, answer) + assert os.path.isfile(fname) - # load the aquifer concentrations and make sure all values are correct - fname = gwtname + ".ucn" - fname = os.path.join(sim.simpath, fname) - cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") - caq = cobj.get_alldata() - # print(caq) - answer = np.array( - [4.86242795, 27.24270616, 64.55536421, 27.24270616, 4.86242795] - ) - # assert np.allclose(caq[-1].flatten(), answer), '{} {}'.format(caq[-1].flatten(), answer) - - # mwt observation results - fpth = os.path.join(sim.simpath, gwtname + ".mwt.obs.csv") - try: - tc = np.genfromtxt(fpth, names=True, delimiter=",") - except: - assert False, 'could not load data from "{}"'.format(fpth) - - res = tc["MWT1CONC"] - print(res) - answer = np.ones(10) * 100.0 - # assert np.allclose(res, answer), '{} {}'.format(res, answer) - res = tc["MWT1RATE"] - print(res) - answer = np.ones(10) * 0.0 - # assert np.allclose(res, answer), '{} {}'.format(res, answer) - - # uncomment when testing - # assert False + check_obs(sim) return @@ -376,7 +437,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_mwt02.py b/autotest/test_gwt_mwt02.py index 60e3fac2dc9..f91f2a92c6f 100644 --- a/autotest/test_gwt_mwt02.py +++ b/autotest/test_gwt_mwt02.py @@ -2,9 +2,10 @@ # information. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -68,7 +69,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -84,7 +85,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -131,7 +132,7 @@ def build_model(idx, dir): ) # MAW - opth = "{}.maw.obs".format(name) + opth = f"{name}.maw.obs" # [] [] wellbottom = 0.0 wellradius = 0.1 @@ -178,7 +179,7 @@ def build_model(idx, dir): mvr = flopy.mf6.ModflowGwfmvr( gwf, maxmvr=len(perioddata), - budget_filerecord="{}.mvr.bud".format(name), + budget_filerecord=f"{name}.mvr.bud", maxpackages=len(packages), print_flows=True, packages=packages, @@ -188,8 +189,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[ ( @@ -221,7 +222,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -243,7 +244,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -259,13 +260,11 @@ def build_model(idx, dir): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.000, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.000, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # dispersion @@ -276,13 +275,13 @@ def build_model(idx, dir): alh=10.0, ath1=3.0, atv=0.30, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # storage porosity = 0.30 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) mwt_obs = { @@ -372,14 +371,14 @@ def build_model(idx, dir): if not mwton: sourcerecarray.append(("MAW-1", "AUX", "CONCENTRATION")) ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -399,7 +398,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -459,7 +458,7 @@ def eval_results(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") cmwt = cobj.get_data().flatten() answer = np.array([999.98345654, 18.67908708, 15.9497297, 15.94973001]) - assert np.allclose(cmwt, answer), "{} {}".format(cmwt, answer) + assert np.allclose(cmwt, answer), f"{cmwt} {answer}" # make sure concentrations can be loaded fname = gwtname + ".ucn" @@ -472,7 +471,7 @@ def eval_results(sim): try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' res = [ tc["MWT1CONC"][-1], tc["MWT2CONC"][-1], @@ -481,11 +480,11 @@ def eval_results(sim): ] res = np.array(res) answer = np.array([999.98345654, 18.67908708, 15.9497297, 15.94973001]) - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" res = tc["MWT1RATE"] answer = np.ones(res.shape) * 1000.0 - assert np.allclose(res, answer), "{} {}".format(res, answer) + assert np.allclose(res, answer), f"{res} {answer}" # uncomment when testing # assert False @@ -522,7 +521,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_obs01.py b/autotest/test_gwt_obs01.py index ad2b1d64ef5..6dab2574d55 100644 --- a/autotest/test_gwt_obs01.py +++ b/autotest/test_gwt_obs01.py @@ -5,8 +5,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -72,7 +73,7 @@ def build_model(idx, dir): sim, modelname=gwfname, save_flows=True, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) # create iterative model solution and register the gwf model with it @@ -89,7 +90,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -103,13 +104,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -145,8 +144,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -158,7 +157,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -176,7 +175,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -190,17 +189,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme=scheme[idx], filename="{}.adv".format(gwtname) + gwt, scheme=scheme[idx], filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -209,14 +206,14 @@ def build_model(idx, dir): # sources sourcerecarray = [("WEL-1", "AUX", "CONCENTRATION")] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -239,7 +236,7 @@ def build_model(idx, dir): obs_package = flopy.mf6.ModflowUtlobs( gwt, pname="conc_obs", - filename="{}.obs".format(gwtname), + filename=f"{gwtname}.obs", digits=10, print_input=True, continuous=obs_data, @@ -251,7 +248,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -264,21 +261,21 @@ def eval_transport(sim): gwtname = "gwt_" + name # MODFLOW 6 output control concentrations - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_alldata() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # MODFLOW 6 observation package concentrations fpth = os.path.join(sim.simpath, "conc_obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' assert np.allclose( tc["1_1_10"], conc[:, 0, 0, 9] @@ -323,7 +320,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_prudic2004t2.py b/autotest/test_gwt_prudic2004t2.py index 3498772f358..2d1f2d411ee 100644 --- a/autotest/test_gwt_prudic2004t2.py +++ b/autotest/test_gwt_prudic2004t2.py @@ -5,9 +5,10 @@ # through the system. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -42,6 +43,7 @@ def build_model(idx, dir): exe_name="mf6", sim_ws=ws, continue_=False, + memory_print_option="ALL", ) # number of time steps for period 2 are reduced from 12 * 25 to 25 in @@ -73,7 +75,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) nlay = 8 @@ -98,6 +100,7 @@ def build_model(idx, dir): top=top, botm=botm, idomain=idomain, + length_units="feet", ) idomain = dis.idomain.array @@ -127,8 +130,8 @@ def build_model(idx, dir): oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -324,13 +327,16 @@ def build_model(idx, dir): [1, 35.2, nlakecon[1], "lake2"], ] # - outlets = [[0, 0, -1, "MANNING", 44.5, 5.000000, 0.03, 0.2187500e-02]] + outlets = [ + [0, 0, -1, "MANNING", 44.5, 3.36493214532915, 0.03, 0.2187500e-02] + ] lake_on = True if lake_on: lak = flopy.mf6.ModflowGwflak( gwf, time_conversion=86400.000, + length_conversion=3.28081, print_stage=True, print_flows=True, stage_filerecord=gwfname + ".lak.bin", @@ -387,7 +393,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -434,13 +440,50 @@ def build_model(idx, dir): (0, "STATUS", "ACTIVE"), (1, "STATUS", "ACTIVE"), ] - lkt_obs = { - (gwtname + ".lkt.obs.csv",): [ - ("lkt1conc", "CONCENTRATION", 1), - ("lkt2conc", "CONCENTRATION", 2), - ], - } - lkt_obs["digits"] = 7 + + lkt_obs = {} + for obstype in [ + "CONCENTRATION", + "STORAGE", + "CONSTANT", + "FROM-MVR", + "TO-MVR", + "RAINFALL", + "EVAPORATION", + "RUNOFF", + "EXT-INFLOW", + "WITHDRAWAL", + "EXT-OUTFLOW", + ]: + fname = f"{gwtname}.lkt.obs.{obstype.lower()}.csv" + obs1 = [] + ncv = 2 + if obstype == "TO-MVR": + ncv = 1 + obs1 = [(f"lkt{i + 1}", obstype, i + 1) for i in range(ncv)] + obs2 = [ + (f"blkt{i + 1}", obstype, f"mylake{i + 1}") for i in range(ncv) + ] + lkt_obs[fname] = obs1 + obs2 + + # add LKT specific obs + obstype = "LKT" + ncv = 2 + nconn = [67, 32] + fname = f"{gwtname}.lkt.obs.{obstype.lower()}.csv" + obs1 = [ + (f"lkt{1}-{iconn + 1}", obstype, 1, iconn + 1) + for iconn in range(nconn[0]) # lake 1 + ] + [ + (f"lkt{2}-{iconn + 1}", obstype, 2, iconn + 1) + for iconn in range(nconn[1]) # lake 2 + ] + obs2 = [ + (f"blkt{i + 1}", obstype, f"mylake{i + 1}") for i in range(ncv) + ] + lkt_obs[fname] = obs1 + obs2 + + lkt_obs["digits"] = 15 lkt_obs["print_input"] = True lkt_obs["filename"] = gwtname + ".lkt.obs" @@ -464,19 +507,53 @@ def build_model(idx, dir): sftpackagedata = [] for irno in range(sfrpd.shape[0]): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [(0, "STATUS", "ACTIVE"), (0, "CONCENTRATION", 0.0)] - sft_obs = { - (gwtname + ".sft.obs.csv",): [ - ("sft{}conc".format(i + 1), "CONCENTRATION", i + 1) + sft_obs = {} + for obstype in [ + "CONCENTRATION", + "STORAGE", + "CONSTANT", + "FROM-MVR", + "TO-MVR", + "SFT", + "RAINFALL", + "EVAPORATION", + "RUNOFF", + "EXT-INFLOW", + "EXT-OUTFLOW", + ]: + fname = f"{gwtname}.sft.obs.{obstype.lower()}.csv" + obs1 = [ + (f"sft{i + 1}", obstype, i + 1) for i in range(sfrpd.shape[0]) + ] + obs2 = [ + (f"bsft{i + 1}", obstype, f"myreach{i + 1}") for i in range(sfrpd.shape[0]) ] - } + sft_obs[fname] = obs1 + obs2 + + obstype = "FLOW-JA-FACE" + fname = f"{gwtname}.sft.obs.{obstype.lower()}.csv" + obs1 = [] + for id1, reach_connections in enumerate(sfrconnectiondata): + for id2 in reach_connections: + id2 = abs(id2) + if id1 != id2: + obs1.append( + (f"sft{id1 + 1}x{id2 + 1}", obstype, id1 + 1, id2 + 1) + ) + obs2 = [ + (f"bsft{i + 1}", obstype, f"myreach{i + 1}") + for i in range(sfrpd.shape[0]) + ] + sft_obs[fname] = obs1 + obs2 + # append additional obs attributes to obs dictionary - sft_obs["digits"] = 7 + sft_obs["digits"] = 15 sft_obs["print_input"] = True sft_obs["filename"] = gwtname + ".sft.obs" @@ -503,8 +580,8 @@ def build_model(idx, dir): oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -618,6 +695,141 @@ def make_concentration_map(sim): return +def check_obs(sim): + print("checking obs...") + name = ex[sim.idxsim] + ws = exdirs[sim.idxsim] + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) + gwfname = "gwf_" + name + gwtname = "gwt_" + name + gwf = sim.get_model(gwfname) + gwt = sim.get_model(gwtname) + + # ensure SFT obs are the same whether specified by + # boundname or by reach + csvfiles = gwt.sft.obs.output.obs_names + for csvfile in csvfiles: + if ".flow-ja-face.csv" in csvfile: + continue + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.sft.obs.output.obs(f=csvfile).data + # save a couple entries for comparison with lake + if ".to-mvr." in csvfile: + sft6tomvr = conc_ra[f"BSFT6"] + if ".from-mvr." in csvfile: + sft7tomvr = conc_ra[f"BSFT7"] + success = True + for ireach in range(38): + # print(f" Checking reach {ireach + 1}") + is_same = np.allclose( + conc_ra[f"SFT{ireach + 1}"], conc_ra[f"BSFT{ireach + 1}"] + ) + if not is_same: + success = False + for t, x, y in zip( + conc_ra["totim"], + conc_ra[f"SFT{ireach + 1}"], + conc_ra[f"BSFT{ireach + 1}"], + ): + print(t, x, y) + + # process the sft values and make sure the individual connection rates add up to the boundname rate + csvfile = "gwt_prudic2004t2.sft.obs.flow-ja-face.csv" + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.sft.obs.output.obs(f=csvfile).data + ntimes = conc_ra.shape[0] + for ireach in range(38): + connection_sum = np.zeros(ntimes) + for column_name in conc_ra.dtype.names: + if f"SFT{ireach + 1}X" in column_name: + connection_sum += conc_ra[column_name] + is_same = np.allclose(connection_sum, conc_ra[f"BSFT{ireach + 1}"]) + if not is_same: + success = False + diff = connection_sum - conc_ra[f"BSFT{ireach + 1}"] + print( + f"Problem with SFT {ireach + 1}; mindiff {diff.min()} and maxdiff {diff.max()}" + ) + # for itime, (cs, bsft) in enumerate(zip(connection_sum, conc_ra[f"BSFT{ireach + 1}"])): + # print(itime, cs, bsft) + + assert success, "One or more SFT obs checks did not pass" + + # ensure LKT obs are the same whether specified by + # boundname or by reach + csvfiles = gwt.lkt.obs.output.obs_names + for csvfile in csvfiles: + if ".lkt.csv" in csvfile: + continue + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.lkt.obs.output.obs(f=csvfile).data + if ".from-mvr." in csvfile: + lkt1frommvr = conc_ra[f"BLKT1"] + if ".to-mvr." in csvfile: + lkt1tomvr = conc_ra[f"BLKT1"] + success = True + if ".to-mvr." in csvfile: + numvalues = 1 # outlet + else: + numvalues = 2 # lakes + for ilake in range(numvalues): + # print(f" Checking lake {ilake + 1}") + is_same = np.allclose( + conc_ra[f"LKT{ilake + 1}"], conc_ra[f"BLKT{ilake + 1}"] + ) + if not is_same: + success = False + for t, x, y in zip( + conc_ra["totim"], + conc_ra[f"LKT{ilake + 1}"], + conc_ra[f"BLKT{ilake + 1}"], + ): + print(t, x, y) + + # process the lkt values and make sure the individual connection rates add up to the boundname rate + csvfile = "gwt_prudic2004t2.lkt.obs.lkt.csv" + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.lkt.obs.output.obs(f=csvfile).data + ntimes = conc_ra.shape[0] + for ilake in [0, 1]: + connection_sum = np.zeros(ntimes) + for column_name in conc_ra.dtype.names: + if f"LKT{ilake + 1}" in column_name and column_name.startswith( + "LKT" + ): + connection_sum += conc_ra[column_name] + is_same = np.allclose(connection_sum, conc_ra[f"BLKT{ilake + 1}"]) + if not is_same: + success = False + print(f"Problem with Lake {ilake + 1}") + for itime, (cs, blkt) in enumerate( + zip(connection_sum, conc_ra[f"BLKT1"]) + ): + print(itime, cs, blkt) + + assert success, "One or more LKT obs checks did not pass" + + # check that SFT6 to-mvr is equal to LKT1 from-mvr + success = True + is_same = np.allclose(-sft6tomvr, lkt1frommvr, atol=0.1) + if not is_same: + success = False + print(f"Problem with sft6tomvr comparison to lkt1frommvr") + for itime, (a, b) in enumerate(zip(-sft6tomvr, lkt1frommvr)): + print(itime, a, b) + + is_same = np.allclose(-lkt1tomvr, sft7tomvr) + if not is_same: + success = False + print(f"Problem with lkt1tomvr comparison to sft7tomvr") + for itime, (a, b) in enumerate(zip(-lkt1tomvr, sft7tomvr)): + print(itime, a, b) + + assert success, "One or more SFT-LKT obs checks did not pass" + + return + + def eval_results(sim): print("evaluating results...") @@ -635,6 +847,8 @@ def eval_results(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name + check_obs(sim) + fname = gwtname + ".lkt.bin" fname = os.path.join(ws, fname) bobj = flopy.utils.HeadFile( @@ -688,7 +902,7 @@ def eval_results(sim): ] ans_lak1 = np.array(ans_lak1) d = res_lak1 - ans_lak1 - msg = "{} {} {}".format(res_lak1, ans_lak1, d) + msg = f"{res_lak1} {ans_lak1} {d}" assert np.allclose(res_lak1, ans_lak1, atol=atol), msg res_sfr3 = sfaconc[:, 30] @@ -722,7 +936,7 @@ def eval_results(sim): ] ans_sfr3 = np.array(ans_sfr3) d = res_sfr3 - ans_sfr3 - msg = "{} {} {}".format(res_sfr3, ans_sfr3, d) + msg = f"{res_sfr3} {ans_sfr3} {d}" assert np.allclose(res_sfr3, ans_sfr3, atol=atol), msg res_sfr4 = sfaconc[:, 37] @@ -756,7 +970,7 @@ def eval_results(sim): ] ans_sfr4 = np.array(ans_sfr4) d = res_sfr4 - ans_sfr4 - msg = "{} {} {}".format(res_sfr4, ans_sfr4, d) + msg = f"{res_sfr4} {ans_sfr4} {d}" assert np.allclose(res_sfr4, ans_sfr4, atol=atol), msg # used to make results for the gwtgwt version of this problem @@ -802,7 +1016,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_prudic2004t2fmi.py b/autotest/test_gwt_prudic2004t2fmi.py index 09502a6e1ef..00551a1d3a6 100644 --- a/autotest/test_gwt_prudic2004t2fmi.py +++ b/autotest/test_gwt_prudic2004t2fmi.py @@ -1,9 +1,10 @@ # tests to ability to run flow model first followed by transport model import os -import pytest import shutil + import numpy as np +import pytest try: import pymake @@ -22,9 +23,8 @@ raise Exception(msg) -from framework import set_teardown_test - import targets +from framework import set_teardown_test exe_name_mf6 = targets.target_dict["mf6"] exe_name_mf6 = os.path.abspath(exe_name_mf6) @@ -85,7 +85,7 @@ def run_flow_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -128,8 +128,8 @@ def run_flow_model(): oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -354,13 +354,16 @@ def run_flow_model(): [1, 35.2, nlakecon[1], "lake2"], ] # - outlets = [[0, 0, -1, "MANNING", 44.5, 5.000000, 0.03, 0.2187500e-02]] + outlets = [ + [0, 0, -1, "MANNING", 44.5, 3.36493214532915, 0.03, 0.2187500e-02] + ] lake_on = True if lake_on: lak = flopy.mf6.ModflowGwflak( gwf, time_conversion=86400.000, + length_conversion=3.28081, print_stage=True, print_flows=True, stage_filerecord=gwfname + ".lak.bin", @@ -498,7 +501,7 @@ def run_transport_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -512,6 +515,7 @@ def run_transport_model(): top=top, botm=botm, idomain=idomain, + length_units="feet", ) ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0) sto = flopy.mf6.ModflowGwtmst(gwt, porosity=0.3) @@ -580,15 +584,14 @@ def run_transport_model(): nreach = 38 sftpackagedata = [] for irno in range(nreach): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [(0, "STATUS", "ACTIVE"), (0, "CONCENTRATION", 0.0)] sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft{}conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(nreach) + (f"sft{i + 1}conc", "CONCENTRATION", i + 1) for i in range(nreach) ] } # append additional obs attributes to obs dictionary @@ -628,9 +631,9 @@ def run_transport_model(): oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - budgetcsv_filerecord="{}.bud.csv".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + budgetcsv_filerecord=f"{gwtname}.bud.csv", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -694,7 +697,7 @@ def run_transport_model(): ] ans_lak1 = np.array(ans_lak1) d = res_lak1 - ans_lak1 - msg = "{}\n{}\n{}".format(res_lak1, ans_lak1, d) + msg = f"{res_lak1}\n{ans_lak1}\n{d}" assert np.allclose(res_lak1, ans_lak1, atol=atol), msg res_sfr3 = sfaconc[:, 30] @@ -728,7 +731,7 @@ def run_transport_model(): ] ans_sfr3 = np.array(ans_sfr3) d = res_sfr3 - ans_sfr3 - msg = "{}\n{}\n{}".format(res_sfr3, ans_sfr3, d) + msg = f"{res_sfr3}\n{ans_sfr3}\n{d}" assert np.allclose(res_sfr3, ans_sfr3, atol=atol), msg res_sfr4 = sfaconc[:, 37] @@ -762,7 +765,7 @@ def run_transport_model(): ] ans_sfr4 = np.array(ans_sfr4) d = res_sfr4 - ans_sfr4 - msg = "{}\n{}\n{}".format(res_sfr4, ans_sfr4, d) + msg = f"{res_sfr4}\n{ans_sfr4}\n{d}" assert np.allclose(res_sfr4, ans_sfr4, atol=atol), msg # make some checks on lake obs csv file @@ -771,20 +774,18 @@ def run_transport_model(): try: tc = np.genfromtxt(fname, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fname) - errmsg = "to-mvr boundname and outlet number do not match for {}".format( - fname - ) + assert False, f'could not load data from "{fname}"' + errmsg = f"to-mvr boundname and outlet number do not match for {fname}" assert np.allclose(tc["LKT1TOMVR"], tc["LKT1BNTOMVR"]), errmsg # Compare the budget terms from the list file and the budgetcsvfile - fname = "{}.bud.csv".format(gwtname) + fname = f"{gwtname}.bud.csv" fname = os.path.join(wst, fname) csvra = np.genfromtxt( fname, dtype=None, names=True, delimiter=",", deletechars="" ) - fname = "{}.lst".format(gwtname) + fname = f"{gwtname}.lst" fname = os.path.join(wst, fname) lst = flopy.utils.Mf6ListBudget( fname, budgetkey="MASS BUDGET FOR ENTIRE MODEL" @@ -826,7 +827,7 @@ def test_prudic2004t2fmi(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run tests test_prudic2004t2fmi() diff --git a/autotest/test_gwt_prudic2004t2fmiats.py b/autotest/test_gwt_prudic2004t2fmiats.py index fad8f3b52f7..68b1651eec9 100644 --- a/autotest/test_gwt_prudic2004t2fmiats.py +++ b/autotest/test_gwt_prudic2004t2fmiats.py @@ -5,9 +5,10 @@ # failure occurs. import os -import pytest import shutil + import numpy as np +import pytest try: import pymake @@ -26,9 +27,8 @@ raise Exception(msg) -from framework import set_teardown_test - import targets +from framework import set_teardown_test exe_name_mf6 = targets.target_dict["mf6"] exe_name_mf6 = os.path.abspath(exe_name_mf6) @@ -89,7 +89,7 @@ def run_flow_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -102,6 +102,7 @@ def run_flow_model(): top=top, botm=botm, idomain=idomain, + length_units="feet", ) idomain = dis.idomain.array @@ -132,8 +133,8 @@ def run_flow_model(): oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -358,13 +359,16 @@ def run_flow_model(): [1, 35.2, nlakecon[1], "lake2"], ] # - outlets = [[0, 0, -1, "MANNING", 44.5, 5.000000, 0.03, 0.2187500e-02]] + outlets = [ + [0, 0, -1, "MANNING", 44.5, 3.36493214532915, 0.03, 0.2187500e-02] + ] lake_on = True if lake_on: lak = flopy.mf6.ModflowGwflak( gwf, time_conversion=86400.000, + length_conversion=3.28081, print_stage=True, print_flows=True, stage_filerecord=gwfname + ".lak.bin", @@ -465,30 +469,30 @@ def run_transport_model(): continue_=False, ) - ats_filerecord = None + tdis_rc = [(1.0, 1, 1.0), (365.25 * 25, 25, 1.0)] + nper = len(tdis_rc) + tdis = flopy.mf6.ModflowTdis( + sim, + time_units="DAYS", + nper=nper, + perioddata=tdis_rc, + ) + if True: dt0 = 100 dtmin = 1.0e-5 dtmax = 10000.0 dtadj = 2.0 dtfailadj = 5.0 + ats_filerecord = name + ".ats" atsperiod = [ (1, dt0, dtmin, dtmax, dtadj, dtfailadj), ] - ats = flopy.mf6.ModflowUtlats( - sim, maxats=len(atsperiod), perioddata=atsperiod + tdis.ats.initialize( + maxats=len(atsperiod), + perioddata=atsperiod, + filename=ats_filerecord, ) - ats_filerecord = name + ".ats" - - tdis_rc = [(1.0, 1, 1.0), (365.25 * 25, 25, 1.0)] - nper = len(tdis_rc) - tdis = flopy.mf6.ModflowTdis( - sim, - time_units="DAYS", - nper=nper, - perioddata=tdis_rc, - ats_filerecord=ats_filerecord, - ) gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) @@ -512,7 +516,7 @@ def run_transport_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -594,15 +598,14 @@ def run_transport_model(): nreach = 38 sftpackagedata = [] for irno in range(nreach): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [(0, "STATUS", "ACTIVE"), (0, "CONCENTRATION", 0.0)] sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft{}conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(nreach) + (f"sft{i + 1}conc", "CONCENTRATION", i + 1) for i in range(nreach) ] } # append additional obs attributes to obs dictionary @@ -642,8 +645,8 @@ def run_transport_model(): oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -751,7 +754,7 @@ def run_transport_model(): ] ans_lak1 = np.array(ans_lak1) d = res_lak1 - ans_lak1 - msg = "{}\n{}\n{}".format(res_lak1, ans_lak1, d) + msg = f"{res_lak1}\n{ans_lak1}\n{d}" assert np.allclose(res_lak1, ans_lak1, atol=atol), msg res_sfr3 = sfaconc[:, 30] @@ -790,7 +793,7 @@ def run_transport_model(): ] ans_sfr3 = np.array(ans_sfr3) d = res_sfr3 - ans_sfr3 - msg = "{}\n{}\n{}".format(res_sfr3, ans_sfr3, d) + msg = f"{res_sfr3}\n{ans_sfr3}\n{d}" assert np.allclose(res_sfr3, ans_sfr3, atol=atol), msg res_sfr4 = sfaconc[:, 37] @@ -829,7 +832,7 @@ def run_transport_model(): ] ans_sfr4 = np.array(ans_sfr4) d = res_sfr4 - ans_sfr4 - msg = "{}\n{}\n{}".format(res_sfr4, ans_sfr4, d) + msg = f"{res_sfr4}\n{ans_sfr4}\n{d}" assert np.allclose(res_sfr4, ans_sfr4, atol=atol), msg # make some checks on lake obs csv file @@ -838,10 +841,8 @@ def run_transport_model(): try: tc = np.genfromtxt(fname, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fname) - errmsg = "to-mvr boundname and outlet number do not match for {}".format( - fname - ) + assert False, f'could not load data from "{fname}"' + errmsg = f"to-mvr boundname and outlet number do not match for {fname}" assert np.allclose(tc["LKT1TOMVR"], tc["LKT1BNTOMVR"]), errmsg # check simulation list file for ats information @@ -863,7 +864,7 @@ def run_transport_model(): ] all_found = True for stxt in txtlist: - msg = "Checking for string in mfsim.lst: {}".format(stxt) + msg = f"Checking for string in mfsim.lst: {stxt}" found = False for line in lines: if stxt in line: @@ -872,7 +873,7 @@ def run_transport_model(): if not found: msg += " -- NOT FOUND!" all_found = False - print("text not found in mfsim.lst: {}".format(stxt)) + print(f"text not found in mfsim.lst: {stxt}") print(msg) assert ( all_found @@ -894,7 +895,7 @@ def test_prudic2004t2fmiats(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run tests test_prudic2004t2fmiats() diff --git a/autotest/test_gwt_prudic2004t2gwtgwt.py b/autotest/test_gwt_prudic2004t2gwtgwt.py index 63d139f91ac..022a9ddc17d 100644 --- a/autotest/test_gwt_prudic2004t2gwtgwt.py +++ b/autotest/test_gwt_prudic2004t2gwtgwt.py @@ -5,9 +5,10 @@ # through the system. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -195,9 +196,6 @@ def build_model(idx, ws): gwfgwf_data.append(connection) # GWF-GWF - mvr_filerecord = None - if across_model_mvr_on: - mvr_filerecord = f"{name}.gwfgwf.mvr" gwfgwf = flopy.mf6.ModflowGwfgwf( sim, exgtype="GWF6-GWF6", @@ -206,7 +204,6 @@ def build_model(idx, ws): exgmnameb=gwfnames[1], # south exchangedata=gwfgwf_data, auxiliary=["ANGLDEGX", "CDIST"], - mvr_filerecord=mvr_filerecord, dev_interfacemodel_on=False, ) @@ -215,21 +212,18 @@ def build_model(idx, ws): maxmvr, maxpackages = 1, 2 mvrpack_sim = [["flow1", "lak-1"], ["flow2", "sfr-2"]] mvrspd = [["flow1", "lak-1", 0, "flow2", "sfr-2", 0, "FACTOR", 1.00]] - mvr = flopy.mf6.ModflowMvr( - sim, + mvr_filerecord = f"{name}.gwfgwf.mvr" + gwfgwf.mvr.initialize( modelnames=True, maxmvr=maxmvr, print_flows=True, maxpackages=maxpackages, packages=mvrpack_sim, perioddata=mvrspd, - filename=f"{name}.gwfgwf.mvr", + filename=mvr_filerecord, ) # GWT-GWT - mvt_filerecord = None - if across_model_mvt_on: - mvt_filerecord = f"{name}.gwtgwt.mvt" gwtgwt = flopy.mf6.ModflowGwtgwt( sim, exgtype="GWT6-GWT6", @@ -240,15 +234,13 @@ def build_model(idx, ws): gwfmodelname2=gwfnames[1], exchangedata=gwfgwf_data, auxiliary=["ANGLDEGX", "CDIST"], - mvt_filerecord=mvt_filerecord, # dev_interfacemodel_on=False, ) # simulation GWT-GWT Mover if across_model_mvt_on: - mvt = flopy.mf6.modflow.ModflowGwtmvt( - sim, filename=f"{name}.gwtgwt.mvt" - ) + mvt_filerecord = f"{name}.gwtgwt.mvt" + gwtgwt.mvt.initialize(filename=f"{name}.gwtgwt.mvt") regression = None return sim, regression @@ -342,8 +334,8 @@ def build_gwfgwt_combo( oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -512,7 +504,9 @@ def build_gwfgwt_combo( if icombo == 1: lakpackagedata = [[0, 44.0, nlakecon[0], "lake1"]] # - outlets = [[0, 0, -1, "MANNING", 44.5, 5.000000, 0.03, 0.2187500e-02]] + outlets = [ + [0, 0, -1, "MANNING", 44.5, 3.36493214532915, 0.03, 0.2187500e-02] + ] noutlets = 1 elif icombo == 2: lakpackagedata = [[0, 35.2, nlakecon[0], "lake2"]] @@ -527,6 +521,7 @@ def build_gwfgwt_combo( lak = flopy.mf6.ModflowGwflak( gwf, time_conversion=86400.000, + length_conversion=3.28081, print_stage=True, print_flows=True, stage_filerecord=gwfname + ".lak.bin", @@ -667,7 +662,7 @@ def build_gwfgwt_combo( nreaches = sfrpack.nreaches.get_data() sftpackagedata = [] for irno in range(nreaches): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sft_obs = { @@ -705,8 +700,8 @@ def build_gwfgwt_combo( oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -960,21 +955,21 @@ def eval_results(sim): res_lak1 = lkaconc[:, 0] d = res_lak1 - ans_lak1 print(f"lak1 max diff {d.max()}; min diff {d.min()}") - msg = "{} {} {}".format(res_lak1, ans_lak1, d) + msg = f"{res_lak1} {ans_lak1} {d}" assert np.allclose(res_lak1, ans_lak1, atol=atol), msg if sft3outflowconc is not None: res_sfr3 = sft3outflowconc d = res_sfr3 - ans_sfr3 print(f"sfr3 max diff {d.max()}; min diff {d.min()}") - msg = "{} {} {}".format(res_sfr3, ans_sfr3, d) + msg = f"{res_sfr3} {ans_sfr3} {d}" assert np.allclose(res_sfr3, ans_sfr3, atol=atol), msg if sft4outflowconc is not None: res_sfr4 = sft4outflowconc d = res_sfr4 - ans_sfr4 print(f"sfr4 max diff {d.max()}; min diff {d.min()}") - msg = "{} {} {}".format(res_sfr4, ans_sfr4, d) + msg = f"{res_sfr4} {ans_sfr4} {d}" assert np.allclose(res_sfr4, ans_sfr4, atol=atol), msg # uncomment when testing @@ -1012,7 +1007,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_sft01.py b/autotest/test_gwt_sft01.py index 063bf3672da..81e75c0bd65 100644 --- a/autotest/test_gwt_sft01.py +++ b/autotest/test_gwt_sft01.py @@ -6,9 +6,10 @@ # There is no flow between the stream and the aquifer. import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -76,7 +77,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) imsgwf = flopy.mf6.ModflowIms( @@ -92,7 +93,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) idomain = np.full((nlay, nrow, ncol), 1) @@ -134,7 +135,7 @@ def build_model(idx, dir): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # wel files @@ -149,7 +150,7 @@ def build_model(idx, dir): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # pak_data = [ [] []] @@ -224,8 +225,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -237,7 +238,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) if not single_matrix: @@ -254,7 +255,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -274,18 +275,18 @@ def build_model(idx, dir): ic = flopy.mf6.ModflowGwtic( gwt, strt=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - filename="{}.ic".format(gwtname), + filename=f"{gwtname}.ic", ) # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = 1.0 sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -293,7 +294,7 @@ def build_model(idx, dir): ("WEL-1", "AUX", "CONCENTRATION"), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) # cnc files @@ -310,15 +311,14 @@ def build_model(idx, dir): sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = [(0, "STATUS", "CONSTANT"), (0, "CONCENTRATION", 100.0)] sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -356,8 +356,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -371,7 +371,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -397,20 +397,20 @@ def eval_results(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") caq = cobj.get_data().flatten() - assert np.allclose(csft, caq), "{} {}".format(csft, caq) + assert np.allclose(csft, caq), f"{csft} {caq}" # sft observation results fpth = os.path.join(sim.simpath, gwtname + ".sft.obs.csv") try: tc = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # compare observation concs with binary file concs for i in range(7): - oname = "SFT{}CONC".format(i + 1) - assert np.allclose(tc[oname][-1], csft[i]), "{} {}".format( + oname = f"SFT{i + 1}CONC" + assert np.allclose( tc[oname][-1], csft[i] - ) + ), f"{tc[oname][-1]} {csft[i]}" # load the sft budget file fname = gwtname + ".sft.bud" @@ -430,7 +430,7 @@ def eval_results(sim): res = bobj.get_data(text="constant")[-1] qs = res["q"] qa = np.array([100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - msg = "{} /= {}".format(qs, qa) + msg = f"{qs} /= {qa}" assert np.allclose(qs, qa), msg # uncomment when testing @@ -468,7 +468,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_sft01gwtgwt.py b/autotest/test_gwt_sft01gwtgwt.py index 47b9049c89c..005374a5934 100644 --- a/autotest/test_gwt_sft01gwtgwt.py +++ b/autotest/test_gwt_sft01gwtgwt.py @@ -17,9 +17,10 @@ import os -import pytest import sys + import numpy as np +import pytest try: import flopy @@ -274,7 +275,7 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): save_flows=False, pname="CHD-1", auxiliary="CONCENTRATION", - filename="{}.chd".format(gwfname), + filename=f"{gwfname}.chd", ) # wel files @@ -291,7 +292,7 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): save_flows=False, pname="WEL-1", auxiliary="CONCENTRATION", - filename="{}.wel".format(gwfname), + filename=f"{gwfname}.wel", ) # pak_data = [ [] []] @@ -369,8 +370,8 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -423,7 +424,7 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): sftpackagedata = [] for irno in range(ncol): - t = (irno, 0.0, 99.0, 999.0, "myreach{}".format(irno + 1)) + t = (irno, 0.0, 99.0, 999.0, f"myreach{irno + 1}") sftpackagedata.append(t) sftperioddata = None @@ -435,8 +436,7 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): sft_obs = { (gwtname + ".sft.obs.csv",): [ - ("sft-{}-conc".format(i + 1), "CONCENTRATION", i + 1) - for i in range(7) + (f"sft-{i + 1}-conc", "CONCENTRATION", i + 1) for i in range(7) ] + [ ("sft-1-extinflow", "EXT-INFLOW", 1), @@ -474,8 +474,8 @@ def build_gwfgwt_combo(sim, gwfname, gwtname, icombo): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -558,7 +558,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_src01.py b/autotest/test_gwt_src01.py index 29fe6ced287..4121f4fb4dc 100644 --- a/autotest/test_gwt_src01.py +++ b/autotest/test_gwt_src01.py @@ -7,9 +7,10 @@ """ import os -import pytest import sys + import numpy as np +import pytest try: import pymake @@ -84,7 +85,7 @@ def build_model(idx, dir): sim, model_type="gwf6", modelname=gwfname, - model_nam_file="{}.nam".format(gwfname), + model_nam_file=f"{gwfname}.nam", ) gwf.name_file.save_flows = True @@ -102,7 +103,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -116,13 +117,11 @@ def build_model(idx, dir): top=top, botm=botm, idomain=np.ones((nlay, nrow, ncol), dtype=int), - filename="{}.dis".format(gwfname), + filename=f"{gwfname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwfic( - gwf, strt=strt, filename="{}.ic".format(gwfname) - ) + ic = flopy.mf6.ModflowGwfic(gwf, strt=strt, filename=f"{gwfname}.ic") # node property flow npf = flopy.mf6.ModflowGwfnpf( @@ -141,8 +140,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -154,7 +153,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -172,7 +171,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -186,17 +185,15 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # dispersion @@ -209,7 +206,7 @@ def build_model(idx, dir): alv=0.0, ath1=0.0, atv=0.0, - filename="{}.dsp".format(gwtname), + filename=f"{gwtname}.dsp", ) # constant concentration @@ -236,15 +233,13 @@ def build_model(idx, dir): mst = flopy.mf6.ModflowGwtmst(gwt, porosity=0.1) # sources - ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=[[]], filename="{}.ssm".format(gwtname) - ) + ssm = flopy.mf6.ModflowGwtssm(gwt, sources=[[]], filename=f"{gwtname}.ssm") # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -258,7 +253,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -270,14 +265,14 @@ def eval_transport(sim): name = ex[sim.idxsim] gwtname = "gwt_" + name - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # This is the answer to this problem. These concentrations are for # steady state and calculated from F = D * (c1 - c2) / L @@ -321,7 +316,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ssm01fmi.py b/autotest/test_gwt_ssm01fmi.py index e96694b6322..7c3c83aa145 100644 --- a/autotest/test_gwt_ssm01fmi.py +++ b/autotest/test_gwt_ssm01fmi.py @@ -4,9 +4,10 @@ # be 100. import os -import pytest import shutil + import numpy as np +import pytest try: import pymake @@ -80,7 +81,7 @@ def run_flow_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) dis = flopy.mf6.ModflowGwfdis( @@ -120,8 +121,8 @@ def run_flow_model(): oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[ ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -151,13 +152,13 @@ def run_flow_model(): for ipak, i in enumerate(rows): blist = [] blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) - fname = "flow.{}.ghb".format(ipak + 1) + fname = f"flow.{ipak + 1}.ghb" ghb = flopy.mf6.ModflowGwfghb( gwf, stress_period_data=blist, auxiliary=["concentration"], filename=fname, - pname="GHB-{}".format(ipak + 1), + pname=f"GHB-{ipak + 1}", ) # riv @@ -165,13 +166,13 @@ def run_flow_model(): for ipak, i in enumerate(rows): blist = [] blist.append(((0, i, ncol - 1), 50.0, 1000.0, 0.0, 100.0)) - fname = "flow.{}.riv".format(ipak + 1) + fname = f"flow.{ipak + 1}.riv" riv = flopy.mf6.ModflowGwfriv( gwf, stress_period_data=blist, auxiliary=["concentration"], filename=fname, - pname="RIV-{}".format(ipak + 1), + pname=f"RIV-{ipak + 1}", ) # drn @@ -179,18 +180,18 @@ def run_flow_model(): for ipak, i in enumerate(rows): blist = [] blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) - fname = "flow.{}.drn".format(ipak + 1) + fname = f"flow.{ipak + 1}.drn" drn = flopy.mf6.ModflowGwfdrn( gwf, stress_period_data=blist, auxiliary=["concentration"], filename=fname, - pname="DRN-{}".format(ipak + 1), + pname=f"DRN-{ipak + 1}", ) sim.write_simulation() success, buff = sim.run_simulation(silent=False) - errmsg = "flow model did not terminate successfully\n{}".format(buff) + errmsg = f"flow model did not terminate successfully\n{buff}" assert success, errmsg return @@ -235,7 +236,7 @@ def run_transport_model(): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -303,7 +304,7 @@ def run_transport_model(): sim.write_simulation() success, buff = sim.run_simulation(silent=False) - errmsg = "transport model did not terminate successfully\n{}".format(buff) + errmsg = f"transport model did not terminate successfully\n{buff}" assert success, errmsg # ensure budget table can be parsed @@ -325,7 +326,7 @@ def run_transport_model(): a1 = d0["WEL(SSM_WEL-1)_IN"] / 10.0 a2 = d0[name] print(f"Checking budet term {name} against WEL-1_IN / 10.") - errmsg = "{} not equal WEL-1_IN / 10.\n{}\n{}".format(name, a1, a2) + errmsg = f"{name} not equal WEL-1_IN / 10.\n{a1}\n{a2}" assert np.allclose(a1, a2), errmsg print("Checking that all simulated concentrations are 100.") @@ -351,7 +352,7 @@ def test_ssm01fmi(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run tests test_ssm01fmi() diff --git a/autotest/test_gwt_ssm02.py b/autotest/test_gwt_ssm02.py index 36032e90468..b746e5a07b7 100644 --- a/autotest/test_gwt_ssm02.py +++ b/autotest/test_gwt_ssm02.py @@ -8,8 +8,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -96,7 +97,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -146,8 +147,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL")], printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], @@ -159,7 +160,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) # create iterative model solution and register the gwt model with it @@ -176,7 +177,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -190,7 +191,7 @@ def build_model(idx, dir): top=top, botm=botm, idomain=1, - filename="{}.dis".format(gwtname), + filename=f"{gwtname}.dis", ) # initial conditions @@ -198,7 +199,7 @@ def build_model(idx, dir): # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # mass storage and transfer @@ -214,8 +215,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -229,7 +230,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -242,21 +243,21 @@ def eval_transport(sim): gwtname = "gwt_" + name gwfname = "gwf_" + name - fpth = os.path.join(sim.simpath, "{}.hds".format(gwfname)) + fpth = os.path.join(sim.simpath, f"{gwfname}.hds") try: hobj = flopy.utils.HeadFile(fpth, precision="double") head = hobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_alldata().flatten() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # calculations times = hobj.get_times() @@ -312,7 +313,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ssm03.py b/autotest/test_gwt_ssm03.py index 11d5c162695..d94d3f91ab6 100644 --- a/autotest/test_gwt_ssm03.py +++ b/autotest/test_gwt_ssm03.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -81,7 +82,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -131,8 +132,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -144,7 +145,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -162,7 +163,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -203,8 +204,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -233,7 +234,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -246,24 +247,24 @@ def eval_transport(sim): gwtname = "gwt_" + name # load concentration file - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # load transport budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.cbc") try: bobj = flopy.utils.CellBudgetFile( fpth, precision="double", ) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' ssmbudall = bobj.get_data(text="SOURCE-SINK MIX") for ssmbud in ssmbudall: @@ -313,7 +314,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ssm04.py b/autotest/test_gwt_ssm04.py index b278b031a53..84485de916e 100644 --- a/autotest/test_gwt_ssm04.py +++ b/autotest/test_gwt_ssm04.py @@ -12,8 +12,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -97,7 +98,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -220,8 +221,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -233,7 +234,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -251,7 +252,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -373,8 +374,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -403,7 +404,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -416,24 +417,24 @@ def eval_transport(sim): gwtname = "gwt_" + name # load concentration file - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # load transport budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.cbc") try: bobj = flopy.utils.CellBudgetFile( fpth, precision="double", ) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' ssmbudall = bobj.get_data(text="SOURCE-SINK MIX") times = cobj.get_times() @@ -534,7 +535,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ssm05.py b/autotest/test_gwt_ssm05.py index d9f43fee83a..e6a84fd536d 100644 --- a/autotest/test_gwt_ssm05.py +++ b/autotest/test_gwt_ssm05.py @@ -6,8 +6,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import flopy @@ -91,7 +92,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -146,8 +147,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.cbc".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.cbc", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], printrecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], @@ -159,7 +160,7 @@ def build_model(idx, dir): sim, model_type="gwt6", modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) gwt.name_file.save_flows = True @@ -177,7 +178,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -212,8 +213,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.cbc", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -242,7 +243,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -255,24 +256,24 @@ def eval_transport(sim): gwtname = "gwt_" + name # load concentration file - fpth = os.path.join(sim.simpath, "{}.ucn".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.ucn") try: cobj = flopy.utils.HeadFile( fpth, precision="double", text="CONCENTRATION" ) conc = cobj.get_data() except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' # load transport budget file - fpth = os.path.join(sim.simpath, "{}.cbc".format(gwtname)) + fpth = os.path.join(sim.simpath, f"{gwtname}.cbc") try: bobj = flopy.utils.CellBudgetFile( fpth, precision="double", ) except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' ssmbudall = bobj.get_data(text="SOURCE-SINK MIX") times = cobj.get_times() @@ -366,7 +367,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwt_ssm06.py b/autotest/test_gwt_ssm06.py new file mode 100644 index 00000000000..4755fa610f9 --- /dev/null +++ b/autotest/test_gwt_ssm06.py @@ -0,0 +1,393 @@ +# Derived from test_gwt_ssm01fmi.py, but drops RIV and adds SFR. +# See test_gwt_ssm06fmi.py for additional detail on what this test is about. + +import os +import shutil + +import numpy as np + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + + +import targets + +exe_name_mf6 = targets.target_dict["mf6"] +exe_name_mf6 = os.path.abspath(exe_name_mf6) + +testdir = "./temp" +testgroup = "ssm06" +d = os.path.join(testdir, testgroup) +if os.path.isdir(d): + shutil.rmtree(d) + + +nlay = 1 +nrow = 10 +ncol = 10 +delr = 10.0 +delc = 10.0 +top = 100.0 +botm = 0.0 + +# +# Add SFR for serving as a MVR receiver (something's up when multiple packages +# appear in SSM and MVR is active. When MVR is inactive, all seem to work well. +# However, things break as soon as MVR is activated. +# + +conns = [(0, -1), (1, 0, -2), (2, 1, -3), (3, 2, -4), (4, 3)] + +sfrcells = [(0, 4, 5), (0, 4, 6), (0, 4, 7), (0, 4, 8), (0, 4, 9)] + +rlen = [100.0, 100.0, 100.0, 100.0, 100.0] + +rbt = [99.409676, 99.320812, 99.221775, 99.146317, 99.074970] + +rgrd = 0.12e-03 +rwid = 20 +rbth = 1.5 +rbhk = 0.1 +man = 0.04 +ustrf = 1.0 +ndv = 0 + + +def run_flw_and_trnprt_models(): + global idomain + gwfname = "gwf-" + testgroup + ws = os.path.join(testdir, testgroup) + sim = flopy.mf6.MFSimulation( + sim_name=testgroup, sim_ws=ws, exe_name=exe_name_mf6 + ) + tdis_rc = [(100.0, 10, 1.0), (100.0, 10, 1.0)] + nper = len(tdis_rc) + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + gwf = flopy.mf6.ModflowGwf(sim, modelname=gwfname, save_flows=True) + + # ims + hclose = 1.0e-6 + rclose = 1.0e-6 + nouter = 1000 + ninner = 100 + relax = 0.99 + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + sim.register_ims_package(imsgwf, gwfname) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + ic = flopy.mf6.ModflowGwfic(gwf, strt=100.0) + + npf = flopy.mf6.ModflowGwfnpf( + gwf, + xt3doptions=False, + save_flows=True, + save_specific_discharge=True, + save_saturation=True, + icelltype=[1], + k=10.0, + ) + + sto = flopy.mf6.ModflowGwfsto( + gwf, + save_flows=True, + iconvert=[1], + ss=1.0e-5, + sy=0.3, + transient={0: True}, + ) + + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[ + ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + # wel + wellist = [] + for i in np.arange(3, 7, 2): + wellist.append(((0, i, 2), -100.0, 0.0)) + wel = flopy.mf6.ModflowGwfwel( + gwf, + mover=True, + stress_period_data=wellist, + auxiliary=["concentration"], + pname="WEL-1", + ) + + # ghb + rows = [0, 1, 2, 3] + for ipak, i in enumerate(rows): + blist = [] + blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) + fname = gwfname + f"_{ipak + 1}.ghb" + ghb = flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=blist, + auxiliary=["concentration"], + filename=fname, + pname=f"GHB-{ipak + 1}", + ) + + # drn + rows = [7, 8, 9] + for ipak, i in enumerate(rows): + blist = [] + blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) + fname = gwfname + f"_{ipak + 1}.drn" + drn = flopy.mf6.ModflowGwfdrn( + gwf, + stress_period_data=blist, + auxiliary=["concentration"], + filename=fname, + pname=f"DRN-{ipak + 1}", + ) + + # sfr - stream starts in the middle of domain and goes due east + sfr_pkdat = [] + for i in np.arange(len(rlen)): + ncon = len(conns[i]) - 1 + sfr_pkdat.append( + ( + i, + sfrcells[i], + rlen[i], + rwid, + rgrd, + rbt[i], + rbth, + rbhk, + man, + ncon, + ustrf, + ndv, + ) + ) + + sfrspd = {0: [[0, "INFLOW", 86400.0]]} + sfr = flopy.mf6.ModflowGwfsfr( + gwf, + print_stage=True, + print_flows=True, + mover=True, + stage_filerecord=gwfname + ".sfr.stg", + budget_filerecord=gwfname + ".sfr.bud", + save_flows=True, + pname="SFR-1", + unit_conversion=86400.0 * 1.486, + boundnames=False, + nreaches=len(conns), + packagedata=sfr_pkdat, + connectiondata=conns, + perioddata=sfrspd, + filename=f"{gwfname}.sfr", + ) + + # mvr + mvrpack = [["SFR-1"], ["WEL-1"]] + static_mvrperioddata = [] + wel_idx = 0 + for wl in np.arange(2): # There are only a maximum of 2 wells + static_mvrperioddata.append( + ("WEL-1", wel_idx, "SFR-1", 0, "FACTOR", 1.0) + ) + wel_idx += 1 + + mvrspd = {0: static_mvrperioddata} + maxmvr = len(static_mvrperioddata) + flopy.mf6.ModflowGwfmvr( + gwf, + maxmvr=maxmvr, + print_flows=False, + maxpackages=len(mvrpack), + packages=mvrpack, + perioddata=mvrspd, + budget_filerecord=gwfname + ".mvr.bud", + ) + + # Transport + # ---------- + gwtname = "gwt-" + testgroup + + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # ims + hclose = 0.001 + rclose = 0.001 + nouter = 50 + ninner = 20 + relax = 0.97 + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwtname}.ims", + ) + sim.register_ims_package(imsgwt, gwtname) + + dis = flopy.mf6.ModflowGwtdis( + gwt, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=100.0) + sto = flopy.mf6.ModflowGwtmst(gwt, porosity=0.3) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="TVD") + dsp = flopy.mf6.ModflowGwtdsp(gwt, alh=20.0, ath1=2, atv=0.2) + + # Create the ssm sources block information + sourcerecarray = [] + # sourcerecarray += [("WEL-1", "AUX", "CONCENTRATION")] + sourcerecarray += [ + (f"GHB-{i+1}", "AUX", "CONCENTRATION") for i in [0, 1, 2, 3] + ] + sourcerecarray += [ + (f"DRN-{i+1}", "AUX", "CONCENTRATION") for i in [0, 1, 2] + ] + sourcerecarray += [(f"WEL-{i+1}", "AUX", "CONCENTRATION") for i in [0]] + ssm = flopy.mf6.ModflowGwtssm( + gwt, + print_flows=True, + sources=sourcerecarray, + ) + + fmi = flopy.mf6.ModflowGwtfmi(gwt, flow_imbalance_correction=True) + + sftpkdat = [] + for irno in range(len(sfrcells)): + t = (irno, 1.0) + sftpkdat.append(t) + + sftspd = {0: [[0, "INFLOW", 1.0]]} + sft = flopy.mf6.modflow.ModflowGwtsft( + gwt, + boundnames=False, + flow_package_name="SFR-1", + print_concentration=True, + save_flows=True, + concentration_filerecord=gwtname + ".sft.bin", + budget_filerecord=gwtname + ".sft.bud", + packagedata=sftpkdat, + reachperioddata=sftspd, + pname="SFT-1", + ) + + mvt = flopy.mf6.modflow.ModflowGwtmvt( + gwt, + pname="MVT-1", + ) + + oc = flopy.mf6.ModflowGwtoc( + gwt, + budget_filerecord=f"{gwtname}.cbc", + budgetcsv_filerecord=f"{gwtname}.cbc.csv", + concentration_filerecord=f"{gwtname}.ucn", + concentrationprintrecord=[ + ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + printrecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + ) + + flopy.mf6.ModflowGwfgwt( + sim, + exgtype="GWF6-GWT6", + exgmnamea=gwfname, + exgmnameb=gwtname, + filename=f"{gwfname}.gwfgwt", + ) + + sim.write_simulation() + success, buff = sim.run_simulation(silent=False) + errmsg = f"transport model did not terminate successfully\n{buff}" + assert success, errmsg + + # ensure budget table can be parsed + fname = gwtname + ".lst" + fname = os.path.join(ws, fname) + budl = flopy.utils.Mf6ListBudget( + fname, budgetkey="MASS BUDGET FOR ENTIRE MODEL" + ) + d0 = budl.get_budget()[0] + + # Load the csv representation of the budget + fname = f"{gwtname}.cbc.csv" + fname = os.path.join(ws, fname) + d0 = np.genfromtxt(fname, names=True, delimiter=",", deletechars="") + print(d0.dtype.names) + + return + + +def test_ssm06(): + run_flw_and_trnprt_models() + d = os.path.join(testdir, testgroup) + if os.path.isdir(d): + shutil.rmtree(d) + return + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run tests + test_ssm06() diff --git a/autotest/test_gwt_ssm06fmi.py b/autotest/test_gwt_ssm06fmi.py new file mode 100644 index 00000000000..47db31182a9 --- /dev/null +++ b/autotest/test_gwt_ssm06fmi.py @@ -0,0 +1,428 @@ +# Derived from test_gwt_ssm01fmi.py, but drops RIV and adds SFR. +# In that autotest, flow and transport run separately, which is the case here +# as well. However, by adding SFR we can now invoke MVR, in this case +# WEL -> SFR at the same time as invoking auxiliary variables. A +# companion autotest runs this same simulation (uses SFR in place of RIV for +# receiving MVR water), but runs both flow and tranport simultaneously which, +# at one time, wrongly threw an input error. However, running the models +# separately never threw the error. + +import os +import shutil + +import numpy as np + +try: + import pymake +except: + msg = "Error. Pymake package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install https://github.com/modflowpy/pymake/zipball/master" + raise Exception(msg) + +try: + import flopy +except: + msg = "Error. FloPy package is not available.\n" + msg += "Try installing using the following command:\n" + msg += " pip install flopy" + raise Exception(msg) + + +import targets + +exe_name_mf6 = targets.target_dict["mf6"] +exe_name_mf6 = os.path.abspath(exe_name_mf6) + +testdir = "./temp" +testgroup = "ssm06fmi" +d = os.path.join(testdir, testgroup) +if os.path.isdir(d): + shutil.rmtree(d) + + +nlay = 1 +nrow = 10 +ncol = 10 +delr = 10.0 +delc = 10.0 +top = 100.0 +botm = 0.0 + +# +# Add SFR for serving as a MVR receiver (something's up when multiple packages +# appear in SSM and MVR is active. When MVR is inactive, all seem to work well. +# However, things break as soon as MVR is activated. +# + +conns = [(0, -1), (1, 0, -2), (2, 1, -3), (3, 2, -4), (4, 3)] + +sfrcells = [(0, 4, 5), (0, 4, 6), (0, 4, 7), (0, 4, 8), (0, 4, 9)] + +rlen = [100.0, 100.0, 100.0, 100.0, 100.0] + +rbt = [99.409676, 99.320812, 99.221775, 99.146317, 99.074970] + +rgrd = 0.12e-03 +rwid = 20 +rbth = 1.5 +rbhk = 0.1 +man = 0.04 +ustrf = 1.0 +ndv = 0 + + +def run_flow_model(): + global idomain + name = "flow" + gwfname = name + wsf = os.path.join(testdir, testgroup, name) + sim = flopy.mf6.MFSimulation( + sim_name=name, sim_ws=wsf, exe_name=exe_name_mf6 + ) + tdis_rc = [(100.0, 1, 1.0), (100.0, 1, 1.0)] + nper = len(tdis_rc) + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + gwf = flopy.mf6.ModflowGwf(sim, modelname=gwfname, save_flows=True) + + # ims + hclose = 1.0e-6 + rclose = 1.0e-6 + nouter = 1000 + ninner = 100 + relax = 0.99 + imsgwf = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="CG", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwfname}.ims", + ) + + dis = flopy.mf6.ModflowGwfdis( + gwf, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + + ic = flopy.mf6.ModflowGwfic(gwf, strt=100.0) + + npf = flopy.mf6.ModflowGwfnpf( + gwf, + xt3doptions=False, + save_flows=True, + save_specific_discharge=True, + save_saturation=True, + icelltype=[1], + k=10.0, + ) + + sto_on = False + if sto_on: + sto = flopy.mf6.ModflowGwfsto( + gwf, + save_flows=True, + iconvert=[1], + ss=1.0e-5, + sy=0.3, + steady_state={0: True}, + transient={0: False}, + ) + + oc = flopy.mf6.ModflowGwfoc( + gwf, + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", + headprintrecord=[ + ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + printrecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], + ) + + rch_on = False + if rch_on: + rch = flopy.mf6.ModflowGwfrcha( + gwf, recharge={0: 4.79e-3}, pname="RCH-1" + ) + + # wel + wellist = [] + for i in np.arange(3, 7, 2): + wellist.append(((0, i, 2), -100.0, 0.0)) + wel = flopy.mf6.ModflowGwfwel( + gwf, + mover=True, + stress_period_data=wellist, + auxiliary=["concentration"], + pname="WEL-1", + ) + + # ghb + rows = [0, 1, 2, 3] + for ipak, i in enumerate(rows): + blist = [] + blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) + fname = f"flow.{ipak + 1}.ghb" + ghb = flopy.mf6.ModflowGwfghb( + gwf, + stress_period_data=blist, + auxiliary=["concentration"], + filename=fname, + pname=f"GHB-{ipak + 1}", + ) + + # drn + rows = [7, 8, 9] + for ipak, i in enumerate(rows): + blist = [] + blist.append(((0, i, ncol - 1), 50.0, 1000.0, 100.0)) + fname = f"flow.{ipak + 1}.drn" + drn = flopy.mf6.ModflowGwfdrn( + gwf, + stress_period_data=blist, + auxiliary=["concentration"], + filename=fname, + pname=f"DRN-{ipak + 1}", + ) + + # sfr - stream starts in the middle of domain and goes due east + sfr_pkdat = [] + for i in np.arange(len(rlen)): + ncon = len(conns[i]) - 1 + sfr_pkdat.append( + ( + i, + sfrcells[i], + rlen[i], + rwid, + rgrd, + rbt[i], + rbth, + rbhk, + man, + ncon, + ustrf, + ndv, + ) + ) + + sfrspd = {0: [[0, "INFLOW", 86400.0]]} + sfr = flopy.mf6.ModflowGwfsfr( + gwf, + print_stage=True, + print_flows=True, + mover=True, + stage_filerecord=gwfname + ".sfr.stg", + budget_filerecord=gwfname + ".sfr.bud", + save_flows=True, + pname="SFR-1", + unit_conversion=86400.0 * 1.486, + boundnames=False, + nreaches=len(conns), + packagedata=sfr_pkdat, + connectiondata=conns, + perioddata=sfrspd, + filename=f"{gwfname}.sfr", + ) + + # mvr + mvrpack = [["SFR-1"], ["WEL-1"]] + static_mvrperioddata = [] + wel_idx = 0 + for wl in np.arange(2): # There are only a maximum of 2 wells + static_mvrperioddata.append( + ("WEL-1", wel_idx, "SFR-1", 0, "FACTOR", 1.0) + ) + wel_idx += 1 + + mvrspd = {0: static_mvrperioddata} + maxmvr = len(static_mvrperioddata) + flopy.mf6.ModflowGwfmvr( + gwf, + maxmvr=maxmvr, + print_flows=False, + maxpackages=len(mvrpack), + packages=mvrpack, + perioddata=mvrspd, + budget_filerecord=gwfname + ".mvr.bud", + ) + + sim.write_simulation() + success, buff = sim.run_simulation(silent=False) + errmsg = f"flow model did not terminate successfully\n{buff}" + assert success, errmsg + + return + + +def run_transport_model(): + name = "transport" + gwtname = name + wst = os.path.join(testdir, testgroup, name) + sim = flopy.mf6.MFSimulation( + sim_name=name, + version="mf6", + exe_name=exe_name_mf6, + sim_ws=wst, + continue_=False, + ) + + tdis_rc = [(100.0, 10, 1.0), (100.0, 10, 1.0)] + nper = len(tdis_rc) + tdis = flopy.mf6.ModflowTdis( + sim, time_units="DAYS", nper=nper, perioddata=tdis_rc + ) + + gwt = flopy.mf6.ModflowGwt(sim, modelname=gwtname) + + # ims + hclose = 0.001 + rclose = 0.001 + nouter = 50 + ninner = 20 + relax = 0.97 + imsgwt = flopy.mf6.ModflowIms( + sim, + print_option="ALL", + outer_dvclose=hclose, + outer_maximum=nouter, + under_relaxation="NONE", + inner_maximum=ninner, + inner_dvclose=hclose, + rcloserecord=rclose, + linear_acceleration="BICGSTAB", + scaling_method="NONE", + reordering_method="NONE", + relaxation_factor=relax, + filename=f"{gwtname}.ims", + ) + sim.register_ims_package(imsgwt, [gwt.name]) + + dis = flopy.mf6.ModflowGwtdis( + gwt, + nlay=nlay, + nrow=nrow, + ncol=ncol, + delr=delr, + delc=delc, + top=top, + botm=botm, + ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=100.0) + sto = flopy.mf6.ModflowGwtmst(gwt, porosity=0.3) + adv = flopy.mf6.ModflowGwtadv(gwt, scheme="TVD") + dsp = flopy.mf6.ModflowGwtdsp(gwt, alh=20.0, ath1=2, atv=0.2) + + # Create the ssm sources block information + sourcerecarray = [] + sourcerecarray += [("WEL-1", "AUX", "CONCENTRATION")] + sourcerecarray += [ + (f"GHB-{i+1}", "AUX", "CONCENTRATION") for i in [0, 1, 2, 3] + ] + sourcerecarray += [ + (f"DRN-{i+1}", "AUX", "CONCENTRATION") for i in [0, 1, 2] + ] + + ssm = flopy.mf6.ModflowGwtssm( + gwt, print_flows=True, sources=sourcerecarray + ) + + pd = [ + ("GWFHEAD", "../flow/flow.hds", None), + ("GWFBUDGET", "../flow/flow.bud", None), + ("GWFMOVER", "../flow/flow.mvr.bud", None), + ("SFR-1", "../flow/flow.sfr.bud", None), + ] + fmi = flopy.mf6.ModflowGwtfmi( + gwt, packagedata=pd, flow_imbalance_correction=True + ) + + sftpkdat = [] + for irno in range(len(sfrcells)): + t = (irno, 1.0) + sftpkdat.append(t) + + sftspd = {0: [[0, "INFLOW", 1.0]]} + sft = flopy.mf6.modflow.ModflowGwtsft( + gwt, + boundnames=False, + flow_package_name="SFR-1", + print_concentration=True, + save_flows=True, + concentration_filerecord=gwtname + ".sft.bin", + budget_filerecord=gwtname + ".sft.bud", + packagedata=sftpkdat, + reachperioddata=sftspd, + pname="SFT-1", + ) + + mvt = flopy.mf6.modflow.ModflowGwtmvt( + gwt, + pname="MVT-1", + ) + + oc = flopy.mf6.ModflowGwtoc( + gwt, + budget_filerecord=f"{gwtname}.cbc", + budgetcsv_filerecord=f"{gwtname}.cbc.csv", + concentration_filerecord=f"{gwtname}.ucn", + concentrationprintrecord=[ + ("COLUMNS", ncol, "WIDTH", 15, "DIGITS", 6, "GENERAL") + ], + saverecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + printrecord=[("CONCENTRATION", "ALL"), ("BUDGET", "ALL")], + ) + + sim.write_simulation() + success, buff = sim.run_simulation(silent=False) + errmsg = f"transport model did not terminate successfully\n{buff}" + assert success, errmsg + + # ensure budget table can be parsed + fname = gwtname + ".lst" + fname = os.path.join(wst, fname) + budl = flopy.utils.Mf6ListBudget( + fname, budgetkey="MASS BUDGET FOR ENTIRE MODEL" + ) + d0 = budl.get_budget()[0] + + # Load the csv representation of the budget for confirming that the model ran + fname = f"{gwtname}.cbc.csv" + fname = os.path.join(wst, fname) + d0 = np.genfromtxt(fname, names=True, delimiter=",", deletechars="") + print(d0.dtype.names) + return + + +def test_ssm06fmi(): + run_flow_model() + run_transport_model() + d = os.path.join(testdir, testgroup) + if os.path.isdir(d): + shutil.rmtree(d) + return + + +if __name__ == "__main__": + # print message + print(f"standalone run of {os.path.basename(__file__)}") + + # run tests + test_ssm06fmi() diff --git a/autotest/test_gwt_uzt01.py b/autotest/test_gwt_uzt01.py index d39736fcbb0..01946fb5b5d 100644 --- a/autotest/test_gwt_uzt01.py +++ b/autotest/test_gwt_uzt01.py @@ -7,8 +7,9 @@ """ import os -import pytest + import numpy as np +import pytest try: import pymake @@ -108,7 +109,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwfname), + filename=f"{gwfname}.ims", ) sim.register_ims_package(imsgwf, [gwf.name]) @@ -158,7 +159,7 @@ def build_model(idx, dir): uzf_obs = { gwfname + ".uzf.obs.csv": [ - ("wc{}".format(k + 1), "water-content", k + 1, 0.5 * delv) + (f"wc{k + 1}", "water-content", k + 1, 0.5 * delv) for k in range(nlay) ] } @@ -190,7 +191,7 @@ def build_model(idx, dir): thts, thti, brooks_corey_epsilon, - "uzf0{}".format(k + 1), + f"uzf0{k + 1}", ] for k in range(1, nlay) ] @@ -222,17 +223,17 @@ def build_model(idx, dir): nuzfcells=len(uzf_pkdat), packagedata=uzf_pkdat, perioddata=uzf_spd, - budget_filerecord="{}.uzf.bud".format(gwfname), + budget_filerecord=f"{gwfname}.uzf.bud", observations=uzf_obs, pname="UZF-1", - filename="{}.uzf".format(gwfname), + filename=f"{gwfname}.uzf", ) # output control oc = flopy.mf6.ModflowGwfoc( gwf, - budget_filerecord="{}.bud".format(gwfname), - head_filerecord="{}.hds".format(gwfname), + budget_filerecord=f"{gwfname}.bud", + head_filerecord=f"{gwfname}.hds", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "ALL"), ("BUDGET", "ALL")], printrecord=[("HEAD", "LAST"), ("BUDGET", "ALL")], @@ -241,7 +242,7 @@ def build_model(idx, dir): obs_lst = [] obs_lst.append(["obs1", "head", (0, 0, 0)]) obs_lst.append(["obs2", "head", (1, 0, 0)]) - obs_dict = {"{}.obs.csv".format(gwfname): obs_lst} + obs_dict = {f"{gwfname}.obs.csv": obs_lst} obs = flopy.mf6.ModflowUtlobs( gwf, pname="head_obs", digits=20, continuous=obs_dict ) @@ -252,7 +253,7 @@ def build_model(idx, dir): sim, save_flows=True, modelname=gwtname, - model_nam_file="{}.nam".format(gwtname), + model_nam_file=f"{gwtname}.nam", ) imsgwt = flopy.mf6.ModflowIms( @@ -268,7 +269,7 @@ def build_model(idx, dir): scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format(gwtname), + filename=f"{gwtname}.ims", ) sim.register_ims_package(imsgwt, [gwt.name]) @@ -285,19 +286,17 @@ def build_model(idx, dir): ) # initial conditions - ic = flopy.mf6.ModflowGwtic( - gwt, strt=0.0, filename="{}.ic".format(gwtname) - ) + ic = flopy.mf6.ModflowGwtic(gwt, strt=0.0, filename=f"{gwtname}.ic") # advection adv = flopy.mf6.ModflowGwtadv( - gwt, scheme="UPSTREAM", filename="{}.adv".format(gwtname) + gwt, scheme="UPSTREAM", filename=f"{gwtname}.adv" ) # storage porosity = sy sto = flopy.mf6.ModflowGwtmst( - gwt, porosity=porosity, filename="{}.sto".format(gwtname) + gwt, porosity=porosity, filename=f"{gwtname}.sto" ) # sources sourcerecarray = [ @@ -305,25 +304,54 @@ def build_model(idx, dir): # ('WEL-1', 'AUX', 'CONCENTRATION'), ] ssm = flopy.mf6.ModflowGwtssm( - gwt, sources=sourcerecarray, filename="{}.ssm".format(gwtname) + gwt, sources=sourcerecarray, filename=f"{gwtname}.ssm" ) - uztpackagedata = [ - (iuz, 0.0, "uzt{}".format(iuz + 1)) for iuz in range(nlay) - ] + uztpackagedata = [(iuz, 0.0, f"myuzt{iuz + 1}") for iuz in range(nlay)] uztperioddata = [ (0, "INFILTRATION", 100.0), (0, "UZET", 100.0), ] - uzt_obs = { - (gwtname + ".uzt.obs.csv",): [ - ("uztconc{}".format(k + 1), "CONCENTRATION", k + 1) - for k in range(nlay) - ], - } + ncv = nlay + uzt_obs = {} + for obstype in [ + "CONCENTRATION", + "STORAGE", + "CONSTANT", + "FROM-MVR", + "UZT", + "INFILTRATION", + "REJ-INF", + "UZET", + "REJ-INF-TO-MVR", + ]: + fname = f"{gwtname}.uzt.obs.{obstype.lower()}.csv" + obs1 = [(f"uzt{i + 1}", obstype, i + 1) for i in range(ncv)] + obs2 = [(f"buzt{i + 1}", obstype, f"myuzt{i + 1}") for i in range(ncv)] + uzt_obs[fname] = obs1 + obs2 + + obstype = "FLOW-JA-FACE" + fname = f"{gwtname}.uzt.obs.{obstype.lower()}.csv" + obs1 = [] + for id1 in range(ncv): + id2list = [] + if id1 > 0: + id2list.append(id1 - 1) + if id1 < ncv - 1: + id2list.append(id1 + 1) + for id2 in id2list: + obs1.append( + (f"uzt{id1 + 1}x{id2 + 1}", obstype, id1 + 1, id2 + 1) + ) + obs2 = [ + (f"buzt{i + 1}", obstype, f"myuzt{i + 1}") + for i in range(ncv) + ] + uzt_obs[fname] = obs1 + obs2 + # append additional obs attributes to obs dictionary - uzt_obs["digits"] = 7 + uzt_obs["digits"] = 15 uzt_obs["print_input"] = True uzt_obs["filename"] = gwtname + ".uzt.obs" @@ -345,8 +373,8 @@ def build_model(idx, dir): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.bud".format(gwtname), - concentration_filerecord="{}.ucn".format(gwtname), + budget_filerecord=f"{gwtname}.bud", + concentration_filerecord=f"{gwtname}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -366,7 +394,7 @@ def build_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=gwfname, exgmnameb=gwtname, - filename="{}.gwfgwt".format(name), + filename=f"{name}.gwfgwt", ) return sim, None @@ -392,7 +420,7 @@ def make_plot(sim, obsvals): ax = fig.add_subplot(1, 1, 1) depth = np.arange(1, 31, 2.0) for row in obsvals: - label = "time {}".format(row[0]) + label = f"time {row[0]}" ax.plot(row[1:], depth, label=label, marker="o") ax.set_ylim(0.0, 30.0) ax.set_xlim(0.0, 100.0) @@ -408,6 +436,79 @@ def make_plot(sim, obsvals): return +def check_obs(sim): + print("checking obs...") + name = ex[sim.idxsim] + ws = exdirs[sim.idxsim] + sim = flopy.mf6.MFSimulation.load(sim_ws=ws) + gwfname = "gwf_" + name + gwtname = "gwt_" + name + gwf = sim.get_model(gwfname) + gwt = sim.get_model(gwtname) + + ncv = nlay + + # extract uzt concentrations from binary output file + conc_uzt = gwt.uzt.output.concentration().get_alldata() + ntimes = conc_uzt.shape[0] + conc_uzt = conc_uzt.reshape((ntimes, ncv)) + + # ensure uzt obs are the same whether specified by + # boundname or by control volume + csvfiles = gwt.uzt.obs.output.obs_names + for csvfile in csvfiles: + if ".flow-ja-face.csv" in csvfile: + continue + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.uzt.obs.output.obs(f=csvfile).data + success = True + # check boundname observations with numeric ID observations + for icv in range(ncv): + # print(f" Checking control volume {icv + 1}") + + if ".concentration.csv" in csvfile: + is_same = np.allclose(conc_ra[f"BUZT{icv + 1}"], conc_uzt[:, icv]) + if not is_same: + success = False + print( + "Binary concentrations do not match with observation concentrations for uzt1" + ) + print(conc_ra[f"BUZT1"], conc_uzt) + + is_same = np.allclose( + conc_ra[f"UZT{icv + 1}"], conc_ra[f"BUZT{icv + 1}"] + ) + if not is_same: + success = False + for t, x, y in zip( + conc_ra["totim"], + conc_ra[f"UZT{icv + 1}"], + conc_ra[f"BUZT{icv + 1}"], + ): + print(t, x, y) + + # Sum individual iconn uzt rates and compare with total rate + csvfile = f"{gwtname}.uzt.obs.flow-ja-face.csv" + print(f"Checking csv file: {csvfile}") + conc_ra = gwt.uzt.obs.output.obs(f=csvfile).data + ntimes = conc_ra.shape[0] + for iuzt in range(ncv): + connection_sum = np.zeros(ntimes) + for column_name in conc_ra.dtype.names: + if f"UZT{icv + 1}X" in column_name: + connection_sum += conc_ra[column_name] + is_same = np.allclose(connection_sum, conc_ra[f"BUZT{icv + 1}"]) + if not is_same: + success = False + diff = connection_sum - conc_ra[f"BMWTUZT{icv + 1}"] + print( + f"Problem with UZT {icv + 1}; mindiff {diff.min()} and maxdiff {diff.max()}" + ) + + assert success, "One or more UZT obs checks did not pass" + return + + def eval_flow(sim): print("evaluating flow...") @@ -427,7 +528,7 @@ def eval_flow(sim): conc = cobj.get_alldata() for conc_this_time in conc: c = conc_this_time.flatten() - errmsg = "conc[0] must be 100 and conc[-1] must be 0: {}".format(c) + errmsg = f"conc[0] must be 100 and conc[-1] must be 0: {c}" # assert np.allclose(c[0], 100.), errmsg assert np.allclose(c[-1], 0.0), errmsg @@ -449,9 +550,7 @@ def eval_flow(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg bpth = os.path.join(ws, gwtname + ".uzt.bud") @@ -461,9 +560,7 @@ def eval_flow(sim): for uz in uzet[ 100: ]: # Need to look later in simulation when ET demand is met - msg = "unsat ET not correct. Found {}. Should be {}".format( - uz["q"], uz_answer - ) + msg = f"unsat ET not correct. Found {uz['q']}. Should be {uz_answer}" assert np.allclose(uz["q"], uz_answer), msg uzinfil = bobj.get_data(text="INFILTRATION") @@ -476,17 +573,18 @@ def eval_flow(sim): cobj = flopy.utils.HeadFile(fname, text="CONCENTRATION") c = cobj.get_data().flatten() canswer = 10 * [100.0] + 5 * [0.0] - msg = "Ending uzf concentrations {} do not match known concentrations {}".format( - c, canswer - ) + msg = f"Ending uzf concentrations {c} do not match known concentrations {canswer}" assert np.allclose(c, canswer) + # check observations + check_obs(sim) + # Make plot of obs - fpth = os.path.join(sim.simpath, gwtname + ".uzt.obs.csv") + fpth = os.path.join(sim.simpath, gwtname + ".uzt.obs.concentration.csv") try: obsvals = np.genfromtxt(fpth, names=True, delimiter=",") except: - assert False, 'could not load data from "{}"'.format(fpth) + assert False, f'could not load data from "{fpth}"' if False: make_plot(sim, obsvals) return @@ -523,7 +621,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_gwtgwt_oldexg.py b/autotest/test_gwtgwt_oldexg.py index 8cf8f30a583..21e91f109d6 100644 --- a/autotest/test_gwtgwt_oldexg.py +++ b/autotest/test_gwtgwt_oldexg.py @@ -1,4 +1,5 @@ import os + import numpy as np import pytest @@ -130,7 +131,7 @@ def get_model(idx, dir): rcloserecord=rclose, linear_acceleration="BICGSTAB", relaxation_factor=relax, - filename="{}.ims".format("gwf"), + filename="gwf.ims", ) # the full gwf model as a reference @@ -151,12 +152,12 @@ def get_model(idx, dir): under_relaxation="NONE", inner_maximum=ninner, inner_dvclose=hclose, - rcloserecord="{} strict".format(rclose), + rcloserecord=f"{rclose} strict", linear_acceleration="BICGSTAB", scaling_method="NONE", reordering_method="NONE", relaxation_factor=relax, - filename="{}.ims".format("gwt"), + filename="gwt.ims", ) gwt = add_gwtrefmodel(sim) @@ -172,21 +173,21 @@ def get_model(idx, dir): exgtype="GWF6-GWT6", exgmnamea=mname_ref, exgmnameb=mname_gwtref, - filename="{}.gwfgwt".format("reference"), + filename="reference.gwfgwt", ) gwfgwt_left = flopy.mf6.ModflowGwfgwt( sim, exgtype="GWF6-GWT6", exgmnamea=mname_left, exgmnameb=mname_gwtleft, - filename="{}.gwfgwt".format("left"), + filename="left.gwfgwt", ) gwfgwt_right = flopy.mf6.ModflowGwfgwt( sim, exgtype="GWF6-GWT6", exgmnamea=mname_right, exgmnameb=mname_gwtright, - filename="{}.gwfgwt".format("right"), + filename="right.gwfgwt", ) return sim @@ -235,8 +236,8 @@ def add_refmodel(sim): # output control oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_ref), - budget_filerecord="{}.cbc".format(mname_ref), + head_filerecord=f"{mname_ref}.hds", + budget_filerecord=f"{mname_ref}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -279,8 +280,8 @@ def add_leftmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_left) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_left), - budget_filerecord="{}.cbc".format(mname_left), + head_filerecord=f"{mname_left}.hds", + budget_filerecord=f"{mname_left}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -326,8 +327,8 @@ def add_rightmodel(sim): chd = flopy.mf6.ModflowGwfchd(gwf, stress_period_data=chd_spd_right) oc = flopy.mf6.ModflowGwfoc( gwf, - head_filerecord="{}.hds".format(mname_right), - budget_filerecord="{}.cbc".format(mname_right), + head_filerecord=f"{mname_right}.hds", + budget_filerecord=f"{mname_right}.cbc", headprintrecord=[("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL")], saverecord=[("HEAD", "LAST"), ("BUDGET", "LAST")], ) @@ -407,8 +408,8 @@ def add_gwtrefmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtref), - concentration_filerecord="{}.ucn".format(mname_gwtref), + budget_filerecord=f"{mname_gwtref}.cbc", + concentration_filerecord=f"{mname_gwtref}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -460,8 +461,8 @@ def add_gwtleftmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtleft), - concentration_filerecord="{}.ucn".format(mname_gwtleft), + budget_filerecord=f"{mname_gwtleft}.cbc", + concentration_filerecord=f"{mname_gwtleft}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -516,8 +517,8 @@ def add_gwtrightmodel(sim): # output control oc = flopy.mf6.ModflowGwtoc( gwt, - budget_filerecord="{}.cbc".format(mname_gwtright), - concentration_filerecord="{}.ucn".format(mname_gwtright), + budget_filerecord=f"{mname_gwtright}.cbc", + concentration_filerecord=f"{mname_gwtright}.ucn", concentrationprintrecord=[ ("COLUMNS", 10, "WIDTH", 15, "DIGITS", 6, "GENERAL") ], @@ -598,24 +599,24 @@ def compare_to_ref(sim): def compare_gwf_to_ref(sim): print("comparing heads and spec. discharge to single model reference...") - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.hds") hds = flopy.utils.HeadFile(fpth) heads = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_ref)) + fpth = os.path.join(sim.simpath, f"{mname_ref}.cbc") nlay, nrow, ncol = heads.shape qxb, qyb, qzb = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.hds") hds = flopy.utils.HeadFile(fpth) heads_left = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_left)) + fpth = os.path.join(sim.simpath, f"{mname_left}.cbc") nlay, nrow, ncol = heads_left.shape qxb_left, qyb_left, qzb_left = qxqyqz(fpth, nlay, nrow, ncol) - fpth = os.path.join(sim.simpath, "{}.hds".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.hds") hds = flopy.utils.HeadFile(fpth) heads_right = hds.get_data() - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname_right)) + fpth = os.path.join(sim.simpath, f"{mname_right}.cbc") nlay, nrow, ncol = heads_right.shape qxb_right, qyb_right, qzb_right = qxqyqz(fpth, nlay, nrow, ncol) @@ -686,7 +687,7 @@ def compare_gwf_to_ref(sim): # check budget error from .lst file for mname in [mname_ref, mname_left, mname_right]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -704,7 +705,7 @@ def compare_gwf_to_ref(sim): grb = flopy.mf6.utils.MfGrdFile(fpth) ia = grb._datadict["IA"] - 1 - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.cbc") assert os.path.isfile(fpth) cbb = flopy.utils.CellBudgetFile(fpth, precision="double") flow_ja_face = cbb.get_data(idx=0) @@ -715,9 +716,7 @@ def compare_gwf_to_ref(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg return @@ -726,13 +725,13 @@ def compare_gwf_to_ref(sim): def compare_gwt_to_ref(sim): print("comparing concentration to single model reference...") - fpth = os.path.join(sim.simpath, "{}.ucn".format(mname_gwtref)) + fpth = os.path.join(sim.simpath, f"{mname_gwtref}.ucn") cnc = flopy.utils.HeadFile(fpth, text="CONCENTRATION") conc = cnc.get_data() - fpth = os.path.join(sim.simpath, "{}.ucn".format(mname_gwtleft)) + fpth = os.path.join(sim.simpath, f"{mname_gwtleft}.ucn") cnc = flopy.utils.HeadFile(fpth, text="CONCENTRATION") conc_left = cnc.get_data() - fpth = os.path.join(sim.simpath, "{}.ucn".format(mname_gwtright)) + fpth = os.path.join(sim.simpath, f"{mname_gwtright}.ucn") cnc = flopy.utils.HeadFile(fpth, text="CONCENTRATION") conc_right = cnc.get_data() @@ -749,7 +748,7 @@ def compare_gwt_to_ref(sim): # check budget error from .lst file for mname in [mname_gwtref, mname_gwtleft, mname_gwtright]: - fpth = os.path.join(sim.simpath, "{}.lst".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.lst") for line in open(fpth): if line.lstrip().startswith("PERCENT"): cumul_balance_error = float(line.split()[3]) @@ -768,7 +767,7 @@ def compare_gwt_to_ref(sim): grb = flopy.mf6.utils.MfGrdFile(fpth) ia = grb._datadict["IA"] - 1 - fpth = os.path.join(sim.simpath, "{}.cbc".format(mname)) + fpth = os.path.join(sim.simpath, f"{mname}.cbc") assert os.path.isfile(fpth) cbb = flopy.utils.CellBudgetFile(fpth, precision="double") flow_ja_face = cbb.get_data(idx=0) @@ -779,9 +778,7 @@ def compare_gwt_to_ref(sim): for fjf in flow_ja_face: fjf = fjf.flatten() res = fjf[ia[:-1]] - errmsg = "min or max residual too large {} {}".format( - res.min(), res.max() - ) + errmsg = f"min or max residual too large {res.min()} {res.max()}" assert np.allclose(res, 0.0, atol=1.0e-6), errmsg return @@ -818,7 +815,7 @@ def main(): if __name__ == "__main__": # print message - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/autotest/test_mf6_tmp_simulations.py b/autotest/test_mf6_tmp_simulations.py index 25f9b15da32..c97cea10dc8 100644 --- a/autotest/test_mf6_tmp_simulations.py +++ b/autotest/test_mf6_tmp_simulations.py @@ -1,7 +1,8 @@ import os -import pytest import sys +import pytest + try: import pymake except: @@ -27,8 +28,8 @@ def dir_avail(): avail = os.path.isdir(exdir) if not avail: - print('"{}" does not exist'.format(exdir)) - print("no need to run {}".format(os.path.basename(__file__))) + print(f'"{exdir}" does not exist') + print(f"no need to run {os.path.basename(__file__)}") return avail @@ -104,7 +105,7 @@ def get_mf6_models(): if len(dirs) < 1: msg = "Selected packages not available [" for pak in select_packages: - msg += " {}".format(pak) + msg += f" {pak}" msg += "]" print(msg) @@ -138,7 +139,7 @@ def test_mf6model(idx, dir): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) # get a list of test models to run @@ -154,7 +155,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") delFiles = True for idx, arg in enumerate(sys.argv): diff --git a/autotest/test_z01_testmodels_mf6.py b/autotest/test_z01_testmodels_mf6.py index fecf5717bee..b2ba1797cef 100644 --- a/autotest/test_z01_testmodels_mf6.py +++ b/autotest/test_z01_testmodels_mf6.py @@ -1,7 +1,8 @@ import os -import pytest -import sys import subprocess +import sys + +import pytest try: import pymake @@ -19,19 +20,17 @@ msg += " pip install flopy" raise Exception(msg) -from simulation import Simulation -from targets import get_mf6_version - from common_regression import ( - get_home_dir, get_example_basedir, - is_directory_available, get_example_dirs, + get_home_dir, get_select_dirs, get_select_packages, + is_directory_available, set_mf6_regression, ) - +from simulation import Simulation +from targets import get_mf6_version # find path to examples directory home = get_home_dir() @@ -80,7 +79,7 @@ def get_mf6_models(): branch = os.path.basename(os.environ["GITHUB_REF"]) else: branch = get_branch() - print("On branch {}".format(branch)) + print(f"On branch {branch}") # tuple of example files to exclude # exclude = (None,) @@ -95,7 +94,7 @@ def get_mf6_models(): # write a summary of the files to exclude print("list of tests to exclude:") for idx, ex in enumerate(exclude): - print(" {}: {}".format(idx + 1, ex)) + print(f" {idx + 1}: {ex}") # build list of directories with valid example files if example_basedir is not None: @@ -148,7 +147,7 @@ def get_mf6_models(): if len(example_dirs) < 1: msg = "Selected packages not available [" for pak in select_packages: - msg += " {}".format(pak) + msg += f" {pak}" msg += "]" print(msg) @@ -196,9 +195,9 @@ def set_make_comparison(test): make_comparison = True if test in compare_tests.keys(): version = get_mf6_version() - print("MODFLOW version='{}'".format(version)) + print(f"MODFLOW version='{version}'") version = get_mf6_version(version="mf6-regression") - print("MODFLOW regression version='{}'".format(version)) + print(f"MODFLOW regression version='{version}'") if version in compare_tests[test]: make_comparison = False return make_comparison @@ -226,7 +225,7 @@ def test_mf6model(exdir): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) # determine if test directory exists @@ -252,7 +251,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") delFiles = True for idx, arg in enumerate(sys.argv): diff --git a/autotest/test_z02_testmodels_mf5to6.py b/autotest/test_z02_testmodels_mf5to6.py index 10ec9c76630..cd11f613889 100644 --- a/autotest/test_z02_testmodels_mf5to6.py +++ b/autotest/test_z02_testmodels_mf5to6.py @@ -1,10 +1,10 @@ import os -import pytest -import sys import pathlib - -import time import shutil +import sys +import time + +import pytest try: import pymake @@ -22,19 +22,18 @@ msg += " pip install flopy" raise Exception(msg) -from simulation import Simulation - -from targets import target_dict as target_dict -from targets import get_mf6_version from common_regression import ( - get_home_dir, get_example_basedir, - is_directory_available, get_example_dirs, + get_home_dir, get_select_dirs, get_select_packages, + is_directory_available, set_mf6_regression, ) +from simulation import Simulation +from targets import get_mf6_version +from targets import target_dict as target_dict # find path to examples directory home = get_home_dir() @@ -56,7 +55,7 @@ def get_mf5to6_models(): # write a summary of the files to exclude print("list of tests to exclude:") for idx, ex in enumerate(exclude): - print(" {}: {}".format(idx + 1, ex)) + print(f" {idx + 1}: {ex}") # build list of directories with valid example files if example_basedir is not None: @@ -98,7 +97,7 @@ def get_mf5to6_models(): if len(example_dirs) < 1: msg = "Selected packages not available [" for idx, pak in enumerate(select_packages): - msg += "{}".format(pak) + msg += f"{pak}" if idx + 1 < len(select_packages): msg += ", " msg += "]" @@ -152,7 +151,7 @@ def run_mf5to6(sim): else: npths = pymake.get_namefiles(src) if len(npths) < 1: - msg = "No name files in {}".format(src) + msg = f"No name files in {src}" print(msg) assert False npth = npths[0] @@ -192,7 +191,7 @@ def run_mf5to6(sim): # clean up temp/working directory (src) if os.path.exists(src): - msg = "Removing {} directory".format(src) + msg = f"Removing {src} directory" print(msg) shutil.rmtree(src) time.sleep(0.5) @@ -213,9 +212,9 @@ def set_make_comparison(test): make_comparison = True if test in compare_tests.keys(): version = get_mf6_version() - print("MODFLOW version='{}'".format(version)) + print(f"MODFLOW version='{version}'") version = get_mf6_version(version="mf6-regression") - print("MODFLOW regression version='{}'".format(version)) + print(f"MODFLOW regression version='{version}'") if version in compare_tests[test]: make_comparison = False return make_comparison @@ -241,7 +240,7 @@ def test_model(exdir): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) # get name of current file @@ -265,7 +264,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") delFiles = True for idx, arg in enumerate(sys.argv): diff --git a/autotest/test_z03_examples.py b/autotest/test_z03_examples.py index 1b2f4dd905c..6983e411a9b 100644 --- a/autotest/test_z03_examples.py +++ b/autotest/test_z03_examples.py @@ -1,7 +1,8 @@ import os -import pytest import sys +import pytest + try: import pymake except: @@ -18,16 +19,16 @@ msg += " pip install flopy" raise Exception(msg) -from simulation import Simulation -from targets import get_mf6_version from common_regression import ( - get_home_dir, get_example_basedir, - is_directory_available, get_example_dirs, + get_home_dir, get_select_dirs, get_select_packages, + is_directory_available, ) +from simulation import Simulation +from targets import get_mf6_version # find path to modflow6-examples directory home = get_home_dir() @@ -62,7 +63,7 @@ def get_mf6_models(): # write a summary of the files to exclude print("list of tests to exclude:") for idx, ex in enumerate(exclude): - print(" {}: {}".format(idx + 1, ex)) + print(f" {idx + 1}: {ex}") # build list of directories with valid example files if example_basedir is not None: @@ -99,7 +100,7 @@ def get_mf6_models(): if len(example_dirs) < 1: msg = "Selected packages not available [" for pak in select_packages: - msg += " {}".format(pak) + msg += f" {pak}" msg += "]" print(msg) @@ -134,14 +135,14 @@ def set_make_comparison(test): "ex-gwf-sfr-p01": ("6.2.1",), "ex-gwf-lgr": ("6.2.2",), "ex-gwt-rotate": ("6.2.2",), - "ex-gwtgwt-mt3dms-p10": ("6.2.2",), + "ex-gwt-gwtgwt-mt3dms-p10": ("6.3.0",), } make_comparison = True if test in compare_tests.keys(): version = get_mf6_version() - print("MODFLOW version='{}'".format(version)) + print(f"MODFLOW version='{version}'") version = get_mf6_version(version="mf6-regression") - print("MODFLOW regression version='{}'".format(version)) + print(f"MODFLOW regression version='{version}'") if version in compare_tests[test]: print( f"Test {test} does not run with versions {compare_tests[test]}" @@ -175,7 +176,7 @@ def test_mf6model(exdir): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) # get a list of test models to run @@ -200,7 +201,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") delFiles = True for idx, arg in enumerate(sys.argv): diff --git a/autotest/test_z03_largetests.py b/autotest/test_z03_largetestmodels.py similarity index 93% rename from autotest/test_z03_largetests.py rename to autotest/test_z03_largetestmodels.py index d3ce8c9c0e5..dc3fa8e2c8f 100644 --- a/autotest/test_z03_largetests.py +++ b/autotest/test_z03_largetestmodels.py @@ -1,7 +1,8 @@ import os -import pytest import sys +import pytest + try: import pymake except: @@ -18,17 +19,17 @@ msg += " pip install flopy" raise Exception(msg) -from simulation import Simulation -from targets import get_mf6_version from common_regression import ( - get_home_dir, get_example_basedir, - is_directory_available, get_example_dirs, + get_home_dir, get_select_dirs, get_select_packages, + is_directory_available, set_mf6_regression, ) +from simulation import Simulation +from targets import get_mf6_version home = get_home_dir() @@ -61,7 +62,7 @@ def get_mf6_models(): # write a summary of the files to exclude print("list of tests to exclude:") for idx, ex in enumerate(exclude): - print(" {}: {}".format(idx + 1, ex)) + print(f" {idx + 1}: {ex}") # build list of directories with valid example files if example_basedir is not None: @@ -100,7 +101,7 @@ def get_mf6_models(): if len(example_dirs) < 1: msg = "Selected packages not available [" for pak in select_packages: - msg += " {}".format(pak) + msg += f" {pak}" msg += "]" print(msg) @@ -132,9 +133,9 @@ def set_make_comparison(test): make_comparison = True if test in compare_tests.keys(): version = get_mf6_version() - print("MODFLOW version='{}'".format(version)) + print(f"MODFLOW version='{version}'") version = get_mf6_version(version="mf6-regression") - print("MODFLOW regression version='{}'".format(version)) + print(f"MODFLOW regression version='{version}'") if version in compare_tests[test]: make_comparison = False return make_comparison @@ -162,7 +163,7 @@ def test_mf6model(exdir): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) # get a list of test models to run @@ -183,7 +184,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") delFiles = True for idx, arg in enumerate(sys.argv): diff --git a/autotest/update_flopy.py b/autotest/update_flopy.py index a1f168d1571..42db0b3539e 100644 --- a/autotest/update_flopy.py +++ b/autotest/update_flopy.py @@ -1,13 +1,13 @@ +import importlib import os import shutil import subprocess -import importlib from contextlib import contextmanager import flopy flopypth = flopy.__path__[0] -print("flopy is installed in {}".format(flopypth)) +print(f"flopy is installed in {flopypth}") @contextmanager @@ -53,7 +53,7 @@ def test_copy_dfn(): if "dfn" in ext: fpth0 = os.path.join(pth0, fn) fpth1 = os.path.join(pth1, fn) - print('copying {} from "{}" to "{}"'.format(fn, pth0, pth1)) + print(f'copying {fn} from "{pth0}" to "{pth1}"') shutil.copyfile(fpth0, fpth1) @@ -67,16 +67,16 @@ def test_create_packages(): # determine if createpackages.py exists fpth = os.path.join(pth, fn) - print('testing if "{}" exists'.format(fpth)) + print(f'testing if "{fpth}" exists') exist = os.path.isfile(fpth) - assert exist, '"{}" does not exist'.format(fpth) + assert exist, f'"{fpth}" does not exist' # run createrpackages.py script - print("running...{}".format(fn)) + print(f"running...{fn}") cmd = ["python", fn] buff, ierr = run_command(cmd, pth) - assert ierr == 0, "could not run {}".format(fn) - print("successfully ran...{}".format(fn)) + assert ierr == 0, f"could not run {fn}" + print(f"successfully ran...{fn}") # reload flopy print("reloading flopy") @@ -88,7 +88,7 @@ def test_create_packages(): def list_files(pth, exts=["py"]): - print("\nLIST OF FILES IN {}".format(pth)) + print(f"\nLIST OF FILES IN {pth}") files = [ entry for entry in os.listdir(pth) @@ -99,7 +99,7 @@ def list_files(pth, exts=["py"]): ext = os.path.splitext(fn)[1][1:].lower() if ext in exts: idx += 1 - print(" {:5d} - {}".format(idx, fn)) + print(f" {idx:5d} - {fn}") return @@ -115,10 +115,10 @@ def delete_files(files, pth, allow_failure=False, exclude=None): continue fpth = os.path.join(pth, fn) try: - print("removing...{}".format(fn)) + print(f"removing...{fn}") os.remove(fpth) except: - print("could not remove...{}".format(fn)) + print(f"could not remove...{fn}") if not allow_failure: return False return True @@ -148,7 +148,7 @@ def run_command(argv, pth, timeout=10): def main(): # write message tnam = os.path.splitext(os.path.basename(__file__))[0] - msg = "Running {} test".format(tnam) + msg = f"Running {tnam} test" print(msg) print("deleting existing MODFLOW 6 FloPy files") @@ -164,7 +164,7 @@ def main(): if __name__ == "__main__": - print("standalone run of {}".format(os.path.basename(__file__))) + print(f"standalone run of {os.path.basename(__file__)}") # run main routine main() diff --git a/code.json b/code.json index bc4a64f1664..d5e459ab30c 100755 --- a/code.json +++ b/code.json @@ -18,9 +18,9 @@ "email": "langevin@usgs.gov" }, "laborHours": -1, - "version": "6.3.0", + "version": "6.4.0", "date": { - "metadataLastUpdated": "2022-03-04" + "metadataLastUpdated": "2022-12-01" }, "organization": "U.S. Geological Survey", "permissions": { diff --git a/distribution/.fprettify.yaml b/distribution/.fprettify.yaml new file mode 100644 index 00000000000..c19702b116f --- /dev/null +++ b/distribution/.fprettify.yaml @@ -0,0 +1,9 @@ +# MODFLOW 6 configuration for fprettify +# run from root directory using +# fprettify -c distribution/.fprettify.yaml SRC +whitespace-plusminus: 1 +whitespace-multdiv: 1 +line-length: 82 +indent: 2 +enable-decl: true +strip-comments: true diff --git a/distribution/build_makefiles.py b/distribution/build_makefiles.py index af47d57a7a1..113729661af 100644 --- a/distribution/build_makefiles.py +++ b/distribution/build_makefiles.py @@ -1,6 +1,7 @@ import os import sys from contextlib import contextmanager + import pymake if sys.platform.lower() == "win32": @@ -34,7 +35,9 @@ def cwd(path): def run_makefile(target): - assert os.path.isfile("makefile"), f"makefile does not exist in {os.getcwd()}" + assert os.path.isfile( + "makefile" + ), f"makefile does not exist in {os.getcwd()}" base_target = os.path.basename(target) base_message = ( @@ -53,7 +56,9 @@ def run_makefile(target): assert return_code == 0, f"could not make '{base_target}'." + base_message - assert os.path.isfile(target), f"{base_target} does not exist." + base_message + assert os.path.isfile(target), ( + f"{base_target} does not exist." + base_message + ) # clean after successful make print(f"clean {base_target} with makefile") diff --git a/distribution/build_nightly.py b/distribution/build_nightly.py index db2056a154f..a59749dba60 100644 --- a/distribution/build_nightly.py +++ b/distribution/build_nightly.py @@ -1,13 +1,15 @@ import os -import sys +import pathlib import platform import shutil +import sys + import flopy import pymake # add path to build script in autotest directory and reuse mf6 build scripts sys.path.append(os.path.join("..", "autotest")) -from build_exes import build_mf6, build_mf6_so, build_mf5to6, build_zbud6 +from build_exes import meson_build # make sure exe extension is used on windows eext = "" @@ -16,7 +18,9 @@ eext = ".exe" soext = ".dll" -binpth, temppth = os.path.join("..", "bin"), os.path.join("temp") +bin_path = os.path.abspath(os.path.join("..", "bin")) +example_path = os.path.abspath(os.path.join("temp")) +zip_path = os.path.abspath(os.path.join("temp_zip")) def get_zipname(): @@ -28,8 +32,6 @@ def get_zipname(): elif zipname == "win32": if platform.architecture()[0] == "64bit": zipname = "win64" - - # return return zipname @@ -44,67 +46,67 @@ def relpath_fallback(pth): def create_dir(pth): # remove pth directory if it exists if os.path.exists(pth): - print("removing... {}".format(os.path.abspath(pth))) + print(f"removing... {os.path.abspath(pth)}") shutil.rmtree(pth) # create pth directory - print("creating... {}".format(os.path.abspath(pth))) + print(f"creating... {os.path.abspath(pth)}") os.makedirs(pth) - msg = "could not create... {}".format(os.path.abspath(pth)) + msg = f"could not create... {os.path.abspath(pth)}" assert os.path.exists(pth), msg - # return - return - def test_update_version(): from make_release import update_version update_version() - # return - return - def test_create_dirs(): - pths = [binpth, temppth] - - for pth in pths: + for pth in ( + bin_path, + zip_path, + ): create_dir(pth) - # return - return - - -def test_mf6(): - build_mf6() - -def test_libmf6(): - build_mf6_so() - - -def test_mf5to6(): - build_mf5to6() - - -def test_zbud6(): - build_zbud6() +def test_nightly_build(): + meson_build() + + # test if there are any executable files to zip + binpth_files = [ + os.path.join(bin_path, f) + for f in os.listdir(bin_path) + if os.path.isfile(os.path.join(bin_path, f)) + and shutil.which(os.path.join(bin_path, f), mode=os.X_OK) + and pathlib.Path(os.path.join(bin_path, f)).suffix + not in (".a", ".lib", ".pdb") + ] + if len(binpth_files) < 1: + raise FileNotFoundError( + f"No executable files present in {os.path.abspath(bin_path)}.\n" + + f"Available files:\n [{', '.join(os.listdir(bin_path))}]" + ) + else: + print(f"Files to zip:\n [{', '.join(binpth_files)}]") + + zip_pth = os.path.abspath(os.path.join(zip_path, get_zipname() + ".zip")) + print(f"Zipping files to '{zip_pth}'") + success = pymake.zip_all(zip_pth, file_pths=binpth_files) + assert success, f"Could not create '{zip_pth}'" def test_update_mf6io(): from mkdist import update_mf6io_tex_files - if not os.path.isdir(temppth): - os.makedirs(temppth) # build simple model name = "mymodel" - ws = os.path.join(temppth, name) + ws = os.path.join(example_path, name) exe_name = "mf6" if sys.platform.lower() == "win32": exe_name += ".exe" - exe_name = os.path.join(binpth, exe_name) + exe_name = os.path.join(bin_path, exe_name) sim = flopy.mf6.MFSimulation(sim_name=name, sim_ws=ws, exe_name=exe_name) tdis = flopy.mf6.ModflowTdis(sim) ims = flopy.mf6.ModflowIms(sim) @@ -121,33 +123,9 @@ def test_update_mf6io(): # update the mf6io simulation output for LaTeX update_mf6io_tex_files(None, exe_name, expth=ws) - # return - return - - -def test_zip_assets(): - # create temppth if it does not exist - if not os.path.isdir(temppth): - os.makedirs(temppth) - - # zip assets - env = "GITHUB_ACTIONS" - os.environ[env] = "true" - if env in os.environ: - fpth = get_zipname() + ".zip" - # zip up exe's using directories - zip_pth = os.path.join(temppth, fpth) - success = pymake.zip_all(zip_pth, dir_pths=binpth) - assert success, "could not create '{}'".format(zip_pth) - return - if __name__ == "__main__": test_update_version() test_create_dirs() - test_mf6() - test_libmf6() - test_mf5to6() - test_zbud6() + test_nightly_build() test_update_mf6io() - test_zip_assets() diff --git a/distribution/evaluate_run_times.py b/distribution/evaluate_run_times.py index daf80ba3f36..acc3d397401 100644 --- a/distribution/evaluate_run_times.py +++ b/distribution/evaluate_run_times.py @@ -1,17 +1,18 @@ import os -import sys -import flopy -import pymake import shutil import subprocess +import sys from multiprocessing import Pool +import flopy +import pymake + # Set VERIFY VERIFY = False # add path to build script in autotest directory and reuse mf6 build scripts sys.path.append(os.path.join("..", "autotest")) -from build_exes import build_mf6 +from build_exes import meson_build github_repo = "MODFLOW-USGS/modflow6" working_dir = "./temp/" @@ -29,7 +30,9 @@ def _get_version(): version = sys.argv[idx + 1] break if version is None: - version = pymake.repo_latest_version(github_repo=github_repo, verify=VERIFY) + version = pymake.repo_latest_version( + github_repo=github_repo, verify=VERIFY + ) return version @@ -75,17 +78,16 @@ def _get_previous_version(): def build_previous_version(pth): _del_version() - srcdir = os.path.join(pth, "src") - appdir = os.path.join(base_build_dir, "rebuilt") + appdir = os.path.abspath(os.path.join(base_build_dir, "rebuilt")) if not _is_dryrun(): - build_mf6(srcdir=srcdir, appdir=appdir) + meson_build(dir_path=pth, libdir=appdir) return os.path.abspath(os.path.join(appdir, f"mf6{app_ext}")) def build_current_version(): if not _is_dryrun(): - build_mf6(appdir=base_build_dir) + meson_build() return os.path.abspath(os.path.join(base_build_dir, f"mf6{app_ext}")) @@ -159,7 +161,9 @@ def revert_files(app, example): with open(fpth, "w") as f: for line in lines: if replace[0] in line.lower(): - line = line.lower().replace(replace[0], replace[1]) + line = line.lower().replace( + replace[0], replace[1] + ) f.write(line) return @@ -205,7 +209,9 @@ def elapsed_real_to_string(elt): def get_examples(): examples_repo = "MODFLOW-USGS/modflow6-examples" - version = pymake.repo_latest_version(github_repo=examples_repo, verify=VERIFY) + version = pymake.repo_latest_version( + github_repo=examples_repo, verify=VERIFY + ) print(f"current examples version: {version}") url = ( f"https://github.com/{examples_repo}" @@ -282,12 +288,16 @@ def run_model(app, app0, example, fmd, silent=True, pool=False): elt = get_elapsed_time(buff) line += f" {elt} |" else: + print(f"Failure for current app with example: {test}") + for b in buff: + print(b) line += " -- |" if success0: elt0 = get_elapsed_time(buff0) line += f" {elt0} |" else: + print(f"Failure for previous app with example: {test}") line += " -- |" if success and success0: diff --git a/distribution/make_release.py b/distribution/make_release.py index a8699f3cd5c..51865f5b0f3 100644 --- a/distribution/make_release.py +++ b/distribution/make_release.py @@ -46,12 +46,12 @@ """ -import subprocess -import os -import sys -import shutil import datetime import json +import os +import shutil +import subprocess +import sys from collections import OrderedDict # update files and paths so that there are the same number of @@ -71,8 +71,8 @@ if len(paths) != len(files): msg = ( "The number of entries in paths " - + "({}) must equal ".format(len(paths)) - + "the number of entries in files ({})".format(len(files)) + + f"({len(paths)}) must equal " + + f"the number of entries in files ({len(files)})" ) assert False, msg @@ -205,9 +205,9 @@ def get_branch(verbose=False): if verbose: print(line) if verbose: - print("On Branch: {}\n".format(branch)) + print(f"On Branch: {branch}\n") if stderr: - print("Errors:\n{}".format(stderr.decode("utf-8"))) + print(f"Errors:\n{stderr.decode('utf-8')}") if branch is not None: if "master" in branch or "release" in branch: @@ -223,13 +223,13 @@ def get_branch(verbose=False): def get_version_str(v0, v1, v2): - version_type = ("{}".format(v0), "{}".format(v1), "{}".format(v2)) + version_type = (f"{v0}", f"{v1}", f"{v2}") version = ".".join(version_type) return version def get_tag(v0, v1, v2): - tag_type = ("{}".format(v0), "{}".format(v1), "{}".format(v2)) + tag_type = (f"{v0}", f"{v1}", f"{v2}") tag = ".".join(tag_type) return tag @@ -268,10 +268,10 @@ def update_version(): # write new version file f = open(fpth, "w") f.write( - "# {} version file automatically ".format(prod) - + "created using...{}\n".format(os.path.basename(__file__)) + f"# {prod} version file automatically " + + f"created using...{os.path.basename(__file__)}\n" ) - f.write("# created on..." + "{}\n".format(now.strftime("%B %d, %Y %H:%M:%S"))) + f.write("# created on..." + f"{now.strftime('%B %d, %Y %H:%M:%S')}\n") f.write("\n") f.write(f"major = {vmajor}\n") f.write(f"minor = {vminor}\n") @@ -283,31 +283,33 @@ def update_version(): # update version.py in doc directory shutil.copyfile( os.path.abspath(fpth), - os.path.join("..", "doc", os.path.basename(fpth.replace(".txt", ".py"))), + os.path.join( + "..", "doc", os.path.basename(fpth.replace(".txt", ".py")) + ), ) # update latex version file version = get_version_str(vmajor, vminor, vmicro) version_type = get_version_type(get_branch()).strip() if len(version_type) > 0: - version += "---{}".format(version_type) + version += f"---{version_type}" pth = os.path.join(paths[1], files[1]) f = open(pth, "w") - line = "\\newcommand{\\modflowversion}{mf" + "{}".format(version) + "}" - f.write("{}\n".format(line)) + line = "\\newcommand{\\modflowversion}{mf" + f"{version}" + "}" + f.write(f"{line}\n") line = ( "\\newcommand{\\modflowdate}{" - + "{}".format(now.strftime("%B %d, %Y")) + + f"{now.strftime('%B %d, %Y')}" + "}" ) - f.write("{}\n".format(line)) + f.write(f"{line}\n") line = ( "\\newcommand{\\currentmodflowversion}" + "{Version \\modflowversion---\\modflowdate}" ) - f.write("{}\n".format(line)) + f.write(f"{line}\n") f.close() - print("Succesfully updated {}".format(files[1])) + print(f"Succesfully updated {files[1]}") except: msg = "There was a problem updating the version file" raise IOError(msg) @@ -393,17 +395,19 @@ def update_mf6_version(vmajor, vminor, vmicro): skip = False continue elif ":: IDEVELOPMODE =" in line: - line = " integer(I4B), parameter :: " + "IDEVELOPMODE = {}".format( - idevelopmode + line = ( + " integer(I4B), parameter :: " + + f"IDEVELOPMODE = {idevelopmode}" ) elif ":: VERSION =" in line: - line = " character(len=40), parameter :: " + "VERSION = '{}{}{}'".format( - version, version_type, sdate + line = ( + " character(len=40), parameter :: " + + "VERSION = '{}{}{}'".format(version, version_type, sdate) ) elif ":: FMTDISCLAIMER =" in line: line = disclaimerfmt skip = True - f.write("{}\n".format(line)) + f.write(f"{line}\n") f.close() return @@ -434,11 +438,11 @@ def update_readme_markdown(vmajor, vminor, vmicro): f = open(fpth, "w") for line in lines: if "## Version " in line: - line = "### Version {}".format(version) + line = f"### Version {version}" if "develop" in branch: line += sb # This has been commented out as we've generalized this reference. - #elif "https://doi.org/10.5066/F76Q1VQV" in line: + # elif "https://doi.org/10.5066/F76Q1VQV" in line: # line = ( # "[Langevin, C.D., Hughes, J.D., " # + "Banta, E.R., Provost, A.M., " @@ -454,7 +458,7 @@ def update_readme_markdown(vmajor, vminor, vmicro): elif "Disclaimer" in line: line = disclaimer terminate = True - f.write("{}\n".format(line)) + f.write(f"{line}\n") if terminate: break f.close() diff --git a/distribution/mkdist.py b/distribution/mkdist.py index 582237d63de..a6d25399f0d 100644 --- a/distribution/mkdist.py +++ b/distribution/mkdist.py @@ -24,13 +24,14 @@ import os -import sys import shutil import subprocess +import sys import zipfile +from contextlib import contextmanager + import pymake from pymake import download_and_unzip -from contextlib import contextmanager @contextmanager @@ -70,7 +71,7 @@ def get_distribution_info(versiontexname): def zipdir(dirname, zipname): - print("Zipping directory: {}".format(dirname)) + print(f"Zipping directory: {dirname}") zipf = zipfile.ZipFile(zipname, "w", zipfile.ZIP_DEFLATED) for root, dirs, files in os.walk(dirname): for file in files: @@ -90,13 +91,13 @@ def setup(name, destpath, version, subdirs): """ print(2 * "\n") - print("Setting up {} distribution: {}".format(name, version)) + print(f"Setting up {name} distribution: {version}") print("\n") dest = os.path.join(destpath, version) if os.path.exists(dest): # Raise Exception('Destination path exists. Kill it first.') - print("Clobbering destination directory: {}".format(dest)) + print(f"Clobbering destination directory: {dest}") print("\n") shutil.rmtree(dest) os.mkdir(dest) @@ -105,7 +106,7 @@ def setup(name, destpath, version, subdirs): folderdict = {} for sd in subdirs: fullpath = os.path.join(dest, sd) - print(" creating ==> {}".format(fullpath)) + print(f" creating ==> {fullpath}") os.mkdir(fullpath) folderdict[sd] = fullpath print("\n") @@ -122,10 +123,10 @@ def copytree(src, dst, symlinks=False, ignore=None): s = os.path.join(src, item) d = os.path.join(dst, item) if os.path.isdir(s): - print(" copying {} ===> {}".format(s, d)) + print(f" copying {s} ===> {d}") shutil.copytree(s, d, symlinks, ignore) else: - print(" copying {} ===> {}".format(s, d)) + print(f" copying {s} ===> {d}") shutil.copy2(s, d) return @@ -170,15 +171,17 @@ def change_version_module(fname, version): newline = line srchtxt = "character(len=40), parameter :: VERSION" if srchtxt in line: - newline = "{} = '{}'".format(srchtxt, version) + newline = f"{srchtxt} = '{version}'" found1 = True srchtxt = "integer(I4B), parameter :: IDEVELOPMODE" if srchtxt in line: - newline = "{} = {}".format(srchtxt, 0) + newline = f"{srchtxt} = {0}" found2 = True newlines.append(newline) if not found1 or not found2: - raise Exception("could not replace version or developmode in source code") + raise Exception( + "could not replace version or developmode in source code" + ) with open(fname, "w") as f: for line in newlines: f.write(line.strip() + "\n") @@ -251,7 +254,7 @@ def make_zonebudget(srcpath, destpath, win_target_os, exepath): flist = [os.path.join(srcpath, "msvs", "zonebudget.vfproj")] print("Copying zonebudget msvs files") for d in flist: - print(" {} ===> {}".format(d, fd["msvs"])) + print(f" {d} ===> {fd['msvs']}") shutil.copy(d, fd["msvs"]) print("\n") @@ -278,7 +281,7 @@ def make_zonebudget(srcpath, destpath, win_target_os, exepath): if win_target_os: target += ".exe" if not os.path.isfile(target): - raise Exception("Did not build target: {}".format(target)) + raise Exception(f"Did not build target: {target}") return @@ -326,14 +329,14 @@ def make_mf5to6(srcpath, destpath, win_target_os, exepath): for fname in ["makefile", "makedefaults"]: fpath = os.path.join(srcpath, "pymake", fname) d = os.path.join(srcpath, "make", fname) - print(" {} ===> {}".format(fpath, d)) + print(f" {fpath} ===> {d}") shutil.copyfile(fpath, d) # Copy makefile to distribution/xxx/utils/mf5to6/make folder for fname in ["makefile", "makedefaults"]: fpath = os.path.join(srcpath, "pymake", fname) d = os.path.join(fd["make"], fname) - print(" {} ===> {}".format(fpath, d)) + print(f" {fpath} ===> {d}") shutil.copyfile(fpath, d) # Remove makefile and makedefaults from the pymake folder @@ -345,7 +348,7 @@ def make_mf5to6(srcpath, destpath, win_target_os, exepath): flist = [os.path.join(srcpath, "msvs", "mf5to6.vfproj")] print("Copying mf5to6 msvs files") for d in flist: - print(" {} ===> {}".format(d, fd["msvs"])) + print(f" {d} ===> {fd['msvs']}") shutil.copy(d, fd["msvs"]) print("\n") @@ -372,7 +375,7 @@ def make_mf5to6(srcpath, destpath, win_target_os, exepath): if win_target_os: target += ".exe" if not os.path.isfile(target): - raise Exception("Did not build target: {}".format(target)) + raise Exception(f"Did not build target: {target}") return @@ -381,10 +384,10 @@ def delete_files(files, pth, allow_failure=False): for file in files: fpth = os.path.join(pth, file) try: - print("removing...{}".format(file)) + print(f"removing...{file}") os.remove(fpth) except: - print("could not remove...{}".format(file)) + print(f"could not remove...{file}") if not allow_failure: return False return True @@ -416,32 +419,32 @@ def clean_latex_files(): print("Cleaning latex files") exts = ["pdf", "aux", "bbl", "idx", "lof", "out", "toc"] pth = os.path.join("..", "doc", "mf6io") - files = ["mf6io.{}".format(e) for e in exts] + files = [f"mf6io.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") pth = os.path.join("..", "doc", "ReleaseNotes") - files = ["ReleaseNotes.{}".format(e) for e in exts] + files = [f"ReleaseNotes.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") pth = os.path.join("..", "doc", "zonebudget") - files = ["zonebudget.{}".format(e) for e in exts] + files = [f"zonebudget.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") pth = os.path.join("..", "doc", "ConverterGuide") - files = ["converter_mf5to6.{}".format(e) for e in exts] + files = [f"converter_mf5to6.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") pth = os.path.join("..", "..", "modflow6-docs.git", "mf6suptechinfo") - files = ["mf6suptechinfo.{}".format(e) for e in exts] + files = [f"mf6suptechinfo.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") pth = os.path.join("..", "..", "modflow6-examples.git", "doc") - files = ["mf6examples.{}".format(e) for e in exts] + files = [f"mf6examples.{e}" for e in exts] delete_files(files, pth, allow_failure=True) assert not os.path.isfile(pth + ".pdf") @@ -456,7 +459,11 @@ def rebuild_tex_from_dfn(): with cwd(npth): # get list of TeX files - files = [f for f in os.listdir("tex") if os.path.isfile(os.path.join("tex", f))] + files = [ + f + for f in os.listdir("tex") + if os.path.isfile(os.path.join("tex", f)) + ] for f in files: fpth = os.path.join("tex", f) os.remove(fpth) @@ -464,7 +471,7 @@ def rebuild_tex_from_dfn(): # run python argv = ["python", "mf6ivar.py"] buff, ierr = run_command(argv, pth) - msg = "\nERROR {}: could not run {} with {}".format(ierr, argv[0], argv[1]) + msg = f"\nERROR {ierr}: could not run {argv[0]} with {argv[1]}" assert ierr == 0, buff + msg # get list for dfn files @@ -485,13 +492,14 @@ def rebuild_tex_from_dfn(): for f in dfnfiles: if "common" in f: continue - fpth = "{}-desc".format(f) + fpth = f"{f}-desc" if fpth not in texfiles: icnt += 1 - missing += " {:3d} {}.tex\n".format(icnt, fpth) - msg = "\n{} TeX file(s) are missing. ".format( - icnt - ) + "Missing files:\n{}".format(missing) + missing += f" {icnt:3d} {fpth}.tex\n" + msg = ( + "\n{} TeX file(s) are missing. ".format(icnt) + + f"Missing files:\n{missing}" + ) assert icnt == 0, msg return @@ -509,8 +517,8 @@ def update_mf6io_tex_files(distfolder, mf6pth, expth=None): expth = os.path.join(distfolder, "examples", "ex-gwf-twri01") expth = os.path.abspath(expth) - assert os.path.isfile(mf6pth), "{} does not exist".format(mf6pth) - assert os.path.isdir(expth), "{} does not exist".format(expth) + assert os.path.isfile(mf6pth), f"{mf6pth} does not exist" + assert os.path.isdir(expth), f"{expth} does not exist" # run an example model if local: @@ -525,12 +533,12 @@ def update_mf6io_tex_files(distfolder, mf6pth, expth=None): buff, ierr = run_command(cmd, simpth) lines = buff.split("\r\n") with open(fname1, "w") as f: - f.write("{}\n".format("{\\small")) - f.write("{}\n".format("\\begin{lstlisting}[style=modeloutput]")) + f.write("{\\small\n") + f.write("\\begin{lstlisting}[style=modeloutput]\n") for line in lines: f.write(line.rstrip() + "\n") - f.write("{}\n".format("\\end{lstlisting}")) - f.write("{}\n".format("}")) + f.write("\\end{lstlisting}\n") + f.write("}\n") # run model without a namefile present if os.path.isdir("./temp"): @@ -540,24 +548,24 @@ def update_mf6io_tex_files(distfolder, mf6pth, expth=None): buff, ierr = run_command(cmd, "./temp") lines = buff.split("\r\n") with open(fname2, "w") as f: - f.write("{}\n".format("{\\small")) - f.write("{}\n".format("\\begin{lstlisting}[style=modeloutput]")) + f.write("{\\small\n") + f.write("\\begin{lstlisting}[style=modeloutput]\n") for line in lines: f.write(line.rstrip() + "\n") - f.write("{}\n".format("\\end{lstlisting}")) - f.write("{}\n".format("}")) + f.write("\\end{lstlisting}\n") + f.write("}\n") # run mf6 command with -h to show help cmd = [os.path.abspath(mf6pth), "-h"] buff, ierr = run_command(cmd, "./temp") lines = buff.split("\r\n") with open(fname3, "w") as f: - f.write("{}\n".format("{\\small")) - f.write("{}\n".format("\\begin{lstlisting}[style=modeloutput]")) + f.write("{\\small\n") + f.write("\\begin{lstlisting}[style=modeloutput]\n") for line in lines: f.write(line.rstrip() + "\n") - f.write("{}\n".format("\\end{lstlisting}")) - f.write("{}\n".format("}")) + f.write("\\end{lstlisting}\n") + f.write("}\n") # clean up if os.path.isdir("./temp"): @@ -584,7 +592,7 @@ def build_latex_docs(): shutil.copy(os.path.join(pth1, "version.tex"), pth2) for p, d, t in doclist: - print("Building latex document: {}".format(t)) + print(f"Building latex document: {t}") dirname = os.path.join(p, d) with cwd(dirname): @@ -598,25 +606,25 @@ def build_latex_docs(): print(" Pass 1/4...") cmd = pdflatexcmd buff, ierr = run_command(cmd, "./") - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg cmd = ["bibtex", os.path.splitext(t)[0] + ".aux"] print(" Pass 2/4...") buff, ierr = run_command(cmd, "./") - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg print(" Pass 3/4...") cmd = pdflatexcmd buff, ierr = run_command(cmd, "./") - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg print(" Pass 4/4...") cmd = pdflatexcmd buff, ierr = run_command(cmd, "./") - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg fname = os.path.splitext(t)[0] + ".pdf" @@ -633,16 +641,18 @@ def update_latex_releaseinfo(examples_folder): cmd = ["python", "mk_folder_struct.py"] buff, ierr = run_command(cmd, pth) - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg cmd = ["python", "mk_runtimecomp.py"] buff, ierr = run_command(cmd, pth) - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg for f in files: - assert os.path.isfile(os.path.join(pth, f)), "File does not exist: " + f + assert os.path.isfile(os.path.join(pth, f)), ( + "File does not exist: " + f + ) return @@ -674,7 +684,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): "--destination", dest, ] # no run no plot - print("running {} in {}".format(argv, scripts_folder)) + print(f"running {argv} in {scripts_folder}") run_command(argv, scripts_folder) # create list of folders with mfsim.nam @@ -689,7 +699,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): # go through each simulation folder and add a run.bat file for dwpath in simulation_folders: fname = os.path.join(dwpath, "run.bat") - print("Adding {}".format(fname)) + print(f"Adding {fname}") with open(fname, "w") as f: f.write("@echo off" + "\n") runbatloc = os.path.relpath(mf6path, start=dwpath) @@ -703,12 +713,12 @@ def setup_examples(examples_repo, exdestpath, mf6path): with open(fname, "w") as f: for dwpath in simulation_folders: d = os.path.relpath(dwpath, start=exdestpath) - s = "cd {}".format(d) + s = f"cd {d}" f.write(s + "\n") runbatloc = os.path.relpath(mf6path, start=dwpath) f.write(runbatloc + "\n") d = os.path.relpath(exdestpath, start=dwpath) - s = "cd {}".format(d) + s = f"cd {d}" f.write(s + "\n") s = "" f.write(s + "\n") @@ -752,7 +762,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): ] print("Copying msvs files") for d in flist: - print(" {} ===> {}".format(d, fd["msvs"])) + print(f" {d} ===> {fd['msvs']}") shutil.copy(d, fd["msvs"]) print("\n") @@ -795,7 +805,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): # Copy makefile to the distribution for fname in ["makefile", "makedefaults"]: fpath = os.path.join(makedir, fname) - print(" {} ===> {}".format(fpath, fd["make"])) + print(f" {fpath} ===> {fd['make']}") shutil.copy(fpath, fd["make"]) # build MODFLOW 6 executable @@ -811,7 +821,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): if win_target_os: target += ".exe" if not os.path.isfile(target): - raise Exception("Did not build target: {}".format(target)) + raise Exception(f"Did not build target: {target}") # setup zone budget make_zonebudget( @@ -839,7 +849,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): cmd = ["python", "evaluate_run_times.py"] pth = "." buff, ierr = run_command(cmd, pth) - msg = "\nERROR {}: could not run {} on {}".format(ierr, cmd[0], cmd[1]) + msg = f"\nERROR {ierr}: could not run {cmd[0]} on {cmd[1]}" assert ierr == 0, buff + msg # Clean and then remake latex docs @@ -876,7 +886,9 @@ def setup_examples(examples_repo, exdestpath, mf6path): "mf6suptechinfo.pdf", ], [ - os.path.join("..", "..", "modflow6-examples.git", "doc", "mf6examples.pdf"), + os.path.join( + "..", "..", "modflow6-examples.git", "doc", "mf6examples.pdf" + ), "mf6examples.pdf", ], ] @@ -884,7 +896,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): print("Copying documentation") for din, dout in doclist: dst = os.path.join(fd["doc"], dout) - print(" copying {} ===> {}".format(din, dst)) + print(f" copying {din} ===> {dst}") shutil.copy(din, dst) print("\n") @@ -894,7 +906,7 @@ def setup_examples(examples_repo, exdestpath, mf6path): "https://pubs.usgs.gov/tm/06/a55/tm6a55.pdf", "https://pubs.usgs.gov/tm/06/a56/tm6a56.pdf", ]: - print(" downloading {}".format(url)) + print(f" downloading {url}") download_and_unzip(url, pth=fd["doc"], delete_zip=False, verify=False) print("\n") @@ -908,9 +920,9 @@ def setup_examples(examples_repo, exdestpath, mf6path): uflag = "" zipname = version + uflag + ".zip" if os.path.exists(zipname): - print("Removing existing file: {}".format(zipname)) + print(f"Removing existing file: {zipname}") os.remove(zipname) - print("Creating zipped file: {}".format(zipname)) + print(f"Creating zipped file: {zipname}") zipdir(distfolder, zipname) print("\n") diff --git a/doc/Common/gwt-lktobs.tex b/doc/Common/gwt-lktobs.tex index 706088b0269..637dbcf3d49 100644 --- a/doc/Common/gwt-lktobs.tex +++ b/doc/Common/gwt-lktobs.tex @@ -14,7 +14,7 @@ LKT & runoff & lakeno or boundname & -- & Runoff rate applied to a lake or group of lakes multiplied by the runoff concentration. \\ LKT & ext-inflow & lakeno or boundname & -- & Mass inflow into a lake or group of lakes calculated as the external inflow rate multiplied by the inflow concentration. \\ LKT & withdrawal & lakeno or boundname & -- & Specified withdrawal rate from a lake or group of lakes multiplied by the simulated lake concentration. \\ -LKT & ext-outflow & outletno or boundname & -- & External outflow from a lake outlet, a lake, or a group of lakes to an external boundary. If boundname is not specified for ID, then the external outflow from a specific lake outlet is observed. In this case, ID is the outlet number outletno. +LKT & ext-outflow & lakeno or boundname & -- & External outflow from a lake or a group of lakes, through their outlets, to an external boundary. If the water mover is active, the reported ext-outflow value plus the rate to mover is equal to the total outlet outflow. %LKT & outlet-inflow & lakeno or boundname & -- & Simulated inflow from upstream lake outlets into a lake or group of lakes. \\ %LKT & inflow & lakeno or boundname & -- & Sum of specified inflow and simulated inflow from upstream lake outlets into a lake or group of lakes. \\ diff --git a/doc/Common/gwt-sftobs.tex b/doc/Common/gwt-sftobs.tex index da0b3e7687d..7e1da8f9af0 100644 --- a/doc/Common/gwt-sftobs.tex +++ b/doc/Common/gwt-sftobs.tex @@ -5,7 +5,7 @@ SFT & constant & rno or boundname & -- & Simulated mass constant-flow rate for a reach or group of reaches. \\ SFT & from-mvr & rno or boundname & -- & Simulated mass inflow into a reach or group of reaches from the MVT package. Mass inflow is calculated as the product of provider concentration and the mover flow rate. \\ SFT & to-mvr & rno or boundname & -- & Mass outflow from a reach, or a group of reaches that is available for the MVR package. If boundname is not specified for ID, then the outflow available for the MVR package from a specific reach is observed. \\ -SFT & sft & rno or boundname & \texttt{iconn} or -- & Mass flow rate for a reach or group of reaches and its aquifer connection(s). If boundname is not specified for ID, then the simulated reach-aquifer flow rate at a specific reach connection is observed. In this case, ID2 must be specified and is the connection number \texttt{iconn} for reach \texttt{rno}. \\ +SFT & sft & rno or boundname & -- & Mass flow rate for a reach or group of reaches and its aquifer connection(s). \\ %observations specific to the stream transport package % rainfall evaporation runoff ext-inflow withdrawal outflow diff --git a/doc/Common/gwt-uztobs.tex b/doc/Common/gwt-uztobs.tex index 36d4e86f55f..917b46b54a3 100644 --- a/doc/Common/gwt-uztobs.tex +++ b/doc/Common/gwt-uztobs.tex @@ -2,12 +2,13 @@ UZT & concentration & uztno or boundname & -- & uzt cell concentration. If boundname is specified, boundname must be unique for each uzt cell. \\ UZT & flow-ja-face & uztno or boundname & uztno or -- & Mass flow between two uzt cells. If a boundname is specified for ID1, then the result is the total mass flow for all uzt cells. If a boundname is specified for ID1 then ID2 is not used.\\ UZT & storage & uztno or boundname & -- & Simulated mass storage flow rate for a uzt cell or group of uzt cells. \\ +UZT & constant & uztno or boundname & -- & Simulated mass constant-flow rate for a uzt cell or a group of uzt cells. \\ UZT & from-mvr & uztno or boundname & -- & Simulated mass inflow into a uzt cell or group of uzt cells from the MVT package. Mass inflow is calculated as the product of provider concentration and the mover flow rate. \\ -UZT & uzt & uztno or boundname & \texttt{iconn} or -- & Mass flow rate for a uzt cell or group of uzt cells and its aquifer connection(s). If boundname is not specified for ID, then the simulated uzt-aquifer flow rate at a specific uzt cell connection is observed. In this case, ID2 must be specified and is the connection number for the uzt cell. \\ +UZT & uzt & uztno or boundname & -- & Mass flow rate for a uzt cell or group of uzt cells and its aquifer connection(s). \\ %observations specific to the uzt package % infiltration rej-inf uzet rej-inf-to-mvr UZT & infiltration & uztno or boundname & -- & Infiltration rate applied to a uzt cell or group of uzt cells multiplied by the infiltration concentration. \\ UZT & rej-inf & uztno or boundname & -- & Rejected infiltration rate applied to a uzt cell or group of uzt cells multiplied by the infiltration concentration. \\ UZT & uzet & uztno or boundname & -- & Unsaturated zone evapotranspiration rate applied to a uzt cell or group of uzt cells multiplied by the uzt cell concentration. \\ -UZT & infiltration & uztno or boundname & -- & Rejected infiltration rate applied to a uzt cell or group of uzt cells multiplied by the infiltration concentration that is sent to the mover package. \\ +UZT & rej-inf-to-mvr & uztno or boundname & -- & Rejected infiltration rate applied to a uzt cell or group of uzt cells multiplied by the infiltration concentration that is sent to the mover package. \\ diff --git a/doc/MODFLOW6References.bib b/doc/MODFLOW6References.bib index db6303c1e6e..ebd845d7ab0 100644 --- a/doc/MODFLOW6References.bib +++ b/doc/MODFLOW6References.bib @@ -494,7 +494,7 @@ @book{Voss1984sutra Date-Added = {2019-08-29 15:00:00 -0600}, Date-Modified = {2019-08-29 15:00:00 -0600}, Series = {{U.S. Geological Survey Water-Resources Investigations Report 84--4369, 409 p.}}, - Title = {SUTRA---a finite-element simulation model for saturated-unsaturated fluid-density-dependent ground-water flow with energy transport or chemically-reactive single-species solute transport}, + Title = {SUTRA---A finite-element simulation model for saturated-unsaturated fluid-density-dependent ground-water flow with energy transport or chemically-reactive single-species solute transport}, Year = {1984}} @article{VossSouza1987, @@ -597,6 +597,34 @@ @book{langevin2002seawat Year = {2002}, Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/tm6A22}} +@article{diersch2002viscosity, + Author = {Diersch, Hans-Jorg G and Kolditz, Olaf}, + Date-Added = {2022-09-27 11:58:19 -0500}, + Date-Modified = {2022-09-27 12:00:01 -0500}, + Journal = {Advances in Water Resources}, + Pages = {899--944}, + Title = {Variable-density flow and transport in porous media: Approaches and challenges}, + Url = {https://www.sciencedirect.com/science/article/pii/S0309170802000635}, + doi = {https://doi.org/10.1016/S0309-1708(02)00063-5}, + Urldate = {September 27, 2022}, + Volume = {25}, + number = {8}, + Year = {2002}, + issn = {0309-1708}, + Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/tm6A22}} + +@book{kipp1987, + Author = {Kipp, Kenneth L}, + Date-Added = {2022-09-27 11:58:19 -0500}, + Date-Modified = {2022-09-27 12:00:01 -0500}, + Institution = {U.S. Geological Survey}, + Series = {{U.S. Geological Survey Water-Resources Investigation Report 86-4095, 517 p.}}, + Title = {HST3D: A Computer Code for Simulation of Heat and Solute Transport in Three-Dimensional Ground-Water Flow Systems}, + Url = {https://pubs.usgs.gov/wri/1986/4095/report.pdf}, + Urldate = {September 27, 2022}, + Year = {1987}, + Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/wri864095}} + @book{langevin2008seawat, Author = {Langevin, Christian D and Thorne Jr, Daniel T and Dausman, Alyssa M and Sukop, Michael C and Guo, Weixing}, Date-Added = {2019-07-25 11:53:50 -0500}, @@ -2855,3 +2883,38 @@ @book{vs2d Urldate = {June 27, 2017}, Year = {1987}, Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/wri834099}} + +@book{healy1996, + Author = {Healy, Richard W and Ronan, Ann D}, + Date-Added = {2022-09-27 11:58:19 -0500}, + Date-Modified = {2022-09-27 12:00:01 -0500}, + Institution = {U.S. Geological Survey}, + Series = {{U.S. Geological Survey Water-Resources Investigation Report 96-4230, 36 p.}}, + Title = {Documentation of Computer Program VS2DH for Simulation of Energy Transport in Variably Saturated Porous Media: Modification of the U.S. Geological Survey's Computer Program VS2DT}, + Doi = {10.3133/wri964230}, + Url = {https://pubs.usgs.gov/wri/1996/4230/report.pdf}, + Urldate = {September 27, 2022}, + Year = {1996}, + Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/wri964230}} + +@book{hughes2004, + Author = {Hughes, Joseph D and Sanford, Ward E}, + Date-Added = {2019-10-11 15:42:15 -0400}, + Date-Modified = {2019-10-11 15:46:29 -0400}, + Doi = {10.3133/ofr20041207}, + Url = {https://water.usgs.gov/nrp/gwsoftware/SutraMS/OFR2004-1207.pdf}, + Series = {{U.S. Geological Survey Open File Report 2004--1207, 141 p.}}, + Title = {SUTRA-MS: A version of SUTRA modified to simulate heat and multiple-solute transport}, + Urldate = {September 27, 2022}, + Year = {2004}, + Bdsk-Url-1 = {https://pubs.er.usgs.gov/publication/ofr20041207}} + +@book{maidment1993, + Author = {Maidment, David R}, + Date-Added = {2022-10-11 15:42:15 -0400}, + Date-Modified = {2022-10-11 15:46:29 -0400}, + Isbn = {0-07-039732-5}, + Publisher = {McGraw-Hill}, + Address = {New York, USA}, + Title = {Handbook of Hydrology}, + Year = {1993}} diff --git a/doc/ReleaseNotes/ReleaseNotes.tex b/doc/ReleaseNotes/ReleaseNotes.tex index 000db2269e7..7a7af6854ce 100644 --- a/doc/ReleaseNotes/ReleaseNotes.tex +++ b/doc/ReleaseNotes/ReleaseNotes.tex @@ -157,22 +157,23 @@ \section{Release History} \begin{center} \caption{List of MODFLOW 6 Releases} \small -\begin{tabular*}{12cm}{cl} +\begin{tabular*}{13cm}{cll} \hline \hline -\textbf{MODFLOW Version} & \textbf{Date}\\ +\textbf{MODFLOW Version} & \textbf{Date} & \textbf{Digital Object Identifier}\\ \hline -6.0.0 & August 11, 2017 \\ -6.0.1 & September 28, 2017 \\ -6.0.2 & February 23, 2018 \\ -6.0.3 & August 9, 2018 \\ -6.0.4 & March 7, 2019 \\ -6.1.0 & December 12, 2019 \\ -6.1.1 & June 12, 2020 \\ -6.2.0 & October 20, 2020 \\ -6.2.1 & February 18, 2021 \\ -6.2.2 & July 30, 2021 \\ -6.3.0 & March 4, 2022 (this release) \\ +6.0.0 & August 11, 2017 & \url{https://doi.org/10.5066/F76Q1VQV} \\ +6.0.1 & September 28, 2017 & same as above \\ +6.0.2 & February 23, 2018 & same as above \\ +6.0.3 & August 9, 2018 & same as above \\ +6.0.4 & March 7, 2019 & same as above \\ +6.1.0 & December 12, 2019 & same as above \\ +6.1.1 & June 12, 2020 & same as above \\ +6.2.0 & October 20, 2020 & same as above \\ +6.2.1 & February 18, 2021 & same as above \\ +6.2.2 & July 30, 2021 & same as above \\ +6.3.0 & March 4, 2022 & \url{https://doi.org/10.5066/P97FFF9M} \\ +6.4.0 & November 30, 2022 & \url{https://doi.org/10.5066/P9FL1JCC} \\ \hline \label{tab:releases} \end{tabular*} @@ -187,60 +188,79 @@ \section{Changes Introduced in this Release} \begin{itemize} - \item Version mf6.3.0--March 4, 2022 + %\item Version mf6.x.x--Month xx, 202x + \item Version mf6.4.0--November 30, 2022 \underline{NEW FUNCTIONALITY} \begin{itemize} - \item New publications describing MODFLOW~6 were released, including \cite{modflow6api}, \cite{modflow6gwt}, and \cite{modflow6csub}. - \item The GWF-GWF Exchange was updated to support XT3D flow calculations along the edges of connected GWF Models. The XT3D flow calculation is an alternative to the ghost-node correction and has been shown to provide accurate flow calculations for cell connections that do not meet the control-volume finite-difference requirements. This new capability allows the GWF-GWF Exchange to tightly couple a wide variety of parent and child grid configurations. The new XT3D option for the GWF-GWF Exchange can be activated by specifying XT3D in the options block of the GWF-GWF Exchange input file. The XT3D implementation for GWF-GWF is based on a new generalized coupling method that is described in the Supplemental Technical Information document distributed with this release. - \item A new capability was added to support tight coupling of GWT Models through a new GWT-GWT Exchange. The new GWT-GWT Exchange can be used to connect any two GWT Models in a manner similar to the GWF-GWF Exchange. This allows transport to be represented from one GWT Model to another. The GWT-GWT Exchange calculates advective and dispersive fluxes and also supports the Mover Transport (MVT) Package. This first release of the GWT-GWT Exchange is limited to simulations in which the corresponding GWF Models and GWF-GWF Exchanges are run concurrently within the same simulation; the new capability does not support simulation of transport using groundwater flows saved from a previous simulation; however, this may be supported in the future. The new GWT-GWT functionality is activated by creating a GWT-GWT input file and specifying a GWT6-GWT6 exchange in the EXCHANGEDATA block of the simulation name file (mfsim.nam). The GWT-GWT Exchange is based on a new generalized coupling method that is described in the Supplemental Technical Information document distributed with this release. - \item This release introduces the Time-Varying hydraulic conductivity (TVK) and the Time-Varying Storage (TVS) options for the Node Property Flow (NPF) and Storage (STO) Packages, respectively, of the GWF Model. The TVK option is activated by specifying the TVK6 keyword in the OPTIONS block of the NPF Package and by providing a TVK6 input file. The TVS option is activated by specifying the TVS6 keyword in the OPTIONS block of the STO Package, and by providing a TVS6 input file. The TVK6 and TVS6 input files are described in input and output guide (mf6io.pdf). Technical information about the TVK and TVS options is provided in the Supplemental Technical Information report that is provided with the distribution. - \item The option already existed to provide binary budget and head file information from a GWF simulation for only the first time step of a given stress period, in which case that information will be used for all time steps in that stress period in a GWT simulation that reads from those files. The behavior of this option has been extended such that if the binary budget and head file information provided for the final stress period of the GWF simulation is for only one time step, that information will be used for any subsequent time steps and stress periods in the GWT simulation. This extended behavior includes as a special case the use of binary budget and head file information from only one time step in only one stress period (for example, a single steady-state GWF stress period) for all time steps in all stress periods in a GWT simulation. - \item Added new file-based input capability for the GWT Source and Sink Mixing (SSM) Package. The SSM Package previously required that all source and sink concentrations be provided as auxiliary variables for corresponding GWF stress packages. The SSM Package now supports an optional new FILEINPUT block, which can be provided with package names and file names. Files referenced in the FILEINPUT block can be used to provide time-varying source and sink concentrations. Descriptions for this new capability are described in the input and output guide (mf6io.pdf) under the GWT SSM Package, and the GWT Stress Package Concentrations (SPC) for list-based input and array-based input. If used, a single SPC6 input file can be provided for a corresponding GWF stress package. Either an SPC6 input file or the auxiliary variable approach can be used to supply concentrations for a single GWF stress package, but not both. - \item Added BUDGETCSV option to GWF and GWT model output control and to advanced packages (SFR, LAK, MAW, UZF, MVR, SFT, LKT, MWT, UZT, and MVT) that produce summary tables of budget information. If activated, this option will cause a comma-separated value (CSV) file of the model budget terms to be written to a user-specified output file. These output CSV files can be easily read into a spreadsheet or scripting language for plotting of budget terms. - \item Added option to use irregular cross sections to define the reach geometry for individual reaches in the SFR Package. Cross-section data for irregular cross-sections are defined in a separate Cross-Section Table Input File. The station-elevation data for an irregular cross section are specified as xfraction and height data, which is converted to station position using the specified reach width (RWID) and elevation using the specified bottom elevation of the reach (RTP). Manning's roughness coefficient fractions can optionally be specified with the xfraction-height data for a irregular cross section to represent roughness coefficient variations in a channel (for example, different channel and overbank Manning's roughness coefficients). SFR Package irregular cross sections and the method used to solve for streamflow in a reach with non-uniform Manning's roughness coefficients is a generalization of the methods used for 8-point cross-sections in the SFR Package for previous versions of MODFLOW \citep{modflowsfr1pack}. + \item A new Viscosity (VSC) package for the Groundwater Flow (GWF) Model is introduced in this release. The effects of viscosity are accounted for by updates to intercell conductance, as well as the conductance between the aquifer and head-dependent boundaries, based on simulated concentrations and\/or temperatures. The VSC Package is activated by specifying ``VSC6'' as the file type in a GWF name file. Changes to the code and input may be required in the future in response to user needs and testing. Implementation details for the VSC Package are described in the Supplemental Technical Information guide, which is included with the MODFLOW 6 distribution. For this first implementation, the VSC Package cannot be used for a GWF Model that is connected to another GWF Model with a GWF-GWF Exchange. + % \item xxx + % \item xxx \end{itemize} - + \underline{EXAMPLES} \begin{itemize} - \item A new example, ex-gwtgwt-mt3dms-p10, was added to demonstrate the new GWT-GWT Exchange. + \item A new example called ex-gwt-stallman was added. This new problem uses the GWT Model as a surrogate for simulating heat flow. The example represents one-dimensional heat convection and conduction in the subsurface in response to a periodic temperature boundary condition imposed at land surface. Results from the MODFLOW 6 simulation are in good agreement with an analytical solution. + % \item xxx + % \item xxx \end{itemize} \textbf{\underline{BUG FIXES AND OTHER CHANGES TO EXISTING FUNCTIONALITY}} \\ \underline{BASIC FUNCTIONALITY} \begin{itemize} - \item Fixed a bug that caused the last binary budget and head file information provided by a GWF simulation in a given stress period to be used for all subsequent GWT simulation time steps in that stress period, even if binary budget and head file information was provided for more than one time step in that stress period. In that situation, the GWF time steps must match the GWT time steps one-for-one. - \item Boundary packages, such as WEL, DRN and GHB, for example, read lists of data using a general list reader. For text input, the list of data would not be read correctly if it was longer than 300 characters wide. Most lists would normally be less than 300 characters unless a large number of auxiliary variables were specified. In this case, information beyond 300 characters would not be read. The list reader was modified to use an unlimited character length so that any number of auxiliary variables can be specified. - \item The Observation (OBS) functionality can optionally write simulated values to a comma-separated value (CSV) output file. The OBS input file contains a DIGITS option, which controls the number of digits written to the CSV output file. In some cases the ``E'' character was not written, making it difficult to read the CSV output file with other programs. New functionality was programmed to write observations using the maximum number of digits stored internally by the program using the G0 Fortran specifier. The default value for DIGITS was five, but this has been changed to this maximum number of digits. This maximum number of digits can also be activated by specifying a zero for DIGITS. For most applications, observations should be written with the default number of digits so that no precision is lost in the output. - \item Added a check to the Flow Model Interface (FMI) Package of the GWT Model that will cause the program to terminate with an error if flow and budget files needed from a flow model cannot be located. - \item The Output Control Package did not correctly determine if the end of a stress period was reached if the Adaptive Time Stepping (ATS) option was active. Output Control works correctly now with ATS. - \item Budget information for individual boundary package entries can be written to the model list file in a table form. The table no longer includes boundaries that are in cells that are dry. - \item When the simulated concentration in a cell is negative, which can occur due to the numerical methods used to solve the transport equation, then any sinks present in the cell should not add or remove mass. The program was modified so that transport through sinks is deactivated if the simulated concentration in a cell is negative. - \item Parsing of observation input was corrected so that observation names can have spaces if the observation name is enclosed in quotations. - \item The GWF Node Property Flow (NPF) Package can optionally calculate the three components of specific discharge. The program calculates these components using an interpolation method based on the XT3D method, the simulated flows across each cell face, and distances from the center of the cell to each cell face. This release contains a fix for a coding error in the calculation of the distance from the center of the cell to the cell face. The fix will affect the calculated specific discharge for model grids that have variable cell sizes. Because specific discharge is used in the calculation of the dispersion coefficients for GWT Models, simulated concentrations with this release may be different from simulated concentrations from previous releases; however, these concentration differences are expected to be minor. + \item Corrected programming error in XT3D functionality that could affect coupled flow models or coupled transport models. The XT3D code would result in a memory access error when a child model with a much larger level of refinement was coupled to a coarser parent model. The XT3D code was generalized to handle this situation. + \item Corrected a programming error in which the final message would be written twice to the screen and twice to mfsim.lst when the simulation terminated prematurely. + \item Terminate with error if METHOD or METHODS not specified in time series input files. Prior to this change, the program would continue without an interpolated value for one or more time series records. + \item When a GWF Model and a corresponding GWT model are solved in the same simulation, the GWF Model must be solved before the corresponding GWT model. The GWF Model must also be solved by a different IMS than the GWT Model. There was not a check for this in previous versions and if these conditions were not met, the solution would often not converge or it would give erroneous results. + \item The DISV Package would not raise an error if a model cell was defined as a line. The program was modified to check for the case where the calculated cell area is equal to zero. If the calculated cell area is equal to zero, the program terminates with an error. + \item When searching for a required block in an input file, the program would not terminate with a sensible error message if the end of file was found instead of the required block. Program now indicates that the required block was not found. + \item This release contains a first step toward implementation of generic input routines to read input files. The new input routines were implemented for the DIS, DISV, and DISU Packages of the GWF and GWT Models, for the NPF Package of the GWF Model, and the DSP Package of the GWT Model. Output summaries written to the GWF and GWT Model listing files are different from summaries written using previous versions of MODFLOW 6. For packages that use the new input data model, the IPRN capability of the READARRAY utility (described in mf6io.pdf) is no longer supported as a way to write input arrays to the model listing file. The IPRN capability may not be supported in future versions as the new generic input routines are implemented for other packages. + \item Corrected an error in ZONEBUDGET for MODFLOW 6 that prevented the program from running properly in workspaces that contain one or more spaces in the path. + \end{itemize} + + \underline{INTERNAL FLOW PACKAGES} + \begin{itemize} + \item Corrected programming error in the Time-Variable Hydraulic Conductivity (TVK) Package in which the vertical hydraulic conductivity was not reset properly if the K33OVERK option was invoked in the Node Property Flow (NPF) Package. + \item The Node Property Flow (NPF) Package had an error in how the saturated thickness at the interface between two cells was calculated for a DISU connection that is marked as vertically staggered (IHC = 2). The calculation was corrected so that the thickness for two confined cells is based on the overlap of the cells rather than the average thickness of the two cells. + % \item xxx \end{itemize} \underline{STRESS PACKAGES} \begin{itemize} - \item Fixed a bug in the Recharge (RCH) and Evapotranspiration (EVT) Packages that would occur with array-based input (READASARRAYS) combined with the Time-Array Series (TAS) functionality. Because the TAS functionality only works for DIS and DISV models, this fix does not have any effect on models that use DISU discretization. The bug would occur when one or more cells in the upper layer were removed using the IDOMAIN capability. In this special case, the time-array series values did not carry over to the correct locations in the RCH and EVT arrays. This error would be difficult to identify for complex models, because the model would run to completion without any errors. The RCH and EVT Packages were modified to maintain direct correspondence between the \texttt{nodelist} and \texttt{bound} arrays with the arrays provided to the TAS utility. A small and intended consequence of this fix is that the ID2 value written to the binary budget file for array-based RCH and EVT Packages will correspond to the consecutive cell number in the top layer. - \item Recharge and evapotranspiration flows that are written to the GWF Model binary budget file are marked with the text headers ``RCH'' and ``EVT'', respectively. In order to support the array-based input for SSM concentrations, these text headers are marked as ``RCHA'' and ``EVTA'', respectively, if the READASARRAYS option is specified for the package. This change will have no effect on simulation results; however, post processing capabilities may need to be adjusted to account for this minor renaming convention. - \item When the PRINT\_FLOWS option was used with the Source and Sink Mixing (SSM) Package, the cell ID numbers written to the listing file were incorrect. The SSM Package was fixed to output the correct cell ID. - \item Add new AUTO\_FLOW\_REDUCE\_CSV option for the Well Package. If activated, then this option will result in information being written to a comma-separated value file for each well and for each time step in which the extraction rate is reduced. Well extraction rates can be reduced for some groundwater conditions if the AUTO\_FLOW\_REDUCE option is activated. Information is not written for wells in which the extraction rate is equal to the user-specified extraction rate. + \item The Evapotranspiration (EVT) Package was modified to include a new error check if the segmented evapotranspiration capability is active. If the number of ET segments is greater than 1, then the user must specify values for PXDP (as well as PETM). For a cell, PXDP is a one-dimensional array of size NSEG - 1. Values in this array must be greater than zero and less than one. Furthermore, the values in PXDP must increase monotonically. The program now checks for these conditions and terminates with an error if these conditions are not met. The segmented ET capability can be used for list-based EVT Package input. Provided that the PXDP conditions are met, this new error check should have no effect on simulation results. + \item The Evapotranspiration (EVT) Package would throw an index error when SURF\_RATE\_SPECIFIED was specified in the OPTIONS block and NSEG was set equal to 1. The code now supports this combination of input options. + % \item xxx + % \item xxx \end{itemize} \underline{ADVANCED STRESS PACKAGES} \begin{itemize} - \item The Streamflow Routing (SFR) Package would terminate with a floating point error when calculating the stream depth as a function of flow rate, if the flow rate was slightly negative. Added a conditional check to ensure that the stream depth is calculated as zero if the calculated flow rate is zero or less. + \item When the LAK Package was used with a combination of outlets that routed water to another lake and outlets that did not, then the budget information stored for the LAK Package had uninitialized records for LAK to LAK flows. These uninitialized records were used by the LKT Package and possibly other programs. The LAK to LAK budget information was modified to include only valid records. + \item When a WITHDRAWAL value was specified for lakes, only the withdrawal value for the last lake would be reported in budget files, lake budget tables, and in lake withdrawal observations. This error would also be propagated to the GWT Lake Transport (LKT) Package, if active. This error would only show up for models with more than one lake and if the lake withdrawal term was included. + \item When lakes were assigned with the STATUS CONSTANT setting to prescribe the lake stage, the CONSTANT term used in the lake budget table was tabulated using an incorrect sign for aquifer leakage. This error would result in inaccurate budget tables. The program modified to use the correct leakage values for calculating the CONSTANT term. + \item There were several problems in the observation utility for the Streamflow Transport (SFT), Lake Transport (LKT), Multi-Aquifer Well Transport (MWT), and Unsaturated Zone Transport (UZT) Packages. These issues were corrected as well as the descriptions for the observations in the user input and output guide. + \item The BUDGETCSV option for the advanced stress packages would intermittently cause an error due to a variable not being set properly. The BUDGETCSV option did not work at all for the GWT advanced packages. The BUDGETCSV option was fixed to work properly. + \item For multi-layer GWF Models, the UZF Package should generally have UZF cells assigned to each GWF cell that can be dry or partially saturated. If a UZF cell was assigned to an upper layer of a GWF Model, but not to underlying GWF layers, then outflow from the upper UZF cell would not always flow to the water table. The program was modified so that outflow from UZF cells is transferred into the GWF Model when there are no underlying UZF cells. This routing of water to GWF may not work properly unless the Newton-Raphson formulation is active. + % \item xxx \end{itemize} - \underline{SOLUTION} + %\underline{SOLUTION} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + \underline{EXCHANGES} \begin{itemize} - \item The way in which constant head and constant concentration boundary conditions are handled when the conjugate gradient method is used for the linear solve was modified. In previous versions, constant head and concentration conditions would result in an asymmetric coefficient matrix. The program has been modified so that if the conjugate gradient method is selected for the linear solution, then matrix symmetry is preserved by adding adding flows into and out of constant head and concentration cells to the right-hand side of connected cells. + \item The GWT-GWT Exchange did not work when the XT3D\_OFF option was specified. The program was fixed so that the XT3D dispersion terms can be shut off for a GWT-GWT Exchange. GWT-GWT Exchange keywords were renamed from ADVSCHEME, XT3D\_OFF, and XT3D\_RHS to ADV\_SCHEME, DSP\_XT3D\_OFF, and DSP\_XT3D\_RHS, respectively, to more clearly indicate how the keywords relate to the underlying processes. + % \item xxx + % \item xxx \end{itemize} + \end{itemize} - % ------------------------------------------------- \section{Known Issues and Incompatibilities} This section describes known issues with this release of MODFLOW~6. @@ -268,6 +288,12 @@ \section{Known Issues and Incompatibilities} \item If a GWF-GWF Exchange is activated with the XT3D option, then the two connected GWF Models cannot have BUY Packages active. +\item +The Time-Variable Hydraulic Conductivity (TVK) Package is incompatible with the Horizontal Flow Barrier (HFB) Package if the TVK Package is used to change hydraulic properties of cells near horizontal flow barriers. + +\item +If a GWF-GWF Exchange is active, then neither of the connected GWF Models can have an active Viscosity (VSC) Package. + \end{enumerate} In addition to the issues shown here, a comprehensive and up-to-date list is available under the issues tab at \url{https://github.com/MODFLOW-USGS/modflow6}. diff --git a/doc/ReleaseNotes/appendixA.tex b/doc/ReleaseNotes/appendixA.tex index 5321922f9df..df44c0120dd 100644 --- a/doc/ReleaseNotes/appendixA.tex +++ b/doc/ReleaseNotes/appendixA.tex @@ -1,5 +1,61 @@ This appendix describes changes introduced into MODFLOW~6 in previous releases. These changes may substantially affect users. +\begin{itemize} + + \item Version mf6.3.0--March 4, 2022 + + \underline{NEW FUNCTIONALITY} + \begin{itemize} + \item New publications describing MODFLOW~6 were released, including \cite{modflow6api}, \cite{modflow6gwt}, and \cite{modflow6csub}. + \item The GWF-GWF Exchange was updated to support XT3D flow calculations along the edges of connected GWF Models. The XT3D flow calculation is an alternative to the ghost-node correction and has been shown to provide accurate flow calculations for cell connections that do not meet the control-volume finite-difference requirements. This new capability allows the GWF-GWF Exchange to tightly couple a wide variety of parent and child grid configurations. The new XT3D option for the GWF-GWF Exchange can be activated by specifying XT3D in the options block of the GWF-GWF Exchange input file. The XT3D implementation for GWF-GWF is based on a new generalized coupling method that is described in the Supplemental Technical Information document distributed with this release. + \item A new capability was added to support tight coupling of GWT Models through a new GWT-GWT Exchange. The new GWT-GWT Exchange can be used to connect any two GWT Models in a manner similar to the GWF-GWF Exchange. This allows transport to be represented from one GWT Model to another. The GWT-GWT Exchange calculates advective and dispersive fluxes and also supports the Mover Transport (MVT) Package. This first release of the GWT-GWT Exchange is limited to simulations in which the corresponding GWF Models and GWF-GWF Exchanges are run concurrently within the same simulation; the new capability does not support simulation of transport using groundwater flows saved from a previous simulation; however, this may be supported in the future. The new GWT-GWT functionality is activated by creating a GWT-GWT input file and specifying a GWT6-GWT6 exchange in the EXCHANGEDATA block of the simulation name file (mfsim.nam). The GWT-GWT Exchange is based on a new generalized coupling method that is described in the Supplemental Technical Information document distributed with this release. + \item This release introduces the Time-Varying hydraulic conductivity (TVK) and the Time-Varying Storage (TVS) options for the Node Property Flow (NPF) and Storage (STO) Packages, respectively, of the GWF Model. The TVK option is activated by specifying the TVK6 keyword in the OPTIONS block of the NPF Package and by providing a TVK6 input file. The TVS option is activated by specifying the TVS6 keyword in the OPTIONS block of the STO Package, and by providing a TVS6 input file. The TVK6 and TVS6 input files are described in input and output guide (mf6io.pdf). Technical information about the TVK and TVS options is provided in the Supplemental Technical Information report that is provided with the distribution. + \item The option already existed to provide binary budget and head file information from a GWF simulation for only the first time step of a given stress period, in which case that information will be used for all time steps in that stress period in a GWT simulation that reads from those files. The behavior of this option has been extended such that if the binary budget and head file information provided for the final stress period of the GWF simulation is for only one time step, that information will be used for any subsequent time steps and stress periods in the GWT simulation. This extended behavior includes as a special case the use of binary budget and head file information from only one time step in only one stress period (for example, a single steady-state GWF stress period) for all time steps in all stress periods in a GWT simulation. + \item Added new file-based input capability for the GWT Source and Sink Mixing (SSM) Package. The SSM Package previously required that all source and sink concentrations be provided as auxiliary variables for corresponding GWF stress packages. The SSM Package now supports an optional new FILEINPUT block, which can be provided with package names and file names. Files referenced in the FILEINPUT block can be used to provide time-varying source and sink concentrations. Descriptions for this new capability are described in the input and output guide (mf6io.pdf) under the GWT SSM Package, and the GWT Stress Package Concentrations (SPC) for list-based input and array-based input. If used, a single SPC6 input file can be provided for a corresponding GWF stress package. Either an SPC6 input file or the auxiliary variable approach can be used to supply concentrations for a single GWF stress package, but not both. + \item Added BUDGETCSV option to GWF and GWT model output control and to advanced packages (SFR, LAK, MAW, UZF, MVR, SFT, LKT, MWT, UZT, and MVT) that produce summary tables of budget information. If activated, this option will cause a comma-separated value (CSV) file of the model budget terms to be written to a user-specified output file. These output CSV files can be easily read into a spreadsheet or scripting language for plotting of budget terms. + \item Added option to use irregular cross sections to define the reach geometry for individual reaches in the SFR Package. Cross-section data for irregular cross-sections are defined in a separate Cross-Section Table Input File. The station-elevation data for an irregular cross section are specified as xfraction and height data, which is converted to station position using the specified reach width (RWID) and elevation using the specified bottom elevation of the reach (RTP). Manning's roughness coefficient fractions can optionally be specified with the xfraction-height data for a irregular cross section to represent roughness coefficient variations in a channel (for example, different channel and overbank Manning's roughness coefficients). SFR Package irregular cross sections and the method used to solve for streamflow in a reach with non-uniform Manning's roughness coefficients is a generalization of the methods used for 8-point cross-sections in the SFR Package for previous versions of MODFLOW \citep{modflowsfr1pack}. + \end{itemize} + + \underline{EXAMPLES} + \begin{itemize} + \item A new example, ex-gwtgwt-mt3dms-p10, was added to demonstrate the new GWT-GWT Exchange. + \end{itemize} + + \textbf{\underline{BUG FIXES AND OTHER CHANGES TO EXISTING FUNCTIONALITY}} \\ + \underline{BASIC FUNCTIONALITY} + \begin{itemize} + \item Fixed a bug that caused the last binary budget and head file information provided by a GWF simulation in a given stress period to be used for all subsequent GWT simulation time steps in that stress period, even if binary budget and head file information was provided for more than one time step in that stress period. In that situation, the GWF time steps must match the GWT time steps one-for-one. + \item Boundary packages, such as WEL, DRN and GHB, for example, read lists of data using a general list reader. For text input, the list of data would not be read correctly if it was longer than 300 characters wide. Most lists would normally be less than 300 characters unless a large number of auxiliary variables were specified. In this case, information beyond 300 characters would not be read. The list reader was modified to use an unlimited character length so that any number of auxiliary variables can be specified. + \item The Observation (OBS) functionality can optionally write simulated values to a comma-separated value (CSV) output file. The OBS input file contains a DIGITS option, which controls the number of digits written to the CSV output file. In some cases the ``E'' character was not written, making it difficult to read the CSV output file with other programs. New functionality was programmed to write observations using the maximum number of digits stored internally by the program using the G0 Fortran specifier. The default value for DIGITS was five, but this has been changed to this maximum number of digits. This maximum number of digits can also be activated by specifying a zero for DIGITS. For most applications, observations should be written with the default number of digits so that no precision is lost in the output. + \item Added a check to the Flow Model Interface (FMI) Package of the GWT Model that will cause the program to terminate with an error if flow and budget files needed from a flow model cannot be located. + \item The Output Control Package did not correctly determine if the end of a stress period was reached if the Adaptive Time Stepping (ATS) option was active. Output Control works correctly now with ATS. + \item Budget information for individual boundary package entries can be written to the model list file in a table form. The table no longer includes boundaries that are in cells that are dry. + \item When the simulated concentration in a cell is negative, which can occur due to the numerical methods used to solve the transport equation, then any sinks present in the cell should not add or remove mass. The program was modified so that transport through sinks is deactivated if the simulated concentration in a cell is negative. + \item Parsing of observation input was corrected so that observation names can have spaces if the observation name is enclosed in quotations. + \item The GWF Node Property Flow (NPF) Package can optionally calculate the three components of specific discharge. The program calculates these components using an interpolation method based on the XT3D method, the simulated flows across each cell face, and distances from the center of the cell to each cell face. This release contains a fix for a coding error in the calculation of the distance from the center of the cell to the cell face. The fix will affect the calculated specific discharge for model grids that have variable cell sizes. Because specific discharge is used in the calculation of the dispersion coefficients for GWT Models, simulated concentrations with this release may be different from simulated concentrations from previous releases; however, these concentration differences are expected to be minor. + \end{itemize} + + \underline{STRESS PACKAGES} + \begin{itemize} + \item Fixed a bug in the Recharge (RCH) and Evapotranspiration (EVT) Packages that would occur with array-based input (READASARRAYS) combined with the Time-Array Series (TAS) functionality. Because the TAS functionality only works for DIS and DISV models, this fix does not have any effect on models that use DISU discretization. The bug would occur when one or more cells in the upper layer were removed using the IDOMAIN capability. In this special case, the time-array series values did not carry over to the correct locations in the RCH and EVT arrays. This error would be difficult to identify for complex models, because the model would run to completion without any errors. The RCH and EVT Packages were modified to maintain direct correspondence between the \texttt{nodelist} and \texttt{bound} arrays with the arrays provided to the TAS utility. A small and intended consequence of this fix is that the ID2 value written to the binary budget file for array-based RCH and EVT Packages will correspond to the consecutive cell number in the top layer. + \item Recharge and evapotranspiration flows that are written to the GWF Model binary budget file are marked with the text headers ``RCH'' and ``EVT'', respectively. In order to support the array-based input for SSM concentrations, these text headers are marked as ``RCHA'' and ``EVTA'', respectively, if the READASARRAYS option is specified for the package. This change will have no effect on simulation results; however, post processing capabilities may need to be adjusted to account for this minor renaming convention. + \item When the PRINT\_FLOWS option was used with the Source and Sink Mixing (SSM) Package, the cell ID numbers written to the listing file were incorrect. The SSM Package was fixed to output the correct cell ID. + \item Add new AUTO\_FLOW\_REDUCE\_CSV option for the Well Package. If activated, then this option will result in information being written to a comma-separated value file for each well and for each time step in which the extraction rate is reduced. Well extraction rates can be reduced for some groundwater conditions if the AUTO\_FLOW\_REDUCE option is activated. Information is not written for wells in which the extraction rate is equal to the user-specified extraction rate. + \end{itemize} + + \underline{ADVANCED STRESS PACKAGES} + \begin{itemize} + \item The Streamflow Routing (SFR) Package would terminate with a floating point error when calculating the stream depth as a function of flow rate, if the flow rate was slightly negative. Added a conditional check to ensure that the stream depth is calculated as zero if the calculated flow rate is zero or less. + \end{itemize} + + \underline{SOLUTION} + \begin{itemize} + \item The way in which constant head and constant concentration boundary conditions are handled when the conjugate gradient method is used for the linear solve was modified. In previous versions, constant head and concentration conditions would result in an asymmetric coefficient matrix. The program has been modified so that if the conjugate gradient method is selected for the linear solution, then matrix symmetry is preserved by adding adding flows into and out of constant head and concentration cells to the right-hand side of connected cells. + \end{itemize} + +\end{itemize} + + \begin{itemize} \item Version mf6.2.2--July 30, 2021 diff --git a/doc/ReleaseNotes/template.tex b/doc/ReleaseNotes/template.tex new file mode 100644 index 00000000000..e4691084566 --- /dev/null +++ b/doc/ReleaseNotes/template.tex @@ -0,0 +1,65 @@ +% Use this template for starting initializing the release notes +% after a release has just been made. +\begin{itemize} + + \item Version mf6.x.x--Month xx, 202x + + \underline{NEW FUNCTIONALITY} + \begin{itemize} + \item xxx + % \item xxx + % \item xxx + \end{itemize} + + %\underline{EXAMPLES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + \textbf{\underline{BUG FIXES AND OTHER CHANGES TO EXISTING FUNCTIONALITY}} \\ + \underline{BASIC FUNCTIONALITY} + \begin{itemize} + \item xxx + % \item xxx + % \item xxx + \end{itemize} + + %\underline{INTERNAL FLOW PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{STRESS PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{ADVANCED STRESS PACKAGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{SOLUTION} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + %\underline{EXCHANGES} + %\begin{itemize} + % \item xxx + % \item xxx + % \item xxx + %\end{itemize} + + +\end{itemize} diff --git a/doc/SuppTechInfo/Figures/VSCnonlinear.pdf b/doc/SuppTechInfo/Figures/VSCnonlinear.pdf new file mode 100644 index 00000000000..96346ab714c Binary files /dev/null and b/doc/SuppTechInfo/Figures/VSCnonlinear.pdf differ diff --git a/doc/SuppTechInfo/Tables/mf6enhancements.tex b/doc/SuppTechInfo/Tables/mf6enhancements.tex index d7d65318757..4e4183bc02a 100644 --- a/doc/SuppTechInfo/Tables/mf6enhancements.tex +++ b/doc/SuppTechInfo/Tables/mf6enhancements.tex @@ -25,7 +25,8 @@ STO Package Specific Storage Revision & \ref{ch:sto-mod} & 6.1.3 & -- \\ TVK and TVS Capabilities for NPF & \ref{ch:tvk-tvs} & 6.3.0 & -- \\ \rowcolor{Gray} - Generalized Coupling of Numerical Models & \ref{ch:gencouple} & 6.3.0 & -- \\ + Generalized Coupling of Numerical Models & \ref{ch:gencouple} & 6.3.0 & -- \\ + VSC Package & \ref{ch:vscpackage} & 6.4.0 & -- \\ \hline \end{tabular} \label{table:mf6enhance} diff --git a/doc/SuppTechInfo/body.tex b/doc/SuppTechInfo/body.tex index 35e96c48ebf..9b4c38dc6ba 100644 --- a/doc/SuppTechInfo/body.tex +++ b/doc/SuppTechInfo/body.tex @@ -41,6 +41,12 @@ \customlabel{ch:gencouple}{\thechapno} \input{gen-coupling.tex} +\newpage +\incchap +\SECTION{Chapter \thechapno. Accounting for Fluid Viscosity} +\customlabel{ch:vscpackage}{\thechapno} +\input{viscosity.tex} + \newpage \ifx\usgsdirector\undefined diff --git a/doc/SuppTechInfo/mf6suptechinfo.bbl b/doc/SuppTechInfo/mf6suptechinfo.bbl index e7bd7db541b..7a42f1fe96b 100644 --- a/doc/SuppTechInfo/mf6suptechinfo.bbl +++ b/doc/SuppTechInfo/mf6suptechinfo.bbl @@ -1,16 +1,38 @@ -\begin{thebibliography}{7} +\begin{thebibliography}{15} \providecommand{\natexlab}[1]{#1} \expandafter\ifx\csname urlstyle\endcsname\relax \providecommand{\doi}[1]{doi:\discretionary{}{}{}#1}\else \providecommand{\doi}{doi:\discretionary{}{}{}\begingroup \urlstyle{rm}\Url}\fi +\bibitem[{Guo and Langevin(2002)}]{langevin2002seawat} +Guo, Weixing, and Langevin, C.D., 2002, User's Guide to SEAWAT: A Computer + Program for Simulation of Three-Dimensional Variable-Density Ground-Water + Flow: {U.S. Geological Survey Techniques of Water-Resources Investigations + book 6, Chapter A7, 77 p.}, accessed July 25, 2019, at + \url{https://pubs.er.usgs.gov/publication/ofr03426}. + \bibitem[{Harbaugh(2005)}]{modflow2005} Harbaugh, A.W., 2005, MODFLOW-2005, the U.S. Geological Survey modular ground-water model---the Ground-Water Flow Process: {U.S. Geological Survey Techniques and Methods, book 6, chap. A16, variously paged}, accessed June 27, 2017, at \url{https://pubs.usgs.gov/tm/2005/tm6A16/}. +\bibitem[{Healy and Ronan(1996)}]{healy1996} +Healy, R.W., and Ronan, A.D., 1996, Documentation of Computer Program VS2DH for + Simulation of Energy Transport in Variably Saturated Porous Media: + Modification of the U.S. Geological Survey's Computer Program VS2DT: {U.S. + Geological Survey Water-Resources Investigation Report 96-4230, 36 p.}, + accessed September 27, 2022, at \url{https://doi.org/10.3133/wri964230}, at + \url{https://pubs.usgs.gov/wri/1996/4230/report.pdf}. + +\bibitem[{Hughes and Sanford(2004)}]{hughes2004} +Hughes, J.D., and Sanford, W.E., 2004, SUTRA-MS: A version of SUTRA modified to + simulate heat and multiple-solute transport: {U.S. Geological Survey Open + File Report 2004--1207, 141 p.}, accessed September 27, 2022, at + \url{https://doi.org/10.3133/ofr20041207}, at + \url{https://water.usgs.gov/nrp/gwsoftware/SutraMS/OFR2004-1207.pdf}. + \bibitem[{Hughes and others(2017)Hughes, Langevin, and Banta}]{modflow6framework} Hughes, J.D., Langevin, C.D., and Banta, E.R., 2017, Documentation for the @@ -24,6 +46,20 @@ Kavetski, Dmitri, and Kuczera, George, 2007, Model smoothing strategies to no.~3, \url{https://doi.org/10.1029/2006WR005195}, \url{https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2006WR005195}. +\bibitem[{Kipp(1987)}]{kipp1987} +Kipp, K.L., 1987, HST3D: A Computer Code for Simulation of Heat and Solute + Transport in Three-Dimensional Ground-Water Flow Systems: {U.S. Geological + Survey Water-Resources Investigation Report 86-4095, 517 p.}, accessed + September 27, 2022, at \url{https://pubs.usgs.gov/wri/1986/4095/report.pdf}. + +\bibitem[{Langevin and others(2008)Langevin, Thorne~Jr, Dausman, Sukop, and + Guo}]{langevin2008seawat} +Langevin, C.D., Thorne~Jr, D.T., Dausman, A.M., Sukop, M.C., and Guo, Weixing, + 2008, {SEAWAT} Version 4---A computer program for simulation of multi-species + solute and heat transport: {U.S. Geological Survey Techniques and Methods, + book 6, chap. A22, 39 p.}, accessed June 27, 2017, at + \url{https://pubs.er.usgs.gov/publication/tm6A22}. + \bibitem[{Langevin and others(2017)Langevin, Hughes, Provost, Banta, Niswonger, and Panday}]{modflow6gwf} Langevin, C.D., Hughes, J.D., Provost, A.M., Banta, E.R., Niswonger, R.G., and @@ -31,6 +67,9 @@ Langevin, C.D., Hughes, J.D., Provost, A.M., Banta, E.R., Niswonger, R.G., and Model: {U.S. Geological Survey Techniques and Methods, book 6, chap. A55, 197 p.}, \url{https://doi.org/10.3133/tm6A55}. +\bibitem[{Maidment(1993)}]{maidment1993} +Maidment, D.R., 1993, Handbook of Hydrology: New York, USA, McGraw-Hill. + \bibitem[{Panday and others(2013)Panday, Langevin, Niswonger, Ibaraki, and Hughes}]{modflowusg} Panday, Sorab, Langevin, C.D., Niswonger, R.G., Ibaraki, Motomu, and Hughes, @@ -46,6 +85,16 @@ Provost, A.M., Langevin, C.D., and Hughes, J.D., 2017, Documentation for the Geological Survey Techniques and Methods, book 6, chap. A56, 46 p.}, \url{https://doi.org/10.3133/tm6A56}. +\bibitem[{Voss(1984)}]{voss1984sutra} +Voss, C.I., 1984, SUTRA---A finite-element simulation model for + saturated-unsaturated fluid-density-dependent ground-water flow with energy + transport or chemically-reactive single-species solute transport: {U.S. + Geological Survey Water-Resources Investigations Report 84--4369, 409 p.} + +\bibitem[{Zheng(2010)}]{zheng2010supplemental} +Zheng, Chunmiao, 2010, MT3DMS v5.3, Supplemental User's Guide: {Technical + Report Prepared for the U.S. Army Corps of Engineers, 51 p.} + \bibitem[{Zheng and Wang(1999)}]{zheng1999mt3dms} Zheng, Chunmiao, and Wang, P.P., 1999, MT3DMS---A modular three-dimensional multi-species transport model for simulation of advection, dispersion and diff --git a/doc/SuppTechInfo/python/VSC-nonlinear.ipynb b/doc/SuppTechInfo/python/VSC-nonlinear.ipynb new file mode 100644 index 00000000000..c907b5687f0 --- /dev/null +++ b/doc/SuppTechInfo/python/VSC-nonlinear.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.gridspec as gridspec\n", + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " import spnspecs\n", + " spnspecs.set_graph_specifications()\n", + "except:\n", + " spnspecs = None" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "figpth = '../Figures'\n", + "width = 6.8\n", + "dpi = 300" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A common nonlinear function relating viscosity and temperature\n", + "\n", + "The equation that follows is for temperature expressed in $^\\circ$C" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dtype = np.float\n", + "step = 0.01\n", + "T0, T1 = 0, 40\n", + "T = np.arange(T0, T1, step=step, dtype=dtype)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def nonlin_vsc(T):\n", + " a1 = 2.394e-5\n", + " a2 = 10\n", + " a3 = 248.37\n", + " a4 = 133.15\n", + " visc = np.zeros(T.shape, dtype=np.float)\n", + " for idx, val in enumerate(T):\n", + " mu_T = a1 * a2 ** (a3 / (T[idx] + a4))\n", + " visc[idx] = mu_T\n", + " \n", + " return visc" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A linear approximation for the equation given above\n", + "\n", + "That is, contrive a linear approximation to the nonlinear case above" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x_lin_pts = np.array([7.5, 30])\n", + "y_lin_pts = nonlin_vsc(x_lin_pts)\n", + "\n", + "# calc rise/run\n", + "dviscdT = (y_lin_pts[1] - y_lin_pts[0]) / (x_lin_pts[1] - x_lin_pts[0])\n", + "\n", + "# tempearture of reference viscosity\n", + "Tviscref = 20\n", + "\n", + "# reference viscosity\n", + "mu_0 = nonlin_vsc(np.array([Tviscref]))\n", + "\n", + "def lin_vsc(T, dviscdT, Tviscref):\n", + " # use the linear formula\n", + " visc_lin = np.zeros(T.shape, dtype=np.float)\n", + " for idx, val in enumerate(T):\n", + " mu_T = dviscdT * (val - Tviscref) + mu_0\n", + " visc_lin[idx] = mu_T\n", + " \n", + " return visc_lin" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "visc = nonlin_vsc(T)\n", + "visc_lin = lin_vsc(T, dviscdT, Tviscref)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(T,visc)\n", + "plt.plot(T,visc_lin)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x_increment = 5\n", + "x_ticks = np.arange(T0, T1 + x_increment, x_increment)\n", + "y_increment = 2e-4\n", + "y_ticks = np.arange(math.floor(visc.min() * 10000) / 10000, math.ceil(visc.max() * 10000) / 10000 + y_increment, y_increment)\n", + "print(x_ticks)\n", + "print(y_ticks)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#fig, axes = plt.subplots(nrows=1, ncols=1, tight_layout=True, \n", + "# figsize=(width/1.5, width/2))\n", + "\n", + "#if not isinstance(axes, list):\n", + "# axes = [axes]\n", + "\n", + "#for idx, ax in enumerate(axes):\n", + "# ax.set_xlim(T0, T1)\n", + "# ax.set_ylim(y_ticks[0], y_ticks[-2])\n", + "# ax.set_xticks(x_ticks)\n", + "# ax.set_xticklabels(x_ticks)\n", + "# #ax.set_yticks(y_ticks)\n", + "# #ax.set_yticklabels(y_ticks, rotation=90, va='center')\n", + "# if spnspecs is not None:\n", + "# spnspecs.remove_edge_ticks(ax)\n", + "# spnspecs.heading(ax, letter=letters[idx])\n", + " \n", + "\n", + "#ax = axes[0]\n", + "##ax.set_aspect('square', adjustable='box')\n", + "##ax.axhline(0, lw=0.5, ls='-.', color='black')\n", + "##ax.axvline(0, lw=0.5, ls='-.', color='black')\n", + "\n", + "#ax.plot(T, visc, lw=1.25, color='#00BFFF', label=r'$\\mu')\n", + "#ax.plot(T, visc_lin, lw=1., color='black', ls='-', label=r'$\\frac {\\partial \\mu} {\\partial T}')\n", + "#ax.plot([Tviscref], [mu_0], marker=\"o\", markersize=4, markeredgecolor=\"red\", markerfacecolor=\"blue\")\n", + "#text = r'$\\left ( T_0, \\mu_0 \\right )$'\n", + "##ax.text(21, 0.00102, text, style='italic') #fontsize=6)\n", + "#spnspecs.add_text(ax, text=text, x=0.5, y=0.5, transform=False, bold=False, ha='left', va='top')\n", + "\n", + "#if spnspecs is not None:\n", + "# handles, labels = ax.get_legend_handles_labels()\n", + "# spnspecs.graph_legend(ax, handles=handles[::-1], labels=labels[::-1],\n", + "# loc='upper right', bbox_to_anchor=(1.00,0.95),\n", + "# handlelength=1.5)\n", + "#ax.set_xlabel(r'Temperature, in $^\\circ$C')\n", + "#ax.set_ylabel(r'$\\mu$, in $\\frac{kg}{m \\cdot s}$')\n", + "\n", + "#fpth = os.path.join(figpth, 'VSCnonlinear.pdf')\n", + "#fig.savefig(fpth, dpi=dpi)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/doc/SuppTechInfo/viscosity.tex b/doc/SuppTechInfo/viscosity.tex new file mode 100644 index 00000000000..49fdebe18c8 --- /dev/null +++ b/doc/SuppTechInfo/viscosity.tex @@ -0,0 +1,74 @@ + +The dynamic viscosity of a fluid is a function of fluid composition and temperature and typically has a weak dependence on pressure. In some applications, particularly those that involve large variations in temperature, viscosity can vary significantly in space and over time. Variations in viscosity, in turn, can affect groundwater flow by changing the hydraulic conductivity, which is inversely proportional to viscosity. In the original release of \mf, variations in viscosity and their effects on hydraulic conductivity were not taken into account. The \mf Viscosity (VSC) Package allows viscosity to vary as a function of solute concentrations and fluid temperature and accounts for the effect of variable viscosity on hydraulic conductivity in the Node-Property Flow (NPF) Package and in stress packages that involve head-dependent groundwater flow. Temperature-dependent viscosity has been implemented in other groundwater modeling codes, including HST3D \citep{kipp1987}, VS2DH \citep{healy1996}, SUTRA-MS \citep{hughes2004}, and SEAWAT Version 4 \citep{langevin2008seawat}. Like these other codes, the VSC Package does not account for the dependence of viscosity on pressure, which is negligible in most applications. + +For cases in which the rate of groundwater flow is proportional to the head gradient in the direction of flow, as in an isotropic porous medium, the flow between two adjacent locations can be approximated using a one-dimensional form of Darcy's Law \citep[equation 4-15]{modflow6gwf}: + +\begin{equation} +\label{eqn:modflow6gwf-4-15} +Q = C \left( h_{1} - h_{2} \right), +\end{equation} + +\noindent where $h_{1}$ and $h_{2}$ are the hydraulic heads at locations 1 and 2, respectively, $Q$ is the flow from location 1 to location 2, and $C$ is a hydraulic conductance defined by~\citep[equation 4-14]{modflow6gwf}: + +\begin{equation} +\label{eqn:modflowgwf-4-14} +C = \frac{K A} {L_{1,2}}, +\end{equation} + +\noindent where $K$ is the hydraulic conductivity of the porous medium that connects the two locations, $A$ is the cross-sectional area perpendicular to flow, and $L_{1,2}$ is the distance between two locations. A form of equation~\ref{eqn:modflow6gwf-4-15} is used in the \mf ``conductance-based'' formulation for flow between two adjacent model cells \citep{modflow6gwf}. In that case, the conductance is based on an effective hydraulic conductivity between the two cells, the area of the cell-cell interface, and the distance between the cell centers. A form of equation~\ref{eqn:modflow6gwf-4-15} is also used in \mf stress packages in which the flow into or out of the model at a model boundary is head-dependent. For example, in the General-Head Boundary (GHB) Package, flow between an external source and a groundwater model cell is proportional to the difference between the head assigned to the external source and the simulated head in the cell, and the conductance is representative of the material between the external source and the cell center. + +Because hydraulic conductivity is inversely proportional to viscosity, the conductivity $K$ for a simulated fluid composition and temperature is related to the conductivity $K_{0}$ for some reference composition and temperature by + +\begin{equation} +\label{eqn:conductivity-ratio} +K = \frac{\mu_{0}}{\mu} K_{0}. +\end{equation} + +\noindent It follows from equation~\ref{eqn:modflowgwf-4-14} that the conductance $C$ for a simulated fluid composition and temperature is related to the conductance $C_{0}$ for the reference composition and temperature by + +\begin{equation} +\label{eqn:conductance-ratio} +C = \frac{\mu_{0}}{\mu} C_{0}, +\end{equation} + +\noindent where $\mu$ and $\mu_{0}$ are the viscosities at the simulated and reference conditions, respectively. The VSC Package uses equations~\ref{eqn:conductivity-ratio} and~\ref{eqn:conductance-ratio} to update hydraulic conductivities and conductances to account for changes in solute concentrations and temperature during a flow and transport simulation based on the Groundwater Flow (GWF) and Groundwater Transport (GWT) Models. The GWT Model is designed to simulate solute transport but can be used to simulate heat transport in some applications by appropriately scaling the input parameters to render the solute-transport equation mathematically equivalent to the heat-transport equation \citep{zheng2010supplemental}. In such cases, the ``solute concentration'' calculated by a GWT-based heat-transport model can by identified in the VSC Package input file as representing temperature. Although the VSC Package allows viscosity to vary with solute concentration, variations in viscosity are typically most significant in heat-transport applications. + +\subsection{Dependence of Viscosity on Concentration and Temperature} \label{sec:fluidvsc} + +The VSC Package calculates viscosity as a function of concentration and temperature using the following equation \citep[equation 17]{langevin2008seawat}: + +\begin{equation} +\label{eqn:viscfunc} +\mu = \mu_T \left ( T \right ) + \sum_{k=1}^{NS} \frac{\partial \mu} {\partial C^k} \left ( C^k - C_{0}^k \right ) +\end{equation} + +\noindent where $NS$ is the number of chemical species (solutes) whose concentrations affect viscosity, $C^k$ and $C_{0}^k$ are the simulated and user-specified reference concentrations of species $k$, respectively, and $\partial \mu / \partial C^k$ is the user-specified rate at which viscosity changes linearly with the concentration of species $k$. (Symbols $C^k$ and $C_{0}^k$ are not to be confused with the symbols for conducance, $C$ and $C_0$, introduced earlier.) When all concentrations are equal to their reference values, the viscosity is equal to $\mu_T \left ( T \right )$, which embodies the dependence of viscosity on temperature according to + +\begin{align} + \label{eqn:viscT} + \mu_T \left ( T \right ) = \begin{dcases} + \mu_{0} + \frac{\partial \mu} {\partial T} \left ( T - T_{0}\right ) & linear \\ + \mu_{0} A_2^{\frac{A_3 \left ( T_0 - T \right )} {\left ( T + A_4 \right ) \left ( T_0 + A_4 \right ) }} & nonlinear + \end{dcases} . +\end{align} + +\noindent where $T$ and $T_{0}$ are the simulated and user-specified reference temperature, respectively, and $\mu_{0}$ is the user-specified reference viscosity. The reference viscosity is commonly set to 0.001 kg~m$^{-1}$~s$^{-1}$, which is representative of freshwater at a reference temperature of 20$^{\circ}$C \citep[Table 11.1]{maidment1993}. When $T$ equals $T_{0}$, or if temperature is not designated by the user as affecting viscosity, $\mu_T \left ( T \right )$ equals $\mu_{0}$. Equation~\ref{eqn:viscT} includes both linear and nonlinear variation of viscosity with temperature. Linear variation is the default, in which case $\partial \mu / \partial T$ is the user-specified rate at which viscosity changes linearly with temperature. Nonlinear variation is a user-selectable option, in which case the variation of viscosity from the reference value is determined by user-specified parameters $A_2$, $A_3$, and $A_4$. The nonlinear option in equation~\ref{eqn:viscT} is mathematically equivalent to one of the options available in SEAWAT Version 4 \citep[equation 18]{langevin2002seawat} but is written in a form that explicitly sets $\mu_T \left ( T \right )$ equal to $\mu_{0}$ when $T$ equals $T_{0}$. Setting $\mu_0$, $A_2$, $A_3$, and $A_4$ to 0.001002 kg~m$^{-1}$~s$^{-1}$, 10.0, 248.37, and 133.15, respectively, and rounding the lead coefficient to one decimal place gives the temperature dependence of viscosity used in SUTRA \citep{voss1984sutra} and SUTRA-MS \citep{hughes2004}. VS2DH \citep{healy1996} also calculate the temperature dependence of viscosity using functions that are, respectively, mathematically equivalent to and a special case of equation~\ref{eqn:viscT}. + +Over the temperature range $0-40^{\circ}$C, the viscosity of freshwater varies between approximately 0.0007 and 0.00175 kg~m$^{-1}$~s$^{-1}$, as indicated by the nonlinear (blue) curve in figure~\ref{fig:viscosityrelation}. The black line in figure~\ref{fig:viscosityrelation} depicts a linear approximation that coincides with the nonlinear curve at the reference temperature and viscosity, $\left ( T_0, \mu_0 \right ) = \left(\right.$20$^{\circ}$C, 0.001 kg~m$^{-1}$~s$^{-1}\left.\right)$. + +\begin{figure} + \begin{center} + \includegraphics{./Figures/VSCnonlinear.pdf} + \caption[Graph showing the nonlinear response in the viscosity as temperature changes]{Nonlinear dependence of viscosity on temperature (blue curve) that is representative of freshwater over the temperature range $0-40^{\circ}$C, and a linear approximation (black curve) that has the same value $\left ( \mu_0 \right )$ and slope at the reference temperature $\left ( T_0 \right )$. The blue curve is generated using 0.001002 kg~m$^{-1}$~s$^{-1}$,10.0, 248.37, and 133.15 for $\mu_0$, $A_2$, $A_3$, and $A_4$, respectively} + \label{fig:viscosityrelation} + \end{center} +\end{figure} + +\subsection{Accounting for Variable Viscosity in Flows Between Cells} \label{sec:gwfvsc} + +The VSC Package uses concentrations and temperatures calculated for each cell by a GWT model on the previous time step or outer solution iteration to calculate viscosities for the current time step. These viscosities are used to adjust cell hydraulic conductivity values in the NPF Package using equation~\ref{eqn:conductivity-ratio}. The reference values of conductivity are the values specified by the user in the NPF Package and, optionally, the Time-Varying Conductivity (TVK) Package (Chapter 6 of this document). The conductivity adjustment is performed after the user-specified conductivities are read in but before conductivity values are passed to program units that use cell conductivities to formulate expressions for flow between cells, which include the ``conductance-based'' formulation for flow and the XT3D capability \citep{modflow6xt3d}. If the VSC Package is not active, cell conductivities are not adjusted for variable viscosity, and the user-specified values are used. + +\subsection{Accounting for Variable Viscosity in Boundary Flows} \label{sec:gwfvsc} + +The VSC Package uses concentrations and temperatures calculated for each cell by a GWT model on the previous time step or outer solution iteration in calculating viscosities for the current time step. These viscosities are used to adjust hydraulic conductances, using equation~\ref{eqn:conductance-ratio}, in stress packages that involve head-dependent boundary flows, which include the River (RIV), General-Head Boundary (GHB), Drain (DRN), Streamflow Routing (SFR), Lake (LAK), and Multi-Aquifer Well (MAW) Packages \citep{modflow6gwf}. For a boundary flow out of the model, the viscosity is based on the simulated concentration or temperature in the cell from which the boundary flow originates. For a boundary flow into the model, the viscosity is based on the concentration or temperature of the water entering the cell from the boundary. The reference values of conductance are the values normally set or calculated by the stress package based on user input. The conductance adjustment is performed after the stress package completes its normal conductance calculation but before the conductance value is used to formulate the expression for the boundary flow. If the VSC Package is not active, stress-package conductances are not adjusted for variable viscosity. + diff --git a/doc/mf6io/form_of_input.tex b/doc/mf6io/form_of_input.tex index 9ef4e160c81..b974245e575 100644 --- a/doc/mf6io/form_of_input.tex +++ b/doc/mf6io/form_of_input.tex @@ -85,21 +85,21 @@ \subsection{Integer and Floating Point Variables} TINY (smallest non-zero value): 2.225074-308 HUGE (largest value): 1.797693+308 PRECISION: 15 - BIT SIZE: 64 + SIZE IN BITS: 64 Integer Variables KIND: 4 HUGE (largest value): 2147483647 - BIT SIZE: 32 + SIZE IN BITS: 32 Long Integer Variables KIND: 8 HUGE (largest value): 9223372036854775807 - BIT SIZE: 64 + SIZE IN BITS: 64 Logical Variables KIND: 4 - BIT SIZE: 32 + SIZE IN BITS: 32 \end{lstlisting} } diff --git a/doc/mf6io/gwf/array_data.tex b/doc/mf6io/gwf/array_data.tex index d826f09f630..4a2c400bc79 100644 --- a/doc/mf6io/gwf/array_data.tex +++ b/doc/mf6io/gwf/array_data.tex @@ -39,7 +39,7 @@ \subsubsection{READARRAY Variable Descriptions} \item \texttt{(BINARY)}---is an option that indicates the OPEN/CLOSE file contains array data in binary (unformatted) form. A binary file that can be read by MODFLOW may be created in only two ways. The first way is to use MODFLOW to create the file by saving heads in a binary file. This is commonly done when the user desires to use computed heads from one simulation as initial heads for a subsequent simulation. The other way to create a binary file is to write a special program that generates a binary file. ``(BINARY)'' can be specified only when the control line is OPEN/CLOSE. -\item \texttt{IPRN }---are a keyword and a flag that indicates whether the array being read should be written to the Listing File after the array has been read and a code for indicating the format that should be used when the array is written. The format codes are the same as for MODFLOW-2005. IPRN is set to zero when the specified value exceeds those defined. If IPRN is less than zero or if the keyword and flag are omitted, the array will not be printed. +\item \texttt{IPRN }---are a keyword and a flag that indicates whether the array being read should be written to the Listing File after the array has been read and a code for indicating the format that should be used when the array is written. The format codes are the same as for MODFLOW-2005. IPRN is set to zero when the specified value exceeds those defined. If IPRN is less than zero or if the keyword and flag are omitted, the array will not be printed. This IPRN capability is not functional for all data sets, and may be removed in future versions. \end{description} diff --git a/doc/mf6io/gwf/gwf.tex b/doc/mf6io/gwf/gwf.tex index 98cd9b37554..452122446ef 100644 --- a/doc/mf6io/gwf/gwf.tex +++ b/doc/mf6io/gwf/gwf.tex @@ -109,6 +109,10 @@ \subsection{Skeletal Storage, Compaction, and Subsidence (CSUB) Package} \subsection{Buoyancy (BUY) Package} \input{gwf/buy} +\newpage +\subsection{Viscosity (VSC) Package} +\input{gwf/vsc} + \newpage \subsection{Constant-Head (CHD) Package} \input{gwf/chd} diff --git a/doc/mf6io/gwf/namefile.tex b/doc/mf6io/gwf/namefile.tex index 4d8724801ca..f54f1ee1e5f 100644 --- a/doc/mf6io/gwf/namefile.tex +++ b/doc/mf6io/gwf/namefile.tex @@ -31,6 +31,7 @@ \subsubsection{Explanation of Variables} STO6 & Storage Package \\ CSUB6 & Compaction and Subsidence Package \\ BUY6 & Buoyancy Package \\ +VSC6 & Viscosity Package \\ HFB6 & Horizontal Flow Barrier Package\\ CHD6 & Time-Variant Specified Head Option & * \\ WEL6 & Well Package & * \\ diff --git a/doc/mf6io/gwf/vsc.tex b/doc/mf6io/gwf/vsc.tex new file mode 100644 index 00000000000..9a1f3857481 --- /dev/null +++ b/doc/mf6io/gwf/vsc.tex @@ -0,0 +1,73 @@ +Input to the Viscosity (VSC) Package is read from the file that has type ``VSC6'' in the Name File. If the VSC Package is active within a groundwater flow model, then the model will account for the dependence of fluid viscosity on solute concentration and the resulting changes in hydraulic conductivity and stress-package conductances, which vary inversely with viscosity. Viscosity can be calculated as a function of one or more groundwater solute transport (GWT) species using an approach described in the Supplemental Technical Information document distributed with MODFLOW 6 (Chapter 8). Only one VSC Package can be specified for a GWF model. The VSC Package can be coupled with one or more GWT Models so that the fluid viscosity is updated dynamically with one or more simulated concentration fields. + +The VSC Package calculates fluid viscosity using the following equation from \cite{langevin2008seawat}: + +\begin{equation} +\label{eqn:visclinear} +\mu = VISCREF + \sum_{i=1}^{NVISCSPECIES} DVISCDC_i \left ( CONCENTRATION_i - CVISCREF_i \right ) +\end{equation} + +\noindent where $\mu$ is the calculated viscosity, $VISCREF$ is the viscosity of a reference fluid, typically taken to be freshwater at a temperature of 20 degrees Celsius, $NVISCSPECIES$ is the number of chemical species that contribute to the viscosity calculation, $DVISCDC_i$ is the parameter that describes how viscosity changes linearly as a function of concentration for chemical species $i$ (i.e. the slope of a line that relates viscosity to concentration), $CONCENTRATION_i$ is the concentration of species $i$, and $CVISCREF_i$ is the reference concentration for species $i$ corresponding to when the viscosity of the reference fluid is equal to $VISCREF$, which is normally set to a concentration of zero. + +In many applications, variations in temperature have a greater effect on fluid viscosity than variations in solute concentration. When a GWT model is formulated such that one of the transported ``species'' is heat (thermal energy), with ``concentration'' used to represent temperature \citep{zheng2010supplemental}, the viscosity can vary linearly with temperature, as it can with any other ``concentration.'' In that case, $CONCENTRATION_i$ and $CVISCREF_i$ represent the simulated and reference temperatures, respectively, and $DVISCDC_i$ represents the rate at which viscosity changes with temperature. In addition, the viscosity formula can optionally include a nonlinear dependence on temperature. In that case, equation 3 becomes + +\begin{equation} +\label{eqn:viscnonlinear} +\mu = \mu_T(T) + \sum_{i=1}^{NVISCSPECIES} DVISCDC_i \left ( CONCENTRATION_i - CVISCREF_i \right ) +\end{equation} + +\noindent where the first term on the right-hand side, $\mu_T(T)$, is a nonlinear function of temperature, and the summation corresponds to the summation in equation \ref{eqn:visclinear}, in which one of the ``species'' is heat. The nonlinear term in equation \ref{eqn:viscnonlinear} is of the form + +\begin{equation} +\label{eqn:munonlinear} +\mu_T(T) = CVISCREF_i \cdot A_2^{\left [ \frac {-A_3 \left ( CONCENTRATION_i - CVISCREF_i \right ) } {\left ( CONCENTRATION_i + A_4 \right ) \left ( CVISCREF_i + A_4 \right )} \right ]} +\end{equation} + +\noindent where the coefficients $A_2$, $A_3$, and $A_4$ are specified by the user. Values for $A_2$, $A_3$, and $A_4$ are commonly 10, 248.7, and 133.15, respectively \citep{langevin2008seawat, Voss1984sutra}. + +\subsubsection{Stress Packages} + +For head-dependent stress packages, the VSC Package can adjust the conductance used to calculate flow between the boundary and the aquifer to account for variations in viscosity. Conductance is assumed to vary inversely with viscosity. + +By default, the boundary viscosity is set equal to VISCREF, which, for freshwater, is typically set equal to 1.0. However, there are two additional options for setting the viscosity of a boundary package. The first is to assign an auxiliary variable with the name ``VISCOSITY''. If an auxiliary variable named ``VISCOSITY'' is detected, then it will be assigned as the viscosity of the fluid entering from the boundary. Alternatively, a viscosity value can be calculated for each boundary using the viscosity equation described above and one or more concentrations provided as auxiliary variables. In this case, the user must assign one auxiliary variable for each AUXSPECIESNAME listed in the PACKAGEDATA block below. Thus, there must be NVISCSPECIES auxiliary variables, each with the identical name as those specified in PACKAGEDATA. The VSC Package will calculate the viscosity for each boundary using these concentrations and the values specified for VISCREF, DVISCDC, and CVISCREF. If the boundary package contains an auxiliary variable named VISCOSITY and also contains AUXSPECIESNAME auxiliary variables, then the boundary viscosity value will be assigned to the one in the VISCOSITY auxiliary variable. + +A GWT Model can be used to calculate concentrations for the advanced stress packages (LAK, SFR, MAW, and UZF) if corresponding advanced transport packages are specified (LKT, SFT, MWT, and UZT). The advanced stress packages have an input option called FLOW\_PACKAGE\_AUXILIARY\_NAME. When activated, this option will result in the simulated concentration for a lake or other feature being copied from the advanced transport package into the auxiliary variable for the corresponding GWF stress package. This means that the viscosity for a lake or stream, for example, can be dynamically updated during the simulation using concentrations from advanced transport packages that are fed into auxiliary variables in the advanced stress packages, and ultimately used by the VSC Package to calculate a fluid viscosity. This concept also applies when multiple GWT Models are used simultaneously to simulate multiple species. In this case, multiple auxiliary variables are required for an advanced stress package, with each one representing a concentration from a different GWT Model. + + +\begin{longtable}{p{3cm} p{12cm}} +\caption{Description of viscosity terms for stress packages} +\tabularnewline +\hline +\hline +\textbf{Stress Package} & \textbf{Note} \\ +\hline +\endhead +\hline +\endfoot +GHB & A VISCOSITY auxiliary variable or one or more auxiliary variables for calculating viscosity in the equation of state can be specified \\ +RIV & A VISCOSITY auxiliary variable or one or more auxiliary variables for calculating viscosity in the equation of state can be specified \\ +DRN & The drain formulation assumes that the drain boundary contains water of the same viscosity as the discharging water; auxiliary variables have no effect on the drain calculation \\ +LAK & A VISCOSITY auxiliary variable or one or more auxiliary variables for calculating viscosity in the equation of state can be specified \\ +SFR & A VISCOSITY auxiliary variable or one or more auxiliary variables for calculating viscosity in the equation of state can be specified \\ +MAW & A VISCOSITY auxiliary variable or one or more auxiliary variables for calculating viscosity in the equation of state can be specified \\ +UZF & Viscosity variations not implemented \\ +\end{longtable} + +\vspace{5mm} +\subsubsection{Structure of Blocks} + +\vspace{5mm} +\noindent \textit{FOR EACH SIMULATION} +\lstinputlisting[style=blockdefinition]{./mf6ivar/tex/gwf-vsc-options.dat} +\lstinputlisting[style=blockdefinition]{./mf6ivar/tex/gwf-vsc-dimensions.dat} +\lstinputlisting[style=blockdefinition]{./mf6ivar/tex/gwf-vsc-packagedata.dat} + +\vspace{5mm} +\subsubsection{Explanation of Variables} +\begin{description} +\input{./mf6ivar/tex/gwf-vsc-desc.tex} +\end{description} + +\vspace{5mm} +\subsubsection{Example Input File} +\lstinputlisting[style=inputfile]{./mf6ivar/examples/gwf-vsc-example.dat} diff --git a/doc/mf6io/mf6io.bbl b/doc/mf6io/mf6io.bbl index 05fffcda052..c4d7f4a09b6 100644 --- a/doc/mf6io/mf6io.bbl +++ b/doc/mf6io/mf6io.bbl @@ -1,4 +1,4 @@ -\begin{thebibliography}{34} +\begin{thebibliography}{35} \providecommand{\natexlab}[1]{#1} \expandafter\ifx\csname urlstyle\endcsname\relax \providecommand{\doi}[1]{doi:\discretionary{}{}{}#1}\else @@ -228,6 +228,12 @@ Prudic, D.E., Konikow, L.F., and Banta, E.R., 2004, A New Streamflow-Routing {U.S. Geological Survey Open File Report 2004--1042, 104 p.}, accessed June 27, 2017, at \url{https://pubs.er.usgs.gov/publication/ofr20041042}. +\bibitem[{Voss(1984)}]{Voss1984sutra} +Voss, C.I., 1984, SUTRA---A finite-element simulation model for + saturated-unsaturated fluid-density-dependent ground-water flow with energy + transport or chemically-reactive single-species solute transport: {U.S. + Geological Survey Water-Resources Investigations Report 84--4369, 409 p.} + \bibitem[{Zheng(2010)}]{zheng2010supplemental} Zheng, Chunmiao, 2010, MT3DMS v5.3, Supplemental User's Guide: {Technical Report Prepared for the U.S. Army Corps of Engineers, 51 p.} diff --git a/doc/mf6io/mf6ivar/dfn/exg-gwtgwt.dfn b/doc/mf6io/mf6ivar/dfn/exg-gwtgwt.dfn index 668e1131c76..f7956f73687 100644 --- a/doc/mf6io/mf6ivar/dfn/exg-gwtgwt.dfn +++ b/doc/mf6io/mf6ivar/dfn/exg-gwtgwt.dfn @@ -60,7 +60,7 @@ longname keyword to save GWFGWF flows description keyword to indicate that cell-by-cell flow terms will be written to the budget file for each model provided that the Output Control for the models are set up with the ``BUDGET SAVE FILE'' option. block options -name advscheme +name adv_scheme type string valid upstream central tvd reader urword @@ -69,22 +69,22 @@ longname advective scheme description scheme used to solve the advection term. Can be upstream, central, or TVD. If not specified, upstream weighting is the default weighting scheme. block options -name xt3d_off +name dsp_xt3d_off type keyword shape reader urword optional true longname deactivate xt3d -description deactivate the xt3d method and use the faster and less accurate approximation for this exchange. +description deactivate the xt3d method for the dispersive flux and use the faster and less accurate approximation for this exchange. block options -name xt3d_rhs +name dsp_xt3d_rhs type keyword shape reader urword optional true longname xt3d on right-hand side -description add xt3d terms to right-hand side, when possible, for this exchange. +description add xt3d dispersion terms to right-hand side, when possible, for this exchange. block options name filein diff --git a/doc/mf6io/mf6ivar/dfn/gwf-buy.dfn b/doc/mf6io/mf6ivar/dfn/gwf-buy.dfn index 8412b3a783d..b131433b9b1 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-buy.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-buy.dfn @@ -79,7 +79,7 @@ type integer reader urword optional false longname number of species used in density equation of state -description number of species used in density equation of state. This value must be one or greater. The value must be one if concentrations are specified using the CONCENTRATION keyword in the PERIOD block below. +description number of species used in density equation of state. This value must be one or greater if the BUY package is activated. # --------------------- gwf buy packagedata --------------------- @@ -140,6 +140,6 @@ in_record true tagged false shape reader urword -longname modelname +longname auxspeciesname description name of an auxiliary variable in a GWF stress package that will be used for this species to calculate a density value. If a density value is needed by the Buoyancy Package then it will use the concentration values in this AUXSPECIESNAME column in the density equation of state. For advanced stress packages (LAK, SFR, MAW, and UZF) that have an associated advanced transport package (LKT, SFT, MWT, and UZT), the FLOW\_PACKAGE\_AUXILIARY\_NAME option in the advanced transport package can be used to transfer simulated concentrations into the flow package auxiliary variable. In this manner, the Buoyancy Package can calculate density values for lakes, streams, multi-aquifer wells, and unsaturated zone flow cells using simulated concentrations. diff --git a/doc/mf6io/mf6ivar/dfn/gwf-disu.dfn b/doc/mf6io/mf6ivar/dfn/gwf-disu.dfn index e3590bf2519..8c131363e2f 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-disu.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-disu.dfn @@ -48,6 +48,7 @@ optional true default_value 0.0 longname vertical length dimension for top and bottom checking description checks are performed to ensure that the top of a cell is not higher than the bottom of an overlying cell. This option can be used to specify the tolerance that is used for checking. If top of a cell is above the bottom of an overlying cell by a value less than this tolerance, then the program will not terminate with an error. The default value is zero. This option should generally not be used. +mf6internal voffsettol # --------------------- gwf disu dimensions --------------------- @@ -173,6 +174,7 @@ jagged_array iac block vertices name vertices type recarray iv xv yv +shape (nvert) reader urword optional false longname vertices data @@ -215,6 +217,7 @@ description is the y-coordinate for the vertex. block cell2d name cell2d type recarray icell2d xc yc ncvert icvert +shape (nodes) reader urword optional false longname cell2d data diff --git a/doc/mf6io/mf6ivar/dfn/gwf-disv.dfn b/doc/mf6io/mf6ivar/dfn/gwf-disv.dfn index 53ae67bd945..c6bab33389e 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-disv.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-disv.dfn @@ -79,7 +79,7 @@ description is the top elevation for each cell in the top model layer. block griddata name botm type double precision -shape (nlay, ncpl) +shape (ncpl, nlay) reader readarray layered true longname model bottom elevation @@ -88,7 +88,7 @@ description is the bottom elevation for each cell. block griddata name idomain type integer -shape (nlay, ncpl) +shape (ncpl, nlay) reader readarray layered true optional true @@ -101,6 +101,7 @@ description is an optional array that characterizes the existence status of a ce block vertices name vertices type recarray iv xv yv +shape (nvert) reader urword optional false longname vertices data @@ -143,6 +144,7 @@ description is the y-coordinate for the vertex. block cell2d name cell2d type recarray icell2d xc yc ncvert icvert +shape (ncpl) reader urword optional false longname cell2d data diff --git a/doc/mf6io/mf6ivar/dfn/gwf-evt.dfn b/doc/mf6io/mf6ivar/dfn/gwf-evt.dfn index 874114955c1..b66f62301c8 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-evt.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-evt.dfn @@ -160,7 +160,7 @@ type integer reader urword optional false longname number of ET segments -description number of ET segments. Default is one. When NSEG is greater than 1, PXDP and PETM arrays must be specified NSEG - 1 times each, in order from the uppermost segment down. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. +description number of ET segments. Default is one. When NSEG is greater than 1, the PXDP and PETM arrays must be of size NSEG - 1 and be listed in order from the uppermost segment down. Values for PXDP must be listed first followed by the values for PETM. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. # --------------------- gwf evt period --------------------- @@ -237,7 +237,7 @@ in_record true reader urword time_series true longname proportion of ET extinction depth -description is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. +description is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). pxdp is an array of size (nseg - 1). Values in pxdp must be greater than 0.0 and less than 1.0. pxdp values for a cell must increase monotonically. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. block period name petm @@ -248,7 +248,7 @@ in_record true reader urword time_series true longname proportion of maximum ET rate -description is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. +description is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). petm is an array of size (nseg - 1). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. block period name petm0 diff --git a/doc/mf6io/mf6ivar/dfn/gwf-gnc.dfn b/doc/mf6io/mf6ivar/dfn/gwf-gnc.dfn index 551acd3a530..2a6a07c7072 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-gnc.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-gnc.dfn @@ -1,4 +1,6 @@ # --------------------- gwf gnc options --------------------- +# flopy subpackage gnc_filerecord gnc gncdata gncdata +# flopy parent_name_type parent_model_or_package block options name print_input diff --git a/doc/mf6io/mf6ivar/dfn/gwf-lak.dfn b/doc/mf6io/mf6ivar/dfn/gwf-lak.dfn index 9785819bbb5..9173aaec300 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-lak.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-lak.dfn @@ -448,7 +448,7 @@ description character string that defines the lake-GWF connection type for the l block connectiondata name bedleak -type double precision +type string shape tagged false in_record true diff --git a/doc/mf6io/mf6ivar/dfn/gwf-maw.dfn b/doc/mf6io/mf6ivar/dfn/gwf-maw.dfn index e504daf9e6d..bf64974c4a0 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-maw.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-maw.dfn @@ -201,6 +201,39 @@ optional true longname shutdown kappa description value that defines the weight applied to discharge rate for wells that limit the water level in a discharging well (defined using the HEAD\_LIMIT keyword in the stress period data). SHUTDOWN\_KAPPA is used to control discharge rate oscillations when the flow rate from the aquifer is less than the specified flow rate from the aquifer to the well. Values range between 0.0 and 1.0, and larger values increase the weight applied to the well discharge rate. The HEAD\_LIMIT option has been included to facilitate backward compatibility with previous versions of MODFLOW but use of the RATE\_SCALING option instead of the HEAD\_LIMIT option is recommended. By default, SHUTDOWN\_KAPPA is 0.0001. +block options +name mfrcsv_filerecord +type record maw_flow_reduce_csv fileout mfrcsvfile +shape +reader urword +tagged true +optional true +longname +description + +block options +name maw_flow_reduce_csv +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname budget keyword +description keyword to specify that record corresponds to the output option in which a new record is written for each multi-aquifer well and for each time step in which the user-requested extraction or injection rate is reduced by the program. + +block options +name mfrcsvfile +type string +preserve_case true +shape +in_record true +reader urword +tagged false +optional false +longname file keyword +description name of the comma-separated value (CSV) output file to write information about multi-aquifer well extraction or injection rates that have been reduced by the program. Entries are only written if the extraction or injection rates are reduced. + block options name ts_filerecord type record ts6 filein ts6_filename diff --git a/doc/mf6io/mf6ivar/dfn/gwf-mvr.dfn b/doc/mf6io/mf6ivar/dfn/gwf-mvr.dfn index bbc031a9564..a30a29b8c44 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-mvr.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-mvr.dfn @@ -1,4 +1,6 @@ # --------------------- gwf mvr options --------------------- +# flopy subpackage mvr_filerecord mvr perioddata perioddata +# flopy parent_name_type parent_model_or_package MFModel/MFPackage block options name print_input diff --git a/doc/mf6io/mf6ivar/dfn/gwf-npf.dfn b/doc/mf6io/mf6ivar/dfn/gwf-npf.dfn index 76d4d01663f..1c18223cc5a 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-npf.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-npf.dfn @@ -7,6 +7,16 @@ reader urword optional true longname keyword to save NPF flows description keyword to indicate that budget flow terms will be written to the file specified with ``BUDGET SAVE FILE'' in Output Control. +mf6internal ipakcb + +block options +name print_flows +type keyword +reader urword +optional true +longname keyword to print NPF flows to listing file +description keyword to indicate that calculated flows between cells will be printed to the listing file for every stress period time step in which ``BUDGET PRINT'' is specified in Output Control. If there is no Output Control option and ``PRINT\_FLOWS'' is specified, then flow rates are printed for the last time step of each stress period. This option can produce extremely large list files because all cell-by-cell flows are printed. It should only be used with the NPF Package for models that have a small number of cells. +mf6internal iprflow block options name alternative_cell_averaging @@ -16,6 +26,7 @@ reader urword optional true longname conductance weighting option description is a text keyword to indicate that an alternative method will be used for calculating the conductance for horizontal cell connections. The text value for ALTERNATIVE\_CELL\_AVERAGING can be ``LOGARITHMIC'', ``AMT-LMK'', or ``AMT-HMK''. ``AMT-LMK'' signifies that the conductance will be calculated using arithmetic-mean thickness and logarithmic-mean hydraulic conductivity. ``AMT-HMK'' signifies that the conductance will be calculated using arithmetic-mean thickness and harmonic-mean hydraulic conductivity. If the user does not specify a value for ALTERNATIVE\_CELL\_AVERAGING, then the harmonic-mean method will be used. This option cannot be used if the XT3D option is invoked. +mf6internal cellavg block options name thickstrt @@ -24,6 +35,7 @@ reader urword optional true longname keyword to activate THICKSTRT option description indicates that cells having a negative ICELLTYPE are confined, and their cell thickness for conductance calculations will be computed as STRT-BOT rather than TOP-BOT. +mf6internal ithickstrt block options name cvoptions @@ -40,6 +52,7 @@ type keyword reader urword longname keyword to activate VARIABLECV option description keyword to indicate that the vertical conductance will be calculated using the saturated thickness and properties of the overlying cell and the thickness and properties of the underlying cell. If the DEWATERED keyword is also specified, then the vertical conductance is calculated using only the saturated thickness and properties of the overlying cell if the head in the underlying cell is below its top. If these keywords are not specified, then the default condition is to calculate the vertical conductance at the start of the simulation using the initial head and the cell properties. The vertical conductance remains constant for the entire simulation. +mf6internal ivarcv block options name dewatered @@ -49,6 +62,7 @@ reader urword optional true longname keyword to activate DEWATERED option description If the DEWATERED keyword is specified, then the vertical conductance is calculated using only the saturated thickness and properties of the overlying cell if the head in the underlying cell is below its top. +mf6internal idewatcv block options name perched @@ -57,6 +71,7 @@ reader urword optional true longname keyword to activate PERCHED option description keyword to indicate that when a cell is overlying a dewatered convertible cell, the head difference used in Darcy's Law is equal to the head in the overlying cell minus the bottom elevation of the overlying cell. If not specified, then the default is to use the head difference between the two cells. +mf6internal iperched block options name rewet_record @@ -74,6 +89,7 @@ reader urword optional false longname keyword to activate rewetting description activates model rewetting. Rewetting is off by default. +mf6internal irewet block options name wetfct @@ -117,6 +133,7 @@ type keyword reader urword longname keyword to activate XT3D description keyword indicating that the XT3D formulation will be used. If the RHS keyword is also included, then the XT3D additional terms will be added to the right-hand side. If the RHS keyword is excluded, then the XT3D terms will be put into the coefficient matrix. Use of XT3D will substantially increase the computational effort, but will result in improved accuracy for anisotropic conductivity fields and for unstructured grids in which the CVFD requirement is violated. XT3D requires additional information about the shapes of grid cells. If XT3D is active and the DISU Package is used, then the user will need to provide in the DISU Package the angldegx array in the CONNECTIONDATA block and the VERTICES and CELL2D blocks. +mf6internal ixt3d block options name rhs @@ -126,6 +143,7 @@ reader urword optional true longname keyword to XT3D on right hand side description If the RHS keyword is also included, then the XT3D additional terms will be added to the right-hand side. If the RHS keyword is excluded, then the XT3D terms will be put into the coefficient matrix. +mf6internal ixt3drhs block options name save_specific_discharge @@ -134,6 +152,7 @@ reader urword optional true longname keyword to save specific discharge description keyword to indicate that x, y, and z components of specific discharge will be calculated at cell centers and written to the budget file, which is specified with ``BUDGET SAVE FILE'' in Output Control. If this option is activated, then additional information may be required in the discretization packages and the GWF Exchange package (if GWF models are coupled). Specifically, ANGLDEGX must be specified in the CONNECTIONDATA block of the DISU Package; ANGLDEGX must also be specified for the GWF Exchange as an auxiliary variable. +mf6internal isavspdis block options name save_saturation @@ -142,6 +161,7 @@ reader urword optional true longname keyword to save saturation description keyword to indicate that cell saturation will be written to the budget file, which is specified with ``BUDGET SAVE FILE'' in Output Control. Saturation will be saved to the budget file as an auxiliary variable saved with the DATA-SAT text label. Saturation is a cell variable that ranges from zero to one and can be used by post processing programs to determine how much of a cell volume is saturated. If ICELLTYPE is 0, then saturation is always one. +mf6internal isavsat block options name k22overk @@ -150,6 +170,7 @@ reader urword optional true longname keyword to indicate that specified K22 is a ratio description keyword to indicate that specified K22 is a ratio of K22 divided by K. If this option is specified, then the K22 array entered in the NPF Package will be multiplied by K after being read. +mf6internal ik22overk block options name k33overk @@ -158,10 +179,11 @@ reader urword optional true longname keyword to indicate that specified K33 is a ratio description keyword to indicate that specified K33 is a ratio of K33 divided by K. If this option is specified, then the K33 array entered in the NPF Package will be multiplied by K after being read. +mf6internal ik33overk block options name tvk_filerecord -type record tvk6 filein tvk_filename +type record tvk6 filein tvk6_filename shape reader urword tagged true @@ -192,7 +214,7 @@ longname file keyword description keyword to specify that an input filename is expected next. block options -name tvk_filename +name tvk6_filename type string preserve_case true in_record true @@ -202,6 +224,52 @@ tagged false longname file name of TVK information description defines a time-varying hydraulic conductivity (TVK) input file. Records in the TVK file can be used to change hydraulic conductivity properties at specified times or stress periods. +# dev options + +block options +name dev_no_newton +type keyword +reader urword +optional true +longname turn off Newton for unconfined cells +description turn off Newton for unconfined cells +mf6internal inewton + +block options +name dev_modflowusg_upstream_weighted_saturation +type keyword +reader urword +optional true +longname use MODFLOW-USG upstream-weighted saturation approach +description use MODFLOW-USG upstream-weighted saturation approach +mf6internal iusgnrhc + +block options +name dev_modflownwt_upstream_weighting +type keyword +reader urword +optional true +longname use MODFLOW-NWT approach for upstream weighting +description use MODFLOW-NWT approach for upstream weighting +mf6internal inwtupw + +block options +name dev_minimum_saturated_thickness +type double precision +reader urword +optional true +longname set minimum allowed saturated thickness +description set minimum allowed saturated thickness +mf6internal satmin + +block options +name dev_omega +type double precision +reader urword +optional true +longname set saturation omega value +description set saturation omega value +mf6internal satomega # --------------------- gwf npf griddata --------------------- @@ -294,4 +362,3 @@ layered true optional true longname wetdry threshold and factor description is a combination of the wetting threshold and a flag to indicate which neighboring cells can cause a cell to become wet. If WETDRY $<$ 0, only a cell below a dry cell can cause the cell to become wet. If WETDRY $>$ 0, the cell below a dry cell and horizontally adjacent cells can cause a cell to become wet. If WETDRY is 0, the cell cannot be wetted. The absolute value of WETDRY is the wetting threshold. When the sum of BOT and the absolute value of WETDRY at a dry cell is equaled or exceeded by the head at an adjacent cell, the cell is wetted. WETDRY must be specified if ``REWET'' is specified in the OPTIONS block. If ``REWET'' is not specified in the options block, then WETDRY can be entered, and memory will be allocated for it, even though it is not used. - diff --git a/doc/mf6io/mf6ivar/dfn/gwf-sto.dfn b/doc/mf6io/mf6ivar/dfn/gwf-sto.dfn index d9f3b2a4c11..9e5bcd668b3 100644 --- a/doc/mf6io/mf6ivar/dfn/gwf-sto.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwf-sto.dfn @@ -22,7 +22,7 @@ type keyword reader urword optional true longname keyword to indicate specific storage only applied under confined conditions -description keyword to indicate that specific storage is only calculated when a cell is under confined conditions (head greater than or equal to the top of the cell). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. +description keyword to indicate that compressible storage is only calculated for a convertible cell (ICONVERT>0) when the cell is under confined conditions (head greater than or equal to the top of the cell). This option has no effect on cells that are marked as being always confined (ICONVERT=0). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. block options name tvs_filerecord diff --git a/doc/mf6io/mf6ivar/dfn/gwf-vsc.dfn b/doc/mf6io/mf6ivar/dfn/gwf-vsc.dfn new file mode 100644 index 00000000000..9e3ab6d0083 --- /dev/null +++ b/doc/mf6io/mf6ivar/dfn/gwf-vsc.dfn @@ -0,0 +1,174 @@ +# --------------------- gwf vsc options --------------------- + +block options +name viscref +type double +reader urword +optional true +longname reference viscosity +description fluid reference viscosity used in the equation of state. This value is set to 1.0 if not specified as an option. +default_value 1.0 + +block options +name temperature_species_name +type string +shape +reader urword +optional true +longname auxspeciesname that corresponds to temperature +description string used to identify the auxspeciesname in PACKAGEDATA that corresponds to the temperature species. There can be only one occurrence of this temperature species name in the PACKAGEDATA block or the program will terminate with an error. This value has no effect if viscosity does not depend on temperature. + +block options +name thermal_formulation +type string +shape +reader urword +optional true +valid linear nonlinear +longname keyword to specify viscosity formulation for the temperature species +description may be used for specifying which viscosity formulation to use for the temperature species. Can be either LINEAR or NONLINEAR. The LINEAR viscosity formulation is the default. + +block options +name thermal_a2 +type double +reader urword +optional true +longname coefficient used in nonlinear viscosity function +description is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A2 is not specified, a default value of 10.0 is assigned (Voss, 1984). +default_value 10. + +block options +name thermal_a3 +type double +reader urword +optional true +longname coefficient used in nonlinear viscosity function +description is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A3 is not specified, a default value of 248.37 is assigned (Voss, 1984). +default_value 248.37 + +block options +name thermal_a4 +type double precision +reader urword +optional true +longname coefficient used in nonlinear viscosity function +description is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A4 is not specified, a default value of 133.15 is assigned (Voss, 1984). +default_value 133.15 + +block options +name viscosity_filerecord +type record viscosity fileout viscosityfile +shape +reader urword +tagged true +optional true +longname +description + +block options +name viscosity +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname viscosity keyword +description keyword to specify that record corresponds to viscosity. + +block options +name fileout +type keyword +shape +in_record true +reader urword +tagged true +optional false +longname file keyword +description keyword to specify that an output filename is expected next. + +block options +name viscosityfile +type string +preserve_case true +shape +in_record true +reader urword +tagged false +optional false +longname file keyword +description name of the binary output file to write viscosity information. The viscosity file has the same format as the head file. Viscosity values will be written to the viscosity file whenever heads are written to the binary head file. The settings for controlling head output are contained in the Output Control option. + + +# --------------------- gwf vsc dimensions --------------------- + +block dimensions +name nviscspecies +type integer +reader urword +optional false +longname number of species used in viscosity equation of state +description number of species used in the viscosity equation of state. If either concentrations or temperature (or both) are used to update viscosity then then nrhospecies needs to be at least one. + + +# --------------------- gwf vsc packagedata --------------------- + +block packagedata +name packagedata +type recarray iviscspec dviscdc cviscref modelname auxspeciesname +shape (nrhospecies) +reader urword +longname +description + +block packagedata +name iviscspec +type integer +shape +tagged false +in_record true +reader urword +longname species number for this entry +description integer value that defines the species number associated with the specified PACKAGEDATA data entered on each line. IVISCSPECIES must be greater than zero and less than or equal to NVISCSPECIES. Information must be specified for each of the NVISCSPECIES species or the program will terminate with an error. The program will also terminate with an error if information for a species is specified more than once. +numeric_index true + +block packagedata +name dviscdc +type double precision +shape +tagged false +in_record true +reader urword +longname slope of the line that defines the linear relationship between viscosity and temperature or between viscosity and concentration, depending on the type of species entered on each line. +description real value that defines the slope of the line defining the linear relationship between viscosity and temperature or between viscosity and concentration, depending on the type of species entered on each line. If the value of AUXSPECIESNAME entered on a line corresponds to TEMPERATURE\_SPECIES\_NAME (in the OPTIONS block), this value will be used when VISCOSITY\_FUNC is equal to LINEAR (the default) in the OPTIONS block. When VISCOSITY\_FUNC is set to NONLINEAR, a value for DVISCDC must be specified though it is not used. + +block packagedata +name cviscref +type double precision +shape +tagged false +in_record true +reader urword +longname reference temperature value or reference concentration value +description real value that defines the reference temperature or reference concentration value used for this species in the viscosity equation of state. If AUXSPECIESNAME entered on a line corresponds to TEMPERATURE\_SPECIES\_NAME (in the OPTIONS block), then CVISCREF refers to a reference temperature, otherwise it refers to a reference concentration. + +block packagedata +name modelname +type string +in_record true +tagged false +shape +reader urword +longname modelname +description name of a GWT model used to simulate a species that will be used in the viscosity equation of state. This name will have no effect if the simulation does not include a GWT model that corresponds to this GWF model. + +block packagedata +name auxspeciesname +type string +in_record true +tagged false +shape +reader urword +longname auxspeciesname +description name of an auxiliary variable in a GWF stress package that will be used for this species to calculate the viscosity values. If a viscosity value is needed by the Viscosity Package then it will use the temperature or concentration values associated with this AUXSPECIESNAME in the viscosity equation of state. For advanced stress packages (LAK, SFR, MAW, and UZF) that have an associated advanced transport package (LKT, SFT, MWT, and UZT), the FLOW\_PACKAGE\_AUXILIARY\_NAME option in the advanced transport package can be used to transfer simulated temperature or concentration(s) into the flow package auxiliary variable. In this manner, the Viscosity Package can calculate viscosity values for lakes, streams, multi-aquifer wells, and unsaturated zone flow cells using simulated concentrations. + diff --git a/doc/mf6io/mf6ivar/dfn/gwt-mvt.dfn b/doc/mf6io/mf6ivar/dfn/gwt-mvt.dfn index e69b35782a0..4423589f93d 100644 --- a/doc/mf6io/mf6ivar/dfn/gwt-mvt.dfn +++ b/doc/mf6io/mf6ivar/dfn/gwt-mvt.dfn @@ -1,4 +1,6 @@ # --------------------- gwt mvt options --------------------- +# flopy subpackage mvt_filerecord mvt perioddata perioddata +# flopy parent_name_type parent_model_or_package MFModel/MFPackage block options name print_input diff --git a/doc/mf6io/mf6ivar/dfn/utl-ats.dfn b/doc/mf6io/mf6ivar/dfn/utl-ats.dfn index e2bf72761c3..d2cd5a40a01 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-ats.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-ats.dfn @@ -1,5 +1,6 @@ # --------------------- sim ats options --------------------- - +# flopy subpackage ats_filerecord ats perioddata ats_perioddata +# flopy parent_name_type parent_package MFPackage # --------------------- sim ats dimensions --------------------- diff --git a/doc/mf6io/mf6ivar/dfn/utl-laktab.dfn b/doc/mf6io/mf6ivar/dfn/utl-laktab.dfn index a771ea0509c..fe18e4bf99d 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-laktab.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-laktab.dfn @@ -1,4 +1,5 @@ # --------------------- gwf laktab dimensions --------------------- +# flopy multi-package block dimensions name nrow diff --git a/doc/mf6io/mf6ivar/dfn/utl-obs.dfn b/doc/mf6io/mf6ivar/dfn/utl-obs.dfn index e54b0ff5ccb..d75ce62e479 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-obs.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-obs.dfn @@ -1,5 +1,7 @@ # --------------------- gwf obs options --------------------- # flopy multi-package +# flopy subpackage obs_filerecord obs continuous observations +# flopy parent_name_type parent_model_or_package MFModel/MFPackage block options name digits diff --git a/doc/mf6io/mf6ivar/dfn/utl-sfrtab.dfn b/doc/mf6io/mf6ivar/dfn/utl-sfrtab.dfn index 28e693b6efa..ff04c6cfc79 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-sfrtab.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-sfrtab.dfn @@ -1,4 +1,5 @@ # --------------------- gwf sfrtab dimensions --------------------- +# flopy multi-package block dimensions name nrow diff --git a/doc/mf6io/mf6ivar/dfn/utl-tas.dfn b/doc/mf6io/mf6ivar/dfn/utl-tas.dfn index 6414639cc39..6316beba5cd 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-tas.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-tas.dfn @@ -1,5 +1,7 @@ # --------------------- gwf ts attributes --------------------- # flopy multi-package +# flopy subpackage tas_filerecord tas tas_array timearrayseries +# flopy parent_name_type parent_package MFPackage block attributes name time_series_namerecord diff --git a/doc/mf6io/mf6ivar/dfn/utl-ts.dfn b/doc/mf6io/mf6ivar/dfn/utl-ts.dfn index 9e430507ad0..a7165ea3823 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-ts.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-ts.dfn @@ -1,5 +1,7 @@ # --------------------- gwf ts attributes --------------------- # flopy multi-package +# flopy subpackage ts_filerecord ts timeseries timeseries +# flopy parent_name_type parent_package MFPackage block attributes name time_series_namerecord diff --git a/doc/mf6io/mf6ivar/dfn/utl-tvk.dfn b/doc/mf6io/mf6ivar/dfn/utl-tvk.dfn index e0f2960a2b0..5a82f9a77d9 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-tvk.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-tvk.dfn @@ -1,4 +1,6 @@ # --------------------- gwf tvk options --------------------- +# flopy subpackage tvk_filerecord tvk tvk_perioddata perioddata +# flopy parent_name_type parent_package MFPackage block options name print_input diff --git a/doc/mf6io/mf6ivar/dfn/utl-tvs.dfn b/doc/mf6io/mf6ivar/dfn/utl-tvs.dfn index 837319d2937..9ba03c990f2 100644 --- a/doc/mf6io/mf6ivar/dfn/utl-tvs.dfn +++ b/doc/mf6io/mf6ivar/dfn/utl-tvs.dfn @@ -1,4 +1,6 @@ # --------------------- gwf tvs options --------------------- +# flopy subpackage tvs_filerecord tvs tvs_perioddata perioddata +# flopy parent_name_type parent_package MFPackage block options name disable_storage_change_integration diff --git a/doc/mf6io/mf6ivar/examples/gwf-evt-example.dat b/doc/mf6io/mf6ivar/examples/gwf-evt-example.dat index a79706e9e1f..436e0f83f1e 100644 --- a/doc/mf6io/mf6ivar/examples/gwf-evt-example.dat +++ b/doc/mf6io/mf6ivar/examples/gwf-evt-example.dat @@ -9,10 +9,11 @@ PRINT_INPUT BEGIN DIMENSIONS MAXBOUND 10 + NSEG 3 END DIMENSIONS BEGIN PERIOD 1 -# Lay Row Col SURFACE RATE DEPTH PXPD1 PXPD2 PETM1 PETM2 Mult Name +# Lay Row Col SURFACE RATE DEPTH PXDP1 PXDP2 PETM1 PETM2 Mult Name 1 1 13 110.0 et_rate 10.0 0.2 0.5 0.3 0.1 0.2 ET-1 1 2 13 110.0 et_rate 10.0 0.2 0.5 0.3 0.1 0.4 ET-2 1 3 13 110.0 et_rate 10.0 0.2 0.5 0.3 0.1 0.6 ET-3 diff --git a/doc/mf6io/mf6ivar/examples/gwf-vsc-example.dat b/doc/mf6io/mf6ivar/examples/gwf-vsc-example.dat new file mode 100644 index 00000000000..48d21bd801b --- /dev/null +++ b/doc/mf6io/mf6ivar/examples/gwf-vsc-example.dat @@ -0,0 +1,18 @@ +BEGIN OPTIONS + VISCREF 8.904E-04 + THERMAL_FORMULATION NONLINEAR + THERMAL_A2 10.0 + THERMAL_A3 248.37 + THERMAL_A4 133.15 + VISCOSITY FILEOUT GWF-VSC.vsc.bin +END OPTIONS + +BEGIN DIMENSIONS + NVISCSPECIES 2 +END DIMENSIONS + +BEGIN PACKAGEDATA +# ISPEC DVISCDC CVISCREF MODELNAME AUXSPECIESNAME + 1 1.92e-6 0.0 GWT-SALT SALINITY + 2 0.00 25.0 GWT-TEMP TEMPERATURE +END PACKAGEDATA diff --git a/doc/mf6io/mf6ivar/examples/gwt-uzt-example-obs.dat b/doc/mf6io/mf6ivar/examples/gwt-uzt-example-obs.dat index 17a2a88afaa..8d52cf11160 100644 --- a/doc/mf6io/mf6ivar/examples/gwt-uzt-example-obs.dat +++ b/doc/mf6io/mf6ivar/examples/gwt-uzt-example-obs.dat @@ -6,7 +6,7 @@ END options BEGIN continuous FILEOUT gwt_02.uzt.obs.csv mwt-1-conc CONCENTRATION 1 mwt-1-stor STORAGE 1 - mwt-1-gwt1 UZT 1 1 - mwt-1-gwt2 UZT 2 2 - mwt-2-gwt1 UZT 3 3 + mwt-1-gwt1 UZT 1 + mwt-1-gwt2 UZT 2 + mwt-2-gwt1 UZT 3 END continuous diff --git a/doc/mf6io/mf6ivar/md/mf6ivar.md b/doc/mf6io/mf6ivar/md/mf6ivar.md index d8b992b91cb..4423337ddb1 100644 --- a/doc/mf6io/mf6ivar/md/mf6ivar.md +++ b/doc/mf6io/mf6ivar/md/mf6ivar.md @@ -62,9 +62,9 @@ | EXG | GWTGWT | OPTIONS | PRINT_INPUT | KEYWORD | keyword to indicate that the list of exchange entries will be echoed to the listing file immediately after it is read. | | EXG | GWTGWT | OPTIONS | PRINT_FLOWS | KEYWORD | keyword to indicate that the list of exchange flow rates will be printed to the listing file for every stress period in which ``SAVE BUDGET'' is specified in Output Control. | | EXG | GWTGWT | OPTIONS | SAVE_FLOWS | KEYWORD | keyword to indicate that cell-by-cell flow terms will be written to the budget file for each model provided that the Output Control for the models are set up with the ``BUDGET SAVE FILE'' option. | -| EXG | GWTGWT | OPTIONS | ADVSCHEME | STRING | scheme used to solve the advection term. Can be upstream, central, or TVD. If not specified, upstream weighting is the default weighting scheme. | -| EXG | GWTGWT | OPTIONS | XT3D_OFF | KEYWORD | deactivate the xt3d method and use the faster and less accurate approximation for this exchange. | -| EXG | GWTGWT | OPTIONS | XT3D_RHS | KEYWORD | add xt3d terms to right-hand side, when possible, for this exchange. | +| EXG | GWTGWT | OPTIONS | ADV_SCHEME | STRING | scheme used to solve the advection term. Can be upstream, central, or TVD. If not specified, upstream weighting is the default weighting scheme. | +| EXG | GWTGWT | OPTIONS | DSP_XT3D_OFF | KEYWORD | deactivate the xt3d method for the dispersive flux and use the faster and less accurate approximation for this exchange. | +| EXG | GWTGWT | OPTIONS | DSP_XT3D_RHS | KEYWORD | add xt3d dispersion terms to right-hand side, when possible, for this exchange. | | EXG | GWTGWT | OPTIONS | FILEIN | KEYWORD | keyword to specify that an input filename is expected next. | | EXG | GWTGWT | OPTIONS | MVT6 | KEYWORD | keyword to specify that record corresponds to a transport mover file. | | EXG | GWTGWT | OPTIONS | MVT6_FILENAME | STRING | is the file name of the transport mover input file to apply to this exchange. Information for the transport mover are provided in the file provided with these keywords. | @@ -148,8 +148,8 @@ | GWF | DISV | DIMENSIONS | NCPL | INTEGER | is the number of cells per layer. This is a constant value for the grid and it applies to all layers. | | GWF | DISV | DIMENSIONS | NVERT | INTEGER | is the total number of (x, y) vertex pairs used to characterize the horizontal configuration of the model grid. | | GWF | DISV | GRIDDATA | TOP | DOUBLE PRECISION (NCPL) | is the top elevation for each cell in the top model layer. | -| GWF | DISV | GRIDDATA | BOTM | DOUBLE PRECISION (NLAY, NCPL) | is the bottom elevation for each cell. | -| GWF | DISV | GRIDDATA | IDOMAIN | INTEGER (NLAY, NCPL) | is an optional array that characterizes the existence status of a cell. If the IDOMAIN array is not specified, then all model cells exist within the solution. If the IDOMAIN value for a cell is 0, the cell does not exist in the simulation. Input and output values will be read and written for the cell, but internal to the program, the cell is excluded from the solution. If the IDOMAIN value for a cell is 1 or greater, the cell exists in the simulation. If the IDOMAIN value for a cell is -1, the cell does not exist in the simulation. Furthermore, the first existing cell above will be connected to the first existing cell below. This type of cell is referred to as a ``vertical pass through'' cell. | +| GWF | DISV | GRIDDATA | BOTM | DOUBLE PRECISION (NCPL, NLAY) | is the bottom elevation for each cell. | +| GWF | DISV | GRIDDATA | IDOMAIN | INTEGER (NCPL, NLAY) | is an optional array that characterizes the existence status of a cell. If the IDOMAIN array is not specified, then all model cells exist within the solution. If the IDOMAIN value for a cell is 0, the cell does not exist in the simulation. Input and output values will be read and written for the cell, but internal to the program, the cell is excluded from the solution. If the IDOMAIN value for a cell is 1 or greater, the cell exists in the simulation. If the IDOMAIN value for a cell is -1, the cell does not exist in the simulation. Furthermore, the first existing cell above will be connected to the first existing cell below. This type of cell is referred to as a ``vertical pass through'' cell. | | GWF | DISV | VERTICES | IV | INTEGER | is the vertex number. Records in the VERTICES block must be listed in consecutive order from 1 to NVERT. | | GWF | DISV | VERTICES | XV | DOUBLE PRECISION | is the x-coordinate for the vertex. | | GWF | DISV | VERTICES | YV | DOUBLE PRECISION | is the y-coordinate for the vertex. | @@ -187,6 +187,7 @@ | GWF | DISU | CELL2D | ICVERT | INTEGER (NCVERT) | is an array of integer values containing vertex numbers (in the VERTICES block) used to define the cell. Vertices must be listed in clockwise order. | | GWF | IC | GRIDDATA | STRT | DOUBLE PRECISION (NODES) | is the initial (starting) head---that is, head at the beginning of the GWF Model simulation. STRT must be specified for all simulations, including steady-state simulations. One value is read for every model cell. For simulations in which the first stress period is steady state, the values used for STRT generally do not affect the simulation (exceptions may occur if cells go dry and (or) rewet). The execution time, however, will be less if STRT includes hydraulic heads that are close to the steady-state solution. A head value lower than the cell bottom can be provided if a cell should start as dry. | | GWF | NPF | OPTIONS | SAVE_FLOWS | KEYWORD | keyword to indicate that budget flow terms will be written to the file specified with ``BUDGET SAVE FILE'' in Output Control. | +| GWF | NPF | OPTIONS | PRINT_FLOWS | KEYWORD | keyword to indicate that calculated flows between cells will be printed to the listing file for every stress period time step in which ``BUDGET PRINT'' is specified in Output Control. If there is no Output Control option and ``PRINT\_FLOWS'' is specified, then flow rates are printed for the last time step of each stress period. This option can produce extremely large list files because all cell-by-cell flows are printed. It should only be used with the NPF Package for models that have a small number of cells. | | GWF | NPF | OPTIONS | ALTERNATIVE_CELL_AVERAGING | STRING | is a text keyword to indicate that an alternative method will be used for calculating the conductance for horizontal cell connections. The text value for ALTERNATIVE\_CELL\_AVERAGING can be ``LOGARITHMIC'', ``AMT-LMK'', or ``AMT-HMK''. ``AMT-LMK'' signifies that the conductance will be calculated using arithmetic-mean thickness and logarithmic-mean hydraulic conductivity. ``AMT-HMK'' signifies that the conductance will be calculated using arithmetic-mean thickness and harmonic-mean hydraulic conductivity. If the user does not specify a value for ALTERNATIVE\_CELL\_AVERAGING, then the harmonic-mean method will be used. This option cannot be used if the XT3D option is invoked. | | GWF | NPF | OPTIONS | THICKSTRT | KEYWORD | indicates that cells having a negative ICELLTYPE are confined, and their cell thickness for conductance calculations will be computed as STRT-BOT rather than TOP-BOT. | | GWF | NPF | OPTIONS | VARIABLECV | KEYWORD | keyword to indicate that the vertical conductance will be calculated using the saturated thickness and properties of the overlying cell and the thickness and properties of the underlying cell. If the DEWATERED keyword is also specified, then the vertical conductance is calculated using only the saturated thickness and properties of the overlying cell if the head in the underlying cell is below its top. If these keywords are not specified, then the default condition is to calculate the vertical conductance at the start of the simulation using the initial head and the cell properties. The vertical conductance remains constant for the entire simulation. | @@ -204,7 +205,12 @@ | GWF | NPF | OPTIONS | K33OVERK | KEYWORD | keyword to indicate that specified K33 is a ratio of K33 divided by K. If this option is specified, then the K33 array entered in the NPF Package will be multiplied by K after being read. | | GWF | NPF | OPTIONS | TVK6 | KEYWORD | keyword to specify that record corresponds to a time-varying hydraulic conductivity (TVK) file. The behavior of TVK and a description of the input file is provided separately. | | GWF | NPF | OPTIONS | FILEIN | KEYWORD | keyword to specify that an input filename is expected next. | -| GWF | NPF | OPTIONS | TVK_FILENAME | STRING | defines a time-varying hydraulic conductivity (TVK) input file. Records in the TVK file can be used to change hydraulic conductivity properties at specified times or stress periods. | +| GWF | NPF | OPTIONS | TVK6_FILENAME | STRING | defines a time-varying hydraulic conductivity (TVK) input file. Records in the TVK file can be used to change hydraulic conductivity properties at specified times or stress periods. | +| GWF | NPF | OPTIONS | DEV_NO_NEWTON | KEYWORD | turn off Newton for unconfined cells | +| GWF | NPF | OPTIONS | DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION | KEYWORD | use MODFLOW-USG upstream-weighted saturation approach | +| GWF | NPF | OPTIONS | DEV_MODFLOWNWT_UPSTREAM_WEIGHTING | KEYWORD | use MODFLOW-NWT approach for upstream weighting | +| GWF | NPF | OPTIONS | DEV_MINIMUM_SATURATED_THICKNESS | DOUBLE PRECISION | set minimum allowed saturated thickness | +| GWF | NPF | OPTIONS | DEV_OMEGA | DOUBLE PRECISION | set saturation omega value | | GWF | NPF | GRIDDATA | ICELLTYPE | INTEGER (NODES) | flag for each cell that specifies how saturated thickness is treated. 0 means saturated thickness is held constant; $>$0 means saturated thickness varies with computed head when head is below the cell top; $<$0 means saturated thickness varies with computed head unless the THICKSTRT option is in effect. When THICKSTRT is in effect, a negative value of icelltype indicates that saturated thickness will be computed as STRT-BOT and held constant. | | GWF | NPF | GRIDDATA | K | DOUBLE PRECISION (NODES) | is the hydraulic conductivity. For the common case in which the user would like to specify the horizontal hydraulic conductivity and the vertical hydraulic conductivity, then K should be assigned as the horizontal hydraulic conductivity, K33 should be assigned as the vertical hydraulic conductivity, and K22 and the three rotation angles should not be specified. When more sophisticated anisotropy is required, then K corresponds to the K11 hydraulic conductivity axis. All included cells (IDOMAIN $>$ 0) must have a K value greater than zero. | | GWF | NPF | GRIDDATA | K22 | DOUBLE PRECISION (NODES) | is the hydraulic conductivity of the second ellipsoid axis (or the ratio of K22/K if the K22OVERK option is specified); for an unrotated case this is the hydraulic conductivity in the y direction. If K22 is not included in the GRIDDATA block, then K22 is set equal to K. For a regular MODFLOW grid (DIS Package is used) in which no rotation angles are specified, K22 is the hydraulic conductivity along columns in the y direction. For an unstructured DISU grid, the user must assign principal x and y axes and provide the angle for each cell face relative to the assigned x direction. All included cells (IDOMAIN $>$ 0) must have a K22 value greater than zero. | @@ -219,7 +225,7 @@ | GWF | BUY | OPTIONS | FILEOUT | KEYWORD | keyword to specify that an output filename is expected next. | | GWF | BUY | OPTIONS | DENSITYFILE | STRING | name of the binary output file to write density information. The density file has the same format as the head file. Density values will be written to the density file whenever heads are written to the binary head file. The settings for controlling head output are contained in the Output Control option. | | GWF | BUY | OPTIONS | DEV_EFH_FORMULATION | KEYWORD | use the variable-density equivalent freshwater head formulation instead of the hydraulic head head formulation. This dev option has only been implemented for confined aquifer conditions and should generally not be used. | -| GWF | BUY | DIMENSIONS | NRHOSPECIES | INTEGER | number of species used in density equation of state. This value must be one or greater. The value must be one if concentrations are specified using the CONCENTRATION keyword in the PERIOD block below. | +| GWF | BUY | DIMENSIONS | NRHOSPECIES | INTEGER | number of species used in density equation of state. This value must be one or greater if the BUY package is activated. | | GWF | BUY | PACKAGEDATA | IRHOSPEC | INTEGER | integer value that defines the species number associated with the specified PACKAGEDATA data on the line. IRHOSPECIES must be greater than zero and less than or equal to NRHOSPECIES. Information must be specified for each of the NRHOSPECIES species or the program will terminate with an error. The program will also terminate with an error if information for a species is specified more than once. | | GWF | BUY | PACKAGEDATA | DRHODC | DOUBLE PRECISION | real value that defines the slope of the density-concentration line for this species used in the density equation of state. | | GWF | BUY | PACKAGEDATA | CRHOREF | DOUBLE PRECISION | real value that defines the reference concentration value used for this species in the density equation of state. | @@ -227,7 +233,7 @@ | GWF | BUY | PACKAGEDATA | AUXSPECIESNAME | STRING | name of an auxiliary variable in a GWF stress package that will be used for this species to calculate a density value. If a density value is needed by the Buoyancy Package then it will use the concentration values in this AUXSPECIESNAME column in the density equation of state. For advanced stress packages (LAK, SFR, MAW, and UZF) that have an associated advanced transport package (LKT, SFT, MWT, and UZT), the FLOW\_PACKAGE\_AUXILIARY\_NAME option in the advanced transport package can be used to transfer simulated concentrations into the flow package auxiliary variable. In this manner, the Buoyancy Package can calculate density values for lakes, streams, multi-aquifer wells, and unsaturated zone flow cells using simulated concentrations. | | GWF | STO | OPTIONS | SAVE_FLOWS | KEYWORD | keyword to indicate that cell-by-cell flow terms will be written to the file specified with ``BUDGET SAVE FILE'' in Output Control. | | GWF | STO | OPTIONS | STORAGECOEFFICIENT | KEYWORD | keyword to indicate that the SS array is read as storage coefficient rather than specific storage. | -| GWF | STO | OPTIONS | SS_CONFINED_ONLY | KEYWORD | keyword to indicate that specific storage is only calculated when a cell is under confined conditions (head greater than or equal to the top of the cell). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. | +| GWF | STO | OPTIONS | SS_CONFINED_ONLY | KEYWORD | keyword to indicate that compressible storage is only calculated for a convertible cell (ICONVERT>0) when the cell is under confined conditions (head greater than or equal to the top of the cell). This option has no effect on cells that are marked as being always confined (ICONVERT=0). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. | | GWF | STO | OPTIONS | TVS6 | KEYWORD | keyword to specify that record corresponds to a time-varying storage (TVS) file. The behavior of TVS and a description of the input file is provided separately. | | GWF | STO | OPTIONS | FILEIN | KEYWORD | keyword to specify that an input filename is expected next. | | GWF | STO | OPTIONS | TVS_FILENAME | STRING | defines a time-varying storage (TVS) input file. Records in the TVS file can be used to change specific storage and specific yield properties at specified times or stress periods. | @@ -449,14 +455,14 @@ | GWF | EVT | OPTIONS | OBS6_FILENAME | STRING | name of input file to define observations for the Evapotranspiration package. See the ``Observation utility'' section for instructions for preparing observation input files. Tables \ref{table:gwf-obstypetable} and \ref{table:gwt-obstypetable} lists observation type(s) supported by the Evapotranspiration package. | | GWF | EVT | OPTIONS | SURF_RATE_SPECIFIED | KEYWORD | indicates that the proportion of the evapotranspiration rate at the ET surface will be specified as PETM0 in list input. | | GWF | EVT | DIMENSIONS | MAXBOUND | INTEGER | integer value specifying the maximum number of evapotranspiration cells cells that will be specified for use during any stress period. | -| GWF | EVT | DIMENSIONS | NSEG | INTEGER | number of ET segments. Default is one. When NSEG is greater than 1, PXDP and PETM arrays must be specified NSEG - 1 times each, in order from the uppermost segment down. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. | +| GWF | EVT | DIMENSIONS | NSEG | INTEGER | number of ET segments. Default is one. When NSEG is greater than 1, the PXDP and PETM arrays must be of size NSEG - 1 and be listed in order from the uppermost segment down. Values for PXDP must be listed first followed by the values for PETM. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. | | GWF | EVT | PERIOD | IPER | INTEGER | integer value specifying the starting stress period number for which the data specified in the PERIOD block apply. IPER must be less than or equal to NPER in the TDIS Package and greater than zero. The IPER value assigned to a stress period block must be greater than the IPER value assigned for the previous PERIOD block. The information specified in the PERIOD block will continue to apply for all subsequent stress periods, unless the program encounters another PERIOD block. | | GWF | EVT | PERIOD | CELLID | INTEGER (NCELLDIM) | is the cell identifier, and depends on the type of grid that is used for the simulation. For a structured grid that uses the DIS input file, CELLID is the layer, row, and column. For a grid that uses the DISV input file, CELLID is the layer and CELL2D number. If the model uses the unstructured discretization (DISU) input file, CELLID is the node number for the cell. | | GWF | EVT | PERIOD | SURFACE | DOUBLE PRECISION | is the elevation of the ET surface ($L$). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | | GWF | EVT | PERIOD | RATE | DOUBLE PRECISION | is the maximum ET flux rate ($LT^{-1}$). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | | GWF | EVT | PERIOD | DEPTH | DOUBLE PRECISION | is the ET extinction depth ($L$). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | -| GWF | EVT | PERIOD | PXDP | DOUBLE PRECISION (NSEG-1) | is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | -| GWF | EVT | PERIOD | PETM | DOUBLE PRECISION (NSEG-1) | is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | +| GWF | EVT | PERIOD | PXDP | DOUBLE PRECISION (NSEG-1) | is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). pxdp is an array of size (nseg - 1). Values in pxdp must be greater than 0.0 and less than 1.0. pxdp values for a cell must increase monotonically. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | +| GWF | EVT | PERIOD | PETM | DOUBLE PRECISION (NSEG-1) | is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). petm is an array of size (nseg - 1). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | | GWF | EVT | PERIOD | PETM0 | DOUBLE PRECISION | is the proportion of the maximum ET flux rate that will apply when head is at or above the ET surface (dimensionless). PETM0 is read only when the SURF\_RATE\_SPECIFIED option is used. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | | GWF | EVT | PERIOD | AUX | DOUBLE PRECISION (NAUX) | represents the values of the auxiliary variables for each evapotranspiration. The values of auxiliary variables must be present for each evapotranspiration. The values must be specified in the order of the auxiliary variables specified in the OPTIONS block. If the package supports time series and the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value. | | GWF | EVT | PERIOD | BOUNDNAME | STRING | name of the evapotranspiration cell. BOUNDNAME is an ASCII character variable that can contain as many as 40 characters. If BOUNDNAME contains spaces in it, then the entire name must be enclosed within single quotes. | @@ -496,6 +502,8 @@ | GWF | MAW | OPTIONS | FLOWING_WELLS | KEYWORD | keyword that activates the flowing wells option for the multi-aquifer well package. | | GWF | MAW | OPTIONS | SHUTDOWN_THETA | DOUBLE PRECISION | value that defines the weight applied to discharge rate for wells that limit the water level in a discharging well (defined using the HEAD\_LIMIT keyword in the stress period data). SHUTDOWN\_THETA is used to control discharge rate oscillations when the flow rate from the aquifer is less than the specified flow rate from the aquifer to the well. Values range between 0.0 and 1.0, and larger values increase the weight (decrease under-relaxation) applied to the well discharge rate. The HEAD\_LIMIT option has been included to facilitate backward compatibility with previous versions of MODFLOW but use of the RATE\_SCALING option instead of the HEAD\_LIMIT option is recommended. By default, SHUTDOWN\_THETA is 0.7. | | GWF | MAW | OPTIONS | SHUTDOWN_KAPPA | DOUBLE PRECISION | value that defines the weight applied to discharge rate for wells that limit the water level in a discharging well (defined using the HEAD\_LIMIT keyword in the stress period data). SHUTDOWN\_KAPPA is used to control discharge rate oscillations when the flow rate from the aquifer is less than the specified flow rate from the aquifer to the well. Values range between 0.0 and 1.0, and larger values increase the weight applied to the well discharge rate. The HEAD\_LIMIT option has been included to facilitate backward compatibility with previous versions of MODFLOW but use of the RATE\_SCALING option instead of the HEAD\_LIMIT option is recommended. By default, SHUTDOWN\_KAPPA is 0.0001. | +| GWF | MAW | OPTIONS | MAW_FLOW_REDUCE_CSV | KEYWORD | keyword to specify that record corresponds to the output option in which a new record is written for each multi-aquifer well and for each time step in which the user-requested extraction or injection rate is reduced by the program. | +| GWF | MAW | OPTIONS | MFRCSVFILE | STRING | name of the comma-separated value (CSV) output file to write information about multi-aquifer well extraction or injection rates that have been reduced by the program. Entries are only written if the extraction or injection rates are reduced. | | GWF | MAW | OPTIONS | TS6 | KEYWORD | keyword to specify that record corresponds to a time-series file. | | GWF | MAW | OPTIONS | FILEIN | KEYWORD | keyword to specify that an input filename is expected next. | | GWF | MAW | OPTIONS | TS6_FILENAME | STRING | defines a time-series file defining time series that can be used to assign time-varying values. See the ``Time-Variable Input'' section for instructions on using the time-series capability. | @@ -645,7 +653,7 @@ | GWF | LAK | CONNECTIONDATA | ICONN | INTEGER | integer value that defines the GWF connection number for this lake connection entry. ICONN must be greater than zero and less than or equal to NLAKECONN for lake LAKENO. | | GWF | LAK | CONNECTIONDATA | CELLID | INTEGER (NCELLDIM) | is the cell identifier, and depends on the type of grid that is used for the simulation. For a structured grid that uses the DIS input file, CELLID is the layer, row, and column. For a grid that uses the DISV input file, CELLID is the layer and CELL2D number. If the model uses the unstructured discretization (DISU) input file, CELLID is the node number for the cell. | | GWF | LAK | CONNECTIONDATA | CLAKTYPE | STRING | character string that defines the lake-GWF connection type for the lake connection. Possible lake-GWF connection type strings include: VERTICAL--character keyword to indicate the lake-GWF connection is vertical and connection conductance calculations use the hydraulic conductivity corresponding to the $K_{33}$ tensor component defined for CELLID in the NPF package. HORIZONTAL--character keyword to indicate the lake-GWF connection is horizontal and connection conductance calculations use the hydraulic conductivity corresponding to the $K_{11}$ tensor component defined for CELLID in the NPF package. EMBEDDEDH--character keyword to indicate the lake-GWF connection is embedded in a single cell and connection conductance calculations use the hydraulic conductivity corresponding to the $K_{11}$ tensor component defined for CELLID in the NPF package. EMBEDDEDV--character keyword to indicate the lake-GWF connection is embedded in a single cell and connection conductance calculations use the hydraulic conductivity corresponding to the $K_{33}$ tensor component defined for CELLID in the NPF package. Embedded lakes can only be connected to a single cell (NLAKECONN = 1) and there must be a lake table associated with each embedded lake. | -| GWF | LAK | CONNECTIONDATA | BEDLEAK | DOUBLE PRECISION | character string or real value that defines the bed leakance for the lake-GWF connection. BEDLEAK must be greater than or equal to zero or specified to be NONE. If BEDLEAK is specified to be NONE, the lake-GWF connection conductance is solely a function of aquifer properties in the connected GWF cell and lakebed sediments are assumed to be absent. | +| GWF | LAK | CONNECTIONDATA | BEDLEAK | STRING | character string or real value that defines the bed leakance for the lake-GWF connection. BEDLEAK must be greater than or equal to zero or specified to be NONE. If BEDLEAK is specified to be NONE, the lake-GWF connection conductance is solely a function of aquifer properties in the connected GWF cell and lakebed sediments are assumed to be absent. | | GWF | LAK | CONNECTIONDATA | BELEV | DOUBLE PRECISION | real value that defines the bottom elevation for a HORIZONTAL lake-GWF connection. Any value can be specified if CLAKTYPE is VERTICAL, EMBEDDEDH, or EMBEDDEDV. If CLAKTYPE is HORIZONTAL and BELEV is not equal to TELEV, BELEV must be greater than or equal to the bottom of the GWF cell CELLID. If BELEV is equal to TELEV, BELEV is reset to the bottom of the GWF cell CELLID. | | GWF | LAK | CONNECTIONDATA | TELEV | DOUBLE PRECISION | real value that defines the top elevation for a HORIZONTAL lake-GWF connection. Any value can be specified if CLAKTYPE is VERTICAL, EMBEDDEDH, or EMBEDDEDV. If CLAKTYPE is HORIZONTAL and TELEV is not equal to BELEV, TELEV must be less than or equal to the top of the GWF cell CELLID. If TELEV is equal to BELEV, TELEV is reset to the top of the GWF cell CELLID. | | GWF | LAK | CONNECTIONDATA | CONNLEN | DOUBLE PRECISION | real value that defines the distance between the connected GWF CELLID node and the lake for a HORIZONTAL, EMBEDDEDH, or EMBEDDEDV lake-GWF connection. CONLENN must be greater than zero for a HORIZONTAL, EMBEDDEDH, or EMBEDDEDV lake-GWF connection. Any value can be specified if CLAKTYPE is VERTICAL. | @@ -783,6 +791,21 @@ | GWF | OC | PERIOD | LAST | KEYWORD | keyword to indicate save for last step in period. This keyword may be used in conjunction with other keywords to print or save results for multiple time steps. | | GWF | OC | PERIOD | FREQUENCY | INTEGER | save at the specified time step frequency. This keyword may be used in conjunction with other keywords to print or save results for multiple time steps. | | GWF | OC | PERIOD | STEPS | INTEGER (-\.dfn. +2) When your package is ready for release copy the dfn file to the flopy distribution in the flopy/mf6/data/dfn folder, run createpackages.py, and check in your new dfn file. Also check in the package class and the updated \__init\__.py that createpackages.py created. + +## Creating a New Subpackage Definition File + +A subpackage is a package referenced by another package (vs being referenced in the name file). The tas, ts, and obs packages are examples of subpackages. There are a few additional steps required when creating a subpackage definition file. First, verify that the parent package's dfn file has a file record for the subpackage to the option block. For example, for the time series package the file record definition starts with: + + block options + name ts_filerecord + type record ts6 filein ts6_filename + +Verify that the same naming convention is followed as the example above, specifically: + + name _filerecord + record 6 filein 6_filename + +Next, create the child package definition file (see sections below for more information). + +When your child package is ready for release follow the same procedure described in "Creating a Definition File that will Work with Flopy" above along with a few additional steps required for subpackages. At the top of the child dfn file add two lines describing how the parent and child packages are related. The first line determines how the subpackage is linked to the package: + +\# flopy subpackage \ \ \ \ + +* Parent record is the MF6 record name of the filerecord in parent package that references the child packages file name +* Abbreviation is the short abbreviation of the new subclass +* Child data is the name of the child class data that can be passed in as parameter to the parent class. Passing in this parameter to the parent class automatically creates the child class with the data provided. +* Data name is the parent class parameter name that automatically creates the child class with the data provided. + +The example below is the first line from the ts subpackage dfn: + +\# flopy subpackage ts_filerecord ts timeseries timeseries + +The second line determines the variable name of the subpackage's parent and the type of parent (the parent package's object oriented parent): + +\# flopy parent_name_type \ \ + +An example below is the second line in the ts subpackage dfn: + +\# flopy parent_name_type parent_package MFPackage + +There are three possible types (or combination of them) that can be used for "parent package type", MFPackage, MFModel, and MFSimulation. If a package supports multiple types of parents (for example, it can be either in the model namefile or in a package, like the obs package), include all the types supported, seperating each type with a / (MFPackage/MFModel). + +## Creating Definition Files for a New Model + +To create a new type of model choose a unique three letter model abbreviation ("gwf", "gwt", ...). Create a name file dfn with the naming convention \-nam.dfn. The name file must have only an options and packages block (see gwf-nam.dfn as an example). Create a new dfn file for each of the packages in your new model, following the naming convention described above. + +When your model is ready for release copy the dfn file to the flopy distribution in the flopy/mf6/data/dfn folder, run createpackages.py, and check in your new dfn files, the package classes, and updated init.py that createpackages.py created. + +# Simple Definition File Example This example shows how to construct an options block with a couple of optional keywords. diff --git a/doc/mf6io/mf6ivar/tex/appendixA.tex b/doc/mf6io/mf6ivar/tex/appendixA.tex index 32c13f302bf..7cbb933e60e 100644 --- a/doc/mf6io/mf6ivar/tex/appendixA.tex +++ b/doc/mf6io/mf6ivar/tex/appendixA.tex @@ -161,6 +161,10 @@ GWF & OC & OPTIONS & yes \\ GWF & OC & PERIOD & yes \\ \hline +GWF & VSC & OPTIONS & yes \\ +GWF & VSC & DIMENSIONS & yes \\ +GWF & VSC & PACKAGEDATA & yes \\ +\hline GWF & API & OPTIONS & yes \\ GWF & API & DIMENSIONS & yes \\ \hline diff --git a/doc/mf6io/mf6ivar/tex/exg-gwtgwt-desc.tex b/doc/mf6io/mf6ivar/tex/exg-gwtgwt-desc.tex index 8cf204e94eb..85c90ef8aea 100644 --- a/doc/mf6io/mf6ivar/tex/exg-gwtgwt-desc.tex +++ b/doc/mf6io/mf6ivar/tex/exg-gwtgwt-desc.tex @@ -17,11 +17,11 @@ \item \texttt{SAVE\_FLOWS}---keyword to indicate that cell-by-cell flow terms will be written to the budget file for each model provided that the Output Control for the models are set up with the ``BUDGET SAVE FILE'' option. -\item \texttt{advscheme}---scheme used to solve the advection term. Can be upstream, central, or TVD. If not specified, upstream weighting is the default weighting scheme. +\item \texttt{adv\_scheme}---scheme used to solve the advection term. Can be upstream, central, or TVD. If not specified, upstream weighting is the default weighting scheme. -\item \texttt{XT3D\_OFF}---deactivate the xt3d method and use the faster and less accurate approximation for this exchange. +\item \texttt{DSP\_XT3D\_OFF}---deactivate the xt3d method for the dispersive flux and use the faster and less accurate approximation for this exchange. -\item \texttt{XT3D\_RHS}---add xt3d terms to right-hand side, when possible, for this exchange. +\item \texttt{DSP\_XT3D\_RHS}---add xt3d dispersion terms to right-hand side, when possible, for this exchange. \item \texttt{FILEIN}---keyword to specify that an input filename is expected next. diff --git a/doc/mf6io/mf6ivar/tex/exg-gwtgwt-options.dat b/doc/mf6io/mf6ivar/tex/exg-gwtgwt-options.dat index 869c83821b3..0d6e40d9fd7 100644 --- a/doc/mf6io/mf6ivar/tex/exg-gwtgwt-options.dat +++ b/doc/mf6io/mf6ivar/tex/exg-gwtgwt-options.dat @@ -6,9 +6,9 @@ BEGIN OPTIONS [PRINT_INPUT] [PRINT_FLOWS] [SAVE_FLOWS] - [ADVSCHEME ] - [XT3D_OFF] - [XT3D_RHS] + [ADV_SCHEME ] + [DSP_XT3D_OFF] + [DSP_XT3D_RHS] [MVT6 FILEIN ] [OBS6 FILEIN ] END OPTIONS diff --git a/doc/mf6io/mf6ivar/tex/gwf-buy-desc.tex b/doc/mf6io/mf6ivar/tex/gwf-buy-desc.tex index efd09eafbb3..4ce652dd79e 100644 --- a/doc/mf6io/mf6ivar/tex/gwf-buy-desc.tex +++ b/doc/mf6io/mf6ivar/tex/gwf-buy-desc.tex @@ -17,7 +17,7 @@ \item \textbf{Block: DIMENSIONS} \begin{description} -\item \texttt{nrhospecies}---number of species used in density equation of state. This value must be one or greater. The value must be one if concentrations are specified using the CONCENTRATION keyword in the PERIOD block below. +\item \texttt{nrhospecies}---number of species used in density equation of state. This value must be one or greater if the BUY package is activated. \end{description} \item \textbf{Block: PACKAGEDATA} diff --git a/doc/mf6io/mf6ivar/tex/gwf-evt-desc.tex b/doc/mf6io/mf6ivar/tex/gwf-evt-desc.tex index 04810c568df..036cc53ff2b 100644 --- a/doc/mf6io/mf6ivar/tex/gwf-evt-desc.tex +++ b/doc/mf6io/mf6ivar/tex/gwf-evt-desc.tex @@ -35,7 +35,7 @@ \begin{description} \item \texttt{maxbound}---integer value specifying the maximum number of evapotranspiration cells cells that will be specified for use during any stress period. -\item \texttt{nseg}---number of ET segments. Default is one. When NSEG is greater than 1, PXDP and PETM arrays must be specified NSEG - 1 times each, in order from the uppermost segment down. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. +\item \texttt{nseg}---number of ET segments. Default is one. When NSEG is greater than 1, the PXDP and PETM arrays must be of size NSEG - 1 and be listed in order from the uppermost segment down. Values for PXDP must be listed first followed by the values for PETM. PXDP defines the extinction-depth proportion at the bottom of a segment. PETM defines the proportion of the maximum ET flux rate at the bottom of a segment. \end{description} \item \textbf{Block: PERIOD} @@ -51,9 +51,9 @@ \item \textcolor{blue}{\texttt{depth}---is the ET extinction depth ($L$). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} -\item \textcolor{blue}{\texttt{pxdp}---is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} +\item \textcolor{blue}{\texttt{pxdp}---is the proportion of the ET extinction depth at the bottom of a segment (dimensionless). pxdp is an array of size (nseg - 1). Values in pxdp must be greater than 0.0 and less than 1.0. pxdp values for a cell must increase monotonically. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} -\item \textcolor{blue}{\texttt{petm}---is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} +\item \textcolor{blue}{\texttt{petm}---is the proportion of the maximum ET flux rate at the bottom of a segment (dimensionless). petm is an array of size (nseg - 1). If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} \item \textcolor{blue}{\texttt{petm0}---is the proportion of the maximum ET flux rate that will apply when head is at or above the ET surface (dimensionless). PETM0 is read only when the SURF\_RATE\_SPECIFIED option is used. If the Options block includes a TIMESERIESFILE entry (see the ``Time-Variable Input'' section), values can be obtained from a time series by entering the time-series name in place of a numeric value.} diff --git a/doc/mf6io/mf6ivar/tex/gwf-maw-desc.tex b/doc/mf6io/mf6ivar/tex/gwf-maw-desc.tex index a3eb46f9d4f..abb1023e655 100644 --- a/doc/mf6io/mf6ivar/tex/gwf-maw-desc.tex +++ b/doc/mf6io/mf6ivar/tex/gwf-maw-desc.tex @@ -39,6 +39,10 @@ \item \texttt{shutdown\_kappa}---value that defines the weight applied to discharge rate for wells that limit the water level in a discharging well (defined using the HEAD\_LIMIT keyword in the stress period data). SHUTDOWN\_KAPPA is used to control discharge rate oscillations when the flow rate from the aquifer is less than the specified flow rate from the aquifer to the well. Values range between 0.0 and 1.0, and larger values increase the weight applied to the well discharge rate. The HEAD\_LIMIT option has been included to facilitate backward compatibility with previous versions of MODFLOW but use of the RATE\_SCALING option instead of the HEAD\_LIMIT option is recommended. By default, SHUTDOWN\_KAPPA is 0.0001. +\item \texttt{MAW\_FLOW\_REDUCE\_CSV}---keyword to specify that record corresponds to the output option in which a new record is written for each multi-aquifer well and for each time step in which the user-requested extraction or injection rate is reduced by the program. + +\item \texttt{mfrcsvfile}---name of the comma-separated value (CSV) output file to write information about multi-aquifer well extraction or injection rates that have been reduced by the program. Entries are only written if the extraction or injection rates are reduced. + \item \texttt{TS6}---keyword to specify that record corresponds to a time-series file. \item \texttt{FILEIN}---keyword to specify that an input filename is expected next. diff --git a/doc/mf6io/mf6ivar/tex/gwf-maw-options.dat b/doc/mf6io/mf6ivar/tex/gwf-maw-options.dat index 9e7f257a7db..ccb5d5b2d91 100644 --- a/doc/mf6io/mf6ivar/tex/gwf-maw-options.dat +++ b/doc/mf6io/mf6ivar/tex/gwf-maw-options.dat @@ -13,6 +13,7 @@ BEGIN OPTIONS [FLOWING_WELLS] [SHUTDOWN_THETA ] [SHUTDOWN_KAPPA ] + [MAW_FLOW_REDUCE_CSV FILEOUT ] [TS6 FILEIN ] [OBS6 FILEIN ] [MOVER] diff --git a/doc/mf6io/mf6ivar/tex/gwf-sto-desc.tex b/doc/mf6io/mf6ivar/tex/gwf-sto-desc.tex index 7f6579cd922..8b06bcfca16 100644 --- a/doc/mf6io/mf6ivar/tex/gwf-sto-desc.tex +++ b/doc/mf6io/mf6ivar/tex/gwf-sto-desc.tex @@ -7,7 +7,7 @@ \item \texttt{STORAGECOEFFICIENT}---keyword to indicate that the SS array is read as storage coefficient rather than specific storage. -\item \texttt{SS\_CONFINED\_ONLY}---keyword to indicate that specific storage is only calculated when a cell is under confined conditions (head greater than or equal to the top of the cell). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. +\item \texttt{SS\_CONFINED\_ONLY}---keyword to indicate that compressible storage is only calculated for a convertible cell (ICONVERT>0) when the cell is under confined conditions (head greater than or equal to the top of the cell). This option has no effect on cells that are marked as being always confined (ICONVERT=0). This option is identical to the approach used to calculate storage changes under confined conditions in MODFLOW-2005. \item \texttt{TVS6}---keyword to specify that record corresponds to a time-varying storage (TVS) file. The behavior of TVS and a description of the input file is provided separately. diff --git a/doc/mf6io/mf6ivar/tex/gwf-vsc-desc.tex b/doc/mf6io/mf6ivar/tex/gwf-vsc-desc.tex new file mode 100644 index 00000000000..91c9c57423d --- /dev/null +++ b/doc/mf6io/mf6ivar/tex/gwf-vsc-desc.tex @@ -0,0 +1,45 @@ +% DO NOT MODIFY THIS FILE DIRECTLY. IT IS CREATED BY mf6ivar.py + +\item \textbf{Block: OPTIONS} + +\begin{description} +\item \texttt{viscref}---fluid reference viscosity used in the equation of state. This value is set to 1.0 if not specified as an option. + +\item \texttt{temperature\_species\_name}---string used to identify the auxspeciesname in PACKAGEDATA that corresponds to the temperature species. There can be only one occurrence of this temperature species name in the PACKAGEDATA block or the program will terminate with an error. This value has no effect if viscosity does not depend on temperature. + +\item \texttt{thermal\_formulation}---may be used for specifying which viscosity formulation to use for the temperature species. Can be either LINEAR or NONLINEAR. The LINEAR viscosity formulation is the default. + +\item \texttt{thermal\_a2}---is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A2 is not specified, a default value of 10.0 is assigned (Voss, 1984). + +\item \texttt{thermal\_a3}---is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A3 is not specified, a default value of 248.37 is assigned (Voss, 1984). + +\item \texttt{thermal\_a4}---is an empirical parameter specified by the user for calculating viscosity using a nonlinear formulation. If A4 is not specified, a default value of 133.15 is assigned (Voss, 1984). + +\item \texttt{VISCOSITY}---keyword to specify that record corresponds to viscosity. + +\item \texttt{FILEOUT}---keyword to specify that an output filename is expected next. + +\item \texttt{viscosityfile}---name of the binary output file to write viscosity information. The viscosity file has the same format as the head file. Viscosity values will be written to the viscosity file whenever heads are written to the binary head file. The settings for controlling head output are contained in the Output Control option. + +\end{description} +\item \textbf{Block: DIMENSIONS} + +\begin{description} +\item \texttt{nviscspecies}---number of species used in the viscosity equation of state. If either concentrations or temperature (or both) are used to update viscosity then then nrhospecies needs to be at least one. + +\end{description} +\item \textbf{Block: PACKAGEDATA} + +\begin{description} +\item \texttt{iviscspec}---integer value that defines the species number associated with the specified PACKAGEDATA data entered on each line. IVISCSPECIES must be greater than zero and less than or equal to NVISCSPECIES. Information must be specified for each of the NVISCSPECIES species or the program will terminate with an error. The program will also terminate with an error if information for a species is specified more than once. + +\item \texttt{dviscdc}---real value that defines the slope of the line defining the linear relationship between viscosity and temperature or between viscosity and concentration, depending on the type of species entered on each line. If the value of AUXSPECIESNAME entered on a line corresponds to TEMPERATURE\_SPECIES\_NAME (in the OPTIONS block), this value will be used when VISCOSITY\_FUNC is equal to LINEAR (the default) in the OPTIONS block. When VISCOSITY\_FUNC is set to NONLINEAR, a value for DVISCDC must be specified though it is not used. + +\item \texttt{cviscref}---real value that defines the reference temperature or reference concentration value used for this species in the viscosity equation of state. If AUXSPECIESNAME entered on a line corresponds to TEMPERATURE\_SPECIES\_NAME (in the OPTIONS block), then CVISCREF refers to a reference temperature, otherwise it refers to a reference concentration. + +\item \texttt{modelname}---name of a GWT model used to simulate a species that will be used in the viscosity equation of state. This name will have no effect if the simulation does not include a GWT model that corresponds to this GWF model. + +\item \texttt{auxspeciesname}---name of an auxiliary variable in a GWF stress package that will be used for this species to calculate the viscosity values. If a viscosity value is needed by the Viscosity Package then it will use the temperature or concentration values associated with this AUXSPECIESNAME in the viscosity equation of state. For advanced stress packages (LAK, SFR, MAW, and UZF) that have an associated advanced transport package (LKT, SFT, MWT, and UZT), the FLOW\_PACKAGE\_AUXILIARY\_NAME option in the advanced transport package can be used to transfer simulated temperature or concentration(s) into the flow package auxiliary variable. In this manner, the Viscosity Package can calculate viscosity values for lakes, streams, multi-aquifer wells, and unsaturated zone flow cells using simulated concentrations. + +\end{description} + diff --git a/doc/mf6io/mf6ivar/tex/gwf-vsc-dimensions.dat b/doc/mf6io/mf6ivar/tex/gwf-vsc-dimensions.dat new file mode 100644 index 00000000000..8bc1b6fc1fc --- /dev/null +++ b/doc/mf6io/mf6ivar/tex/gwf-vsc-dimensions.dat @@ -0,0 +1,3 @@ +BEGIN DIMENSIONS + NVISCSPECIES +END DIMENSIONS diff --git a/doc/mf6io/mf6ivar/tex/gwf-vsc-options.dat b/doc/mf6io/mf6ivar/tex/gwf-vsc-options.dat new file mode 100644 index 00000000000..0c62b85da3a --- /dev/null +++ b/doc/mf6io/mf6ivar/tex/gwf-vsc-options.dat @@ -0,0 +1,9 @@ +BEGIN OPTIONS + [VISCREF ] + [TEMPERATURE_SPECIES_NAME ] + [THERMAL_FORMULATION ] + [THERMAL_A2 ] + [THERMAL_A3 ] + [THERMAL_A4 ] + [VISCOSITY FILEOUT ] +END OPTIONS diff --git a/doc/mf6io/mf6ivar/tex/gwf-vsc-packagedata.dat b/doc/mf6io/mf6ivar/tex/gwf-vsc-packagedata.dat new file mode 100644 index 00000000000..ff3d65886f9 --- /dev/null +++ b/doc/mf6io/mf6ivar/tex/gwf-vsc-packagedata.dat @@ -0,0 +1,5 @@ +BEGIN PACKAGEDATA + + + ... +END PACKAGEDATA diff --git a/doc/version.py b/doc/version.py index 69888194b97..41f04b4bc40 100644 --- a/doc/version.py +++ b/doc/version.py @@ -1,7 +1,7 @@ # MODFLOW 6 version file automatically created using...make_release.py -# created on...March 04, 2022 11:12:44 +# created on...December 01, 2022 08:04:49 major = 6 -minor = 3 +minor = 4 micro = 0 __version__ = '{:d}.{:d}.{:d}'.format(major, minor, micro) diff --git a/doc/version.tex b/doc/version.tex index b866d55b59c..08363eea319 100644 --- a/doc/version.tex +++ b/doc/version.tex @@ -1,3 +1,3 @@ -\newcommand{\modflowversion}{mf6.3.0} -\newcommand{\modflowdate}{March 04, 2022} +\newcommand{\modflowversion}{mf6.4.0} +\newcommand{\modflowdate}{December 01, 2022} \newcommand{\currentmodflowversion}{Version \modflowversion---\modflowdate} diff --git a/doc/zonebudget/zonebudget.tex b/doc/zonebudget/zonebudget.tex index ad1ea3446e7..a8cf1c6cf86 100644 --- a/doc/zonebudget/zonebudget.tex +++ b/doc/zonebudget/zonebudget.tex @@ -282,10 +282,15 @@ \section{History} \begin{itemize} -\item -\currentmodflowversion +%\item +%\currentmodflowversion +%\begin{itemize} +% \item None. +%\end{itemize} + +\item Version 6.4.0 \begin{itemize} - \item None. + \item Fixed error that prevented the program from working properly when the path to the ZONEBUDGET executable contained one or more spaces in it. \end{itemize} \item Version 6.1.0---December 12, 2019 diff --git a/environment.yml b/environment.yml new file mode 100644 index 00000000000..acdb3fc6451 --- /dev/null +++ b/environment.yml @@ -0,0 +1,23 @@ +name: modflow6 + +channels: + - conda-forge + - defaults + +dependencies: + - appdirs + - fprettify + - numpy + - matplotlib + - meson!=0.63.0 + - ninja + - pip + - pip: + - git+https://github.com/modflowpy/flopy.git + - git+https://github.com/modflowpy/pymake.git + - git+https://github.com/Deltares/xmipy.git + - git+https://github.com/MODFLOW-USGS/modflowapi.git + - pytest + - pytest-xdist + - flaky + - requests diff --git a/make/makedefaults b/make/makedefaults index 6ca158974cc..ea05064e2a2 100644 --- a/make/makedefaults +++ b/make/makedefaults @@ -1,4 +1,4 @@ -# makedefaults created by pymake (version 1.2.3) for the 'mf6' executable. +# makedefaults created by pymake (version 1.2.5) for the 'mf6' executable. # determine OS ifeq ($(OS), Windows_NT) diff --git a/make/makefile b/make/makefile index 6cbb1c9ceae..2cf7532c530 100644 --- a/make/makefile +++ b/make/makefile @@ -1,4 +1,4 @@ -# makefile created by pymake (version 1.2.3) for the 'mf6' executable. +# makefile created by pymake (version 1.2.5) for the 'mf6' executable. include ./makedefaults @@ -6,26 +6,28 @@ include ./makedefaults # Define the source file directories SOURCEDIR1=../src SOURCEDIR2=../src/Exchange -SOURCEDIR3=../src/Solution -SOURCEDIR4=../src/Solution/SparseMatrixSolver -SOURCEDIR5=../src/Timing -SOURCEDIR6=../src/Utilities -SOURCEDIR7=../src/Utilities/TimeSeries -SOURCEDIR8=../src/Utilities/Memory -SOURCEDIR9=../src/Utilities/OutputControl -SOURCEDIR10=../src/Utilities/Libraries -SOURCEDIR11=../src/Utilities/Libraries/rcm -SOURCEDIR12=../src/Utilities/Libraries/blas -SOURCEDIR13=../src/Utilities/Libraries/sparskit2 -SOURCEDIR14=../src/Utilities/Libraries/daglib -SOURCEDIR15=../src/Utilities/Libraries/sparsekit -SOURCEDIR16=../src/Utilities/Observation -SOURCEDIR17=../src/Model -SOURCEDIR18=../src/Model/Connection -SOURCEDIR19=../src/Model/GroundWaterTransport -SOURCEDIR20=../src/Model/ModelUtilities -SOURCEDIR21=../src/Model/GroundWaterFlow -SOURCEDIR22=../src/Model/Geometry +SOURCEDIR3=../src/Model +SOURCEDIR4=../src/Model/Connection +SOURCEDIR5=../src/Model/Geometry +SOURCEDIR6=../src/Model/GroundWaterFlow +SOURCEDIR7=../src/Model/GroundWaterTransport +SOURCEDIR8=../src/Model/ModelUtilities +SOURCEDIR9=../src/Solution +SOURCEDIR10=../src/Solution/LinearMethods +SOURCEDIR11=../src/Timing +SOURCEDIR12=../src/Utilities +SOURCEDIR13=../src/Utilities/ArrayRead +SOURCEDIR14=../src/Utilities/Idm +SOURCEDIR15=../src/Utilities/Libraries +SOURCEDIR16=../src/Utilities/Libraries/blas +SOURCEDIR17=../src/Utilities/Libraries/daglib +SOURCEDIR18=../src/Utilities/Libraries/rcm +SOURCEDIR19=../src/Utilities/Libraries/sparsekit +SOURCEDIR20=../src/Utilities/Libraries/sparskit2 +SOURCEDIR21=../src/Utilities/Memory +SOURCEDIR22=../src/Utilities/Observation +SOURCEDIR23=../src/Utilities/OutputControl +SOURCEDIR24=../src/Utilities/TimeSeries VPATH = \ ${SOURCEDIR1} \ @@ -49,7 +51,9 @@ ${SOURCEDIR18} \ ${SOURCEDIR19} \ ${SOURCEDIR20} \ ${SOURCEDIR21} \ -${SOURCEDIR22} +${SOURCEDIR22} \ +${SOURCEDIR23} \ +${SOURCEDIR24} .SUFFIXES: .f90 .F90 .o @@ -69,6 +73,7 @@ $(OBJDIR)/InputOutput.o \ $(OBJDIR)/TableTerm.o \ $(OBJDIR)/Table.o \ $(OBJDIR)/MemoryHelper.o \ +$(OBJDIR)/CharString.o \ $(OBJDIR)/Memory.o \ $(OBJDIR)/List.o \ $(OBJDIR)/MemoryList.o \ @@ -94,64 +99,94 @@ $(OBJDIR)/ObsOutput.o \ $(OBJDIR)/TimeArraySeries.o \ $(OBJDIR)/ObsOutputList.o \ $(OBJDIR)/Observe.o \ +$(OBJDIR)/InputDefinition.o \ +$(OBJDIR)/ArrayReaderBase.o \ $(OBJDIR)/TimeArraySeriesLink.o \ $(OBJDIR)/ObsUtility.o \ $(OBJDIR)/ObsContainer.o \ +$(OBJDIR)/VectorInt.o \ +$(OBJDIR)/gwt1dspidm.o \ +$(OBJDIR)/gwf3npf8idm.o \ +$(OBJDIR)/gwf3disv8idm.o \ +$(OBJDIR)/gwf3disu8idm.o \ +$(OBJDIR)/gwf3dis8idm.o \ +$(OBJDIR)/Integer2dReader.o \ $(OBJDIR)/BudgetFileReader.o \ $(OBJDIR)/TimeArraySeriesManager.o \ $(OBJDIR)/PackageMover.o \ $(OBJDIR)/Obs3.o \ $(OBJDIR)/NumericalPackage.o \ $(OBJDIR)/Budget.o \ +$(OBJDIR)/StructVector.o \ +$(OBJDIR)/IdmLogger.o \ +$(OBJDIR)/InputDefinitionSelector.o \ +$(OBJDIR)/Integer1dReader.o \ +$(OBJDIR)/Double2dReader.o \ +$(OBJDIR)/Double1dReader.o \ +$(OBJDIR)/sort.o \ +$(OBJDIR)/SfrCrossSectionUtils.o \ $(OBJDIR)/BudgetTerm.o \ $(OBJDIR)/BoundaryPackage.o \ $(OBJDIR)/BaseModel.o \ +$(OBJDIR)/StructArray.o \ +$(OBJDIR)/ModflowInput.o \ +$(OBJDIR)/LayeredArrayReader.o \ +$(OBJDIR)/SfrCrossSectionManager.o \ +$(OBJDIR)/dag_module.o \ +$(OBJDIR)/BudgetObject.o \ +$(OBJDIR)/NumericalModel.o \ +$(OBJDIR)/mf6lists.o \ $(OBJDIR)/PackageBudget.o \ $(OBJDIR)/HeadFileReader.o \ -$(OBJDIR)/BudgetObject.o \ -$(OBJDIR)/sort.o \ -$(OBJDIR)/SfrCrossSectionUtils.o \ $(OBJDIR)/PrintSaveManager.o \ $(OBJDIR)/Xt3dAlgorithm.o \ $(OBJDIR)/gwf3tvbase8.o \ -$(OBJDIR)/NumericalModel.o \ +$(OBJDIR)/LoadMf6FileType.o \ +$(OBJDIR)/gwf3sfr8.o \ +$(OBJDIR)/gwf3riv8.o \ +$(OBJDIR)/gwf3maw8.o \ +$(OBJDIR)/gwf3lak8.o \ +$(OBJDIR)/GwfVscInputData.o \ +$(OBJDIR)/gwf3ghb8.o \ +$(OBJDIR)/gwf3drn8.o \ +$(OBJDIR)/DistributedModel.o \ $(OBJDIR)/BaseExchange.o \ $(OBJDIR)/UzfCellGroup.o \ $(OBJDIR)/gwt1fmi1.o \ -$(OBJDIR)/SfrCrossSectionManager.o \ -$(OBJDIR)/dag_module.o \ $(OBJDIR)/OutputControlData.o \ $(OBJDIR)/gwf3ic8.o \ $(OBJDIR)/Xt3dInterface.o \ $(OBJDIR)/gwf3tvk8.o \ +$(OBJDIR)/MemoryManagerExt.o \ +$(OBJDIR)/IdmMf6FileLoader.o \ +$(OBJDIR)/gwf3vsc8.o \ $(OBJDIR)/GwfNpfOptions.o \ -$(OBJDIR)/GwfNpfGridData.o \ $(OBJDIR)/CellWithNbrs.o \ $(OBJDIR)/NumericalExchange.o \ $(OBJDIR)/Iunit.o \ $(OBJDIR)/gwf3uzf8.o \ $(OBJDIR)/gwt1apt1.o \ $(OBJDIR)/GwtSpc.o \ -$(OBJDIR)/gwf3sfr8.o \ $(OBJDIR)/OutputControl.o \ $(OBJDIR)/gwt1ic1.o \ -$(OBJDIR)/gwf3maw8.o \ -$(OBJDIR)/gwf3lak8.o \ $(OBJDIR)/gwt1mst1.o \ $(OBJDIR)/GwtDspOptions.o \ -$(OBJDIR)/GwtDspGridData.o \ $(OBJDIR)/gwf3npf8.o \ $(OBJDIR)/GwtAdvOptions.o \ $(OBJDIR)/gwf3tvs8.o \ $(OBJDIR)/GwfStorageUtils.o \ $(OBJDIR)/Mover.o \ +$(OBJDIR)/GwfMvrPeriodData.o \ +$(OBJDIR)/ims8misc.o \ $(OBJDIR)/GwfBuyInputData.o \ +$(OBJDIR)/InterfaceMap.o \ $(OBJDIR)/gwf3disu8.o \ $(OBJDIR)/GridSorting.o \ $(OBJDIR)/DisConnExchange.o \ $(OBJDIR)/CsrUtils.o \ +$(OBJDIR)/MappedVariable.o \ +$(OBJDIR)/TransportModel.o \ $(OBJDIR)/NameFile.o \ -$(OBJDIR)/mf6lists.o \ $(OBJDIR)/gwt1uzt1.o \ $(OBJDIR)/gwt1ssm1.o \ $(OBJDIR)/gwt1src1.o \ @@ -169,7 +204,6 @@ $(OBJDIR)/gwf3disv8.o \ $(OBJDIR)/gwf3dis8.o \ $(OBJDIR)/gwf3api8.o \ $(OBJDIR)/gwf3wel8.o \ -$(OBJDIR)/gwf3riv8.o \ $(OBJDIR)/gwf3rch8.o \ $(OBJDIR)/gwf3sto8.o \ $(OBJDIR)/gwf3oc8.o \ @@ -179,12 +213,11 @@ $(OBJDIR)/gwf3hfb8.o \ $(OBJDIR)/gwf3csub8.o \ $(OBJDIR)/gwf3buy8.o \ $(OBJDIR)/GhostNode.o \ -$(OBJDIR)/gwf3ghb8.o \ $(OBJDIR)/gwf3evt8.o \ -$(OBJDIR)/gwf3drn8.o \ $(OBJDIR)/gwf3chd8.o \ $(OBJDIR)/ims8reordering.o \ $(OBJDIR)/GridConnection.o \ +$(OBJDIR)/DistributedData.o \ $(OBJDIR)/gwt1.o \ $(OBJDIR)/gwf3.o \ $(OBJDIR)/ims8base.o \ @@ -207,7 +240,6 @@ $(OBJDIR)/comarg.o \ $(OBJDIR)/mf6core.o \ $(OBJDIR)/BaseGeometry.o \ $(OBJDIR)/mf6.o \ -$(OBJDIR)/VectorInt.o \ $(OBJDIR)/StringList.o \ $(OBJDIR)/MemorySetHandler.o \ $(OBJDIR)/ilut.o \ diff --git a/meson.build b/meson.build index 5db33e9cd0a..1fd28f862f3 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'MODFLOW 6', 'fortran', - version: '6.3.0', + version: '6.4.0', meson_version: '>= 0.59.0', default_options : [ 'b_vscrt=static_from_buildtype', # Link runtime libraries statically on Windows @@ -63,6 +63,8 @@ endif if fc_id == 'intel-cl' # windows compile_args += ['/fpe:0', # Activate all floating point exceptions + '/heap-arrays:0', + '/traceback', '/fpp', # Activate preprocessing '/Qdiag-disable:7416', # f2008 warning '/Qdiag-disable:7025', # f2008 warning @@ -74,9 +76,11 @@ if fc_id == 'intel-cl' elif fc_id == 'intel' # linux and macOS compile_args += ['-fpe0', # Activate all floating point exceptions - '-diag-disable:7416', # f2008 warning - '-diag-disable:7025', # f2008 warning - '-diag-disable:5268', # Line too long + '-no-heap-arrays', + '-traceback', + '-diag-disable:7416', # f2008 warning + '-diag-disable:7025', # f2008 warning + '-diag-disable:5268', # Line too long ] link_args += '-static-intel' endif @@ -92,3 +96,8 @@ subdir('utils') # add unit test directory # subdir('unittests') + +# meson tests to evaluate installation success +test('Test installation version', mf6exe, args : ['-v',]) +test('Test installation compiler', mf6exe, args : ['-c',]) +test('Test installation help', mf6exe, args : ['-h',]) diff --git a/msvs/mf6core.vfproj b/msvs/mf6core.vfproj index 415a7fa5edf..15eb52dea77 100644 --- a/msvs/mf6core.vfproj +++ b/msvs/mf6core.vfproj @@ -57,12 +57,16 @@ + + + + @@ -76,8 +80,11 @@ + + + @@ -87,6 +94,7 @@ + @@ -97,6 +105,7 @@ + @@ -104,6 +113,7 @@ + @@ -123,11 +133,11 @@ - + + - @@ -139,12 +149,14 @@ - + + - - - - + + + + + @@ -152,6 +164,22 @@ + + + + + + + + + + + + + + + + @@ -163,6 +191,7 @@ + @@ -192,6 +221,7 @@ + @@ -225,6 +255,7 @@ + diff --git a/pymake/makefile b/pymake/makefile index d289c3ea4fd..26cb285a460 100644 --- a/pymake/makefile +++ b/pymake/makefile @@ -1,6 +1,4 @@ -# makefile created on 2021-10-12 16:13:16.130574 -# by pymake (version 1.2.1) for the 'mf6' executable -# using the 'gfortran' fortran compiler(s). +# makefile created by pymake (version 1.2.5) for the 'mf6' executable. include ./makedefaults @@ -9,18 +7,27 @@ include ./makedefaults SOURCEDIR1=../src SOURCEDIR2=../src/Exchange SOURCEDIR3=../src/Solution -SOURCEDIR4=../src/Solution/SparseMatrixSolver +SOURCEDIR4=../src/Solution/LinearMethods SOURCEDIR5=../src/Timing SOURCEDIR6=../src/Utilities -SOURCEDIR7=../src/Utilities/TimeSeries -SOURCEDIR8=../src/Utilities/Memory -SOURCEDIR9=../src/Utilities/OutputControl -SOURCEDIR10=../src/Utilities/Observation -SOURCEDIR11=../src/Model -SOURCEDIR12=../src/Model/GroundWaterTransport -SOURCEDIR13=../src/Model/ModelUtilities -SOURCEDIR14=../src/Model/GroundWaterFlow -SOURCEDIR15=../src/Model/Geometry +SOURCEDIR7=../src/Utilities/Idm +SOURCEDIR8=../src/Utilities/TimeSeries +SOURCEDIR9=../src/Utilities/Memory +SOURCEDIR10=../src/Utilities/OutputControl +SOURCEDIR11=../src/Utilities/ArrayRead +SOURCEDIR12=../src/Utilities/Libraries +SOURCEDIR13=../src/Utilities/Libraries/rcm +SOURCEDIR14=../src/Utilities/Libraries/blas +SOURCEDIR15=../src/Utilities/Libraries/sparskit2 +SOURCEDIR16=../src/Utilities/Libraries/daglib +SOURCEDIR17=../src/Utilities/Libraries/sparsekit +SOURCEDIR18=../src/Utilities/Observation +SOURCEDIR19=../src/Model +SOURCEDIR20=../src/Model/Connection +SOURCEDIR21=../src/Model/GroundWaterTransport +SOURCEDIR22=../src/Model/ModelUtilities +SOURCEDIR23=../src/Model/GroundWaterFlow +SOURCEDIR24=../src/Model/Geometry VPATH = \ ${SOURCEDIR1} \ @@ -37,153 +44,207 @@ ${SOURCEDIR11} \ ${SOURCEDIR12} \ ${SOURCEDIR13} \ ${SOURCEDIR14} \ -${SOURCEDIR15} +${SOURCEDIR15} \ +${SOURCEDIR16} \ +${SOURCEDIR17} \ +${SOURCEDIR18} \ +${SOURCEDIR19} \ +${SOURCEDIR20} \ +${SOURCEDIR21} \ +${SOURCEDIR22} \ +${SOURCEDIR23} \ +${SOURCEDIR24} .SUFFIXES: .f90 .F90 .o OBJECTS = \ -$(OBJDIR)/OpenSpec.o \ $(OBJDIR)/kind.o \ -$(OBJDIR)/HashTable.o \ -$(OBJDIR)/compilerversion.o \ $(OBJDIR)/Constants.o \ -$(OBJDIR)/BaseGeometry.o \ $(OBJDIR)/SimVariables.o \ -$(OBJDIR)/GwfNpfOptions.o \ -$(OBJDIR)/ims8reordering.o \ -$(OBJDIR)/Sparse.o \ -$(OBJDIR)/GwfNpfGridData.o \ -$(OBJDIR)/PackageBudget.o \ -$(OBJDIR)/GwfStorageUtils.o \ $(OBJDIR)/genericutils.o \ -$(OBJDIR)/defmacro.o \ -$(OBJDIR)/ims8sparsekit.o \ +$(OBJDIR)/compilerversion.o \ $(OBJDIR)/ArrayHandlers.o \ -$(OBJDIR)/Xt3dAlgorithm.o \ $(OBJDIR)/version.o \ -$(OBJDIR)/SfrCrossSectionUtils.o \ -$(OBJDIR)/SmoothingFunctions.o \ -$(OBJDIR)/List.o \ -$(OBJDIR)/Timer.o \ -$(OBJDIR)/StringList.o \ -$(OBJDIR)/TimeSeriesRecord.o \ -$(OBJDIR)/mf6lists.o \ $(OBJDIR)/Message.o \ -$(OBJDIR)/ObsOutput.o \ +$(OBJDIR)/defmacro.o \ $(OBJDIR)/Sim.o \ -$(OBJDIR)/sort.o \ -$(OBJDIR)/Budget.o \ +$(OBJDIR)/OpenSpec.o \ $(OBJDIR)/InputOutput.o \ -$(OBJDIR)/RectangularGeometry.o \ -$(OBJDIR)/BlockParser.o \ -$(OBJDIR)/Iunit.o \ -$(OBJDIR)/MemoryHelper.o \ -$(OBJDIR)/NameFile.o \ -$(OBJDIR)/ArrayReaders.o \ -$(OBJDIR)/comarg.o \ -$(OBJDIR)/SfrCrossSectionManager.o \ -$(OBJDIR)/ObsOutputList.o \ -$(OBJDIR)/HeadFileReader.o \ -$(OBJDIR)/DisvGeom.o \ -$(OBJDIR)/BudgetFileReader.o \ $(OBJDIR)/TableTerm.o \ -$(OBJDIR)/CircularGeometry.o \ -$(OBJDIR)/TimeSeries.o \ -$(OBJDIR)/PrintSaveManager.o \ -$(OBJDIR)/ims8base.o \ -$(OBJDIR)/TimeSeriesLink.o \ $(OBJDIR)/Table.o \ -$(OBJDIR)/ListReader.o \ -$(OBJDIR)/TimeSeriesFileList.o \ +$(OBJDIR)/MemoryHelper.o \ +$(OBJDIR)/CharString.o \ $(OBJDIR)/Memory.o \ +$(OBJDIR)/List.o \ $(OBJDIR)/MemoryList.o \ +$(OBJDIR)/TimeSeriesRecord.o \ +$(OBJDIR)/BlockParser.o \ $(OBJDIR)/MemoryManager.o \ +$(OBJDIR)/TimeSeries.o \ $(OBJDIR)/ats.o \ -$(OBJDIR)/BaseModel.o \ -$(OBJDIR)/PackageMover.o \ +$(OBJDIR)/TimeSeriesLink.o \ +$(OBJDIR)/TimeSeriesFileList.o \ $(OBJDIR)/tdis.o \ -$(OBJDIR)/ims8linear.o \ -$(OBJDIR)/Connections.o \ -$(OBJDIR)/MemorySetHandler.o \ -$(OBJDIR)/Mover.o \ +$(OBJDIR)/HashTable.o \ +$(OBJDIR)/Sparse.o \ +$(OBJDIR)/DisvGeom.o \ +$(OBJDIR)/ArrayReaders.o \ $(OBJDIR)/TimeSeriesManager.o \ -$(OBJDIR)/UzfCellGroup.o \ -$(OBJDIR)/BaseExchange.o \ +$(OBJDIR)/SmoothingFunctions.o \ +$(OBJDIR)/ListReader.o \ +$(OBJDIR)/Connections.o \ $(OBJDIR)/DiscretizationBase.o \ -$(OBJDIR)/gwf3dis8.o \ -$(OBJDIR)/BudgetTerm.o \ -$(OBJDIR)/Observe.o \ -$(OBJDIR)/gwf3disu8.o \ -$(OBJDIR)/BaseSolution.o \ -$(OBJDIR)/gwf3disv8.o \ -$(OBJDIR)/Xt3dInterface.o \ -$(OBJDIR)/BudgetObject.o \ $(OBJDIR)/TimeArray.o \ +$(OBJDIR)/ObsOutput.o \ +$(OBJDIR)/TimeArraySeries.o \ +$(OBJDIR)/ObsOutputList.o \ +$(OBJDIR)/Observe.o \ +$(OBJDIR)/InputDefinition.o \ +$(OBJDIR)/TimeArraySeriesLink.o \ +$(OBJDIR)/ObsUtility.o \ +$(OBJDIR)/ObsContainer.o \ +$(OBJDIR)/VectorInt.o \ +$(OBJDIR)/gwt1dspidm.o \ +$(OBJDIR)/gwf3npf8idm.o \ +$(OBJDIR)/gwf3disv8idm.o \ +$(OBJDIR)/gwf3disu8idm.o \ +$(OBJDIR)/gwf3dis8idm.o \ +$(OBJDIR)/ArrayReaderBase.o \ +$(OBJDIR)/TimeArraySeriesManager.o \ +$(OBJDIR)/PackageMover.o \ +$(OBJDIR)/Obs3.o \ $(OBJDIR)/NumericalPackage.o \ +$(OBJDIR)/Budget.o \ +$(OBJDIR)/BudgetFileReader.o \ +$(OBJDIR)/StructVector.o \ +$(OBJDIR)/IdmLogger.o \ +$(OBJDIR)/InputDefinitionSelector.o \ +$(OBJDIR)/Integer2dReader.o \ +$(OBJDIR)/Double2dReader.o \ +$(OBJDIR)/BoundaryPackage.o \ +$(OBJDIR)/BaseModel.o \ +$(OBJDIR)/BudgetTerm.o \ +$(OBJDIR)/StructArray.o \ +$(OBJDIR)/ModflowInput.o \ +$(OBJDIR)/Integer1dReader.o \ +$(OBJDIR)/Double1dReader.o \ +$(OBJDIR)/NumericalModel.o \ +$(OBJDIR)/mf6lists.o \ +$(OBJDIR)/PackageBudget.o \ +$(OBJDIR)/HeadFileReader.o \ +$(OBJDIR)/BudgetObject.o \ +$(OBJDIR)/sort.o \ +$(OBJDIR)/SfrCrossSectionUtils.o \ +$(OBJDIR)/PrintSaveManager.o \ +$(OBJDIR)/Xt3dAlgorithm.o \ +$(OBJDIR)/gwf3tvbase8.o \ +$(OBJDIR)/LoadMf6FileType.o \ +$(OBJDIR)/DistributedModel.o \ +$(OBJDIR)/BaseExchange.o \ +$(OBJDIR)/UzfCellGroup.o \ +$(OBJDIR)/gwt1fmi1.o \ +$(OBJDIR)/SfrCrossSectionManager.o \ +$(OBJDIR)/dag_module.o \ $(OBJDIR)/OutputControlData.o \ -$(OBJDIR)/ObsContainer.o \ -$(OBJDIR)/ObsUtility.o \ -$(OBJDIR)/gwf3mvr8.o \ -$(OBJDIR)/gwf3hfb8.o \ -$(OBJDIR)/SolutionGroup.o \ -$(OBJDIR)/TimeArraySeries.o \ $(OBJDIR)/gwf3ic8.o \ -$(OBJDIR)/Obs3.o \ +$(OBJDIR)/Xt3dInterface.o \ +$(OBJDIR)/gwf3tvk8.o \ +$(OBJDIR)/MemoryManagerExt.o \ +$(OBJDIR)/IdmMf6FileLoader.o \ +$(OBJDIR)/GwfNpfOptions.o \ +$(OBJDIR)/CellWithNbrs.o \ +$(OBJDIR)/NumericalExchange.o \ +$(OBJDIR)/Iunit.o \ +$(OBJDIR)/gwf3uzf8.o \ +$(OBJDIR)/gwt1apt1.o \ +$(OBJDIR)/GwtSpc.o \ +$(OBJDIR)/gwf3sfr8.o \ $(OBJDIR)/OutputControl.o \ -$(OBJDIR)/gwf3tvbase8.o \ -$(OBJDIR)/TimeArraySeriesLink.o \ -$(OBJDIR)/gwf3csub8.o \ -$(OBJDIR)/gwt1oc1.o \ $(OBJDIR)/gwt1ic1.o \ -$(OBJDIR)/gwt1obs1.o \ -$(OBJDIR)/TimeArraySeriesManager.o \ -$(OBJDIR)/gwf3tvk8.o \ -$(OBJDIR)/gwf3obs8.o \ +$(OBJDIR)/gwf3maw8.o \ +$(OBJDIR)/gwf3lak8.o \ +$(OBJDIR)/gwt1mst1.o \ +$(OBJDIR)/GwtDspOptions.o \ $(OBJDIR)/gwf3npf8.o \ -$(OBJDIR)/GwtSpc.o \ +$(OBJDIR)/GwtAdvOptions.o \ $(OBJDIR)/gwf3tvs8.o \ -$(OBJDIR)/BoundaryPackage.o \ -$(OBJDIR)/gwf3oc8.o \ -$(OBJDIR)/gwf3lak8.o \ -$(OBJDIR)/gwf3riv8.o \ -$(OBJDIR)/gwf3drn8.o \ -$(OBJDIR)/gwf3ghb8.o \ +$(OBJDIR)/GwfStorageUtils.o \ +$(OBJDIR)/Mover.o \ +$(OBJDIR)/GwfMvrPeriodData.o \ +$(OBJDIR)/ims8misc.o \ +$(OBJDIR)/GwfBuyInputData.o \ +$(OBJDIR)/InterfaceMap.o \ +$(OBJDIR)/gwf3disu8.o \ +$(OBJDIR)/GridSorting.o \ +$(OBJDIR)/DisConnExchange.o \ +$(OBJDIR)/CsrUtils.o \ +$(OBJDIR)/MappedVariable.o \ +$(OBJDIR)/TransportModel.o \ +$(OBJDIR)/NameFile.o \ +$(OBJDIR)/gwt1uzt1.o \ +$(OBJDIR)/gwt1ssm1.o \ +$(OBJDIR)/gwt1src1.o \ +$(OBJDIR)/gwt1sft1.o \ +$(OBJDIR)/gwt1oc1.o \ +$(OBJDIR)/gwt1obs1.o \ +$(OBJDIR)/gwt1mwt1.o \ +$(OBJDIR)/gwt1mvt1.o \ +$(OBJDIR)/gwt1lkt1.o \ +$(OBJDIR)/gwt1ist1.o \ +$(OBJDIR)/gwt1dsp.o \ $(OBJDIR)/gwt1cnc1.o \ -$(OBJDIR)/gwf3uzf8.o \ +$(OBJDIR)/gwt1adv1.o \ +$(OBJDIR)/gwf3disv8.o \ +$(OBJDIR)/gwf3dis8.o \ $(OBJDIR)/gwf3api8.o \ $(OBJDIR)/gwf3wel8.o \ -$(OBJDIR)/gwf3sto8.o \ +$(OBJDIR)/gwf3riv8.o \ $(OBJDIR)/gwf3rch8.o \ -$(OBJDIR)/gwf3maw8.o \ -$(OBJDIR)/gwt1fmi1.o \ -$(OBJDIR)/gwf3evt8.o \ -$(OBJDIR)/gwt1src1.o \ -$(OBJDIR)/gwf3chd8.o \ -$(OBJDIR)/NumericalModel.o \ -$(OBJDIR)/gwf3sfr8.o \ -$(OBJDIR)/gwt1mvt1.o \ -$(OBJDIR)/gwt1mst1.o \ -$(OBJDIR)/gwt1adv1.o \ -$(OBJDIR)/gwt1ist1.o \ +$(OBJDIR)/gwf3sto8.o \ +$(OBJDIR)/gwf3oc8.o \ +$(OBJDIR)/gwf3obs8.o \ +$(OBJDIR)/gwf3mvr8.o \ +$(OBJDIR)/gwf3hfb8.o \ +$(OBJDIR)/gwf3csub8.o \ $(OBJDIR)/gwf3buy8.o \ -$(OBJDIR)/NumericalExchange.o \ -$(OBJDIR)/gwt1apt1.o \ -$(OBJDIR)/gwt1dsp.o \ -$(OBJDIR)/gwt1uzt1.o \ -$(OBJDIR)/gwt1ssm1.o \ $(OBJDIR)/GhostNode.o \ -$(OBJDIR)/gwt1lkt1.o \ -$(OBJDIR)/NumericalSolution.o \ -$(OBJDIR)/gwt1mwt1.o \ -$(OBJDIR)/DisConnExchange.o \ -$(OBJDIR)/gwt1sft1.o \ +$(OBJDIR)/gwf3ghb8.o \ +$(OBJDIR)/gwf3evt8.o \ +$(OBJDIR)/gwf3drn8.o \ +$(OBJDIR)/gwf3chd8.o \ +$(OBJDIR)/ims8reordering.o \ +$(OBJDIR)/GridConnection.o \ +$(OBJDIR)/DistributedData.o \ +$(OBJDIR)/gwt1.o \ $(OBJDIR)/gwf3.o \ +$(OBJDIR)/ims8base.o \ +$(OBJDIR)/SpatialModelConnection.o \ +$(OBJDIR)/GwtInterfaceModel.o \ +$(OBJDIR)/GwtGwtExchange.o \ +$(OBJDIR)/GwfInterfaceModel.o \ $(OBJDIR)/GwfGwfExchange.o \ -$(OBJDIR)/gwt1.o \ +$(OBJDIR)/BaseSolution.o \ +$(OBJDIR)/Timer.o \ +$(OBJDIR)/ims8linear.o \ +$(OBJDIR)/GwtGwtConnection.o \ +$(OBJDIR)/GwfGwfConnection.o \ +$(OBJDIR)/SolutionGroup.o \ +$(OBJDIR)/NumericalSolution.o \ $(OBJDIR)/GwfGwtExchange.o \ $(OBJDIR)/SimulationCreate.o \ +$(OBJDIR)/ConnectionBuilder.o \ +$(OBJDIR)/comarg.o \ $(OBJDIR)/mf6core.o \ -$(OBJDIR)/mf6.o +$(OBJDIR)/BaseGeometry.o \ +$(OBJDIR)/mf6.o \ +$(OBJDIR)/StringList.o \ +$(OBJDIR)/MemorySetHandler.o \ +$(OBJDIR)/ilut.o \ +$(OBJDIR)/sparsekit.o \ +$(OBJDIR)/rcm.o \ +$(OBJDIR)/blas1_d.o \ +$(OBJDIR)/RectangularGeometry.o \ +$(OBJDIR)/CircularGeometry.o # Define the objects that make up the program $(PROGRAM) : $(OBJECTS) diff --git a/requirements.travis.txt b/requirements.travis.txt deleted file mode 100644 index f0b9b6580c8..00000000000 --- a/requirements.travis.txt +++ /dev/null @@ -1,4 +0,0 @@ -numpy -pip -nose-timer -bmipy diff --git a/src/Exchange/BaseExchange.f90 b/src/Exchange/BaseExchange.f90 index 1cf9d630e8f..5b323c6ea52 100644 --- a/src/Exchange/BaseExchange.f90 +++ b/src/Exchange/BaseExchange.f90 @@ -1,20 +1,20 @@ module BaseExchangeModule - - use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: LENEXCHANGENAME, LENMEMPATH - use ListModule, only: ListType - use BaseModelModule, only: BaseModelType + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: LENEXCHANGENAME, LENMEMPATH + use ListModule, only: ListType + use BaseModelModule, only: BaseModelType implicit none - + private public :: BaseExchangeType, AddBaseExchangeToList, GetBaseExchangeFromList private :: CastAsBaseExchangeClass - + type, abstract :: BaseExchangeType - character(len=LENEXCHANGENAME) :: name !< the name of this exchange - character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored - integer(I4B) :: id + character(len=LENEXCHANGENAME) :: name !< the name of this exchange + character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored + integer(I4B) :: id contains procedure(exg_df), deferred :: exg_df procedure(exg_ar), deferred :: exg_ar @@ -39,9 +39,9 @@ subroutine exg_ar(this) end subroutine end interface - - contains - + +contains + subroutine exg_rp(this) ! ****************************************************************************** ! exg_rp -- Read and prepare @@ -63,7 +63,7 @@ subroutine exg_rp(this) ! -- Return return end subroutine exg_rp - + subroutine exg_calculate_delt(this) ! ****************************************************************************** ! exg_calculate_delt -- Calculate time step length @@ -81,7 +81,7 @@ subroutine exg_calculate_delt(this) ! -- Return return end subroutine exg_calculate_delt - + subroutine exg_ot(this) ! ****************************************************************************** ! exg_ot -- Output @@ -97,7 +97,7 @@ subroutine exg_ot(this) ! -- Return return end subroutine exg_ot - + subroutine exg_fp(this) ! ****************************************************************************** ! exg_fp -- Final processing @@ -113,7 +113,7 @@ subroutine exg_fp(this) ! -- Return return end subroutine exg_fp - + subroutine exg_da(this) ! ****************************************************************************** ! exg_da -- Deallocate @@ -134,15 +134,15 @@ end subroutine exg_da !! added to the solution where the model resides !< function connects_model(this, model) result(is_connected) - class(BaseExchangeType) :: this !< the instance of the exchange - class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection - logical(LGP) :: is_connected !< true, when connected + class(BaseExchangeType) :: this !< the instance of the exchange + class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection + logical(LGP) :: is_connected !< true, when connected is_connected = .false. end function - function CastAsBaseExchangeClass(obj) result (res) + function CastAsBaseExchangeClass(obj) result(res) ! ****************************************************************************** ! CastAsBaseExchangeClass ! ****************************************************************************** @@ -173,7 +173,7 @@ subroutine AddBaseExchangeToList(list, exchange) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(BaseExchangeType), pointer, intent(inout) :: exchange ! -- local class(*), pointer :: obj @@ -184,8 +184,8 @@ subroutine AddBaseExchangeToList(list, exchange) ! return end subroutine AddBaseExchangeToList - - function GetBaseExchangeFromList(list, idx) result (res) + + function GetBaseExchangeFromList(list, idx) result(res) ! ****************************************************************************** ! GetBaseExchangeFromList ! ****************************************************************************** @@ -193,9 +193,9 @@ function GetBaseExchangeFromList(list, idx) result (res) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(BaseExchangeType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(BaseExchangeType), pointer :: res ! -- local class(*), pointer :: obj ! ------------------------------------------------------------------------------ diff --git a/src/Exchange/DisConnExchange.f90 b/src/Exchange/DisConnExchange.f90 index e81ea496a2e..917095b268a 100644 --- a/src/Exchange/DisConnExchange.f90 +++ b/src/Exchange/DisConnExchange.f90 @@ -1,440 +1,445 @@ module DisConnExchangeModule -use KindModule, only: I4B, DP, LGP -use SimVariablesModule, only: errmsg -use ConstantsModule, only: LENAUXNAME, LENBOUNDNAME, LINELENGTH -use ListModule, only: ListType -use MemoryManagerModule, only: mem_allocate -use BlockParserModule, only: BlockParserType -use NumericalModelModule, only: NumericalModelType -use NumericalExchangeModule, only: NumericalExchangeType -implicit none - -private -public :: DisConnExchangeType -public :: CastAsDisConnExchangeClass, AddDisConnExchangeToList, & - GetDisConnExchangeFromList - -!> Exchange based on connection between discretizations of DisBaseType. -!! The data specifies the connections, similar to the information stored -!! in the connections object: DisBaseType%con -!< -type, extends(NumericalExchangeType) :: DisConnExchangeType - character(len=LINELENGTH), pointer :: filename => null() !< name of the input file - - class(NumericalModelType), pointer :: model1 => null() !< model 1 - class(NumericalModelType), pointer :: model2 => null() !< model 2 - integer(I4B), pointer :: nexg => null() !< number of exchanges - integer(I4B), dimension(:), pointer, contiguous :: nodem1 => null() !< node numbers in model 1 - integer(I4B), dimension(:), pointer, contiguous :: nodem2 => null() !< node numbers in model 2 - integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !< horizontal connection indicator array, size: nexg - real(DP), dimension(:), pointer, contiguous :: cl1 => null() !< connection length 1, size: nexg - real(DP), dimension(:), pointer, contiguous :: cl2 => null() !< connection length 2, size: nexg - real(DP), dimension(:), pointer, contiguous :: hwva => null() !< horizontal widths, vertical flow areas, size: nexg - integer(I4B), pointer :: naux => null() !< number of auxiliary variables - character(len=LENBOUNDNAME), dimension(:), & - pointer, contiguous :: boundname => null() !< boundnames - - character(len=LENAUXNAME), dimension(:), & - pointer, contiguous :: auxname => null() !< vector of auxname - real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< array of auxiliary variable values - integer(I4B), pointer :: ianglex => null() !< flag indicating anglex was read, if read, ianglex is index in auxvar - integer(I4B), pointer :: icdist => null() !< flag indicating cdist was read, if read, icdist is index in auxvar - integer(I4B), pointer :: iprpak => null() !< print input flag - integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames - - integer(I4B), pointer :: ixt3d => null() !< flag indicating if XT3D should be applied on the interface: 0 = off, 1 = lhs, 2 = rhs - logical(LGP) :: dev_ifmod_on !< development option, forces interface model for this exchange - - type(BlockParserType) :: parser !< block parser for input file (controlled from derived type) + use KindModule, only: I4B, DP, LGP + use SimVariablesModule, only: errmsg + use ConstantsModule, only: LENAUXNAME, LENBOUNDNAME, LINELENGTH + use ListModule, only: ListType + use MemoryManagerModule, only: mem_allocate, mem_reallocate + use BlockParserModule, only: BlockParserType + use NumericalModelModule, only: NumericalModelType + use DistributedModelModule, only: DistributedModelType + use NumericalExchangeModule, only: NumericalExchangeType + implicit none + + private + public :: DisConnExchangeType + public :: CastAsDisConnExchangeClass, AddDisConnExchangeToList, & + GetDisConnExchangeFromList + + !> Exchange based on connection between discretizations of DisBaseType. + !! The data specifies the connections, similar to the information stored + !! in the connections object: DisBaseType%con + !< + type, extends(NumericalExchangeType) :: DisConnExchangeType + character(len=LINELENGTH), pointer :: filename => null() !< name of the input file + + class(NumericalModelType), pointer :: model1 => null() !< model 1 + class(NumericalModelType), pointer :: model2 => null() !< model 2 + class(DistributedModelType), pointer :: dmodel1 => null() !< distributed model 1 + class(DistributedModelType), pointer :: dmodel2 => null() !< distributed model 2 + + integer(I4B), pointer :: nexg => null() !< number of exchanges + integer(I4B), dimension(:), pointer, contiguous :: nodem1 => null() !< node numbers in model 1 + integer(I4B), dimension(:), pointer, contiguous :: nodem2 => null() !< node numbers in model 2 + integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !< horizontal connection indicator array, size: nexg + real(DP), dimension(:), pointer, contiguous :: cl1 => null() !< connection length 1, size: nexg + real(DP), dimension(:), pointer, contiguous :: cl2 => null() !< connection length 2, size: nexg + real(DP), dimension(:), pointer, contiguous :: hwva => null() !< horizontal widths, vertical flow areas, size: nexg + integer(I4B), pointer :: naux => null() !< number of auxiliary variables + character(len=LENBOUNDNAME), dimension(:), & + pointer, contiguous :: boundname => null() !< boundnames + + character(len=LENAUXNAME), dimension(:), & + pointer, contiguous :: auxname => null() !< vector of auxname + real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< array of auxiliary variable values + integer(I4B), pointer :: ianglex => null() !< flag indicating anglex was read, if read, ianglex is index in auxvar + integer(I4B), pointer :: icdist => null() !< flag indicating cdist was read, if read, icdist is index in auxvar + integer(I4B), pointer :: iprpak => null() !< print input flag + integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames + + integer(I4B), pointer :: ixt3d => null() !< flag indicating if XT3D should be applied on the interface: 0 = off, 1 = lhs, 2 = rhs + logical(LGP) :: dev_ifmod_on !< development option, forces interface model for this exchange + + type(BlockParserType) :: parser !< block parser for input file (controlled from derived type) contains - procedure :: allocate_scalars - procedure :: allocate_arrays - procedure :: disconnex_da - procedure :: use_interface_model + procedure :: allocate_scalars + procedure :: allocate_arrays + procedure :: disconnex_da + procedure :: use_interface_model - ! protected - procedure, pass(this) :: parse_option - procedure, pass(this) :: read_dimensions - procedure, pass(this) :: read_data + ! protected + procedure, pass(this) :: parse_option + procedure, pass(this) :: read_dimensions + procedure, pass(this) :: read_data -end type DisConnExchangeType + end type DisConnExchangeType contains -!> @brief Parse option from exchange file -!< -function parse_option(this, keyword, iout) result(parsed) - use ArrayHandlersModule, only: ifind - use InputOutputModule, only: urdaux - class(DisConnExchangeType) :: this !< instance of exchange object - character(len=LINELENGTH), intent(in) :: keyword !< the option name - integer(I4B), intent(in) :: iout !< for logging - logical(LGP) :: parsed !< true when parsed - ! local - integer(I4B) :: istart - integer(I4B) :: istop - integer(I4B) :: lloc - integer(I4B) :: n - integer(I4B) :: ival - - character(len=:), allocatable :: line - character(len=LENAUXNAME), dimension(:), allocatable :: caux - - parsed = .true. - - select case (keyword) - case('AUXILIARY') - call this%parser%GetRemainingLine(line) - lloc = 1 - call urdaux(this%naux, this%parser%iuactive, iout, lloc, istart, & - istop, caux, line, 'GWF_GWF_Exchange') - call mem_allocate(this%auxname, LENAUXNAME, this%naux, & - 'AUXNAME', trim(this%memoryPath)) - do n = 1, this%naux - this%auxname(n) = caux(n) - end do - deallocate(caux) - ! - ! -- If ANGLDEGX is an auxiliary variable, then anisotropy can be - ! used in either model. Store ANGLDEGX position in this%ianglex - ival = ifind(this%auxname, 'ANGLDEGX') - if (ival > 0) then - this%ianglex = ival - end if - ival = ifind(this%auxname, 'CDIST') - if(ival > 0) then - this%icdist = ival - end if - case ('PRINT_INPUT') - this%iprpak = 1 - write(iout,'(4x,a)') & - 'THE LIST OF EXCHANGES WILL BE PRINTED.' - case ('XT3D') - this%ixt3d = 1 - write(iout, '(4x,a)') 'XT3D WILL BE APPLIED ON THE INTERFACE' - case ('BOUNDNAMES') - this%inamedbound = 1 - write(iout, '(4x,a)') 'EXCHANGE BOUNDARIES HAVE NAMES IN LAST COLUMN' - case('DEV_INTERFACEMODEL_ON') - call this%parser%DevOpt() - this%dev_ifmod_on = .true. - write(iout, '(4x,2a)') 'Interface model coupling approach manually & - &activated for ', trim(this%name) - case default - ! not parsed here, assuming it is in derived type - parsed = .false. - end select - -end function parse_option - -!> @brief Read dimensions from file -!< -subroutine read_dimensions(this, iout) - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error - class(DisConnExchangeType) :: this !< instance of exchange object - integer(I4B), intent(in) :: iout !< output file unit - ! local - character(len=LINELENGTH) :: keyword - integer(I4B) :: ierr - logical :: isfound, endOfBlock - - ! get dimensions block - call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) - - ! parse NEXG - if (isfound) then - write(iout,'(1x,a)') 'PROCESSING EXCHANGE DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) + !> @brief Parse option from exchange file + !< + function parse_option(this, keyword, iout) result(parsed) + use ArrayHandlersModule, only: ifind + use InputOutputModule, only: urdaux + class(DisConnExchangeType) :: this !< instance of exchange object + character(len=LINELENGTH), intent(in) :: keyword !< the option name + integer(I4B), intent(in) :: iout !< for logging + logical(LGP) :: parsed !< true when parsed + ! local + integer(I4B) :: istart + integer(I4B) :: istop + integer(I4B) :: lloc + integer(I4B) :: n + integer(I4B) :: ival + + character(len=:), allocatable :: line + character(len=LENAUXNAME), dimension(:), allocatable :: caux + + parsed = .true. + + select case (keyword) + case ('AUXILIARY') + call this%parser%GetRemainingLine(line) + lloc = 1 + call urdaux(this%naux, this%parser%iuactive, iout, lloc, istart, & + istop, caux, line, 'GWF_GWF_Exchange') + call mem_reallocate(this%auxname, LENAUXNAME, this%naux, & + 'AUXNAME', trim(this%memoryPath)) + do n = 1, this%naux + this%auxname(n) = caux(n) + end do + deallocate (caux) + ! + ! -- If ANGLDEGX is an auxiliary variable, then anisotropy can be + ! used in either model. Store ANGLDEGX position in this%ianglex + ival = ifind(this%auxname, 'ANGLDEGX') + if (ival > 0) then + this%ianglex = ival + end if + ival = ifind(this%auxname, 'CDIST') + if (ival > 0) then + this%icdist = ival + end if + case ('PRINT_INPUT') + this%iprpak = 1 + write (iout, '(4x,a)') & + 'THE LIST OF EXCHANGES WILL BE PRINTED.' + case ('XT3D') + this%ixt3d = 1 + write (iout, '(4x,a)') 'XT3D WILL BE APPLIED ON THE INTERFACE' + case ('BOUNDNAMES') + this%inamedbound = 1 + write (iout, '(4x,a)') 'EXCHANGE BOUNDARIES HAVE NAMES IN LAST COLUMN' + case ('DEV_INTERFACEMODEL_ON') + call this%parser%DevOpt() + this%dev_ifmod_on = .true. + write (iout, '(4x,2a)') 'Interface model coupling approach manually & + &activated for ', trim(this%name) + case default + ! not parsed here, assuming it is in derived type + parsed = .false. + end select + + end function parse_option + + !> @brief Read dimensions from file + !< + subroutine read_dimensions(this, iout) + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error + class(DisConnExchangeType) :: this !< instance of exchange object + integer(I4B), intent(in) :: iout !< output file unit + ! local + character(len=LINELENGTH) :: keyword + integer(I4B) :: ierr + logical :: isfound, endOfBlock + + ! get dimensions block + call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & + supportOpenClose=.true.) + + ! parse NEXG + if (isfound) then + write (iout, '(1x,a)') 'PROCESSING EXCHANGE DIMENSIONS' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call this%parser%GetStringCaps(keyword) + select case (keyword) case ('NEXG') this%nexg = this%parser%GetInteger() - write(iout,'(4x,a,i0)') 'NEXG = ', this%nexg + write (iout, '(4x,a,i0)') 'NEXG = ', this%nexg case default - errmsg = "Unknown dimension '" // trim(keyword) // "'." + errmsg = "Unknown dimension '"//trim(keyword)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() - end select - end do - write(iout,'(1x,a)') 'END OF EXCHANGE DIMENSIONS' - else - call store_error('Required dimensions block not found.') - call this%parser%StoreErrorUnit() - end if - - return -end subroutine read_dimensions - -!> @brief Read exchange data block from file -!< -subroutine read_data(this, iout) - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, store_error_unit, count_errors - class(DisConnExchangeType) :: this !< instance of exchange object - integer(I4B), intent(in) :: iout !< the output file unit - ! local - character(len=LINELENGTH) :: nodestr, node1str, node2str, cellid - character(len=2) :: cnfloat - integer(I4B) :: lloc, ierr, nerr, iaux - integer(I4B) :: iexg, nodem1, nodem2, nodeum1, nodeum2 - logical :: isfound, endOfBlock - - character(len=*), parameter :: fmtexglabel = "(5x, 3a10, 50(a16))" - character(len=*), parameter :: fmtexgdata = & - "(5x, a, 1x, a ,I10, 50(1pg16.6))" - character(len=40) :: fmtexgdata2 - - ! get data block - call this%parser%GetBlock('EXCHANGEDATA', isfound, ierr, & - supportOpenClose=.true.) - if (isfound) then - write(iout,'(1x,a)')'PROCESSING EXCHANGEDATA' - if(this%iprpak /= 0) then - if (this%inamedbound==0) then - write(iout, fmtexglabel) 'NODEM1', 'NODEM2', 'IHC', & - 'CL1', 'CL2', 'HWVA', (adjustr(this%auxname(iaux)), & - iaux = 1, this%naux) - else - write(iout, fmtexglabel) 'NODEM1', 'NODEM2', 'IHC', 'CL1', 'CL2', & - 'HWVA', (adjustr(this%auxname(iaux)),iaux=1,this%naux), & - ' BOUNDNAME ' - ! Define format suitable for writing input data, - ! any auxiliary variables, and boundname. - write(cnfloat,'(i0)') 3+this%naux - fmtexgdata2 = '(5x, a, 1x, a, i10, ' // trim(cnfloat) // & - '(1pg16.6), 1x, a)' - endif - endif - do iexg = 1, this%nexg - call this%parser%GetNextLine(endOfBlock) - lloc = 1 - ! - ! -- Read and check node 1 - call this%parser%GetCellid(this%model1%dis%ndim, cellid, flag_string=.true.) - nodem1 = this%model1%dis%noder_from_cellid(cellid, this%parser%iuactive, & - iout, flag_string=.true.) - this%nodem1(iexg) = nodem1 - ! - ! -- Read and check node 2 - call this%parser%GetCellid(this%model2%dis%ndim, cellid, flag_string=.true.) - nodem2 = this%model2%dis%noder_from_cellid(cellid, this%parser%iuactive, & - iout, flag_string=.true.) - this%nodem2(iexg) = nodem2 - ! - ! -- Read rest of input line - this%ihc(iexg) = this%parser%GetInteger() - this%cl1(iexg) = this%parser%GetDouble() - this%cl2(iexg) = this%parser%GetDouble() - this%hwva(iexg) = this%parser%GetDouble() - do iaux = 1, this%naux - this%auxvar(iaux, iexg) = this%parser%GetDouble() - enddo - if (this%inamedbound==1) then - call this%parser%GetStringCaps(this%boundname(iexg)) - endif - ! - ! -- Write the data to listing file if requested - if(this%iprpak /= 0) then - nodeum1 = this%model1%dis%get_nodeuser(nodem1) - call this%model1%dis%nodeu_to_string(nodeum1, node1str) - nodeum2 = this%model2%dis%get_nodeuser(nodem2) - call this%model2%dis%nodeu_to_string(nodeum2, node2str) + end select + end do + write (iout, '(1x,a)') 'END OF EXCHANGE DIMENSIONS' + else + call store_error('Required dimensions block not found.') + call this%parser%StoreErrorUnit() + end if + + return + end subroutine read_dimensions + + !> @brief Read exchange data block from file + !< + subroutine read_data(this, iout) + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error, store_error_unit, count_errors + class(DisConnExchangeType) :: this !< instance of exchange object + integer(I4B), intent(in) :: iout !< the output file unit + ! local + character(len=20) :: cellid1, cellid2 + character(len=2) :: cnfloat + integer(I4B) :: lloc, ierr, nerr, iaux + integer(I4B) :: iexg, nodem1, nodem2 + logical :: isfound, endOfBlock + + character(len=*), parameter :: fmtexglabel = "(5x, 3a10, 50(a16))" + character(len=*), parameter :: fmtexgdata = & + "(5x, a, 1x, a ,I10, 50(1pg16.6))" + character(len=40) :: fmtexgdata2 + + ! get data block + call this%parser%GetBlock('EXCHANGEDATA', isfound, ierr, & + supportOpenClose=.true.) + if (isfound) then + write (iout, '(1x,a)') 'PROCESSING EXCHANGEDATA' + if (this%iprpak /= 0) then if (this%inamedbound == 0) then - write(iout, fmtexgdata) trim(node1str), trim(node2str), & - this%ihc(iexg), this%cl1(iexg), this%cl2(iexg), & - this%hwva(iexg), & - (this%auxvar(iaux, iexg), iaux=1,this%naux) + write (iout, fmtexglabel) 'NODEM1', 'NODEM2', 'IHC', & + 'CL1', 'CL2', 'HWVA', (adjustr(this%auxname(iaux)), & + iaux=1, this%naux) else - write(iout, fmtexgdata2) trim(node1str), trim(node2str), & - this%ihc(iexg), this%cl1(iexg), this%cl2(iexg), & - this%hwva(iexg), & - (this%auxvar(iaux, iexg), iaux=1,this%naux), & - trim(this%boundname(iexg)) - endif - endif + write (iout, fmtexglabel) 'NODEM1', 'NODEM2', 'IHC', 'CL1', 'CL2', & + 'HWVA', (adjustr(this%auxname(iaux)), iaux=1, this%naux), & + ' BOUNDNAME ' + ! Define format suitable for writing input data, + ! any auxiliary variables, and boundname. + write (cnfloat, '(i0)') 3 + this%naux + fmtexgdata2 = '(5x, a, 1x, a, i10, '//trim(cnfloat)// & + '(1pg16.6), 1x, a)' + end if + end if + do iexg = 1, this%nexg + call this%parser%GetNextLine(endOfBlock) + lloc = 1 + ! + ! -- Read and check node 1 + call this%parser%GetCellid(this%model1%dis%ndim, cellid1, & + flag_string=.true.) + nodem1 = this%model1%dis%noder_from_cellid(cellid1, & + this%parser%iuactive, & + iout, flag_string=.true.) + this%nodem1(iexg) = nodem1 + ! + ! -- Read and check node 2 + call this%parser%GetCellid(this%model2%dis%ndim, cellid2, & + flag_string=.true.) + nodem2 = this%model2%dis%noder_from_cellid(cellid2, & + this%parser%iuactive, & + iout, flag_string=.true.) + this%nodem2(iexg) = nodem2 + ! + ! -- Read rest of input line + this%ihc(iexg) = this%parser%GetInteger() + this%cl1(iexg) = this%parser%GetDouble() + this%cl2(iexg) = this%parser%GetDouble() + this%hwva(iexg) = this%parser%GetDouble() + do iaux = 1, this%naux + this%auxvar(iaux, iexg) = this%parser%GetDouble() + end do + if (this%inamedbound == 1) then + call this%parser%GetStringCaps(this%boundname(iexg)) + end if + ! + ! -- Write the data to listing file if requested + if (this%iprpak /= 0) then + if (this%inamedbound == 0) then + write (iout, fmtexgdata) trim(cellid1), trim(cellid2), & + this%ihc(iexg), this%cl1(iexg), this%cl2(iexg), & + this%hwva(iexg), & + (this%auxvar(iaux, iexg), iaux=1, this%naux) + else + write (iout, fmtexgdata2) trim(cellid1), trim(cellid2), & + this%ihc(iexg), this%cl1(iexg), this%cl2(iexg), & + this%hwva(iexg), & + (this%auxvar(iaux, iexg), iaux=1, this%naux), & + trim(this%boundname(iexg)) + end if + end if + ! + ! -- Check to see if nodem1 is outside of active domain + if (nodem1 <= 0) then + write (errmsg, *) & + trim(adjustl(this%model1%name))// & + ' Cell is outside active grid domain ('// & + trim(adjustl(cellid1))//').' + call store_error(errmsg) + end if + ! + ! -- Check to see if nodem2 is outside of active domain + if (nodem2 <= 0) then + write (errmsg, *) & + trim(adjustl(this%model2%name))// & + ' Cell is outside active grid domain ('// & + trim(adjustl(cellid2))//').' + call store_error(errmsg) + end if + end do ! - ! -- Check to see if nodem1 is outside of active domain - if(nodem1 <= 0) then - call this%model1%dis%nodeu_to_string(nodeum1, nodestr) - write(errmsg, *) & - trim(adjustl(this%model1%name)) // & - ' Cell is outside active grid domain ' // & - trim(adjustl(nodestr)) // '.' - call store_error(errmsg) - endif + ! -- Stop if errors + nerr = count_errors() + if (nerr > 0) then + call store_error('Errors encountered in exchange input file.') + call this%parser%StoreErrorUnit() + end if ! - ! -- Check to see if nodem2 is outside of active domain - if(nodem2 <= 0) then - call this%model2%dis%nodeu_to_string(nodeum2, nodestr) - write(errmsg, *) & - trim(adjustl(this%model2%name)) // & - ' Cell is outside active grid domain ' // & - trim(adjustl(nodestr)) // '.' - call store_error(errmsg) - endif - enddo - ! - ! -- Stop if errors - nerr = count_errors() - if(nerr > 0) then - call store_error('Errors encountered in exchange input file.') + write (iout, '(1x,a)') 'END OF EXCHANGEDATA' + else + errmsg = 'Required exchangedata block not found.' + call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! - write(iout,'(1x,a)')'END OF EXCHANGEDATA' - else - errmsg = 'Required exchangedata block not found.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end if - ! - ! -- return - return + ! -- return + return end subroutine read_data -!> @brief Allocate scalars and initialize to defaults -!< -subroutine allocate_scalars(this) - use MemoryManagerModule, only: mem_allocate - class(DisConnExchangeType) :: this !< instance of exchange object - - allocate(this%filename) - this%filename = '' - - call mem_allocate(this%nexg, 'NEXG', this%memoryPath) - call mem_allocate(this%naux, 'NAUX', this%memoryPath) - call mem_allocate(this%ianglex, 'IANGLEX', this%memoryPath) - call mem_allocate(this%icdist, 'ICDIST', this%memoryPath) - call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) - call mem_allocate(this%iprpak, 'IPRPAK', this%memoryPath) - call mem_allocate(this%inamedbound, 'INAMEDBOUND', this%memoryPath) - - this%nexg = 0 - this%naux = 0 - this%ianglex = 0 - this%icdist = 0 - this%ixt3d = 0 - this%inamedbound = 0 - - this%dev_ifmod_on = .false. - -end subroutine allocate_scalars - -!> @brief Allocate array data, using the number of -!! connected nodes @param nexg -!< -subroutine allocate_arrays(this) - use MemoryManagerModule, only: mem_allocate - class(DisConnExchangeType) :: this !< instance of exchange object - - call mem_allocate(this%nodem1, this%nexg, 'NODEM1', this%memoryPath) - call mem_allocate(this%nodem2, this%nexg, 'NODEM2', this%memoryPath) - call mem_allocate(this%ihc, this%nexg, 'IHC', this%memoryPath) - call mem_allocate(this%cl1, this%nexg, 'CL1', this%memoryPath) - call mem_allocate(this%cl2, this%nexg, 'CL2', this%memoryPath) - call mem_allocate(this%hwva, this%nexg, 'HWVA', this%memoryPath) - ! NB: auxname array is allocated while parsing - call mem_allocate(this%auxvar, this%naux, this%nexg, 'AUXVAR', this%memoryPath) - - ! allocate boundname - if(this%inamedbound==1) then - allocate(this%boundname(this%nexg)) - else - allocate(this%boundname(1)) - endif - this%boundname(:) = '' - -end subroutine allocate_arrays - -!> @brief Should interface model be used to handle these -!! exchanges, to be overridden for inheriting types -!< -function use_interface_model(this) result(useIM) - class(DisConnExchangeType) :: this !< instance of exchange object - logical(LGP) :: useIM !< flag whether interface model should be used + !> @brief Allocate scalars and initialize to defaults + !< + subroutine allocate_scalars(this) + use MemoryManagerModule, only: mem_allocate + class(DisConnExchangeType) :: this !< instance of exchange object + + allocate (this%filename) + this%filename = '' + + call mem_allocate(this%nexg, 'NEXG', this%memoryPath) + call mem_allocate(this%naux, 'NAUX', this%memoryPath) + call mem_allocate(this%ianglex, 'IANGLEX', this%memoryPath) + call mem_allocate(this%icdist, 'ICDIST', this%memoryPath) + call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) + call mem_allocate(this%iprpak, 'IPRPAK', this%memoryPath) + call mem_allocate(this%inamedbound, 'INAMEDBOUND', this%memoryPath) + + call mem_allocate(this%auxname, LENAUXNAME, 0, & + 'AUXNAME', trim(this%memoryPath)) + + this%nexg = 0 + this%naux = 0 + this%ianglex = 0 + this%icdist = 0 + this%ixt3d = 0 + this%inamedbound = 0 + + this%dev_ifmod_on = .false. + + end subroutine allocate_scalars + + !> @brief Allocate array data, using the number of + !! connected nodes @param nexg + !< + subroutine allocate_arrays(this) + class(DisConnExchangeType) :: this !< instance of exchange object + + call mem_allocate(this%nodem1, this%nexg, 'NODEM1', this%memoryPath) + call mem_allocate(this%nodem2, this%nexg, 'NODEM2', this%memoryPath) + call mem_allocate(this%ihc, this%nexg, 'IHC', this%memoryPath) + call mem_allocate(this%cl1, this%nexg, 'CL1', this%memoryPath) + call mem_allocate(this%cl2, this%nexg, 'CL2', this%memoryPath) + call mem_allocate(this%hwva, this%nexg, 'HWVA', this%memoryPath) + ! NB: auxname array is allocated while parsing + call mem_allocate(this%auxvar, this%naux, this%nexg, & + 'AUXVAR', this%memoryPath) + + ! allocate boundname + if (this%inamedbound == 1) then + allocate (this%boundname(this%nexg)) + else + allocate (this%boundname(1)) + end if + this%boundname(:) = '' + + end subroutine allocate_arrays + + !> @brief Should interface model be used to handle these + !! exchanges, to be overridden for inheriting types + !< + function use_interface_model(this) result(useIM) + class(DisConnExchangeType) :: this !< instance of exchange object + logical(LGP) :: useIM !< flag whether interface model should be used !! for this exchange instead - useIM = .false. - -end function use_interface_model - -!> @brief Clean up all scalars and arrays -!< -subroutine disconnex_da(this) - use MemoryManagerModule, only: mem_deallocate - class(DisConnExchangeType) :: this !< instance of exchange object - - ! arrays - call mem_deallocate(this%nodem1) - call mem_deallocate(this%nodem2) - call mem_deallocate(this%ihc) - call mem_deallocate(this%cl1) - call mem_deallocate(this%cl2) - call mem_deallocate(this%hwva) - call mem_deallocate(this%auxvar) - - deallocate(this%boundname) - - ! scalars - call mem_deallocate(this%nexg) - call mem_deallocate(this%naux) - call mem_deallocate(this%auxname, 'AUXNAME', trim(this%memoryPath)) - call mem_deallocate(this%ianglex) - call mem_deallocate(this%icdist) - call mem_deallocate(this%ixt3d) - call mem_deallocate(this%iprpak) - call mem_deallocate(this%inamedbound) - -end subroutine disconnex_da - -function CastAsDisConnExchangeClass(obj) result (res) - implicit none - class(*), pointer, intent(inout) :: obj - class(DisConnExchangeType), pointer :: res - ! - res => null() - if (.not. associated(obj)) return - ! - select type (obj) - class is (DisConnExchangeType) - res => obj - end select - return -end function CastAsDisConnExchangeClass - -subroutine AddDisConnExchangeToList(list, exchange) - implicit none - ! -- dummy - type(ListType), intent(inout) :: list - class(DisConnExchangeType), pointer, intent(in) :: exchange - ! -- local - class(*), pointer :: obj - ! - obj => exchange - call list%Add(obj) - ! - return -end subroutine AddDisConnExchangeToList - -function GetDisConnExchangeFromList(list, idx) result (res) - implicit none - ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(DisConnExchangeType), pointer :: res - ! -- local - class(*), pointer :: obj - ! - obj => list%GetItem(idx) - res => CastAsDisConnExchangeClass(obj) - ! - return -end function GetDisConnExchangeFromList - -end module DisConnExchangeModule \ No newline at end of file + useIM = .false. + + end function use_interface_model + + !> @brief Clean up all scalars and arrays + !< + subroutine disconnex_da(this) + use MemoryManagerModule, only: mem_deallocate + class(DisConnExchangeType) :: this !< instance of exchange object + + ! arrays + call mem_deallocate(this%nodem1) + call mem_deallocate(this%nodem2) + call mem_deallocate(this%ihc) + call mem_deallocate(this%cl1) + call mem_deallocate(this%cl2) + call mem_deallocate(this%hwva) + call mem_deallocate(this%auxvar) + + deallocate (this%boundname) + + ! scalars + call mem_deallocate(this%nexg) + call mem_deallocate(this%naux) + call mem_deallocate(this%auxname, 'AUXNAME', trim(this%memoryPath)) + call mem_deallocate(this%ianglex) + call mem_deallocate(this%icdist) + call mem_deallocate(this%ixt3d) + call mem_deallocate(this%iprpak) + call mem_deallocate(this%inamedbound) + + end subroutine disconnex_da + + function CastAsDisConnExchangeClass(obj) result(res) + implicit none + class(*), pointer, intent(inout) :: obj + class(DisConnExchangeType), pointer :: res + ! + res => null() + if (.not. associated(obj)) return + ! + select type (obj) + class is (DisConnExchangeType) + res => obj + end select + return + end function CastAsDisConnExchangeClass + + subroutine AddDisConnExchangeToList(list, exchange) + implicit none + ! -- dummy + type(ListType), intent(inout) :: list + class(DisConnExchangeType), pointer, intent(in) :: exchange + ! -- local + class(*), pointer :: obj + ! + obj => exchange + call list%Add(obj) + ! + return + end subroutine AddDisConnExchangeToList + + function GetDisConnExchangeFromList(list, idx) result(res) + implicit none + ! -- dummy + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(DisConnExchangeType), pointer :: res + ! -- local + class(*), pointer :: obj + ! + obj => list%GetItem(idx) + res => CastAsDisConnExchangeClass(obj) + ! + return + end function GetDisConnExchangeFromList + +end module DisConnExchangeModule diff --git a/src/Exchange/GhostNode.f90 b/src/Exchange/GhostNode.f90 index 649ff9814a3..b0831682432 100644 --- a/src/Exchange/GhostNode.f90 +++ b/src/Exchange/GhostNode.f90 @@ -1,10 +1,10 @@ module GhostNodeModule use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH - use NumericalModelModule, only: NumericalModelType + use ConstantsModule, only: LINELENGTH + use NumericalModelModule, only: NumericalModelType use NumericalPackageModule, only: NumericalPackageType - use BlockParserModule, only: BlockParserType + use BlockParserModule, only: BlockParserType implicit none @@ -13,36 +13,36 @@ module GhostNodeModule public :: gnc_cr type, extends(NumericalPackageType) :: GhostNodeType - logical, pointer :: smgnc => null() ! single model gnc - logical, pointer :: implicit => null() ! lhs or rhs - logical, pointer :: i2kn => null() ! not used - integer(I4B), pointer :: nexg => null() ! number of gncs - integer(I4B), pointer :: numjs => null() ! number of connecting nodes - class(NumericalModelType), pointer :: m1 => null() ! pointer to model 1 - class(NumericalModelType), pointer :: m2 => null() ! pointer to model 2 - integer(I4B), dimension(:), pointer, contiguous :: nodem1 => null() ! array of nodes in model 1 - integer(I4B), dimension(:), pointer, contiguous :: nodem2 => null() ! array of nodes in model 2 - integer(I4B), dimension(:, :), pointer, contiguous :: nodesj => null() ! array of interpolation nodes - real(DP), dimension(:), pointer, contiguous :: cond => null() ! array of conductance - integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() ! connection position in amat - integer(I4B), dimension(:), pointer, contiguous :: idxsymglo => null() ! symmetric position in amat - real(DP), dimension(:, :), pointer, contiguous :: alphasj => null() ! interpolation factors - integer(I4B), dimension(:), pointer, contiguous :: idiagn => null() ! amat diagonal position of n - integer(I4B), dimension(:), pointer, contiguous :: idiagm => null() ! amat diagonal position of m - integer(I4B), dimension(:,:), pointer, contiguous :: jposinrown => null() ! amat j position in row n - integer(I4B), dimension(:,:), pointer, contiguous :: jposinrowm => null() ! amat j position in row m + logical, pointer :: smgnc => null() ! single model gnc + logical, pointer :: implicit => null() ! lhs or rhs + logical, pointer :: i2kn => null() ! not used + integer(I4B), pointer :: nexg => null() ! number of gncs + integer(I4B), pointer :: numjs => null() ! number of connecting nodes + class(NumericalModelType), pointer :: m1 => null() ! pointer to model 1 + class(NumericalModelType), pointer :: m2 => null() ! pointer to model 2 + integer(I4B), dimension(:), pointer, contiguous :: nodem1 => null() ! array of nodes in model 1 + integer(I4B), dimension(:), pointer, contiguous :: nodem2 => null() ! array of nodes in model 2 + integer(I4B), dimension(:, :), pointer, contiguous :: nodesj => null() ! array of interpolation nodes + real(DP), dimension(:), pointer, contiguous :: cond => null() ! array of conductance + integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() ! connection position in amat + integer(I4B), dimension(:), pointer, contiguous :: idxsymglo => null() ! symmetric position in amat + real(DP), dimension(:, :), pointer, contiguous :: alphasj => null() ! interpolation factors + integer(I4B), dimension(:), pointer, contiguous :: idiagn => null() ! amat diagonal position of n + integer(I4B), dimension(:), pointer, contiguous :: idiagm => null() ! amat diagonal position of m + integer(I4B), dimension(:, :), pointer, contiguous :: jposinrown => null() ! amat j position in row n + integer(I4B), dimension(:, :), pointer, contiguous :: jposinrowm => null() ! amat j position in row m contains - procedure :: gnc_df - procedure :: gnc_ac - procedure :: gnc_mc + procedure :: gnc_df + procedure :: gnc_ac + procedure :: gnc_mc procedure, private :: gnc_fmsav - procedure :: gnc_fc - procedure :: gnc_fn - procedure :: gnc_cq - procedure :: gnc_ot - procedure :: gnc_da - procedure :: deltaQgnc - procedure :: allocate_scalars + procedure :: gnc_fc + procedure :: gnc_fn + procedure :: gnc_cq + procedure :: gnc_ot + procedure :: gnc_da + procedure :: deltaQgnc + procedure :: allocate_scalars procedure, private :: allocate_arrays procedure, private :: read_options procedure, private :: read_dimensions @@ -50,7 +50,7 @@ module GhostNodeModule procedure, private :: nodeu_to_noder end type GhostNodeType - contains +contains subroutine gnc_cr(gncobj, name_parent, inunit, iout) ! ****************************************************************************** @@ -68,7 +68,7 @@ subroutine gnc_cr(gncobj, name_parent, inunit, iout) ! ------------------------------------------------------------------------------ ! ! -- Allocate the gnc exchange object - allocate(gncobj) + allocate (gncobj) ! ! -- create name and memory path. name_parent will either be model name or the ! exchange name. @@ -79,7 +79,7 @@ subroutine gnc_cr(gncobj, name_parent, inunit, iout) ! ! -- Set variables gncobj%inunit = inunit - gncobj%iout = iout + gncobj%iout = iout ! ! -- return return @@ -111,7 +111,7 @@ subroutine gnc_df(this, m1, m2) if (present(m2)) then this%m2 => m2 this%smgnc = .false. - endif + end if ! ! -- Initialize block parser call this%parser%Initialize(this%inunit, this%iout) @@ -129,14 +129,14 @@ subroutine gnc_df(this, m1, m2) call this%read_data() ! ! -- Trap for implicit gnc but models are in different solutions - if(this%m1%idsoln /= this%m2%idsoln) then - if(this%implicit) then - write(errmsg, '(a)') 'Error. GNC is implicit but models are in ' // & - 'different solutions.' + if (this%m1%idsoln /= this%m2%idsoln) then + if (this%implicit) then + write (errmsg, '(a)') 'Error. GNC is implicit but models are in '// & + 'different solutions.' call store_error(errmsg) call store_error_unit(this%inunit) - endif - endif + end if + end if ! ! -- return return @@ -162,21 +162,21 @@ subroutine gnc_ac(this, sparse) ! -- Expand the sparse matrix for ghost node connections. No need to add ! connection between n and m as they must be connected some other way ! that will calculate the conductance. - if(this%implicit) then + if (this%implicit) then do ignc = 1, this%nexg noden = this%nodem1(ignc) + this%m1%moffset nodem = this%nodem2(ignc) + this%m2%moffset jloop: do jidx = 1, this%numjs nodej = this%nodesj(jidx, ignc) - if(nodej == 0) cycle + if (nodej == 0) cycle nodej = nodej + this%m1%moffset call sparse%addconnection(nodem, nodej, 1) call sparse%addconnection(nodej, nodem, 1) call sparse%addconnection(noden, nodej, 1) call sparse%addconnection(nodej, noden, 1) - enddo jloop - enddo - endif + end do jloop + end do + end if ! ! -- return return @@ -205,8 +205,8 @@ subroutine gnc_mc(this, iasln, jasln) character(len=LINELENGTH) :: errmsg integer(I4B) :: noden, nodem, ipos, j, ignc, jidx, nodej ! -- formats - character(len=*),parameter :: fmterr = & - "('GHOST NODE ERROR. Cell ', i0, ' in model ', a, & + character(len=*), parameter :: fmterr = & + "('GHOST NODE ERROR. Cell ', i0, ' in model ', a, & &' is not connected to cell ', i0, ' in model ', a)" ! ------------------------------------------------------------------------------ ! @@ -228,78 +228,76 @@ subroutine gnc_mc(this, iasln, jasln) this%idxglo(ignc) = 0 searchloopnm: do ipos = iasln(noden) + 1, iasln(noden + 1) - 1 j = jasln(ipos) - if(j == nodem) then + if (j == nodem) then this%idxglo(ignc) = ipos exit searchloopnm - endif - enddo searchloopnm + end if + end do searchloopnm ! ! -- find location of n in row m of global solution and store in idxsymglo - !if(this%implicit) then - this%idxsymglo(ignc) = 0 - searchloopmn: do ipos = iasln(nodem), iasln(nodem + 1) - 1 - j = jasln(ipos) - if(j == noden) then - this%idxsymglo(ignc) = ipos - exit searchloopmn - endif - enddo searchloopmn - !endif + this%idxsymglo(ignc) = 0 + searchloopmn: do ipos = iasln(nodem), iasln(nodem + 1) - 1 + j = jasln(ipos) + if (j == noden) then + this%idxsymglo(ignc) = ipos + exit searchloopmn + end if + end do searchloopmn ! ! -- Check to make sure idxglo is non-zero - if(this%idxglo(ignc) == 0) then - write(errmsg, fmterr) this%nodem1(ignc), trim(this%m1%name), & - this%nodem2(ignc), trim(this%m2%name) + if (this%idxglo(ignc) == 0) then + write (errmsg, fmterr) this%nodem1(ignc), trim(this%m1%name), & + this%nodem2(ignc), trim(this%m2%name) call store_error(errmsg) - endif - ! - enddo + end if + ! + end do ! ! -- Stop if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call store_error_unit(this%inunit) - endif + end if ! ! -- find locations of j in rows n and row m of global solution - if(this%implicit) then + if (this%implicit) then do ignc = 1, this%nexg noden = this%nodem1(ignc) + this%m1%moffset nodem = this%nodem2(ignc) + this%m2%moffset ! do jidx = 1, this%numjs nodej = this%nodesj(jidx, ignc) - if(nodej > 0) nodej = nodej + this%m1%moffset + if (nodej > 0) nodej = nodej + this%m1%moffset ! ! -- search for nodej in row n, unless it is 0 - if(nodej == 0) then + if (nodej == 0) then ipos = 0 this%jposinrown(jidx, ignc) = ipos else searchloopn: do ipos = iasln(noden), iasln(noden + 1) - 1 j = jasln(ipos) - if(j == nodej) then + if (j == nodej) then this%jposinrown(jidx, ignc) = ipos exit searchloopn - endif - enddo searchloopn - endif + end if + end do searchloopn + end if ! ! -- search for nodej in row m - if(nodej == 0) then + if (nodej == 0) then ipos = 0 this%jposinrowm(jidx, ignc) = ipos else searchloopm: do ipos = iasln(nodem) + 1, iasln(nodem + 1) - 1 j = jasln(ipos) - if(j == nodej) then + if (j == nodej) then this%jposinrowm(jidx, ignc) = ipos exit searchloopm - endif - enddo searchloopm - endif - enddo - enddo - endif + end if + end do searchloopm + end if + end do + end do + end if ! ! -- return return @@ -328,13 +326,13 @@ subroutine gnc_fmsav(this, kiter, amatsln) ! nodem, and therefore the conductance is zero. gncloop: do ignc = 1, this%nexg ipos = this%idxglo(ignc) - if(ipos > 0) then + if (ipos > 0) then cond = amatsln(ipos) else cond = DZERO - endif + end if this%cond(ignc) = cond - enddo gncloop + end do gncloop ! ! -- return return @@ -362,24 +360,24 @@ subroutine gnc_fc(this, kiter, amatsln) ! ! -- If this is a single model gnc (not an exchange across models), then ! pull conductances out of amatsln and store them in this%cond - if(this%smgnc) call this%gnc_fmsav(kiter, amatsln) + if (this%smgnc) call this%gnc_fmsav(kiter, amatsln) ! ! -- Add gnc terms to rhs or to amat depending on whether gnc is implicit ! or explicit gncloop: do ignc = 1, this%nexg noden = this%nodem1(ignc) nodem = this%nodem2(ignc) - if(this%m1%ibound(noden) == 0 .or. & - this%m2%ibound(nodem) == 0) cycle gncloop + if (this%m1%ibound(noden) == 0 .or. & + this%m2%ibound(nodem) == 0) cycle gncloop ipos = this%idxglo(ignc) cond = this%cond(ignc) jloop: do jidx = 1, this%numjs j = this%nodesj(jidx, ignc) - if(j == 0) cycle + if (j == 0) cycle alpha = this%alphasj(jidx, ignc) if (alpha == DZERO) cycle aterm = alpha * cond - if(this%implicit) then + if (this%implicit) then iposjn = this%jposinrown(jidx, ignc) iposjm = this%jposinrowm(jidx, ignc) amatsln(this%idiagn(ignc)) = amatsln(this%idiagn(ignc)) + aterm @@ -390,16 +388,16 @@ subroutine gnc_fc(this, kiter, amatsln) rterm = aterm * (this%m1%x(noden) - this%m1%x(j)) this%m1%rhs(noden) = this%m1%rhs(noden) - rterm this%m2%rhs(nodem) = this%m2%rhs(nodem) + rterm - endif - enddo jloop - enddo gncloop + end if + end do jloop + end do gncloop ! ! -- return return end subroutine gnc_fc - subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & - ivarcv_opt, ictm1_opt, ictm2_opt) + subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & + ivarcv_opt, ictm1_opt, ictm2_opt) ! ****************************************************************************** ! gnc_fn -- Fill GNC Newton terms ! @@ -448,12 +446,12 @@ subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & gncloop: do ignc = 1, this%nexg noden = this%nodem1(ignc) nodem = this%nodem2(ignc) - if(this%m1%ibound(noden) == 0 .or. & - this%m2%ibound(nodem) == 0) cycle gncloop + if (this%m1%ibound(noden) == 0 .or. & + this%m2%ibound(nodem) == 0) cycle gncloop ! ! -- Assign variables depending on whether single model gnc or exchange ! gnc - if(this%smgnc) then + if (this%smgnc) then ipos = this%m1%dis%con%getjaindex(noden, nodem) isympos = this%m1%dis%con%jas(ipos) ihc = this%m1%dis%con%ihc(isympos) @@ -461,10 +459,10 @@ subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & else ihc = ihc_opt(ignc) csat = condsat(ignc) - endif + end if ! ! If vertical connection and not variable cv, then cycle - if(ihc == 0 .and. ivarcv == 0) cycle + if (ihc == 0 .and. ivarcv == 0) cycle ! ! determine upstream node (0 is noden, 1 is nodem) iups = 0 @@ -472,7 +470,7 @@ subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & ! ! -- Set the upstream top and bot, and then recalculate for a ! vertically staggered horizontal connection - if(iups == 0) then + if (iups == 0) then topup = this%m1%dis%top(noden) botup = this%m1%dis%bot(noden) ictup = 1 @@ -484,45 +482,45 @@ subroutine gnc_fn(this, kiter, njasln, amatsln, condsat, ihc_opt, & ictup = 1 if (present(ictm2_opt)) ictup = ictm2_opt(nodem) xup = this%m2%x(nodem) - endif + end if ! ! -- No newton terms if upstream cell is confined if (ictup == 0) cycle ! ! -- Handle vertically staggered horizontal connection - if(ihc == 2) then + if (ihc == 2) then topup = min(this%m1%dis%top(noden), this%m2%dis%top(nodem)) botup = max(this%m1%dis%bot(noden), this%m2%dis%bot(nodem)) - endif + end if ! ! -- Process each contributing node jloop: do jidx = 1, this%numjs nodej = this%nodesj(jidx, ignc) - if(nodej == 0) cycle - if(this%m1%ibound(nodej) == 0) cycle + if (nodej == 0) cycle + if (this%m1%ibound(nodej) == 0) cycle alpha = this%alphasj(jidx, ignc) if (alpha == DZERO) cycle consterm = csat * alpha * (this%m1%x(noden) - this%m1%x(nodej)) derv = sQuadraticSaturationDerivative(topup, botup, xup) term = consterm * derv - if(iups == 0) then + if (iups == 0) then amatsln(this%idiagn(ignc)) = amatsln(this%idiagn(ignc)) + term - if(this%m2%ibound(nodem) > 0) then - amatsln(this%idxsymglo(ignc)) = amatsln(this%idxsymglo(ignc)) - & + if (this%m2%ibound(nodem) > 0) then + amatsln(this%idxsymglo(ignc)) = amatsln(this%idxsymglo(ignc)) - & term - endif + end if this%m1%rhs(noden) = this%m1%rhs(noden) + term * this%m1%x(noden) this%m2%rhs(nodem) = this%m2%rhs(nodem) - term * this%m1%x(noden) else amatsln(this%idiagm(ignc)) = amatsln(this%idiagm(ignc)) - term - if(this%m1%ibound(noden) > 0) then + if (this%m1%ibound(noden) > 0) then amatsln(this%idxglo(ignc)) = amatsln(this%idxglo(ignc)) + term - endif + end if this%m1%rhs(noden) = this%m1%rhs(noden) + term * this%m2%x(nodem) this%m2%rhs(nodem) = this%m2%rhs(nodem) - term * this%m2%x(nodem) - endif - enddo jloop - enddo gncloop + end if + end do jloop + end do gncloop ! ! -- return return @@ -548,19 +546,19 @@ subroutine gnc_ot(this, ibudfl) ! ------------------------------------------------------------------------------ ! ! -- Process each gnc and output deltaQgnc - if(ibudfl /= 0 .and. this%iprflow /= 0) then - write(this%iout, '(//, a)') 'GHOST NODE CORRECTION RESULTS' - write(this%iout, '(3a10, 2a15)') 'GNC NUM', 'NODEN', 'NODEM', & + if (ibudfl /= 0 .and. this%iprflow /= 0) then + write (this%iout, '(//, a)') 'GHOST NODE CORRECTION RESULTS' + write (this%iout, '(3a10, 2a15)') 'GNC NUM', 'NODEN', 'NODEM', & 'DELTAQGNC', 'CONDNM' do ignc = 1, this%nexg deltaQgnc = this%deltaQgnc(ignc) call this%m1%dis%noder_to_string(this%nodem1(ignc), nodenstr) call this%m2%dis%noder_to_string(this%nodem2(ignc), nodemstr) - write(this%iout, fmtgnc) ignc, trim(adjustl(nodenstr)), & - trim(adjustl(nodemstr)), & - deltaQgnc, this%cond(ignc) - enddo - endif + write (this%iout, fmtgnc) ignc, trim(adjustl(nodenstr)), & + trim(adjustl(nodemstr)), & + deltaQgnc, this%cond(ignc) + end do + end if ! ! -- return return @@ -598,7 +596,7 @@ subroutine gnc_cq(this, flowja) flowja(ipos) = flowja(ipos) + deltaQgnc flowja(isympos) = flowja(isympos) - deltaQgnc ! - enddo + end do ! ! -- return return @@ -632,19 +630,19 @@ function deltaQgnc(this, ignc) nodem = this%nodem2(ignc) ! ! -- calculate deltaQgnc - if(this%m1%ibound(noden) /= 0 .and. this%m2%ibound(nodem) /= 0) then + if (this%m1%ibound(noden) /= 0 .and. this%m2%ibound(nodem) /= 0) then jloop: do jidx = 1, this%numjs nodej = this%nodesj(jidx, ignc) - if(nodej == 0) cycle jloop - if(this%m1%ibound(nodej) == 0) cycle jloop + if (nodej == 0) cycle jloop + if (this%m1%ibound(nodej) == 0) cycle jloop alpha = this%alphasj(jidx, ignc) sigalj = sigalj + alpha hd = hd + alpha * this%m1%x(nodej) - enddo jloop + end do jloop aterm = sigalj * this%m1%x(noden) - hd cond = this%cond(ignc) deltaQgnc = aterm * cond - endif + end if ! ! -- return return @@ -699,24 +697,24 @@ subroutine allocate_arrays(this) ! -- allocate memory for arrays call mem_allocate(this%nodem1, this%nexg, 'NODEM1', this%memoryPath) call mem_allocate(this%nodem2, this%nexg, 'NODEM2', this%memoryPath) - call mem_allocate(this%nodesj, this%numjs, this%nexg, 'NODESJ', & + call mem_allocate(this%nodesj, this%numjs, this%nexg, 'NODESJ', & this%memoryPath) - call mem_allocate(this%alphasj, this%numjs, this%nexg, 'ALPHASJ', & + call mem_allocate(this%alphasj, this%numjs, this%nexg, 'ALPHASJ', & this%memoryPath) call mem_allocate(this%cond, this%nexg, 'COND', this%memoryPath) call mem_allocate(this%idxglo, this%nexg, 'IDXGLO', this%memoryPath) call mem_allocate(this%idiagn, this%nexg, 'IDIAGN', this%memoryPath) call mem_allocate(this%idiagm, this%nexg, 'IDIAGM', this%memoryPath) call mem_allocate(this%idxsymglo, this%nexg, 'IDXSYMGLO', this%memoryPath) - if(this%implicit) then - call mem_allocate(this%jposinrown, this%numjs, this%nexg, 'JPOSINROWN', & + if (this%implicit) then + call mem_allocate(this%jposinrown, this%numjs, this%nexg, 'JPOSINROWN', & this%memoryPath) - call mem_allocate(this%jposinrowm, this%numjs, this%nexg, 'JPOSINROWM', & + call mem_allocate(this%jposinrowm, this%numjs, this%nexg, 'JPOSINROWM', & this%memoryPath) else call mem_allocate(this%jposinrown, 0, 0, 'JPOSINROWN', this%memoryPath) call mem_allocate(this%jposinrowm, 0, 0, 'JPOSINROWM', this%memoryPath) - endif + end if ! ! -- Return return @@ -754,7 +752,7 @@ subroutine gnc_da(this) call mem_deallocate(this%idxsymglo) call mem_deallocate(this%jposinrown) call mem_deallocate(this%jposinrowm) - endif + end if ! ! -- deallocate NumericalPackageType call this%NumericalPackageType%da() @@ -787,35 +785,35 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING GNC OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING GNC OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') & - 'THE LIST OF GHOST-NODE CORRECTIONS WILL BE PRINTED.' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') & - 'DELTAQGNC VALUES WILL BE PRINTED TO THE LIST FILE.' - case ('I2KN') - this%i2kn = .true. - write(this%iout,'(4x,a)') & - 'SECOND ORDER CORRECTION WILL BE APPLIED.' - case ('EXPLICIT') - this%implicit = .false. - write(this%iout,'(4x,a)')'GHOST NODE CORRECTION IS EXPLICIT.' - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN GNC OPTION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') & + 'THE LIST OF GHOST-NODE CORRECTIONS WILL BE PRINTED.' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') & + 'DELTAQGNC VALUES WILL BE PRINTED TO THE LIST FILE.' + case ('I2KN') + this%i2kn = .true. + write (this%iout, '(4x,a)') & + 'SECOND ORDER CORRECTION WILL BE APPLIED.' + case ('EXPLICIT') + this%implicit = .false. + write (this%iout, '(4x,a)') 'GHOST NODE CORRECTION IS EXPLICIT.' + case default + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN GNC OPTION: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF GNC OPTIONS' + write (this%iout, '(1x,a)') 'END OF GNC OPTIONS' end if ! ! -- Set the iasym flag if the correction is implicit @@ -849,26 +847,26 @@ subroutine read_dimensions(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING GNC DIMENSIONS' + write (this%iout, '(1x,a)') 'PROCESSING GNC DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('NUMGNC') - this%nexg = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NUMGNC = ', this%nexg - case ('NUMALPHAJ') - this%numjs = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NUMAPHAJ = ', this%numjs - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN GNC DIMENSION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('NUMGNC') + this%nexg = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'NUMGNC = ', this%nexg + case ('NUMALPHAJ') + this%numjs = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'NUMAPHAJ = ', this%numjs + case default + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN GNC DIMENSION: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF GNC DIMENSIONS' + write (this%iout, '(1x,a)') 'END OF GNC DIMENSIONS' else call store_error('Required DIMENSIONS block not found.', terminate=.TRUE.) end if @@ -892,7 +890,7 @@ subroutine read_data(this) ! -- local character(len=LINELENGTH) :: line, errmsg, nodestr, fmtgnc, cellid, & cellidm, cellidn - integer(I4B) :: lloc,ierr,ival + integer(I4B) :: lloc, ierr, ival integer(I4B) :: ignc, jidx, nodeun, nodeum, nerr integer(I4B), dimension(:), allocatable :: nodesuj logical :: isfound, endOfBlock @@ -900,19 +898,19 @@ subroutine read_data(this) ! ------------------------------------------------------------------------------ ! ! -- Construct the fmtgnc format - write(fmtgnc, '("(2i10,",i0,"i10,",i0, "(1pg15.6))")') this%numjs, & - this%numjs + write (fmtgnc, '("(2i10,",i0,"i10,",i0, "(1pg15.6))")') this%numjs, & + this%numjs ! ! -- Allocate the temporary nodesuj, which stores the user-based nodej ! node numbers - allocate(nodesuj(this%numjs)) + allocate (nodesuj(this%numjs)) ! ! -- get GNCDATA block call this%parser%GetBlock('GNCDATA', isfound, ierr, supportOpenClose=.true.) ! ! -- process GNC data if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING GNCDATA' + write (this%iout, '(1x,a)') 'PROCESSING GNCDATA' do ignc = 1, this%nexg call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -921,7 +919,7 @@ subroutine read_data(this) ! ! -- cellidn (read as cellid and convert to user node) call this%parser%GetCellid(this%m1%dis%ndim, cellidn) - nodeun = this%m1%dis%nodeu_from_cellid(cellidn, this%parser%iuactive, & + nodeun = this%m1%dis%nodeu_from_cellid(cellidn, this%parser%iuactive, & this%iout) ! ! -- convert user node to reduced node number @@ -929,87 +927,87 @@ subroutine read_data(this) ! ! -- cellidm (read as cellid and convert to user node) call this%parser%GetCellid(this%m2%dis%ndim, cellidm) - nodeum = this%m2%dis%nodeu_from_cellid(cellidm, this%parser%iuactive, & + nodeum = this%m2%dis%nodeu_from_cellid(cellidm, this%parser%iuactive, & this%iout) ! ! -- convert user node to reduced node number call this%nodeu_to_noder(nodeum, this%nodem2(ignc), this%m2) ! ! -- cellidsj (read as cellid) - do jidx=1, this%numjs + do jidx = 1, this%numjs ! read cellidj as cellid of model 1 call this%parser%GetCellid(this%m1%dis%ndim, cellid) - ival = this%m1%dis%nodeu_from_cellid(cellid, this%parser%iuactive, & + ival = this%m1%dis%nodeu_from_cellid(cellid, this%parser%iuactive, & this%iout, allow_zero=.true.) nodesuj(jidx) = ival - if(ival > 0) then + if (ival > 0) then call this%nodeu_to_noder(ival, this%nodesj(jidx, ignc), this%m1) else this%nodesj(jidx, ignc) = 0 - endif - enddo + end if + end do ! ! -- alphaj - do jidx=1, this%numjs + do jidx = 1, this%numjs this%alphasj(jidx, ignc) = this%parser%GetDouble() - enddo + end do ! ! -- Echo if requested - if(this%iprpak /= 0) & - write(this%iout, fmtgnc) nodeun, nodeum, & - (nodesuj(jidx), jidx = 1, this%numjs), & - (this%alphasj(jidx, ignc), jidx = 1, this%numjs) + if (this%iprpak /= 0) & + write (this%iout, fmtgnc) nodeun, nodeum, & + (nodesuj(jidx), jidx=1, this%numjs), & + (this%alphasj(jidx, ignc), jidx=1, this%numjs) ! ! -- Check to see if noden is outside of active domain - if(this%nodem1(ignc) <= 0) then + if (this%nodem1(ignc) <= 0) then call this%m1%dis%nodeu_to_string(nodeun, nodestr) - write(errmsg, *) & - trim(adjustl(this%m1%name)) // & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + trim(adjustl(this%m1%name))// & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif + end if ! ! -- Check to see if nodem is outside of active domain - if(this%nodem2(ignc) <= 0) then + if (this%nodem2(ignc) <= 0) then call this%m2%dis%nodeu_to_string(nodeum, nodestr) - write(errmsg, *) & - trim(adjustl(this%m2%name)) // & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + trim(adjustl(this%m2%name))// & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif + end if ! ! -- Check to see if any nodejs are outside of active domain do jidx = 1, this%numjs - if(this%nodesj(jidx, ignc) < 0) then + if (this%nodesj(jidx, ignc) < 0) then call this%m1%dis%nodeu_to_string(nodesuj(jidx), nodestr) - write(errmsg, *) & - trim(adjustl(this%m1%name)) // & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + trim(adjustl(this%m1%name))// & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif - enddo + end if + end do ! - enddo + end do ! ! -- Stop if errors nerr = count_errors() - if(nerr > 0) then + if (nerr > 0) then call store_error('Errors encountered in GNC input file.') call this%parser%StoreErrorUnit() - endif + end if ! - write(this%iout,'(1x,a)')'END OF GNCDATA' + write (this%iout, '(1x,a)') 'END OF GNCDATA' else - write(errmsg, '(1x,a)')'ERROR. REQUIRED GNCDATA BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED GNCDATA BLOCK NOT FOUND.' call store_error(errmsg) call this%parser%StoreErrorUnit() end if ! ! -- deallocate nodesuj array - deallocate(nodesuj) + deallocate (nodesuj) ! ! -- return return @@ -1034,18 +1032,17 @@ subroutine nodeu_to_noder(this, nodeu, noder, model) character(len=LINELENGTH) :: errmsg ! ------------------------------------------------------------------------------ ! - if(nodeu < 1 .or. nodeu > model%dis%nodesuser) then - write(errmsg, *) & - trim(adjustl(model%name)) // & - ' node number < 0 or > model nodes: ', nodeu + if (nodeu < 1 .or. nodeu > model%dis%nodesuser) then + write (errmsg, *) & + trim(adjustl(model%name))// & + ' node number < 0 or > model nodes: ', nodeu call store_error(errmsg) else noder = model%dis%get_nodenumber(nodeu, 0) - endif + end if ! ! -- Return return end subroutine nodeu_to_noder - end module GhostNodeModule diff --git a/src/Exchange/GwfGwfExchange.f90 b/src/Exchange/GwfGwfExchange.f90 index 5e2f48b68d2..2af258c19ab 100644 --- a/src/Exchange/GwfGwfExchange.f90 +++ b/src/Exchange/GwfGwfExchange.f90 @@ -9,25 +9,26 @@ !< module GwfGwfExchangeModule - use KindModule, only: DP, I4B, LGP - use SimVariablesModule, only: errmsg - use SimModule, only: store_error - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList - use ConstantsModule, only: LENBOUNDNAME, NAMEDBOUNDFLAG, LINELENGTH, & - TABCENTER, TABLEFT, LENAUXNAME, DNODATA - use ListModule, only: ListType - use ListsModule, only: basemodellist - use DisConnExchangeModule, only: DisConnExchangeType - use GwfModule, only: GwfModelType - use GhostNodeModule, only: GhostNodeType - use GwfMvrModule, only: GwfMvrType - use ObserveModule, only: ObserveType - use ObsModule, only: ObsType - use SimModule, only: count_errors, store_error, store_error_unit - use SimVariablesModule, only: errmsg - use BlockParserModule, only: BlockParserType - use TableModule, only: TableType, table_cr + use KindModule, only: DP, I4B, LGP + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList + use ConstantsModule, only: LENBOUNDNAME, NAMEDBOUNDFLAG, LINELENGTH, & + TABCENTER, TABLEFT, LENAUXNAME, DNODATA + use ListModule, only: ListType + use ListsModule, only: basemodellist, distmodellist + use DisConnExchangeModule, only: DisConnExchangeType + use GwfModule, only: GwfModelType + use DistributedModelModule, only: DistributedModelType, GetDistModelFromList + use GhostNodeModule, only: GhostNodeType + use GwfMvrModule, only: GwfMvrType + use ObserveModule, only: ObserveType + use ObsModule, only: ObsType + use SimModule, only: count_errors, store_error, store_error_unit + use SimVariablesModule, only: errmsg + use BlockParserModule, only: BlockParserType + use TableModule, only: TableType, table_cr implicit none @@ -37,78 +38,78 @@ module GwfGwfExchangeModule public :: GetGwfExchangeFromList public :: CastAsGwfExchange - !> @brief Derived type for GwfExchangeType + !> @brief Derived type for GwfExchangeType !! !! This derived type contains information and methods for !! connecting two GWF models. !! !< type, extends(DisConnExchangeType) :: GwfExchangeType - type(GwfModelType), pointer :: gwfmodel1 => null() !< pointer to GWF Model 1 - type(GwfModelType), pointer :: gwfmodel2 => null() !< pointer to GWF Model 2 - ! - ! -- GWF specific option block: - integer(I4B), pointer :: iprflow => null() !< print flag for cell by cell flows - integer(I4B), pointer :: ipakcb => null() !< save flag for cell by cell flows - integer(I4B), pointer :: inewton => null() !< newton flag (1 newton is on) - integer(I4B), pointer :: icellavg => null() !< cell averaging - integer(I4B), pointer :: ivarcv => null() !< variable cv - integer(I4B), pointer :: idewatcv => null() !< dewatered cv - integer(I4B), pointer :: ingnc => null() !< unit number for gnc (0 if off) - type(GhostNodeType), pointer :: gnc => null() !< gnc object - integer(I4B), pointer :: inmvr => null() !< unit number for mover (0 if off) - type(GwfMvrType), pointer :: mvr => null() !< water mover object - integer(I4B), pointer :: inobs => null() !< unit number for GWF-GWF observations - type(ObsType), pointer :: obs => null() !< observation object + type(GwfModelType), pointer :: gwfmodel1 => null() !< pointer to GWF Model 1 + type(GwfModelType), pointer :: gwfmodel2 => null() !< pointer to GWF Model 2 + ! + ! -- GWF specific option block: + integer(I4B), pointer :: iprflow => null() !< print flag for cell by cell flows + integer(I4B), pointer :: ipakcb => null() !< save flag for cell by cell flows + integer(I4B), pointer :: inewton => null() !< newton flag (1 newton is on) + integer(I4B), pointer :: icellavg => null() !< cell averaging + integer(I4B), pointer :: ivarcv => null() !< variable cv + integer(I4B), pointer :: idewatcv => null() !< dewatered cv + integer(I4B), pointer :: ingnc => null() !< unit number for gnc (0 if off) + type(GhostNodeType), pointer :: gnc => null() !< gnc object + integer(I4B), pointer :: inmvr => null() !< unit number for mover (0 if off) + type(GwfMvrType), pointer :: mvr => null() !< water mover object + integer(I4B), pointer :: inobs => null() !< unit number for GWF-GWF observations + type(ObsType), pointer :: obs => null() !< observation object ! ! -- internal data - real(DP), dimension(:), pointer, contiguous :: cond => null() !< conductance - real(DP), dimension(:), pointer, contiguous :: condsat => null() !< saturated conductance - integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() !< mapping to global (solution) amat - integer(I4B), dimension(:), pointer, contiguous :: idxsymglo => null() !< mapping to global (solution) symmetric amat - real(DP), pointer :: satomega => null() !< saturation smoothing - real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated flow rate for each exchange + real(DP), dimension(:), pointer, contiguous :: cond => null() !< conductance + real(DP), dimension(:), pointer, contiguous :: condsat => null() !< saturated conductance + integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() !< mapping to global (solution) amat + integer(I4B), dimension(:), pointer, contiguous :: idxsymglo => null() !< mapping to global (solution) symmetric amat + real(DP), pointer :: satomega => null() !< saturation smoothing + real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated flow rate for each exchange ! ! -- table objects type(TableType), pointer :: outputtab1 => null() - type(TableType), pointer :: outputtab2 => null() + type(TableType), pointer :: outputtab2 => null() contains - procedure :: exg_df => gwf_gwf_df - procedure :: exg_ac => gwf_gwf_ac - procedure :: exg_mc => gwf_gwf_mc - procedure :: exg_ar => gwf_gwf_ar - procedure :: exg_rp => gwf_gwf_rp - procedure :: exg_ad => gwf_gwf_ad - procedure :: exg_cf => gwf_gwf_cf - procedure :: exg_fc => gwf_gwf_fc - procedure :: exg_fn => gwf_gwf_fn - procedure :: exg_cq => gwf_gwf_cq - procedure :: exg_bd => gwf_gwf_bd - procedure :: exg_ot => gwf_gwf_ot - procedure :: exg_da => gwf_gwf_da - procedure :: exg_fp => gwf_gwf_fp - procedure :: get_iasym => gwf_gwf_get_iasym - procedure :: connects_model => gwf_gwf_connects_model - procedure :: use_interface_model - procedure :: allocate_scalars - procedure :: allocate_arrays - procedure :: read_options - procedure :: parse_option - procedure :: read_gnc - procedure :: read_mvr + procedure :: exg_df => gwf_gwf_df + procedure :: exg_ac => gwf_gwf_ac + procedure :: exg_mc => gwf_gwf_mc + procedure :: exg_ar => gwf_gwf_ar + procedure :: exg_rp => gwf_gwf_rp + procedure :: exg_ad => gwf_gwf_ad + procedure :: exg_cf => gwf_gwf_cf + procedure :: exg_fc => gwf_gwf_fc + procedure :: exg_fn => gwf_gwf_fn + procedure :: exg_cq => gwf_gwf_cq + procedure :: exg_bd => gwf_gwf_bd + procedure :: exg_ot => gwf_gwf_ot + procedure :: exg_da => gwf_gwf_da + procedure :: exg_fp => gwf_gwf_fp + procedure :: get_iasym => gwf_gwf_get_iasym + procedure :: connects_model => gwf_gwf_connects_model + procedure :: use_interface_model + procedure :: allocate_scalars + procedure :: allocate_arrays + procedure :: read_options + procedure :: parse_option + procedure :: read_gnc + procedure :: read_mvr procedure, private :: condcalc procedure, private :: rewet procedure, private :: qcalc - procedure :: gwf_gwf_bdsav + procedure :: gwf_gwf_bdsav procedure, private :: gwf_gwf_df_obs procedure, private :: gwf_gwf_rp_obs - procedure, public :: gwf_gwf_save_simvals + procedure, public :: gwf_gwf_save_simvals procedure, private :: gwf_gwf_calc_simvals - procedure, public :: gwf_gwf_set_spdis + procedure, public :: gwf_gwf_set_spdis procedure, private :: validate_exchange - procedure :: gwf_gwf_add_to_flowja + procedure :: gwf_gwf_add_to_flowja end type GwfExchangeType contains @@ -126,10 +127,10 @@ subroutine gwfexchange_create(filename, id, m1id, m2id) use ObsModule, only: obs_cr use MemoryHelperModule, only: create_mem_path ! -- dummy - character(len=*),intent(in) :: filename !< filename for reading - integer(I4B), intent(in) :: id !< id for the exchange - integer(I4B), intent(in) :: m1id !< id for model 1 - integer(I4B), intent(in) :: m2id !< id for model 2 + character(len=*), intent(in) :: filename !< filename for reading + integer(I4B), intent(in) :: id !< id for the exchange + integer(I4B), intent(in) :: m1id !< id for model 1 + integer(I4B), intent(in) :: m2id !< id for model 2 ! -- local type(GwfExchangeType), pointer :: exchange class(BaseModelType), pointer :: mb @@ -137,14 +138,14 @@ subroutine gwfexchange_create(filename, id, m1id, m2id) character(len=20) :: cint ! ! -- Create a new exchange and add it to the baseexchangelist container - allocate(exchange) + allocate (exchange) baseexchange => exchange call AddBaseExchangeToList(baseexchangelist, baseexchange) ! ! -- Assign id and name exchange%id = id - write(cint, '(i0)') id - exchange%name = 'GWF-GWF_' // trim(adjustl(cint)) + write (cint, '(i0)') id + exchange%name = 'GWF-GWF_'//trim(adjustl(cint)) exchange%memoryPath = create_mem_path(exchange%name) ! ! -- allocate scalars and set defaults @@ -153,12 +154,13 @@ subroutine gwfexchange_create(filename, id, m1id, m2id) exchange%typename = 'GWF-GWF' ! ! -- set gwfmodel1 - mb => GetBaseModelFromList(basemodellist, m1id) + mb => GetBaseModelFromList(basemodellist, m1id) select type (mb) type is (GwfModelType) exchange%model1 => mb exchange%gwfmodel1 => mb end select + exchange%dmodel1 => GetDistModelFromList(distmodellist, m1id) ! ! -- set gwfmodel2 mb => GetBaseModelFromList(basemodellist, m2id) @@ -167,10 +169,11 @@ subroutine gwfexchange_create(filename, id, m1id, m2id) exchange%model2 => mb exchange%gwfmodel2 => mb end select + exchange%dmodel2 => GetDistModelFromList(distmodellist, m2id) ! ! -- Verify that gwf model1 is of the correct type if (.not. associated(exchange%gwfmodel1)) then - write(errmsg, '(3a)') 'Problem with GWF-GWF exchange ', & + write (errmsg, '(3a)') 'Problem with GWF-GWF exchange ', & trim(exchange%name), & '. First specified GWF Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) @@ -178,7 +181,7 @@ subroutine gwfexchange_create(filename, id, m1id, m2id) ! ! -- Verify that gwf model2 is of the correct type if (.not. associated(exchange%gwfmodel2)) then - write(errmsg, '(3a)') 'Problem with GWF-GWF exchange ', & + write (errmsg, '(3a)') 'Problem with GWF-GWF exchange ', & trim(exchange%name), & '. Second specified GWF Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) @@ -202,25 +205,25 @@ subroutine gwf_gwf_df(this) use InputOutputModule, only: getunit, openfile use GhostNodeModule, only: gnc_cr ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: inunit ! ! -- open the file inunit = getunit() - write(iout,'(/a,a)') ' Creating exchange: ', this%name + write (iout, '(/a,a)') ' Creating exchange: ', this%name call openfile(inunit, iout, this%filename, 'GWF-GWF') ! call this%parser%Initialize(inunit, iout) ! ! -- Ensure models are in same solution - if(this%gwfmodel1%idsoln /= this%gwfmodel2%idsoln) then - call store_error('ERROR. TWO MODELS ARE CONNECTED ' // & - 'IN A GWF EXCHANGE BUT THEY ARE IN DIFFERENT SOLUTIONS. ' // & - 'GWF MODELS MUST BE IN SAME SOLUTION: ' // & - trim(this%gwfmodel1%name) // ' ' // trim(this%gwfmodel2%name) ) + if (this%gwfmodel1%idsoln /= this%gwfmodel2%idsoln) then + call store_error('ERROR. TWO MODELS ARE CONNECTED IN A GWF '// & + 'EXCHANGE BUT THEY ARE IN DIFFERENT SOLUTIONS. '// & + 'GWF MODELS MUST BE IN SAME SOLUTION: '// & + trim(this%gwfmodel1%name)//' '//trim(this%gwfmodel2%name)) call this%parser%StoreErrorUnit() - endif + end if ! ! -- read options call this%read_options(iout) @@ -239,22 +242,22 @@ subroutine gwf_gwf_df(this) call this%gwfmodel2%npf%increase_edge_count(this%nexg) ! ! -- Create and read ghost node information - if(this%ingnc > 0) then + if (this%ingnc > 0) then call gnc_cr(this%gnc, this%name, this%ingnc, iout) call this%read_gnc() - endif + end if ! ! -- Read mover information - if(this%inmvr > 0) then + if (this%inmvr > 0) then call this%read_mvr(iout) - endif + end if ! ! -- close the file - close(inunit) + close (inunit) ! ! -- Store obs call this%gwf_gwf_df_obs() - call this%obs%obs_df(iout, this%name, 'GWF-GWF', this%gwfmodel1%dis) + call this%obs%obs_df(iout, this%name, 'GWF-GWF', this%gwfmodel1%dis) ! ! -- validate call this%validate_exchange() @@ -266,15 +269,15 @@ end subroutine gwf_gwf_df !> @brief validate exchange data after reading !< subroutine validate_exchange(this) - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! local - + ! Periodic boundary condition in exchange don't allow XT3D (=interface model) if (associated(this%model1, this%model2)) then if (this%ixt3d > 0) then - write(errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & - ' is a periodic boundary condition which cannot'// & - ' be configured with XT3D' + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' is a periodic boundary condition which cannot'// & + ' be configured with XT3D' call store_error(errmsg, terminate=.TRUE.) end if end if @@ -282,43 +285,53 @@ subroutine validate_exchange(this) ! Check to see if horizontal anisotropy is in either model1 or model2. ! If so, then ANGLDEGX must be provided as an auxiliary variable for this ! GWF-GWF exchange (this%ianglex > 0). - if(this%gwfmodel1%npf%ik22 /= 0 .or. this%gwfmodel2%npf%ik22 /= 0) then - if(this%ianglex == 0) then - write(errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & - ' requires that ANGLDEGX be specified as an'// & - ' auxiliary variable because K22 was specified'// & - ' in one or both groundwater models.' + if (this%gwfmodel1%npf%ik22 /= 0 .or. this%gwfmodel2%npf%ik22 /= 0) then + if (this%ianglex == 0) then + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' requires that ANGLDEGX be specified as an'// & + ' auxiliary variable because K22 was specified'// & + ' in one or both groundwater models.' call store_error(errmsg, terminate=.TRUE.) - endif - endif - + end if + end if + ! Check to see if specific discharge is needed for model1 or model2. ! If so, then ANGLDEGX must be provided as an auxiliary variable for this ! GWF-GWF exchange (this%ianglex > 0). - if(this%gwfmodel1%npf%icalcspdis /= 0 .or. & - this%gwfmodel2%npf%icalcspdis /= 0) then - if(this%ianglex == 0) then - write(errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & - ' requires that ANGLDEGX be specified as an'// & - ' auxiliary variable because specific discharge'// & - ' is being calculated in one or both'// & - ' groundwater models.' + if (this%gwfmodel1%npf%icalcspdis /= 0 .or. & + this%gwfmodel2%npf%icalcspdis /= 0) then + if (this%ianglex == 0) then + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' requires that ANGLDEGX be specified as an'// & + ' auxiliary variable because specific discharge'// & + ' is being calculated in one or both'// & + ' groundwater models.' call store_error(errmsg, terminate=.TRUE.) - endif - if(this%icdist == 0) then - write(errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & - ' requires that CDIST be specified as an'// & - ' auxiliary variable because specific discharge'// & - ' is being calculated in one or both'// & - ' groundwater models.' + end if + if (this%icdist == 0) then + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' requires that CDIST be specified as an'// & + ' auxiliary variable because specific discharge'// & + ' is being calculated in one or both'// & + ' groundwater models.' call store_error(errmsg, terminate=.TRUE.) - endif - endif + end if + end if if (this%ixt3d > 0 .and. this%ianglex == 0) then - write(errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & - ' requires that ANGLDEGX be specified as an'// & - ' auxiliary variable because XT3D is enabled' + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' requires that ANGLDEGX be specified as an'// & + ' auxiliary variable because XT3D is enabled' + call store_error(errmsg, terminate=.TRUE.) + end if + + ! If viscosity is on in either model, then terminate with an + ! error as viscosity package doesn't work yet with exchanges. + if (this%gwfmodel1%npf%invsc /= 0 .or. & + this%gwfmodel2%npf%invsc /= 0) then + write (errmsg, '(3a)') 'GWF-GWF exchange ', trim(this%name), & + ' requires that the Viscosity Package is inactive'// & + ' in both of the connected models.' call store_error(errmsg, terminate=.TRUE.) end if @@ -331,9 +344,9 @@ end subroutine validate_exchange !< subroutine gwf_gwf_ac(this, sparse) ! -- modules - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType type(sparsematrix), intent(inout) :: sparse ! -- local integer(I4B) :: n, iglo, jglo @@ -344,12 +357,12 @@ subroutine gwf_gwf_ac(this, sparse) jglo = this%nodem2(n) + this%gwfmodel2%moffset call sparse%addconnection(iglo, jglo, 1) call sparse%addconnection(jglo, iglo, 1) - enddo + end do ! ! -- add gnc connections - if(this%ingnc > 0) then + if (this%ingnc > 0) then call this%gnc%gnc_ac(sparse) - endif + end if ! ! -- Return return @@ -362,9 +375,9 @@ end subroutine gwf_gwf_ac !< subroutine gwf_gwf_mc(this, iasln, jasln) ! -- modules - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), dimension(:), intent(in) :: iasln integer(I4B), dimension(:), intent(in) :: jasln ! -- local @@ -372,28 +385,28 @@ subroutine gwf_gwf_mc(this, iasln, jasln) ! ! -- map exchange connections do n = 1, this%nexg - iglo = this%nodem1(n)+this%gwfmodel1%moffset - jglo = this%nodem2(n)+this%gwfmodel2%moffset + iglo = this%nodem1(n) + this%gwfmodel1%moffset + jglo = this%nodem2(n) + this%gwfmodel2%moffset ! -- find jglobal value in row iglo and store in idxglo do ipos = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(ipos)) then + if (jglo == jasln(ipos)) then this%idxglo(n) = ipos exit - endif - enddo + end if + end do ! -- find and store symmetric location do ipos = iasln(jglo), iasln(jglo + 1) - 1 - if(iglo == jasln(ipos)) then + if (iglo == jasln(ipos)) then this%idxsymglo(n) = ipos exit - endif - enddo - enddo + end if + end do + end do ! ! -- map gnc connections - if(this%ingnc > 0) then + if (this%ingnc > 0) then call this%gnc%gnc_mc(iasln, jasln) - endif + end if ! ! -- Return return @@ -409,7 +422,7 @@ subroutine gwf_gwf_ar(this) use ConstantsModule, only: LINELENGTH, DZERO, DHALF, DONE, DPIO180 use GwfNpfModule, only: condmean, vcond, hcond ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: iexg integer(I4B) :: n, m, ihc @@ -423,7 +436,7 @@ subroutine gwf_gwf_ar(this) real(DP), dimension(3) :: vg ! ! -- If mover is active, then call ar routine - if(this%inmvr > 0) call this%mvr%mvr_ar() + if (this%inmvr > 0) call this%mvr%mvr_ar() ! ! -- Go through each connection and calculate the saturated conductance do iexg = 1, this%nexg @@ -441,7 +454,7 @@ subroutine gwf_gwf_ar(this) thickm = (topm - botm) * satm ! ! -- Calculate conductance depending on connection orientation - if(ihc == 0) then + if (ihc == 0) then ! ! -- Vertical conductance for fully saturated conditions vg(1) = DZERO @@ -449,13 +462,13 @@ subroutine gwf_gwf_ar(this) vg(3) = DONE hyn = this%gwfmodel1%npf%hy_eff(n, 0, ihc, vg=vg) hym = this%gwfmodel2%npf%hy_eff(m, 0, ihc, vg=vg) - csat = vcond(1, 1, 1, 1, 0, 1, 1, DONE, & - botn, botm, & - hyn, hym, & - satn, satm, & - topn, topm, & - botn, botm, & - this%hwva(iexg)) + csat = vcond(1, 1, 1, 1, 0, 1, 1, DONE, & + botn, botm, & + hyn, hym, & + satn, satm, & + topn, topm, & + botn, botm, & + this%hwva(iexg)) else ! ! -- Calculate horizontal conductance @@ -463,44 +476,43 @@ subroutine gwf_gwf_ar(this) hym = this%gwfmodel2%npf%k11(m) ! ! -- Check for anisotropy in models, and recalculate hyn and hym - if(this%ianglex > 0) then + if (this%ianglex > 0) then angle = this%auxvar(this%ianglex, iexg) * DPIO180 vg(1) = abs(cos(angle)) vg(2) = abs(sin(angle)) vg(3) = DZERO ! ! -- anisotropy in model 1 - if(this%gwfmodel1%npf%ik22 /= 0) then + if (this%gwfmodel1%npf%ik22 /= 0) then hyn = this%gwfmodel1%npf%hy_eff(n, 0, ihc, vg=vg) - endif + end if ! ! -- anisotropy in model 2 - if(this%gwfmodel2%npf%ik22 /= 0) then + if (this%gwfmodel2%npf%ik22 /= 0) then hym = this%gwfmodel2%npf%hy_eff(m, 0, ihc, vg=vg) - endif - endif + end if + end if ! fawidth = this%hwva(iexg) - csat = hcond(1, 1, 1, 1, this%inewton, 0, ihc, & - this%icellavg, 0, 0, DONE, & - topn, topm, satn, satm, hyn, hym, & - topn, topm, & - botn, botm, & - this%cl1(iexg), this%cl2(iexg), & - fawidth, this%satomega) - endif + csat = hcond(1, 1, 1, 1, this%inewton, 0, ihc, & + this%icellavg, 0, 0, DONE, & + topn, topm, satn, satm, hyn, hym, & + topn, topm, & + botn, botm, & + this%cl1(iexg), this%cl2(iexg), & + fawidth, this%satomega) + end if ! ! -- store csat in condsat this%condsat(iexg) = csat - enddo + end do ! ! -- Observation AR call this%obs%obs_ar() ! ! -- Return return - end subroutine gwf_gwf_ar - + end subroutine gwf_gwf_ar !> @ brief Read and prepare !! @@ -511,13 +523,13 @@ subroutine gwf_gwf_rp(this) ! -- modules use TdisModule, only: readnewdata ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! ! -- Check with TDIS on whether or not it is time to RP if (.not. readnewdata) return ! ! -- Read and prepare for mover - if(this%inmvr > 0) call this%mvr%mvr_rp() + if (this%inmvr > 0) call this%mvr%mvr_rp() ! ! -- Read and prepare for observations call this%gwf_gwf_rp_obs() @@ -534,11 +546,11 @@ end subroutine gwf_gwf_rp subroutine gwf_gwf_ad(this) ! -- modules ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local ! ! -- Advance mover - if(this%inmvr > 0) call this%mvr%mvr_ad() + if (this%inmvr > 0) call this%mvr%mvr_ad() ! ! -- Push simulated values to preceding time step call this%obs%obs_ad() @@ -554,7 +566,7 @@ end subroutine gwf_gwf_ad !< subroutine gwf_gwf_cf(this, kiter) ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: kiter ! -- local ! @@ -565,7 +577,7 @@ subroutine gwf_gwf_cf(this, kiter) ! -- Return return end subroutine gwf_gwf_cf - + !> @ brief Fill coefficients !! !! Calculate conductance and fill coefficient matrix @@ -576,11 +588,11 @@ subroutine gwf_gwf_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) use ConstantsModule, only: DHALF use GwfNpfModule, only: hcond, vcond ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: kiter integer(I4B), dimension(:), intent(in) :: iasln real(DP), dimension(:), intent(inout) :: amatsln - real(DP), dimension(:), intent(inout) ::rhssln + real(DP), dimension(:), intent(inout) :: rhssln integer(I4B), optional, intent(in) :: inwtflag ! -- local integer(I4B) :: inwt, iexg @@ -592,11 +604,11 @@ subroutine gwf_gwf_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) ! ! -- if gnc is active, then copy cond into gnc cond (might consider a ! pointer here in the future) - if(this%ingnc > 0) then + if (this%ingnc > 0) then do iexg = 1, this%nexg this%gnc%cond(iexg) = this%cond(iexg) - enddo - endif + end do + end if ! ! -- Put this%cond into amatsln do i = 1, this%nexg @@ -608,35 +620,35 @@ subroutine gwf_gwf_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) amatsln(idiagsln) = amatsln(idiagsln) - this%cond(i) idiagsln = iasln(nodem2sln) amatsln(idiagsln) = amatsln(idiagsln) - this%cond(i) - enddo + end do ! ! -- Fill the gnc terms in the solution matrix - if(this%ingnc > 0) then + if (this%ingnc > 0) then call this%gnc%gnc_fc(kiter, amatsln) - endif + end if ! ! -- Call mvr fc routine - if(this%inmvr > 0) call this%mvr%mvr_fc() + if (this%inmvr > 0) call this%mvr%mvr_fc() ! ! -- Set inwt to exchange newton, but shut off if requested by caller inwt = this%inewton - if(present(inwtflag)) then + if (present(inwtflag)) then if (inwtflag == 0) inwt = 0 - endif + end if if (inwt /= 0) then call this%exg_fn(kiter, iasln, amatsln) - endif + end if ! ! -- Ghost node Newton-Raphson if (this%ingnc > 0) then if (inwt /= 0) then njasln = size(amatsln) - call this%gnc%gnc_fn(kiter, njasln, amatsln, this%condsat, & - ihc_opt=this%ihc, ivarcv_opt=this%ivarcv, & - ictm1_opt=this%gwfmodel1%npf%icelltype, & - ictm2_opt=this%gwfmodel2%npf%icelltype) - endif - endif + call this%gnc%gnc_fn(kiter, njasln, amatsln, this%condsat, & + ihc_opt=this%ihc, ivarcv_opt=this%ivarcv, & + ictm1_opt=this%gwfmodel1%npf%icelltype, & + ictm2_opt=this%gwfmodel2%npf%icelltype) + end if + end if ! ! -- Return return @@ -651,7 +663,7 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) ! -- modules use SmoothingModule, only: sQuadraticSaturationDerivative ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: kiter integer(I4B), dimension(:), intent(in) :: iasln real(DP), dimension(:), intent(inout) :: amatsln @@ -685,15 +697,15 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) botm = this%gwfmodel2%dis%bot(m) hn = this%gwfmodel1%x(n) hm = this%gwfmodel2%x(m) - if(this%ihc(iexg) == 0) then + if (this%ihc(iexg) == 0) then ! -- vertical connection, newton not supported else ! -- determine upstream node nisup = .false. - if(hm < hn) nisup = .true. + if (hm < hn) nisup = .true. ! ! -- set upstream top and bot - if(nisup) then + if (nisup) then topup = topn botup = botn hup = hn @@ -703,7 +715,7 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) botup = botm hup = hm hdn = hn - endif + end if ! ! -- no newton terms if upstream cell is confined if (nisup) then @@ -713,10 +725,10 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) end if ! ! -- set topup and botup - if(this%ihc(iexg) == 2) then + if (this%ihc(iexg) == 2) then topup = min(topn, topm) botup = max(botn, botm) - endif + end if ! ! get saturated conductivity for derivative cond = this%condsat(iexg) @@ -728,16 +740,16 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) derv = sQuadraticSaturationDerivative(topup, botup, hup) idiagnsln = iasln(nodensln) idiagmsln = iasln(nodemsln) - if(nisup) then + if (nisup) then ! ! -- fill jacobian with n being upstream term = consterm * derv this%gwfmodel1%rhs(n) = this%gwfmodel1%rhs(n) + term * hn this%gwfmodel2%rhs(m) = this%gwfmodel2%rhs(m) - term * hn amatsln(idiagnsln) = amatsln(idiagnsln) + term - if(ibdm > 0) then + if (ibdm > 0) then amatsln(this%idxsymglo(iexg)) = amatsln(this%idxsymglo(iexg)) - term - endif + end if else ! ! -- fill jacobian with m being upstream @@ -745,12 +757,12 @@ subroutine gwf_gwf_fn(this, kiter, iasln, amatsln) this%gwfmodel1%rhs(n) = this%gwfmodel1%rhs(n) + term * hm this%gwfmodel2%rhs(m) = this%gwfmodel2%rhs(m) - term * hm amatsln(idiagmsln) = amatsln(idiagmsln) - term - if(ibdn > 0) then + if (ibdn > 0) then amatsln(this%idxglo(iexg)) = amatsln(this%idxglo(iexg)) + term - endif - endif - endif - enddo + end if + end if + end if + end do ! ! -- Return return @@ -765,14 +777,14 @@ end subroutine gwf_gwf_fn subroutine gwf_gwf_cq(this, icnvg, isuppress_output, isolnid) ! -- modules ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(inout) :: icnvg integer(I4B), intent(in) :: isuppress_output integer(I4B), intent(in) :: isolnid ! -- local ! ! -- calculate flow and store in simvals - call this%gwf_gwf_calc_simvals() + call this%gwf_gwf_calc_simvals() ! ! -- calculate specific discharge and set to model call this%gwf_gwf_set_spdis() @@ -788,7 +800,7 @@ end subroutine gwf_gwf_cq !< store them in a member array subroutine gwf_gwf_calc_simvals(this) use ConstantsModule, only: DZERO - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! local integer(I4B) :: i integer(I4B) :: n1, n2 @@ -801,22 +813,22 @@ subroutine gwf_gwf_calc_simvals(this) n2 = this%nodem2(i) ibdn1 = this%gwfmodel1%ibound(n1) ibdn2 = this%gwfmodel2%ibound(n2) - if(ibdn1 /= 0 .and. ibdn2 /= 0) then + if (ibdn1 /= 0 .and. ibdn2 /= 0) then rrate = this%qcalc(i, n1, n2) - if(this%ingnc > 0) then + if (this%ingnc > 0) then rrate = rrate + this%gnc%deltaqgnc(i) - endif - endif + end if + end if this%simvals(i) = rrate end do - + return end subroutine gwf_gwf_calc_simvals !> @brief Add exchange flow to each model flowja diagonal !< position so that residual is calculated correctly. subroutine gwf_gwf_add_to_flowja(this) - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! local integer(I4B) :: i integer(I4B) :: n @@ -824,19 +836,19 @@ subroutine gwf_gwf_add_to_flowja(this) real(DP) :: flow do i = 1, this%nexg - + flow = this%simvals(i) n = this%nodem1(i) idiag = this%gwfmodel1%ia(n) this%gwfmodel1%flowja(idiag) = this%gwfmodel1%flowja(idiag) + flow - + flow = -this%simvals(i) n = this%nodem2(i) idiag = this%gwfmodel2%ia(n) this%gwfmodel2%flowja(idiag) = this%gwfmodel2%flowja(idiag) + flow - + end do - + return end subroutine gwf_gwf_add_to_flowja @@ -845,7 +857,7 @@ end subroutine gwf_gwf_add_to_flowja subroutine gwf_gwf_set_spdis(this) use ConstantsModule, only: DZERO, DPIO180 use GwfNpfModule, only: thksatnm - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! local integer(I4B) :: iusg integer(I4B) :: i @@ -873,8 +885,8 @@ subroutine gwf_gwf_set_spdis(this) ! -- initialize iusg = 0 ! - ! -- Loop through all exchanges using the flow rate - ! stored in simvals + ! -- Loop through all exchanges using the flow rate + ! stored in simvals do i = 1, this%nexg rrate = this%simvals(i) n1 = this%nodem1(i) @@ -895,64 +907,64 @@ subroutine gwf_gwf_set_spdis(this) hn2 = this%gwfmodel2%x(n2) ! ! -- Calculate face normal components - if(ihc == 0) then + if (ihc == 0) then nx = DZERO ny = DZERO area = hwva if (botn1 < botn2) then ! -- n1 is beneath n2, so rate is positive downward. Flip rate ! upward so that points in positive z direction - rrate = - rrate - endif + rrate = -rrate + end if else - if(this%ianglex > 0) then + if (this%ianglex > 0) then angle = this%auxvar(this%ianglex, i) * DPIO180 nx = cos(angle) ny = sin(angle) else ! error? call store_error('error in gwf_gwf_cq', terminate=.TRUE.) - endif + end if ! ! -- Calculate the saturated thickness at interface between n1 and n2 - thksat = thksatnm(ibdn1, ibdn2, ictn1, ictn2, this%inewton, ihc, & - iusg, hn1, hn2, satn1, satn2, & + thksat = thksatnm(ibdn1, ibdn2, ictn1, ictn2, this%inewton, ihc, & + iusg, hn1, hn2, satn1, satn2, & topn1, topn2, botn1, botn2, this%satomega) area = hwva * thksat - endif + end if ! ! -- Submit this connection and flow information to the npf ! package of gwfmodel1 - if(this%icdist > 0) then + if (this%icdist > 0) then dltot = this%auxvar(this%icdist, i) else call store_error('error in gwf_gwf_cq', terminate=.TRUE.) - endif + end if distance = dltot * this%cl1(i) / (this%cl1(i) + this%cl2(i)) if (this%gwfmodel1%npf%icalcspdis == 1) then - call this%gwfmodel1%npf%set_edge_properties(n1, ihc, rrate, area, & + call this%gwfmodel1%npf%set_edge_properties(n1, ihc, rrate, area, & nx, ny, distance) - endif + end if ! ! -- Submit this connection and flow information to the npf ! package of gwfmodel2 - if(this%icdist > 0) then + if (this%icdist > 0) then dltot = this%auxvar(this%icdist, i) else call store_error('error in gwf_gwf_cq', terminate=.TRUE.) - endif + end if if (this%gwfmodel2%npf%icalcspdis == 1) then distance = dltot * this%cl2(i) / (this%cl1(i) + this%cl2(i)) if (ihc /= 0) rrate = -rrate - call this%gwfmodel2%npf%set_edge_properties(n2, ihc, rrate, area, & + call this%gwfmodel2%npf%set_edge_properties(n2, ihc, rrate, area, & -nx, -ny, distance) - endif + end if ! - enddo + end do ! return end subroutine gwf_gwf_set_spdis - + !> @ brief Budget !! !! Accumulate budget terms @@ -963,7 +975,7 @@ subroutine gwf_gwf_bd(this, icnvg, isuppress_output, isolnid) use ConstantsModule, only: DZERO, LENBUDTXT, LENPACKAGENAME use BudgetModule, only: rate_accumulator ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(inout) :: icnvg integer(I4B), intent(in) :: isuppress_output integer(I4B), intent(in) :: isolnid @@ -990,12 +1002,12 @@ subroutine gwf_gwf_bd(this, icnvg, isuppress_output, isolnid) call this%gwfmodel2%model_bdentry(budterm, budtxt, this%name) ! ! -- Call mvr bd routine - if(this%inmvr > 0) call this%mvr%mvr_bd() + if (this%inmvr > 0) call this%mvr%mvr_bd() ! ! -- return return end subroutine gwf_gwf_bd - + !> @ brief Budget save !! !! Output individual flows to listing file and binary budget files @@ -1006,11 +1018,11 @@ subroutine gwf_gwf_bdsav(this) use ConstantsModule, only: DZERO, LENBUDTXT, LENPACKAGENAME use TdisModule, only: kstp, kper ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local character(len=LENBOUNDNAME) :: bname - character(len=LENPACKAGENAME+4) :: packname1 - character(len=LENPACKAGENAME+4) :: packname2 + character(len=LENPACKAGENAME + 4) :: packname1 + character(len=LENPACKAGENAME + 4) :: packname2 character(len=LENBUDTXT), dimension(1) :: budtxt character(len=20) :: nodestr integer(I4B) :: ntabrows @@ -1037,7 +1049,7 @@ subroutine gwf_gwf_bdsav(this) if (this%gwfmodel1%oc%oc_save('BUDGET')) then call this%outputtab1%set_title(packname1) end if - if (this%gwfmodel2%oc%oc_save('BUDGET')) then + if (this%gwfmodel2%oc%oc_save('BUDGET')) then call this%outputtab2%set_title(packname2) end if ! @@ -1052,7 +1064,7 @@ subroutine gwf_gwf_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if (this%gwfmodel1%ibound(n1) /= 0 .and. & + if (this%gwfmodel1%ibound(n1) /= 0 .and. & this%gwfmodel2%ibound(n2) /= 0) then ntabrows = ntabrows + 1 end if @@ -1066,27 +1078,30 @@ subroutine gwf_gwf_bdsav(this) ! -- Print and write budget terms for model 1 ! ! -- Set binary unit numbers for saving flows - if(this%ipakcb /= 0) then + if (this%ipakcb /= 0) then ibinun1 = this%gwfmodel1%oc%oc_save_unit('BUDGET') else ibinun1 = 0 - endif + end if ! ! -- If save budget flag is zero for this stress period, then ! shut off saving - if(.not. this%gwfmodel1%oc%oc_save('BUDGET')) ibinun1 = 0 - if(isuppress_output /= 0) then + if (.not. this%gwfmodel1%oc%oc_save('BUDGET')) ibinun1 = 0 + if (isuppress_output /= 0) then ibinun1 = 0 - endif + end if ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun1 /= 0) then - call this%gwfmodel1%dis%record_srcdst_list_header(budtxt(1), & - this%gwfmodel1%name, this%name, & - this%gwfmodel2%name, this%name, & - this%naux, this%auxname, & - ibinun1, this%nexg, this%gwfmodel1%iout) - endif + if (ibinun1 /= 0) then + call this%gwfmodel1%dis%record_srcdst_list_header(budtxt(1), & + this%gwfmodel1%name, & + this%name, & + this%gwfmodel2%name, & + this%name, & + this%naux, this%auxname, & + ibinun1, this%nexg, & + this%gwfmodel1%iout) + end if ! ! Initialize accumulators ratin = DZERO @@ -1096,11 +1111,11 @@ subroutine gwf_gwf_bdsav(this) do i = 1, this%nexg ! ! -- Assign boundary name - if (this%inamedbound>0) then + if (this%inamedbound > 0) then bname = this%boundname(i) else bname = '' - endif + end if ! ! -- Calculate the flow rate between n1 and n2 rrate = DZERO @@ -1108,62 +1123,65 @@ subroutine gwf_gwf_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if(this%gwfmodel1%ibound(n1) /= 0 .and. & + if (this%gwfmodel1%ibound(n1) /= 0 .and. & this%gwfmodel2%ibound(n2) /= 0) then rrate = this%simvals(i) ! ! -- Print the individual rates to model list files if requested - if(this%iprflow /= 0) then - if(this%gwfmodel1%oc%oc_save('BUDGET')) then + if (this%iprflow /= 0) then + if (this%gwfmodel1%oc%oc_save('BUDGET')) then ! ! -- set nodestr and write outputtab table nodeu = this%gwfmodel1%dis%get_nodeuser(n1) call this%gwfmodel1%dis%nodeu_to_string(nodeu, nodestr) - call this%outputtab1%print_list_entry(i, trim(adjustl(nodestr)), & + call this%outputtab1%print_list_entry(i, trim(adjustl(nodestr)), & rrate, bname) end if - endif - if(rrate < DZERO) then + end if + if (rrate < DZERO) then ratout = ratout - rrate else ratin = ratin + rrate - endif - endif + end if + end if ! ! -- If saving cell-by-cell flows in list, write flow n1u = this%gwfmodel1%dis%get_nodeuser(n1) n2u = this%gwfmodel2%dis%get_nodeuser(n2) - if(ibinun1 /= 0) & - call this%gwfmodel1%dis%record_mf6_list_entry( & - ibinun1, n1u, n2u, rrate, this%naux, this%auxvar(:, i), & - .false., .false.) + if (ibinun1 /= 0) & + call this%gwfmodel1%dis%record_mf6_list_entry( & + ibinun1, n1u, n2u, rrate, this%naux, this%auxvar(:, i), & + .false., .false.) ! - enddo + end do ! ! -- Print and write budget terms for model 2 ! ! -- Set binary unit numbers for saving flows - if(this%ipakcb /= 0) then + if (this%ipakcb /= 0) then ibinun2 = this%gwfmodel2%oc%oc_save_unit('BUDGET') else ibinun2 = 0 - endif + end if ! ! -- If save budget flag is zero for this stress period, then ! shut off saving - if(.not. this%gwfmodel2%oc%oc_save('BUDGET')) ibinun2 = 0 - if(isuppress_output /= 0) then + if (.not. this%gwfmodel2%oc%oc_save('BUDGET')) ibinun2 = 0 + if (isuppress_output /= 0) then ibinun2 = 0 - endif + end if ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun2 /= 0) then - call this%gwfmodel2%dis%record_srcdst_list_header(budtxt(1), & - this%gwfmodel2%name, this%name, & - this%gwfmodel1%name, this%name, & - this%naux, this%auxname, & - ibinun2, this%nexg, this%gwfmodel2%iout) - endif + if (ibinun2 /= 0) then + call this%gwfmodel2%dis%record_srcdst_list_header(budtxt(1), & + this%gwfmodel2%name, & + this%name, & + this%gwfmodel1%name, & + this%name, & + this%naux, this%auxname, & + ibinun2, this%nexg, & + this%gwfmodel2%iout) + end if ! ! Initialize accumulators ratin = DZERO @@ -1173,11 +1191,11 @@ subroutine gwf_gwf_bdsav(this) do i = 1, this%nexg ! ! -- Assign boundary name - if (this%inamedbound>0) then + if (this%inamedbound > 0) then bname = this%boundname(i) else bname = '' - endif + end if ! ! -- Calculate the flow rate between n1 and n2 rrate = DZERO @@ -1185,37 +1203,37 @@ subroutine gwf_gwf_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if(this%gwfmodel1%ibound(n1) /= 0 .and. & + if (this%gwfmodel1%ibound(n1) /= 0 .and. & this%gwfmodel2%ibound(n2) /= 0) then rrate = this%simvals(i) ! ! -- Print the individual rates to model list files if requested - if(this%iprflow /= 0) then - if(this%gwfmodel2%oc%oc_save('BUDGET')) then + if (this%iprflow /= 0) then + if (this%gwfmodel2%oc%oc_save('BUDGET')) then ! ! -- set nodestr and write outputtab table nodeu = this%gwfmodel2%dis%get_nodeuser(n2) call this%gwfmodel2%dis%nodeu_to_string(nodeu, nodestr) - call this%outputtab2%print_list_entry(i, trim(adjustl(nodestr)), & + call this%outputtab2%print_list_entry(i, trim(adjustl(nodestr)), & -rrate, bname) end if - endif - if(rrate < DZERO) then + end if + if (rrate < DZERO) then ratout = ratout - rrate else ratin = ratin + rrate - endif - endif + end if + end if ! ! -- If saving cell-by-cell flows in list, write flow n1u = this%gwfmodel1%dis%get_nodeuser(n1) n2u = this%gwfmodel2%dis%get_nodeuser(n2) - if(ibinun2 /= 0) & - call this%gwfmodel2%dis%record_mf6_list_entry( & - ibinun2, n2u, n1u, -rrate, this%naux, this%auxvar(:, i), & - .false., .false.) + if (ibinun2 /= 0) & + call this%gwfmodel2%dis%record_mf6_list_entry( & + ibinun2, n2u, n1u, -rrate, this%naux, this%auxvar(:, i), & + .false., .false.) ! - enddo + end do ! ! -- Set icbcfl, ibudfl to zero so that flows will be printed and ! saved, if the options were set in the MVR package @@ -1223,17 +1241,17 @@ subroutine gwf_gwf_bdsav(this) ibudfl = 1 ! ! -- Call mvr bd routine - if(this%inmvr > 0) call this%mvr%mvr_bdsav(icbcfl, ibudfl, isuppress_output) + if (this%inmvr > 0) call this%mvr%mvr_bdsav(icbcfl, ibudfl, isuppress_output) ! ! -- Calculate and write simulated values for observations - if(this%inobs /= 0) then + if (this%inobs /= 0) then call this%gwf_gwf_save_simvals() - endif + end if ! ! -- return return end subroutine gwf_gwf_bdsav - + !> @ brief Output !! !! Write output @@ -1244,21 +1262,21 @@ subroutine gwf_gwf_ot(this) use SimVariablesModule, only: iout use ConstantsModule, only: DZERO, LINELENGTH ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: iexg, n1, n2 integer(I4B) :: ibudfl real(DP) :: flow, deltaqgnc character(len=LINELENGTH) :: node1str, node2str ! -- format - character(len=*), parameter :: fmtheader = & - "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & + character(len=*), parameter :: fmtheader = & + "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & &2a16, 5a16, /, 112('-'))" - character(len=*), parameter :: fmtheader2 = & - "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & + character(len=*), parameter :: fmtheader2 = & + "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & &2a16, 4a16, /, 96('-'))" - character(len=*), parameter :: fmtdata = & - "(2a16, 5(1pg16.6))" + character(len=*), parameter :: fmtdata = & + "(2a16, 5(1pg16.6))" ! ! -- Call bdsave call this%gwf_gwf_bdsav() @@ -1267,39 +1285,39 @@ subroutine gwf_gwf_ot(this) deltaqgnc = DZERO ! ! -- Write a table of exchanges - if(this%iprflow /= 0) then - if(this%ingnc > 0) then - write(iout, fmtheader) trim(adjustl(this%name)), this%id, 'NODEM1', & - 'NODEM2', 'COND', 'X_M1', 'X_M2', 'DELTAQGNC', & - 'FLOW' + if (this%iprflow /= 0) then + if (this%ingnc > 0) then + write (iout, fmtheader) trim(adjustl(this%name)), this%id, 'NODEM1', & + 'NODEM2', 'COND', 'X_M1', 'X_M2', 'DELTAQGNC', & + 'FLOW' else - write(iout, fmtheader2) trim(adjustl(this%name)), this%id, 'NODEM1', & - 'NODEM2', 'COND', 'X_M1', 'X_M2', 'FLOW' - endif + write (iout, fmtheader2) trim(adjustl(this%name)), this%id, 'NODEM1', & + 'NODEM2', 'COND', 'X_M1', 'X_M2', 'FLOW' + end if do iexg = 1, this%nexg n1 = this%nodem1(iexg) n2 = this%nodem2(iexg) flow = this%simvals(iexg) call this%gwfmodel1%dis%noder_to_string(n1, node1str) call this%gwfmodel2%dis%noder_to_string(n2, node2str) - if(this%ingnc > 0) then + if (this%ingnc > 0) then deltaqgnc = this%gnc%deltaqgnc(iexg) - write(iout, fmtdata) trim(adjustl(node1str)), & - trim(adjustl(node2str)), & - this%cond(iexg), this%gwfmodel1%x(n1), & - this%gwfmodel2%x(n2), deltaqgnc, flow + write (iout, fmtdata) trim(adjustl(node1str)), & + trim(adjustl(node2str)), & + this%cond(iexg), this%gwfmodel1%x(n1), & + this%gwfmodel2%x(n2), deltaqgnc, flow else - write(iout, fmtdata) trim(adjustl(node1str)), & - trim(adjustl(node2str)), & - this%cond(iexg), this%gwfmodel1%x(n1), & - this%gwfmodel2%x(n2), flow - endif - enddo - endif + write (iout, fmtdata) trim(adjustl(node1str)), & + trim(adjustl(node2str)), & + this%cond(iexg), this%gwfmodel1%x(n1), & + this%gwfmodel2%x(n2), flow + end if + end do + end if ! ! -- Mover budget output ibudfl = 1 - if(this%inmvr > 0) call this%mvr%mvr_ot_bdsummary(ibudfl) + if (this%inmvr > 0) call this%mvr%mvr_ot_bdsummary(ibudfl) ! ! -- OBS output call this%obs%obs_ot() @@ -1316,24 +1334,24 @@ end subroutine gwf_gwf_ot subroutine read_options(this, iout) ! -- modules use ConstantsModule, only: LINELENGTH, LENAUXNAME, DEM6 - use MemoryManagerModule, only: mem_allocate + use MemoryManagerModule, only: mem_allocate use SimModule, only: store_error, store_error_unit ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: iout ! -- local character(len=LINELENGTH) :: keyword logical :: isfound - logical :: endOfBlock + logical :: endOfBlock integer(I4B) :: ierr ! ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + call this%parser%GetBlock('OPTIONS', isfound, ierr, & + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING GWF-GWF EXCHANGE OPTIONS' + write (iout, '(1x,a)') 'PROCESSING GWF-GWF EXCHANGE OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) then @@ -1352,12 +1370,12 @@ subroutine read_options(this, iout) end if ! unknown option - errmsg = "Unknown GWF-GWF exchange option '" // trim(keyword) // "'." + errmsg = "Unknown GWF-GWF exchange option '"//trim(keyword)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() end do - write(iout,'(1x,a)') 'END OF GWF-GWF EXCHANGE OPTIONS' + write (iout, '(1x,a)') 'END OF GWF-GWF EXCHANGE OPTIONS' end if ! ! -- set omega value used for saturation calculations @@ -1373,11 +1391,11 @@ end subroutine read_options !< function parse_option(this, keyword, iout) result(parsed) use InputOutputModule, only: getunit, openfile - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType character(len=LINELENGTH), intent(in) :: keyword !< the option name - integer(I4B), intent(in) :: iout !< for logging - logical(LGP) :: parsed !< true when parsed - ! local + integer(I4B), intent(in) :: iout !< for logging + logical(LGP) :: parsed !< true when parsed + ! local character(len=LINELENGTH) :: fname integer(I4B) :: inobs character(len=LINELENGTH) :: subkey @@ -1387,80 +1405,80 @@ function parse_option(this, keyword, iout) result(parsed) select case (keyword) case ('PRINT_FLOWS') this%iprflow = 1 - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'EXCHANGE FLOWS WILL BE PRINTED TO LIST FILES.' case ('SAVE_FLOWS') this%ipakcb = -1 - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'EXCHANGE FLOWS WILL BE SAVED TO BINARY BUDGET FILES.' case ('ALTERNATIVE_CELL_AVERAGING') call this%parser%GetStringCaps(subkey) - select case(subkey) - case('LOGARITHMIC') + select case (subkey) + case ('LOGARITHMIC') this%icellavg = 1 - case('AMT-LMK') + case ('AMT-LMK') this%icellavg = 2 case default - errmsg = "Unknown cell averaging method '" // trim(subkey) // "'." + errmsg = "Unknown cell averaging method '"//trim(subkey)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() end select - write(iout,'(4x,a,a)') & + write (iout, '(4x,a,a)') & 'CELL AVERAGING METHOD HAS BEEN SET TO: ', trim(subkey) case ('VARIABLECV') this%ivarcv = 1 - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'VERTICAL CONDUCTANCE VARIES WITH WATER TABLE.' call this%parser%GetStringCaps(subkey) - if(subkey == 'DEWATERED') then + if (subkey == 'DEWATERED') then this%idewatcv = 1 - write(iout,'(4x,a)') & - 'VERTICAL CONDUCTANCE ACCOUNTS FOR DEWATERED PORTION OF ' // & + write (iout, '(4x,a)') & + 'VERTICAL CONDUCTANCE ACCOUNTS FOR DEWATERED PORTION OF '// & 'AN UNDERLYING CELL.' - endif + end if case ('NEWTON') this%inewton = 1 - write(iout, '(4x,a)') & - 'NEWTON-RAPHSON method used for unconfined cells' + write (iout, '(4x,a)') & + 'NEWTON-RAPHSON method used for unconfined cells' case ('GNC6') call this%parser%GetStringCaps(subkey) - if(subkey /= 'FILEIN') then - call store_error('GNC6 KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') + if (subkey /= 'FILEIN') then + call store_error('GNC6 KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetString(fname) - if(fname == '') then + if (fname == '') then call store_error('NO GNC6 FILE SPECIFIED.') call this%parser%StoreErrorUnit() - endif + end if this%ingnc = getunit() call openfile(this%ingnc, iout, fname, 'GNC') - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'GHOST NODES WILL BE READ FROM ', trim(fname) case ('MVR6') call this%parser%GetStringCaps(subkey) - if(subkey /= 'FILEIN') then - call store_error('MVR6 KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') + if (subkey /= 'FILEIN') then + call store_error('MVR6 KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetString(fname) - if(fname == '') then + if (fname == '') then call store_error('NO MVR6 FILE SPECIFIED.') call this%parser%StoreErrorUnit() - endif + end if this%inmvr = getunit() call openfile(this%inmvr, iout, fname, 'MVR') - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'WATER MOVER INFORMATION WILL BE READ FROM ', trim(fname) case ('OBS6') call this%parser%GetStringCaps(subkey) - if(subkey /= 'FILEIN') then - call store_error('OBS8 KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') + if (subkey /= 'FILEIN') then + call store_error('OBS8 KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') call this%parser%StoreErrorUnit() - endif + end if this%obs%active = .true. call this%parser%GetString(this%obs%inputFilename) inobs = GetUnit() @@ -1471,10 +1489,10 @@ function parse_option(this, keyword, iout) result(parsed) end select end function parse_option - + !> @ brief Read ghost nodes !! - !! Read and process ghost nodes + !! Read and process ghost nodes !! !< subroutine read_gnc(this) @@ -1482,54 +1500,55 @@ subroutine read_gnc(this) use SimModule, only: store_error, store_error_unit, count_errors use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: i, nm1, nm2, nmgnc1, nmgnc2 character(len=*), parameter :: fmterr = & - "('EXCHANGE NODES ', i0, ' AND ', i0," // & - "' NOT CONSISTENT WITH GNC NODES ', i0, ' AND ', i0)" + "('EXCHANGE NODES ', i0, ' AND ', i0,"// & + "' NOT CONSISTENT WITH GNC NODES ', "// & + "i0, ' AND ', i0)" ! ! -- If exchange has ghost nodes, then initialize ghost node object ! This will read the ghost node blocks from the gnc input file. call this%gnc%gnc_df(this%gwfmodel1, m2=this%gwfmodel2) ! ! -- Verify gnc is implicit if exchange has Newton Terms - if(.not. this%gnc%implicit .and. this%inewton /= 0) then + if (.not. this%gnc%implicit .and. this%inewton /= 0) then call store_error('GNC IS EXPLICIT, BUT GWF EXCHANGE HAS ACTIVE NEWTON.') - call store_error('ADD IMPLICIT OPTION TO GNC OR REMOVE NEWTON FROM ' // & - 'GWF EXCHANGE.') + call store_error('ADD IMPLICIT OPTION TO GNC OR REMOVE NEWTON FROM '// & + 'GWF EXCHANGE.') call store_error_unit(this%ingnc) - endif + end if ! ! -- Perform checks to ensure GNCs match with GWF-GWF nodes - if(this%nexg /= this%gnc%nexg) then + if (this%nexg /= this%gnc%nexg) then call store_error('NUMBER OF EXCHANGES DOES NOT MATCH NUMBER OF GNCs') call store_error_unit(this%ingnc) - endif + end if ! ! -- Go through each entry and confirm do i = 1, this%nexg - if(this%nodem1(i) /= this%gnc%nodem1(i) .or. & - this%nodem2(i) /= this%gnc%nodem2(i) ) then + if (this%nodem1(i) /= this%gnc%nodem1(i) .or. & + this%nodem2(i) /= this%gnc%nodem2(i)) then nm1 = this%gwfmodel1%dis%get_nodeuser(this%nodem1(i)) nm2 = this%gwfmodel2%dis%get_nodeuser(this%nodem2(i)) nmgnc1 = this%gwfmodel1%dis%get_nodeuser(this%gnc%nodem1(i)) nmgnc2 = this%gwfmodel2%dis%get_nodeuser(this%gnc%nodem2(i)) - write(errmsg, fmterr) nm1, nm2, nmgnc1, nmgnc2 + write (errmsg, fmterr) nm1, nm2, nmgnc1, nmgnc2 call store_error(errmsg) - endif - enddo - if(count_errors() > 0) then + end if + end do + if (count_errors() > 0) then call store_error_unit(this%ingnc) - endif + end if ! ! -- close the file - close(this%ingnc) + close (this%ingnc) ! ! -- return return end subroutine read_gnc - + !> @ brief Read mover !! !! Read and process movers @@ -1539,23 +1558,23 @@ subroutine read_mvr(this, iout) ! -- modules use GwfMvrModule, only: mvr_cr ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: iout ! -- local ! ! -- Create and initialize the mover object Here, dis is set to the one ! for gwfmodel1 so that a call to save flows has an associated dis ! object. Because the conversion flags for the mover are both false, - ! the dis object does not convert from reduced to user node numbers. + ! the dis object does not convert from reduced to user node numbers. ! So in this case, the dis object is just writing unconverted package ! numbers to the binary budget file. - call mvr_cr(this%mvr, this%name, this%inmvr, iout, this%gwfmodel1%dis, & + call mvr_cr(this%mvr, this%name, this%inmvr, iout, this%gwfmodel1%dis, & iexgmvr=1) ! ! -- Return return end subroutine read_mvr - + !> @ brief Rewet !! !! Check if rewetting should propagate from one model to another @@ -1565,7 +1584,7 @@ subroutine rewet(this, kiter) ! -- modules use TdisModule, only: kper, kstp ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: kiter ! -- local integer(I4B) :: iexg @@ -1575,8 +1594,8 @@ subroutine rewet(this, kiter) real(DP) :: hn, hm integer(I4B) :: irewet character(len=30) :: nodestrn, nodestrm - character(len=*),parameter :: fmtrwt = & - "(1x, 'CELL ',A,' REWET FROM GWF MODEL ',A,' CELL ',A, & + character(len=*), parameter :: fmtrwt = & + "(1x, 'CELL ',A,' REWET FROM GWF MODEL ',A,' CELL ',A, & &' FOR ITER. ',I0, ' STEP ',I0, ' PERIOD ', I0)" ! ! -- Use model 1 to rewet model 2 and vice versa @@ -1588,29 +1607,29 @@ subroutine rewet(this, kiter) ibdn = this%gwfmodel1%ibound(n) ibdm = this%gwfmodel2%ibound(m) ihc = this%ihc(iexg) - call this%gwfmodel1%npf%rewet_check(kiter, n, hm, ibdm, ihc, & - this%gwfmodel1%x, irewet) - if(irewet == 1) then + call this%gwfmodel1%npf%rewet_check(kiter, n, hm, ibdm, ihc, & + this%gwfmodel1%x, irewet) + if (irewet == 1) then call this%gwfmodel1%dis%noder_to_string(n, nodestrn) call this%gwfmodel2%dis%noder_to_string(m, nodestrm) - write(this%gwfmodel1%iout, fmtrwt) trim(nodestrn), & + write (this%gwfmodel1%iout, fmtrwt) trim(nodestrn), & trim(this%gwfmodel2%name), trim(nodestrm), kiter, kstp, kper - endif - call this%gwfmodel2%npf%rewet_check(kiter, m, hn, ibdn, ihc, & - this%gwfmodel2%x, irewet) - if(irewet == 1) then + end if + call this%gwfmodel2%npf%rewet_check(kiter, m, hn, ibdn, ihc, & + this%gwfmodel2%x, irewet) + if (irewet == 1) then call this%gwfmodel1%dis%noder_to_string(n, nodestrm) call this%gwfmodel2%dis%noder_to_string(m, nodestrn) - write(this%gwfmodel2%iout, fmtrwt) trim(nodestrn), & + write (this%gwfmodel2%iout, fmtrwt) trim(nodestrn), & trim(this%gwfmodel1%name), trim(nodestrm), kiter, kstp, kper - endif + end if ! - enddo + end do ! ! -- Return return end subroutine rewet - + !> @ brief Calculate the conductance !! !! Calculate the conductance based on state @@ -1621,7 +1640,7 @@ subroutine condcalc(this) use ConstantsModule, only: DHALF, DZERO, DONE use GwfNpfModule, only: hcond, vcond ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: iexg integer(I4B) :: n, m, ihc @@ -1656,7 +1675,7 @@ subroutine condcalc(this) hm = this%gwfmodel2%x(m) ! ! -- Calculate conductance depending on connection orientation - if(ihc == 0) then + if (ihc == 0) then ! ! -- Vertical connection vg(1) = DZERO @@ -1664,8 +1683,8 @@ subroutine condcalc(this) vg(3) = DONE hyn = this%gwfmodel1%npf%hy_eff(n, 0, ihc, vg=vg) hym = this%gwfmodel2%npf%hy_eff(m, 0, ihc, vg=vg) - cond = vcond(ibdn, ibdm, ictn, ictm, this%inewton, this%ivarcv, & - this%idewatcv, this%condsat(iexg), hn, hm, hyn, hym, & + cond = vcond(ibdn, ibdm, ictn, ictm, this%inewton, this%ivarcv, & + this%idewatcv, this%condsat(iexg), hn, hm, hyn, hym, & satn, satm, topn, topm, botn, botm, this%hwva(iexg)) else ! @@ -1674,33 +1693,33 @@ subroutine condcalc(this) hym = this%gwfmodel2%npf%k11(m) ! ! -- Check for anisotropy in models, and recalculate hyn and hym - if(this%ianglex > 0) then + if (this%ianglex > 0) then angle = this%auxvar(this%ianglex, iexg) vg(1) = abs(cos(angle)) vg(2) = abs(sin(angle)) vg(3) = DZERO ! ! -- anisotropy in model 1 - if(this%gwfmodel1%npf%ik22 /= 0) then + if (this%gwfmodel1%npf%ik22 /= 0) then hyn = this%gwfmodel1%npf%hy_eff(n, 0, ihc, vg=vg) - endif + end if ! ! -- anisotropy in model 2 - if(this%gwfmodel2%npf%ik22 /= 0) then + if (this%gwfmodel2%npf%ik22 /= 0) then hym = this%gwfmodel2%npf%hy_eff(m, 0, ihc, vg=vg) - endif - endif + end if + end if ! fawidth = this%hwva(iexg) - cond = hcond(ibdn, ibdm, ictn, ictm, this%inewton, this%inewton, & - this%ihc(iexg), this%icellavg, 0, 0, this%condsat(iexg), & - hn, hm, satn, satm, hyn, hym, topn, topm, botn, botm, & + cond = hcond(ibdn, ibdm, ictn, ictm, this%inewton, this%inewton, & + this%ihc(iexg), this%icellavg, 0, 0, this%condsat(iexg), & + hn, hm, satn, satm, hyn, hym, topn, topm, botn, botm, & this%cl1(iexg), this%cl2(iexg), fawidth, this%satomega) - endif + end if ! this%cond(iexg) = cond ! - enddo + end do ! ! -- Return return @@ -1716,7 +1735,7 @@ subroutine allocate_scalars(this) use MemoryManagerModule, only: mem_allocate use ConstantsModule, only: DZERO ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local ! call this%DisConnExchangeType%allocate_scalars() @@ -1730,7 +1749,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%icellavg, 'ICELLAVG', this%memoryPath) call mem_allocate(this%ivarcv, 'IVARCV', this%memoryPath) call mem_allocate(this%idewatcv, 'IDEWATCV', this%memoryPath) - call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) + call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) call mem_allocate(this%ingnc, 'INGNC', this%memoryPath) call mem_allocate(this%inmvr, 'INMVR', this%memoryPath) call mem_allocate(this%inobs, 'INOBS', this%memoryPath) @@ -1738,7 +1757,7 @@ subroutine allocate_scalars(this) this%icellavg = 0 this%ivarcv = 0 this%idewatcv = 0 - this%inewton = 0 + this%inewton = 0 this%ingnc = 0 this%inmvr = 0 this%inobs = 0 @@ -1757,23 +1776,23 @@ subroutine gwf_gwf_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local ! ! -- objects - if(this%ingnc > 0) then + if (this%ingnc > 0) then call this%gnc%gnc_da() - deallocate(this%gnc) - endif + deallocate (this%gnc) + end if if (this%inmvr > 0) then call this%mvr%mvr_da() - deallocate(this%mvr) - endif + deallocate (this%mvr) + end if call this%obs%obs_da() - deallocate(this%obs) + deallocate (this%obs) ! ! -- arrays - call mem_deallocate(this%cond) + call mem_deallocate(this%cond) call mem_deallocate(this%condsat) call mem_deallocate(this%idxglo) call mem_deallocate(this%idxsymglo) @@ -1782,17 +1801,17 @@ subroutine gwf_gwf_da(this) ! -- output table objects if (associated(this%outputtab1)) then call this%outputtab1%table_da() - deallocate(this%outputtab1) - nullify(this%outputtab1) + deallocate (this%outputtab1) + nullify (this%outputtab1) end if if (associated(this%outputtab2)) then call this%outputtab2%table_da() - deallocate(this%outputtab2) - nullify(this%outputtab2) + deallocate (this%outputtab2) + nullify (this%outputtab2) end if ! - ! -- scalars - deallocate(this%filename) + ! -- scalars + deallocate (this%filename) call mem_deallocate(this%iprflow) call mem_deallocate(this%ipakcb) ! @@ -1811,7 +1830,7 @@ subroutine gwf_gwf_da(this) ! -- return return end subroutine gwf_gwf_da - + !> @ brief Allocate arrays !! !! Allocate arrays @@ -1821,16 +1840,16 @@ subroutine allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local character(len=LINELENGTH) :: text integer(I4B) :: ntabcol, i ! call this%DisConnExchangeType%allocate_arrays() - ! + ! call mem_allocate(this%cond, this%nexg, 'COND', this%memoryPath) call mem_allocate(this%idxglo, this%nexg, 'IDXGLO', this%memoryPath) - call mem_allocate(this%idxsymglo, this%nexg, 'IDXSYMGLO', this%memoryPath) ! + call mem_allocate(this%idxsymglo, this%nexg, 'IDXSYMGLO', this%memoryPath) ! call mem_allocate(this%condsat, this%nexg, 'CONDSAT', this%memoryPath) call mem_allocate(this%simvals, this%nexg, 'SIMVALS', this%memoryPath) ! @@ -1851,7 +1870,7 @@ subroutine allocate_arrays(this) ! -- initialize the output table objects ! outouttab1 call table_cr(this%outputtab1, this%name, ' ') - call this%outputtab1%table_df(this%nexg, ntabcol, this%gwfmodel1%iout, & + call this%outputtab1%table_df(this%nexg, ntabcol, this%gwfmodel1%iout, & transient=.TRUE.) text = 'NUMBER' call this%outputtab1%initialize_column(text, 10, alignment=TABCENTER) @@ -1865,7 +1884,7 @@ subroutine allocate_arrays(this) end if ! outouttab2 call table_cr(this%outputtab2, this%name, ' ') - call this%outputtab2%table_df(this%nexg, ntabcol, this%gwfmodel2%iout, & + call this%outputtab2%table_df(this%nexg, ntabcol, this%gwfmodel2%iout, & transient=.TRUE.) text = 'NUMBER' call this%outputtab2%initialize_column(text, 10, alignment=TABCENTER) @@ -1890,7 +1909,7 @@ end subroutine allocate_arrays !< subroutine gwf_gwf_df_obs(this) ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: indx ! @@ -1902,7 +1921,7 @@ subroutine gwf_gwf_df_obs(this) ! -- return return end subroutine gwf_gwf_df_obs - + !> @ brief Read and prepare observations !! !! Handle observation exchanges exchange-boundary names. @@ -1912,7 +1931,7 @@ subroutine gwf_gwf_rp_obs(this) ! -- modules use ConstantsModule, only: DZERO ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: i integer(I4B) :: j @@ -1920,15 +1939,15 @@ subroutine gwf_gwf_rp_obs(this) character(len=LENBOUNDNAME) :: bname logical :: jfound ! -- formats -10 format('Exchange "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') -20 format('Exchange id "',i0,'" for observation "',a, & - '" is invalid in package "',a,'"') +10 format('Exchange "', a, '" for observation "', a, & + '" is invalid in package "', a, '"') +20 format('Exchange id "', i0, '" for observation "', a, & + '" is invalid in package "', a, '"') ! do i = 1, this%obs%npakobs obsrv => this%obs%pakobs(i)%obsrv ! - ! -- indxbnds needs to be reset each stress period because + ! -- indxbnds needs to be reset each stress period because ! list of boundaries can change each stress period. ! -- Not true for exchanges, but leave this in for now anyway. call obsrv%ResetObsIndex() @@ -1940,18 +1959,18 @@ subroutine gwf_gwf_rp_obs(this) ! Iterate through all boundaries to identify and store ! corresponding index(indices) in bound array. jfound = .false. - do j=1,this%nexg + do j = 1, this%nexg if (this%boundname(j) == bname) then jfound = .true. obsrv%BndFound = .true. obsrv%CurrentTimeStepEndValue = DZERO call obsrv%AddObsIndex(j) - endif - enddo + end if + end do if (.not. jfound) then - write(errmsg, 10) trim(bname), trim(obsrv%ObsTypeId) , trim(this%name) + write (errmsg, 10) trim(bname), trim(obsrv%ObsTypeId), trim(this%name) call store_error(errmsg) - endif + end if else ! -- Observation location is a single exchange number if (obsrv%intPak1 <= this%nexg .and. obsrv%intPak1 > 0) then @@ -1961,23 +1980,23 @@ subroutine gwf_gwf_rp_obs(this) call obsrv%AddObsIndex(obsrv%intPak1) else jfound = .false. - endif + end if if (.not. jfound) then - write(errmsg, 20) obsrv%intPak1, trim(obsrv%ObsTypeId) , trim(this%name) + write (errmsg, 20) obsrv%intPak1, trim(obsrv%ObsTypeId), trim(this%name) call store_error(errmsg) - endif - endif - enddo + end if + end if + end do ! ! -- write summary of error messages if (count_errors() > 0) then call store_error_unit(this%inobs) - endif + end if ! ! -- Return return end subroutine gwf_gwf_rp_obs - + !> @ brief Final processing !! !! Conduct any final processing @@ -1985,11 +2004,11 @@ end subroutine gwf_gwf_rp_obs !< subroutine gwf_gwf_fp(this) ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! return end subroutine gwf_gwf_fp - + !> @ brief Calculate flow !! !! Calculate the flow for the specified exchange and node numbers @@ -1999,7 +2018,7 @@ function qcalc(this, iexg, n1, n2) ! -- return real(DP) :: qcalc ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType integer(I4B), intent(in) :: iexg integer(I4B), intent(in) :: n1 integer(I4B), intent(in) :: n2 @@ -2018,9 +2037,9 @@ end function qcalc !! coefficient matrix to be asymmetric. !! !< - function gwf_gwf_get_iasym(this) result (iasym) + function gwf_gwf_get_iasym(this) result(iasym) ! -- dummy - class(GwfExchangeType) :: this !< GwfExchangeType + class(GwfExchangeType) :: this !< GwfExchangeType ! -- local integer(I4B) :: iasym ! @@ -2033,29 +2052,29 @@ function gwf_gwf_get_iasym(this) result (iasym) ! -- GNC if (this%ingnc > 0) then if (this%gnc%iasym /= 0) iasym = 1 - endif + end if ! ! -- return return end function gwf_gwf_get_iasym - !> @brief Return true when this exchange provides matrix + !> @brief Return true when this exchange provides matrix !! coefficients for solving @param model !< function gwf_gwf_connects_model(this, model) result(is_connected) - class(GwfExchangeType) :: this !< GwfExchangeType - class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection - logical(LGP) :: is_connected !< true, when connected + class(GwfExchangeType) :: this !< GwfExchangeType + class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection + logical(LGP) :: is_connected !< true, when connected is_connected = .false. ! only connected when model is GwfModelType of course - select type(model) - class is (GwfModelType) - if (associated(this%gwfmodel1, model)) then - is_connected = .true. - else if (associated(this%gwfmodel2, model)) then - is_connected = .true. - end if + select type (model) + class is (GwfModelType) + if (associated(this%gwfmodel1, model)) then + is_connected = .true. + else if (associated(this%gwfmodel2, model)) then + is_connected = .true. + end if end select end function gwf_gwf_connects_model @@ -2064,10 +2083,10 @@ end function gwf_gwf_connects_model !< function use_interface_model(this) result(useIM) class(GwfExchangeType) :: this !< GwfExchangeType - logical(LGP) :: useIM !< true when interface model should be used - + logical(LGP) :: useIM !< true when interface model should be used + useIM = (this%ixt3d > 0) - + end function !> @ brief Save simulated flow observations @@ -2096,7 +2115,7 @@ subroutine gwf_gwf_save_simvals(this) call this%obs%obs_bd_clear() do i = 1, this%obs%npakobs obsrv => this%obs%pakobs(i)%obsrv - do j = 1, obsrv%indxbnds_count + do j = 1, obsrv%indxbnds_count iexg = obsrv%indxbnds(j) v = DZERO select case (obsrv%ObsTypeId) @@ -2105,15 +2124,15 @@ subroutine gwf_gwf_save_simvals(this) n2 = this%nodem2(iexg) v = this%simvals(iexg) case default - msg = 'Error: Unrecognized observation type: ' // & + msg = 'Error: Unrecognized observation type: '// & trim(obsrv%ObsTypeId) call store_error(msg) call store_error_unit(this%inobs) end select call this%obs%SaveOneSimval(obsrv, v) - enddo - enddo - endif + end do + end do + end if ! return end subroutine gwf_gwf_save_simvals @@ -2130,10 +2149,10 @@ subroutine gwf_gwf_process_obsID(obsrv, dis, inunitobs, iout) use ObserveModule, only: ObserveType use BaseDisModule, only: DisBaseType ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: n, iexg, istat integer(I4B) :: icol, istart, istop @@ -2155,7 +2174,7 @@ subroutine gwf_gwf_process_obsID(obsrv, dis, inunitobs, iout) ! boundaries, so assign intPak1 as a value that indicates observation ! is for a named exchange boundary or group of exchange boundaries. obsrv%intPak1 = NAMEDBOUNDFLAG - endif + end if ! return end subroutine gwf_gwf_process_obsID @@ -2165,7 +2184,7 @@ end subroutine gwf_gwf_process_obsID !! Cast polymorphic object as exchange !! !< - function CastAsGwfExchange(obj) result (res) + function CastAsGwfExchange(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(GwfExchangeType), pointer :: res @@ -2185,12 +2204,12 @@ end function CastAsGwfExchange !! Return an exchange from the list for specified index !! !< - function GetGwfExchangeFromList(list, idx) result (res) + function GetGwfExchangeFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(GwfExchangeType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(GwfExchangeType), pointer :: res ! -- local class(*), pointer :: obj ! @@ -2200,7 +2219,5 @@ function GetGwfExchangeFromList(list, idx) result (res) return end function GetGwfExchangeFromList - - end module GwfGwfExchangeModule diff --git a/src/Exchange/GwfGwtExchange.f90 b/src/Exchange/GwfGwtExchange.f90 index 640107a4df2..44e040b5986 100644 --- a/src/Exchange/GwfGwtExchange.f90 +++ b/src/Exchange/GwfGwtExchange.f90 @@ -1,34 +1,33 @@ module GwfGwtExchangeModule - use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: LENPACKAGENAME - use ListsModule, only: basemodellist, baseexchangelist, & - baseconnectionlist - use SimModule, only: store_error - use SimVariablesModule, only: errmsg - use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList - use SpatialModelConnectionModule, only: SpatialModelConnectionType, & + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: LENPACKAGENAME + use ListsModule, only: basemodellist, baseexchangelist, & + baseconnectionlist + use SimModule, only: store_error + use SimVariablesModule, only: errmsg + use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList + use SpatialModelConnectionModule, only: SpatialModelConnectionType, & GetSpatialModelConnectionFromList - use GwtGwtConnectionModule, only: GwtGwtConnectionType, CastAsGwtGwtConnection - use GwfGwfConnectionModule, only: GwfGwfConnectionType, CastAsGwfGwfConnection - use GwfGwfExchangeModule, only: GwfExchangeType, & - GetGwfExchangeFromList - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use GwfModule, only: GwfModelType - use GwtModule, only: GwtModelType - use BndModule, only: BndType, GetBndFromList - - + use GwtGwtConnectionModule, only: GwtGwtConnectionType, CastAsGwtGwtConnection + use GwfGwfConnectionModule, only: GwfGwfConnectionType, CastAsGwfGwfConnection + use GwfGwfExchangeModule, only: GwfExchangeType, & + GetGwfExchangeFromList + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use GwfModule, only: GwfModelType + use GwtModule, only: GwtModelType + use BndModule, only: BndType, GetBndFromList + implicit none public :: GwfGwtExchangeType public :: gwfgwt_cr - + type, extends(BaseExchangeType) :: GwfGwtExchangeType integer(I4B), pointer :: m1id => null() integer(I4B), pointer :: m2id => null() contains - + procedure :: exg_df procedure :: exg_ar procedure :: exg_da @@ -37,11 +36,11 @@ module GwfGwtExchangeModule procedure, private :: gwfbnd2gwtfmi procedure, private :: gwfconn2gwtconn procedure, private :: link_connections - + end type GwfGwtExchangeType - - contains - + +contains + subroutine gwfgwt_cr(filename, id, m1id, m2id) ! ****************************************************************************** ! gwfgwt_cr -- Create a new GWF to GWT exchange object @@ -62,14 +61,14 @@ subroutine gwfgwt_cr(filename, id, m1id, m2id) ! ------------------------------------------------------------------------------ ! ! -- Create a new exchange and add it to the baseexchangelist container - allocate(exchange) + allocate (exchange) baseexchange => exchange call AddBaseExchangeToList(baseexchangelist, baseexchange) ! ! -- Assign id and name exchange%id = id - write(cint, '(i0)') id - exchange%name = 'GWF-GWT_' // trim(adjustl(cint)) + write (cint, '(i0)') id + exchange%name = 'GWF-GWT_'//trim(adjustl(cint)) exchange%memoryPath = exchange%name ! ! -- allocate scalars @@ -83,7 +82,7 @@ subroutine gwfgwt_cr(filename, id, m1id, m2id) ! -- return return end subroutine gwfgwt_cr - + subroutine set_model_pointers(this) ! ****************************************************************************** ! set_model_pointers -- allocate and read @@ -118,14 +117,14 @@ subroutine set_model_pointers(this) ! ! -- Verify that gwf model is of the correct type if (.not. associated(gwfmodel)) then - write(errmsg, '(3a)') 'Problem with GWF-GWT exchange ', trim(this%name), & + write (errmsg, '(3a)') 'Problem with GWF-GWT exchange ', trim(this%name), & '. Specified GWF Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) end if ! ! -- Verify that gwt model is of the correct type if (.not. associated(gwtmodel)) then - write(errmsg, '(3a)') 'Problem with GWF-GWT exchange ', trim(this%name), & + write (errmsg, '(3a)') 'Problem with GWF-GWT exchange ', trim(this%name), & '. Specified GWF Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) end if @@ -140,7 +139,7 @@ subroutine set_model_pointers(this) ! -- return return end subroutine set_model_pointers - + subroutine exg_df(this) ! ****************************************************************************** ! exg_df -- define @@ -149,14 +148,13 @@ subroutine exg_df(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules + use MemoryManagerModule, only: mem_checkin ! -- dummy class(GwfGwtExchangeType) :: this ! -- local class(BaseModelType), pointer :: mb => null() type(GwfModelType), pointer :: gwfmodel => null() type(GwtModelType), pointer :: gwtmodel => null() - integer(I4B) :: ngwfpack, ip - class(BndType), pointer :: packobj => null() ! ------------------------------------------------------------------------------ ! ! @@ -174,35 +172,42 @@ subroutine exg_df(this) gwtmodel => mb end select ! + ! -- Check to make sure that flow is solved before transport and in a + ! different IMS solution + if (gwfmodel%idsoln >= gwtmodel%idsoln) then + write (errmsg, '(3a)') 'Problem with GWF-GWT exchange ', trim(this%name), & + '. The GWF model must be solved by a different IMS than the GWT model. & + &Furthermore, the IMS specified for GWF must be listed in mfsim.nam & + &before the IMS for GWT.' + call store_error(errmsg, terminate=.true.) + end if + ! ! -- Set pointer to flowja gwtmodel%fmi%gwfflowja => gwfmodel%flowja + call mem_checkin(gwtmodel%fmi%gwfflowja, & + 'GWFFLOWJA', gwtmodel%fmi%memoryPath, & + 'FLOWJA', gwfmodel%memoryPath) + ! - ! -- Set the npf flag so that specific discharge is available for + ! -- Set the npf flag so that specific discharge is available for ! transport calculations if dispersion is active if (gwtmodel%indsp > 0) then gwfmodel%npf%icalcspdis = 1 end if ! - ! -- Set the auxiliary names for gwf flow packages in gwt%fmi - ngwfpack = gwfmodel%bndlist%Count() - do ip = 1, ngwfpack - packobj => GetBndFromList(gwfmodel%bndlist, ip) - call gwtmodel%fmi%gwfpackages(ip)%set_auxname(packobj%naux, & - packobj%auxname) - end do - ! ! -- return return end subroutine exg_df - + subroutine exg_ar(this) ! ****************************************************************************** -! exg_ar -- +! exg_ar -- ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules + use MemoryManagerModule, only: mem_checkin ! -- dummy class(GwfGwtExchangeType) :: this ! -- local @@ -210,7 +215,7 @@ subroutine exg_ar(this) type(GwfModelType), pointer :: gwfmodel => null() type(GwtModelType), pointer :: gwtmodel => null() ! -- formats - character(len=*),parameter :: fmtdiserr = & + character(len=*), parameter :: fmtdiserr = & "('GWF and GWT Models do not have the same discretization for exchange& & ',a,'.& & GWF Model has ', i0, ' user nodes and ', i0, ' reduced nodes.& @@ -233,39 +238,54 @@ subroutine exg_ar(this) end select ! ! -- Check to make sure sizes are identical - if (gwtmodel%dis%nodes /= gwfmodel%dis%nodes .or.& + if (gwtmodel%dis%nodes /= gwfmodel%dis%nodes .or. & gwtmodel%dis%nodesuser /= gwfmodel%dis%nodesuser) then - write(errmsg, fmtdiserr) trim(this%name), & - gwfmodel%dis%nodesuser, & - gwfmodel%dis%nodes, & - gwtmodel%dis%nodesuser, & - gwtmodel%dis%nodes + write (errmsg, fmtdiserr) trim(this%name), & + gwfmodel%dis%nodesuser, & + gwfmodel%dis%nodes, & + gwtmodel%dis%nodesuser, & + gwtmodel%dis%nodes call store_error(errmsg, terminate=.TRUE.) end if ! ! -- setup pointers to gwf variables allocated in gwf_ar - gwtmodel%fmi%gwfhead => gwfmodel%x - gwtmodel%fmi%gwfsat => gwfmodel%npf%sat - gwtmodel%fmi%gwfspdis => gwfmodel%npf%spdis + gwtmodel%fmi%gwfhead => gwfmodel%x + call mem_checkin(gwtmodel%fmi%gwfhead, & + 'GWFHEAD', gwtmodel%fmi%memoryPath, & + 'X', gwfmodel%memoryPath) + gwtmodel%fmi%gwfsat => gwfmodel%npf%sat + call mem_checkin(gwtmodel%fmi%gwfsat, & + 'GWFSAT', gwtmodel%fmi%memoryPath, & + 'SAT', gwfmodel%npf%memoryPath) + gwtmodel%fmi%gwfspdis => gwfmodel%npf%spdis + call mem_checkin(gwtmodel%fmi%gwfspdis, & + 'GWFSPDIS', gwtmodel%fmi%memoryPath, & + 'SPDIS', gwfmodel%npf%memoryPath) ! ! -- setup pointers to the flow storage rates. GWF strg arrays are ! available after the gwf_ar routine is called. - if(gwtmodel%inmst > 0) then + if (gwtmodel%inmst > 0) then if (gwfmodel%insto > 0) then gwtmodel%fmi%gwfstrgss => gwfmodel%sto%strgss gwtmodel%fmi%igwfstrgss = 1 if (gwfmodel%sto%iusesy == 1) then gwtmodel%fmi%gwfstrgsy => gwfmodel%sto%strgsy gwtmodel%fmi%igwfstrgsy = 1 - endif - endif - endif + end if + end if + end if ! - ! -- Set a pointer to conc + ! -- Set a pointer to conc in buy if (gwfmodel%inbuy > 0) then call gwfmodel%buy%set_concentration_pointer(gwtmodel%name, gwtmodel%x, & gwtmodel%ibound) - endif + end if + ! + ! -- Set a pointer to conc (which could be a temperature) in vsc + if (gwfmodel%invsc > 0) then + call gwfmodel%vsc%set_concentration_pointer(gwtmodel%name, gwtmodel%x, & + gwtmodel%ibound) + end if ! ! -- transfer the boundary package information from gwf to gwt call this%gwfbnd2gwtfmi() @@ -281,17 +301,18 @@ subroutine exg_ar(this) ! -- return return end subroutine exg_ar - + !> @brief Link GWT connections to GWF connections or exchanges !< subroutine gwfconn2gwtconn(this, gwfModel, gwtModel) use SimModule, only: store_error use SimVariablesModule, only: iout - class(GwfGwtExchangeType) :: this !< this exchange + use MemoryManagerModule, only: mem_checkin + class(GwfGwtExchangeType) :: this !< this exchange type(GwfModelType), pointer :: gwfModel !< the flow model type(GwtModelType), pointer :: gwtModel !< the transport model - ! local - class(SpatialModelConnectionType), pointer :: conn => null() + ! local + class(SpatialModelConnectionType), pointer :: conn => null() class(*), pointer :: objPtr => null() class(GwtGwtConnectionType), pointer :: gwtConn => null() class(GwfGwfConnectionType), pointer :: gwfConn => null() @@ -303,7 +324,7 @@ subroutine gwfconn2gwtconn(this, gwfModel, gwtModel) ! loop over all connections gwtloop: do ic1 = 1, baseconnectionlist%Count() - conn => GetSpatialModelConnectionFromList(baseconnectionlist,ic1) + conn => GetSpatialModelConnectionFromList(baseconnectionlist, ic1) if (.not. associated(conn%owner, gwtModel)) cycle gwtloop ! start with a GWT conn. @@ -314,25 +335,25 @@ subroutine gwfconn2gwtconn(this, gwfModel, gwtModel) ! find matching GWF conn. in same list gwfloop: do ic2 = 1, baseconnectionlist%Count() - conn => GetSpatialModelConnectionFromList(baseconnectionlist,ic2) - + conn => GetSpatialModelConnectionFromList(baseconnectionlist, ic2) + if (associated(conn%owner, gwfModel)) then objPtr => conn - gwfConn => CastAsGwfGwfConnection(objPtr) + gwfConn => CastAsGwfGwfConnection(objPtr) - ! for now, connecting the same nodes nrs will be + ! for now, connecting the same nodes nrs will be ! sufficient evidence of equality - areEqual = all(gwfConn%primaryExchange%nodem1 == & - gwtConn%primaryExchange%nodem1) - areEqual = areEqual .and. all(gwfConn%primaryExchange%nodem2 == & - gwtConn%primaryExchange%nodem2) + areEqual = all(gwfConn%primaryExchange%nodem1 == & + gwtConn%primaryExchange%nodem1) + areEqual = areEqual .and. all(gwfConn%primaryExchange%nodem2 == & + gwtConn%primaryExchange%nodem2) if (areEqual) then ! same DIS, same exchange: link and go to next GWT conn. - write(iout,'(/6a)') 'Linking exchange ', & - trim(gwtConn%primaryExchange%name), & - ' to ', trim(gwfConn%primaryExchange%name), & - ' (using interface model) for GWT model ', & - trim(gwtModel%name) + write (iout, '(/6a)') 'Linking exchange ', & + trim(gwtConn%primaryExchange%name), & + ' to ', trim(gwfConn%primaryExchange%name), & + ' (using interface model) for GWT model ', & + trim(gwtModel%name) gwfConnIdx = ic2 call this%link_connections(gwtConn, gwfConn) exit gwfloop @@ -345,35 +366,41 @@ subroutine gwfconn2gwtconn(this, gwfModel, gwtModel) if (gwfConnIdx == -1) then gwfloopexg: do iex = 1, baseexchangelist%Count() gwfEx => GetGwfExchangeFromList(baseexchangelist, iex) - + ! -- There is no guarantee that iex is a gwfExg, in which case ! it will return as null. cycle if so. if (.not. associated(gwfEx)) cycle gwfloopexg - if (associated(gwfEx%model1, gwfModel) .or. & + if (associated(gwfEx%model1, gwfModel) .or. & associated(gwfEx%model2, gwfModel)) then - ! again, connecting the same nodes nrs will be + ! again, connecting the same nodes nrs will be ! sufficient evidence of equality areEqual = all(gwfEx%nodem1 == gwtConn%primaryExchange%nodem1) - areEqual = areEqual .and. & - all(gwfEx%nodem2 == gwtConn%primaryExchange%nodem2) - if (areEqual) then + areEqual = areEqual .and. & + all(gwfEx%nodem2 == gwtConn%primaryExchange%nodem2) + if (areEqual) then ! link exchange to connection - write(iout,'(/6a)') 'Linking exchange ', & - trim(gwtConn%primaryExchange%name), & - ' to ', trim(gwfEx%name), ' for GWT model ', & - trim(gwtModel%name) + write (iout, '(/6a)') 'Linking exchange ', & + trim(gwtConn%primaryExchange%name), & + ' to ', trim(gwfEx%name), ' for GWT model ', & + trim(gwtModel%name) gwfExIdx = iex - gwtConn%exgflowja => gwfEx%simvals - + if (gwtConn%exchangeIsOwned) then + gwtConn%gwtExchange%gwfsimvals => gwfEx%simvals + call mem_checkin(gwtConn%gwtExchange%gwfsimvals, & + 'GWFSIMVALS', gwtConn%gwtExchange%memoryPath, & + 'SIMVALS', gwfEx%memoryPath) + end if + !cdl link up mvt to mvr if (gwfEx%inmvr > 0) then if (gwtConn%exchangeIsOwned) then !cdl todo: check and make sure gwtEx has mvt active - call gwtConn%gwtExchange%mvt%set_pointer_mvrbudobj(gwfEx%mvr%budobj) + call gwtConn%gwtExchange%mvt%set_pointer_mvrbudobj( & + gwfEx%mvr%budobj) end if end if - + if (associated(gwfEx%model2, gwfModel)) gwtConn%exgflowSign = -1 gwtConn%gwtInterfaceModel%fmi%flows_from_file = .false. @@ -381,55 +408,62 @@ subroutine gwfconn2gwtconn(this, gwfModel, gwtModel) end if end if - end do gwfloopexg end if if (gwfConnIdx == -1 .and. gwfExIdx == -1) then ! none found, report - write(errmsg, '(/6a)') 'Missing GWF-GWF exchange when connecting GWT'// & - ' model ', trim(gwtModel%name), ' with exchange ', & - trim(gwtConn%primaryExchange%name), ' to GWF model ', & - trim(gwfModel%name) + write (errmsg, '(/6a)') 'Missing GWF-GWF exchange when connecting GWT'// & + ' model ', trim(gwtModel%name), ' with exchange ', & + trim(gwtConn%primaryExchange%name), ' to GWF model ', & + trim(gwfModel%name) call store_error(errmsg, terminate=.true.) end if end do gwtloop - end subroutine gwfconn2gwtconn - + end subroutine gwfconn2gwtconn !> @brief Links a GWT connection to its GWF counterpart !< subroutine link_connections(this, gwtConn, gwfConn) - class(GwfGwtExchangeType) :: this !< this exchange + use MemoryManagerModule, only: mem_checkin + class(GwfGwtExchangeType) :: this !< this exchange class(GwtGwtConnectionType), pointer :: gwtConn !< GWT connection class(GwfGwfConnectionType), pointer :: gwfConn !< GWF connection !gwtConn%exgflowja => gwfConn%exgflowja - gwtConn%exgflowja => gwfConn%gwfExchange%simvals - + if (gwtConn%exchangeIsOwned) then + gwtConn%gwtExchange%gwfsimvals => gwfConn%gwfExchange%simvals + call mem_checkin(gwtConn%gwtExchange%gwfsimvals, & + 'GWFSIMVALS', gwtConn%gwtExchange%memoryPath, & + 'SIMVALS', gwfConn%gwfExchange%memoryPath) + end if + !cdl link up mvt to mvr if (gwfConn%gwfExchange%inmvr > 0) then if (gwtConn%exchangeIsOwned) then !cdl todo: check and make sure gwtEx has mvt active - call gwtConn%gwtExchange%mvt%set_pointer_mvrbudobj(gwfConn%gwfExchange%mvr%budobj) + call gwtConn%gwtExchange%mvt%set_pointer_mvrbudobj( & + gwfConn%gwfExchange%mvr%budobj) end if end if - - if (associated(gwfConn%gwfExchange%model2, gwfConn%owner)) gwtConn%exgflowSign = -1 + + if (associated(gwfConn%gwfExchange%model2, gwfConn%owner)) then + gwtConn%exgflowSign = -1 + end if ! fmi flows are not read from file gwtConn%gwtInterfaceModel%fmi%flows_from_file = .false. ! set concentration pointer for buoyancy - call gwfConn%gwfInterfaceModel%buy%set_concentration_pointer( & - gwtConn%gwtModel%name, & - gwtConn%conc, & - gwtConn%icbound) + call gwfConn%gwfInterfaceModel%buy%set_concentration_pointer( & + gwtConn%gwtModel%name, & + gwtConn%conc, & + gwtConn%icbound) end subroutine link_connections - + subroutine exg_da(this) ! ****************************************************************************** ! allocate_scalars @@ -512,9 +546,9 @@ subroutine gwfbnd2gwtfmi(this) iterm = 1 do ip = 1, ngwfpack packobj => GetBndFromList(gwfmodel%bndlist, ip) - call gwtmodel%fmi%gwfpackages(iterm)%set_pointers( & - 'SIMVALS', & - packobj%memoryPath) + call gwtmodel%fmi%gwfpackages(iterm)%set_pointers( & + 'SIMVALS', & + packobj%memoryPath) iterm = iterm + 1 ! ! -- If a mover is active for this package, then establish a separate @@ -522,9 +556,9 @@ subroutine gwfbnd2gwtfmi(this) imover = packobj%imover if (packobj%isadvpak /= 0) imover = 0 if (imover /= 0) then - call gwtmodel%fmi%gwfpackages(iterm)%set_pointers( & - 'SIMTOMVR', & - packobj%memoryPath) + call gwtmodel%fmi%gwfpackages(iterm)%set_pointers( & + 'SIMTOMVR', & + packobj%memoryPath) iterm = iterm + 1 end if end do @@ -533,4 +567,4 @@ subroutine gwfbnd2gwtfmi(this) return end subroutine gwfbnd2gwtfmi -end module GwfGwtExchangeModule \ No newline at end of file +end module GwfGwtExchangeModule diff --git a/src/Exchange/GwtGwtExchange.f90 b/src/Exchange/GwtGwtExchange.f90 index e6bc50c77f2..b12e5c30c04 100644 --- a/src/Exchange/GwtGwtExchange.f90 +++ b/src/Exchange/GwtGwtExchange.f90 @@ -9,26 +9,27 @@ !< module GwtGwtExchangeModule - use KindModule, only: DP, I4B, LGP - use SimVariablesModule, only: errmsg - use SimModule, only: store_error - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList - use ConstantsModule, only: LENBOUNDNAME, NAMEDBOUNDFLAG, LINELENGTH, & - TABCENTER, TABLEFT, LENAUXNAME, DNODATA, & - LENMODELNAME - use ListModule, only: ListType - use ListsModule, only: basemodellist - use DisConnExchangeModule, only: DisConnExchangeType - use GwtModule, only: GwtModelType - use GwtMvtModule, only: GwtMvtType - use ObserveModule, only: ObserveType - use ObsModule, only: ObsType - use SimModule, only: count_errors, store_error, & - store_error_unit, ustop - use SimVariablesModule, only: errmsg - use BlockParserModule, only: BlockParserType - use TableModule, only: TableType, table_cr + use KindModule, only: DP, I4B, LGP + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList + use ConstantsModule, only: LENBOUNDNAME, NAMEDBOUNDFLAG, LINELENGTH, & + TABCENTER, TABLEFT, LENAUXNAME, DNODATA, & + LENMODELNAME + use ListModule, only: ListType + use ListsModule, only: basemodellist, distmodellist + use DisConnExchangeModule, only: DisConnExchangeType + use GwtModule, only: GwtModelType + use DistributedModelModule, only: GetDistModelFromList + use GwtMvtModule, only: GwtMvtType + use ObserveModule, only: ObserveType + use ObsModule, only: ObsType + use SimModule, only: count_errors, store_error, & + store_error_unit, ustop + use SimVariablesModule, only: errmsg + use BlockParserModule, only: BlockParserType + use TableModule, only: TableType, table_cr implicit none @@ -38,7 +39,7 @@ module GwtGwtExchangeModule public :: GetGwtExchangeFromList public :: CastAsGwtExchange - !> @brief Derived type for GwtExchangeType + !> @brief Derived type for GwtExchangeType !! !! This derived type contains information and methods for !! connecting two GWT models. @@ -47,58 +48,59 @@ module GwtGwtExchangeModule type, extends(DisConnExchangeType) :: GwtExchangeType ! ! -- names of the GWF models that are connected by this exchange - character(len=LENMODELNAME) :: gwfmodelname1 = '' !< name of gwfmodel that corresponds to gwtmodel1 - character(len=LENMODELNAME) :: gwfmodelname2 = '' !< name of gwfmodel that corresponds to gwtmodel2 + character(len=LENMODELNAME) :: gwfmodelname1 = '' !< name of gwfmodel that corresponds to gwtmodel1 + character(len=LENMODELNAME) :: gwfmodelname2 = '' !< name of gwfmodel that corresponds to gwtmodel2 + real(DP), dimension(:), pointer, contiguous :: gwfsimvals => null() !< simulated gwf flow rate for each exchange ! ! -- pointers to gwt models - type(GwtModelType), pointer :: gwtmodel1 => null() !< pointer to GWT Model 1 - type(GwtModelType), pointer :: gwtmodel2 => null() !< pointer to GWT Model 2 - ! - ! -- GWT specific option block: - integer(I4B), pointer :: inewton => null() !< unneeded newton flag allows for mvt to be used here - integer(I4B), pointer :: iprflow => null() !< print flag for cell by cell flows - integer(I4B), pointer :: ipakcb => null() !< save flag for cell by cell flows - integer(I4B), pointer :: iAdvScheme !< the advection scheme at the interface: + type(GwtModelType), pointer :: gwtmodel1 => null() !< pointer to GWT Model 1 + type(GwtModelType), pointer :: gwtmodel2 => null() !< pointer to GWT Model 2 + ! + ! -- GWT specific option block: + integer(I4B), pointer :: inewton => null() !< unneeded newton flag allows for mvt to be used here + integer(I4B), pointer :: iprflow => null() !< print flag for cell by cell flows + integer(I4B), pointer :: ipakcb => null() !< save flag for cell by cell flows + integer(I4B), pointer :: iAdvScheme !< the advection scheme at the interface: !! 0 = upstream, 1 = central, 2 = TVD ! ! -- Mover transport package - integer(I4B), pointer :: inmvt => null() !< unit number for mover transport (0 if off) - type(GwtMvtType), pointer :: mvt => null() !< water mover object + integer(I4B), pointer :: inmvt => null() !< unit number for mover transport (0 if off) + type(GwtMvtType), pointer :: mvt => null() !< water mover object ! ! -- Observation package - integer(I4B), pointer :: inobs => null() !< unit number for GWT-GWT observations - type(ObsType), pointer :: obs => null() !< observation object + integer(I4B), pointer :: inobs => null() !< unit number for GWT-GWT observations + type(ObsType), pointer :: obs => null() !< observation object ! ! -- internal data - real(DP), dimension(:), pointer, contiguous :: cond => null() !< conductance - real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated flow rate for each exchange + real(DP), dimension(:), pointer, contiguous :: cond => null() !< conductance + real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated flow rate for each exchange ! ! -- table objects type(TableType), pointer :: outputtab1 => null() - type(TableType), pointer :: outputtab2 => null() + type(TableType), pointer :: outputtab2 => null() contains - procedure :: exg_df => gwt_gwt_df - procedure :: exg_ar => gwt_gwt_ar - procedure :: exg_rp => gwt_gwt_rp - procedure :: exg_ad => gwt_gwt_ad - procedure :: exg_fc => gwt_gwt_fc - procedure :: exg_bd => gwt_gwt_bd - procedure :: exg_ot => gwt_gwt_ot - procedure :: exg_da => gwt_gwt_da - procedure :: exg_fp => gwt_gwt_fp - procedure :: connects_model => gwt_gwt_connects_model - procedure :: use_interface_model - procedure :: allocate_scalars - procedure :: allocate_arrays - procedure :: read_options - procedure :: parse_option - procedure :: read_mvt - procedure :: gwt_gwt_bdsav + procedure :: exg_df => gwt_gwt_df + procedure :: exg_ar => gwt_gwt_ar + procedure :: exg_rp => gwt_gwt_rp + procedure :: exg_ad => gwt_gwt_ad + procedure :: exg_fc => gwt_gwt_fc + procedure :: exg_bd => gwt_gwt_bd + procedure :: exg_ot => gwt_gwt_ot + procedure :: exg_da => gwt_gwt_da + procedure :: exg_fp => gwt_gwt_fp + procedure :: connects_model => gwt_gwt_connects_model + procedure :: use_interface_model + procedure :: allocate_scalars + procedure :: allocate_arrays + procedure :: read_options + procedure :: parse_option + procedure :: read_mvt + procedure :: gwt_gwt_bdsav procedure, private :: gwt_gwt_df_obs procedure, private :: gwt_gwt_rp_obs - procedure, public :: gwt_gwt_save_simvals + procedure, public :: gwt_gwt_save_simvals procedure, private :: validate_exchange end type GwtExchangeType @@ -117,10 +119,10 @@ subroutine gwtexchange_create(filename, id, m1id, m2id) use ObsModule, only: obs_cr use MemoryHelperModule, only: create_mem_path ! -- dummy - character(len=*),intent(in) :: filename !< filename for reading - integer(I4B), intent(in) :: id !< id for the exchange - integer(I4B), intent(in) :: m1id !< id for model 1 - integer(I4B), intent(in) :: m2id !< id for model 2 + character(len=*), intent(in) :: filename !< filename for reading + integer(I4B), intent(in) :: id !< id for the exchange + integer(I4B), intent(in) :: m1id !< id for model 1 + integer(I4B), intent(in) :: m2id !< id for model 2 ! -- local type(GwtExchangeType), pointer :: exchange class(BaseModelType), pointer :: mb @@ -128,14 +130,14 @@ subroutine gwtexchange_create(filename, id, m1id, m2id) character(len=20) :: cint ! ! -- Create a new exchange and add it to the baseexchangelist container - allocate(exchange) + allocate (exchange) baseexchange => exchange call AddBaseExchangeToList(baseexchangelist, baseexchange) ! ! -- Assign id and name exchange%id = id - write(cint, '(i0)') id - exchange%name = 'GWT-GWT_' // trim(adjustl(cint)) + write (cint, '(i0)') id + exchange%name = 'GWT-GWT_'//trim(adjustl(cint)) exchange%memoryPath = create_mem_path(exchange%name) ! ! -- allocate scalars and set defaults @@ -146,12 +148,13 @@ subroutine gwtexchange_create(filename, id, m1id, m2id) exchange%ixt3d = 1 ! ! -- set gwtmodel1 - mb => GetBaseModelFromList(basemodellist, m1id) + mb => GetBaseModelFromList(basemodellist, m1id) select type (mb) type is (GwtModelType) exchange%model1 => mb exchange%gwtmodel1 => mb end select + exchange%dmodel1 => GetDistModelFromList(distmodellist, m1id) ! ! -- set gwtmodel2 mb => GetBaseModelFromList(basemodellist, m2id) @@ -160,10 +163,11 @@ subroutine gwtexchange_create(filename, id, m1id, m2id) exchange%model2 => mb exchange%gwtmodel2 => mb end select + exchange%dmodel2 => GetDistModelFromList(distmodellist, m2id) ! ! -- Verify that gwt model1 is of the correct type if (.not. associated(exchange%gwtmodel1)) then - write(errmsg, '(3a)') 'Problem with GWT-GWT exchange ', & + write (errmsg, '(3a)') 'Problem with GWT-GWT exchange ', & trim(exchange%name), & '. First specified GWT Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) @@ -171,7 +175,7 @@ subroutine gwtexchange_create(filename, id, m1id, m2id) ! ! -- Verify that gwf model2 is of the correct type if (.not. associated(exchange%gwtmodel2)) then - write(errmsg, '(3a)') 'Problem with GWT-GWT exchange ', & + write (errmsg, '(3a)') 'Problem with GWT-GWT exchange ', & trim(exchange%name), & '. Second specified GWT Model does not appear to be of the correct type.' call store_error(errmsg, terminate=.true.) @@ -195,25 +199,25 @@ subroutine gwt_gwt_df(this) use InputOutputModule, only: getunit, openfile use GhostNodeModule, only: gnc_cr ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local integer(I4B) :: inunit ! ! -- open the file inunit = getunit() - write(iout,'(/a,a)') ' Creating exchange: ', this%name + write (iout, '(/a,a)') ' Creating exchange: ', this%name call openfile(inunit, iout, this%filename, 'GWT-GWT') ! call this%parser%Initialize(inunit, iout) ! ! -- Ensure models are in same solution - if(this%gwtmodel1%idsoln /= this%gwtmodel2%idsoln) then - call store_error('ERROR. TWO MODELS ARE CONNECTED ' // & - 'IN A GWT EXCHANGE BUT THEY ARE IN DIFFERENT SOLUTIONS. ' // & - 'GWT MODELS MUST BE IN SAME SOLUTION: ' // & - trim(this%gwtmodel1%name) // ' ' // trim(this%gwtmodel2%name) ) + if (this%gwtmodel1%idsoln /= this%gwtmodel2%idsoln) then + call store_error('ERROR. TWO MODELS ARE CONNECTED IN A GWT '// & + 'EXCHANGE BUT THEY ARE IN DIFFERENT SOLUTIONS. '// & + 'GWT MODELS MUST BE IN SAME SOLUTION: '// & + trim(this%gwtmodel1%name)//' '//trim(this%gwtmodel2%name)) call this%parser%StoreErrorUnit() - endif + end if ! ! -- read options call this%read_options(iout) @@ -228,17 +232,17 @@ subroutine gwt_gwt_df(this) call this%read_data(iout) ! ! -- Read mover information - if(this%inmvt > 0) then + if (this%inmvt > 0) then call this%read_mvt(iout) call this%mvt%mvt_df(this%gwtmodel1%dis) - endif + end if ! ! -- close the file - close(inunit) + close (inunit) ! ! -- Store obs call this%gwt_gwt_df_obs() - call this%obs%obs_df(iout, this%name, 'GWT-GWT', this%gwtmodel1%dis) + call this%obs%obs_df(iout, this%name, 'GWT-GWT', this%gwtmodel1%dis) ! ! -- validate call this%validate_exchange() @@ -250,29 +254,29 @@ end subroutine gwt_gwt_df !> @brief validate exchange data after reading !< subroutine validate_exchange(this) - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! local - + ! Ensure gwfmodel names were entered if (this%gwfmodelname1 == '') then - write(errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & + write (errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & ' requires that GWFMODELNAME1 be entered in the & &OPTIONS block.' call store_error(errmsg) end if if (this%gwfmodelname2 == '') then - write(errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & + write (errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & ' requires that GWFMODELNAME2 be entered in the & &OPTIONS block.' call store_error(errmsg) end if - + ! Periodic boundary condition in exchange don't allow XT3D (=interface model) if (associated(this%model1, this%model2)) then if (this%ixt3d > 0) then - write(errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & - ' is a periodic boundary condition which cannot'// & - ' be configured with XT3D' + write (errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & + ' is a periodic boundary condition which cannot'// & + ' be configured with XT3D' call store_error(errmsg) end if end if @@ -280,23 +284,23 @@ subroutine validate_exchange(this) ! Check to see if dispersion is on in either model1 or model2. ! If so, then ANGLDEGX must be provided as an auxiliary variable for this ! GWT-GWT exchange (this%ianglex > 0). - if(this%gwtmodel1%indsp /= 0 .or. this%gwtmodel2%indsp /= 0) then - if(this%ianglex == 0) then - write(errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & - ' requires that ANGLDEGX be specified as an'// & - ' auxiliary variable because dispersion was '// & - 'specified in one or both transport models.' + if (this%gwtmodel1%indsp /= 0 .or. this%gwtmodel2%indsp /= 0) then + if (this%ianglex == 0) then + write (errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & + ' requires that ANGLDEGX be specified as an'// & + ' auxiliary variable because dispersion was '// & + 'specified in one or both transport models.' call store_error(errmsg) - endif - endif + end if + end if if (this%ixt3d > 0 .and. this%ianglex == 0) then - write(errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & - ' requires that ANGLDEGX be specified as an'// & - ' auxiliary variable because XT3D is enabled' + write (errmsg, '(3a)') 'GWT-GWT exchange ', trim(this%name), & + ' requires that ANGLDEGX be specified as an'// & + ' auxiliary variable because XT3D is enabled' call store_error(errmsg) end if - + if (count_errors() > 0) then call ustop() end if @@ -311,19 +315,18 @@ end subroutine validate_exchange subroutine gwt_gwt_ar(this) ! -- modules ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local ! ! -- If mover is active, then call ar routine - if(this%inmvt > 0) call this%mvt%mvt_ar() + if (this%inmvt > 0) call this%mvt%mvt_ar() ! ! -- Observation AR call this%obs%obs_ar() ! ! -- Return return - end subroutine gwt_gwt_ar - + end subroutine gwt_gwt_ar !> @ brief Read and prepare !! @@ -334,13 +337,13 @@ subroutine gwt_gwt_rp(this) ! -- modules use TdisModule, only: readnewdata ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! ! -- Check with TDIS on whether or not it is time to RP if (.not. readnewdata) return ! ! -- Read and prepare for mover - if(this%inmvt > 0) call this%mvt%mvt_rp() + if (this%inmvt > 0) call this%mvt%mvt_rp() ! ! -- Read and prepare for observations call this%gwt_gwt_rp_obs() @@ -357,7 +360,7 @@ end subroutine gwt_gwt_rp subroutine gwt_gwt_ad(this) ! -- modules ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local ! ! -- Advance mover @@ -378,16 +381,16 @@ end subroutine gwt_gwt_ad subroutine gwt_gwt_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) ! -- modules ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType integer(I4B), intent(in) :: kiter integer(I4B), dimension(:), intent(in) :: iasln real(DP), dimension(:), intent(inout) :: amatsln - real(DP), dimension(:), intent(inout) ::rhssln + real(DP), dimension(:), intent(inout) :: rhssln integer(I4B), optional, intent(in) :: inwtflag ! -- local ! ! -- Call mvt fc routine - if(this%inmvt > 0) call this%mvt%mvt_fc(this%gwtmodel1%x, this%gwtmodel2%x) + if (this%inmvt > 0) call this%mvt%mvt_fc(this%gwtmodel1%x, this%gwtmodel2%x) ! ! -- Return return @@ -403,7 +406,7 @@ subroutine gwt_gwt_bd(this, icnvg, isuppress_output, isolnid) use ConstantsModule, only: DZERO, LENBUDTXT, LENPACKAGENAME use BudgetModule, only: rate_accumulator ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType integer(I4B), intent(inout) :: icnvg integer(I4B), intent(in) :: isuppress_output integer(I4B), intent(in) :: isolnid @@ -430,12 +433,12 @@ subroutine gwt_gwt_bd(this, icnvg, isuppress_output, isolnid) call this%gwtmodel2%model_bdentry(budterm, budtxt, this%name) ! ! -- Call mvt bd routine - if(this%inmvt > 0) call this%mvt%mvt_bd(this%gwtmodel1%x, this%gwtmodel2%x) + if (this%inmvt > 0) call this%mvt%mvt_bd(this%gwtmodel1%x, this%gwtmodel2%x) ! ! -- return return end subroutine gwt_gwt_bd - + !> @ brief Budget save !! !! Output individual flows to listing file and binary budget files @@ -446,11 +449,11 @@ subroutine gwt_gwt_bdsav(this) use ConstantsModule, only: DZERO, LENBUDTXT, LENPACKAGENAME use TdisModule, only: kstp, kper ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local character(len=LENBOUNDNAME) :: bname - character(len=LENPACKAGENAME+4) :: packname1 - character(len=LENPACKAGENAME+4) :: packname2 + character(len=LENPACKAGENAME + 4) :: packname1 + character(len=LENPACKAGENAME + 4) :: packname2 character(len=LENBUDTXT), dimension(1) :: budtxt character(len=20) :: nodestr integer(I4B) :: ntabrows @@ -477,7 +480,7 @@ subroutine gwt_gwt_bdsav(this) if (this%gwtmodel1%oc%oc_save('BUDGET')) then call this%outputtab1%set_title(packname1) end if - if (this%gwtmodel2%oc%oc_save('BUDGET')) then + if (this%gwtmodel2%oc%oc_save('BUDGET')) then call this%outputtab2%set_title(packname2) end if ! @@ -492,7 +495,7 @@ subroutine gwt_gwt_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if (this%gwtmodel1%ibound(n1) /= 0 .and. & + if (this%gwtmodel1%ibound(n1) /= 0 .and. & this%gwtmodel2%ibound(n2) /= 0) then ntabrows = ntabrows + 1 end if @@ -506,27 +509,30 @@ subroutine gwt_gwt_bdsav(this) ! -- Print and write budget terms for model 1 ! ! -- Set binary unit numbers for saving flows - if(this%ipakcb /= 0) then + if (this%ipakcb /= 0) then ibinun1 = this%gwtmodel1%oc%oc_save_unit('BUDGET') else ibinun1 = 0 - endif + end if ! ! -- If save budget flag is zero for this stress period, then ! shut off saving - if(.not. this%gwtmodel1%oc%oc_save('BUDGET')) ibinun1 = 0 - if(isuppress_output /= 0) then + if (.not. this%gwtmodel1%oc%oc_save('BUDGET')) ibinun1 = 0 + if (isuppress_output /= 0) then ibinun1 = 0 - endif + end if ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun1 /= 0) then - call this%gwtmodel1%dis%record_srcdst_list_header(budtxt(1), & - this%gwtmodel1%name, this%name, & - this%gwtmodel2%name, this%name, & - this%naux, this%auxname, & - ibinun1, this%nexg, this%gwtmodel1%iout) - endif + if (ibinun1 /= 0) then + call this%gwtmodel1%dis%record_srcdst_list_header(budtxt(1), & + this%gwtmodel1%name, & + this%name, & + this%gwtmodel2%name, & + this%name, & + this%naux, this%auxname, & + ibinun1, this%nexg, & + this%gwtmodel1%iout) + end if ! ! Initialize accumulators ratin = DZERO @@ -536,11 +542,11 @@ subroutine gwt_gwt_bdsav(this) do i = 1, this%nexg ! ! -- Assign boundary name - if (this%inamedbound>0) then + if (this%inamedbound > 0) then bname = this%boundname(i) else bname = '' - endif + end if ! ! -- Calculate the flow rate between n1 and n2 rrate = DZERO @@ -548,62 +554,65 @@ subroutine gwt_gwt_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if(this%gwtmodel1%ibound(n1) /= 0 .and. & + if (this%gwtmodel1%ibound(n1) /= 0 .and. & this%gwtmodel2%ibound(n2) /= 0) then rrate = this%simvals(i) ! ! -- Print the individual rates to model list files if requested - if(this%iprflow /= 0) then - if(this%gwtmodel1%oc%oc_save('BUDGET')) then + if (this%iprflow /= 0) then + if (this%gwtmodel1%oc%oc_save('BUDGET')) then ! ! -- set nodestr and write outputtab table nodeu = this%gwtmodel1%dis%get_nodeuser(n1) call this%gwtmodel1%dis%nodeu_to_string(nodeu, nodestr) - call this%outputtab1%print_list_entry(i, trim(adjustl(nodestr)), & + call this%outputtab1%print_list_entry(i, trim(adjustl(nodestr)), & rrate, bname) end if - endif - if(rrate < DZERO) then + end if + if (rrate < DZERO) then ratout = ratout - rrate else ratin = ratin + rrate - endif - endif + end if + end if ! ! -- If saving cell-by-cell flows in list, write flow n1u = this%gwtmodel1%dis%get_nodeuser(n1) n2u = this%gwtmodel2%dis%get_nodeuser(n2) - if(ibinun1 /= 0) & - call this%gwtmodel1%dis%record_mf6_list_entry( & - ibinun1, n1u, n2u, rrate, this%naux, this%auxvar(:, i), & - .false., .false.) + if (ibinun1 /= 0) & + call this%gwtmodel1%dis%record_mf6_list_entry( & + ibinun1, n1u, n2u, rrate, this%naux, this%auxvar(:, i), & + .false., .false.) ! - enddo + end do ! ! -- Print and write budget terms for model 2 ! ! -- Set binary unit numbers for saving flows - if(this%ipakcb /= 0) then + if (this%ipakcb /= 0) then ibinun2 = this%gwtmodel2%oc%oc_save_unit('BUDGET') else ibinun2 = 0 - endif + end if ! ! -- If save budget flag is zero for this stress period, then ! shut off saving - if(.not. this%gwtmodel2%oc%oc_save('BUDGET')) ibinun2 = 0 - if(isuppress_output /= 0) then + if (.not. this%gwtmodel2%oc%oc_save('BUDGET')) ibinun2 = 0 + if (isuppress_output /= 0) then ibinun2 = 0 - endif + end if ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun2 /= 0) then - call this%gwtmodel2%dis%record_srcdst_list_header(budtxt(1), & - this%gwtmodel2%name, this%name, & - this%gwtmodel1%name, this%name, & - this%naux, this%auxname, & - ibinun2, this%nexg, this%gwtmodel2%iout) - endif + if (ibinun2 /= 0) then + call this%gwtmodel2%dis%record_srcdst_list_header(budtxt(1), & + this%gwtmodel2%name, & + this%name, & + this%gwtmodel1%name, & + this%name, & + this%naux, this%auxname, & + ibinun2, this%nexg, & + this%gwtmodel2%iout) + end if ! ! Initialize accumulators ratin = DZERO @@ -613,11 +622,11 @@ subroutine gwt_gwt_bdsav(this) do i = 1, this%nexg ! ! -- Assign boundary name - if (this%inamedbound>0) then + if (this%inamedbound > 0) then bname = this%boundname(i) else bname = '' - endif + end if ! ! -- Calculate the flow rate between n1 and n2 rrate = DZERO @@ -625,37 +634,37 @@ subroutine gwt_gwt_bdsav(this) n2 = this%nodem2(i) ! ! -- If both cells are active then calculate flow rate - if(this%gwtmodel1%ibound(n1) /= 0 .and. & + if (this%gwtmodel1%ibound(n1) /= 0 .and. & this%gwtmodel2%ibound(n2) /= 0) then rrate = this%simvals(i) ! ! -- Print the individual rates to model list files if requested - if(this%iprflow /= 0) then - if(this%gwtmodel2%oc%oc_save('BUDGET')) then + if (this%iprflow /= 0) then + if (this%gwtmodel2%oc%oc_save('BUDGET')) then ! ! -- set nodestr and write outputtab table nodeu = this%gwtmodel2%dis%get_nodeuser(n2) call this%gwtmodel2%dis%nodeu_to_string(nodeu, nodestr) - call this%outputtab2%print_list_entry(i, trim(adjustl(nodestr)), & + call this%outputtab2%print_list_entry(i, trim(adjustl(nodestr)), & -rrate, bname) end if - endif - if(rrate < DZERO) then + end if + if (rrate < DZERO) then ratout = ratout - rrate else ratin = ratin + rrate - endif - endif + end if + end if ! ! -- If saving cell-by-cell flows in list, write flow n1u = this%gwtmodel1%dis%get_nodeuser(n1) n2u = this%gwtmodel2%dis%get_nodeuser(n2) - if(ibinun2 /= 0) & - call this%gwtmodel2%dis%record_mf6_list_entry( & - ibinun2, n2u, n1u, -rrate, this%naux, this%auxvar(:, i), & - .false., .false.) + if (ibinun2 /= 0) & + call this%gwtmodel2%dis%record_mf6_list_entry( & + ibinun2, n2u, n1u, -rrate, this%naux, this%auxvar(:, i), & + .false., .false.) ! - enddo + end do ! ! -- Set icbcfl, ibudfl to zero so that flows will be printed and ! saved, if the options were set in the MVT package @@ -666,14 +675,14 @@ subroutine gwt_gwt_bdsav(this) !cdl todo: if(this%inmvt > 0) call this%mvt%mvt_bdsav(icbcfl, ibudfl, isuppress_output) ! ! -- Calculate and write simulated values for observations - if(this%inobs /= 0) then + if (this%inobs /= 0) then call this%gwt_gwt_save_simvals() - endif + end if ! ! -- return return end subroutine gwt_gwt_bdsav - + !> @ brief Output !! !! Write output @@ -684,46 +693,46 @@ subroutine gwt_gwt_ot(this) use SimVariablesModule, only: iout use ConstantsModule, only: DZERO, LINELENGTH ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local integer(I4B) :: iexg, n1, n2 integer(I4B) :: ibudfl real(DP) :: flow character(len=LINELENGTH) :: node1str, node2str ! -- format - character(len=*), parameter :: fmtheader = & - "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & + character(len=*), parameter :: fmtheader = & + "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & &2a16, 5a16, /, 112('-'))" - character(len=*), parameter :: fmtheader2 = & - "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & + character(len=*), parameter :: fmtheader2 = & + "(/1x, 'SUMMARY OF EXCHANGE RATES FOR EXCHANGE ', a, ' WITH ID ', i0, /, & &2a16, 4a16, /, 96('-'))" - character(len=*), parameter :: fmtdata = & - "(2a16, 5(1pg16.6))" + character(len=*), parameter :: fmtdata = & + "(2a16, 5(1pg16.6))" ! ! -- Call bdsave call this%gwt_gwt_bdsav() ! ! -- Write a table of exchanges - if(this%iprflow /= 0) then - write(iout, fmtheader2) trim(adjustl(this%name)), this%id, 'NODEM1', & - 'NODEM2', 'COND', 'X_M1', 'X_M2', 'FLOW' + if (this%iprflow /= 0) then + write (iout, fmtheader2) trim(adjustl(this%name)), this%id, 'NODEM1', & + 'NODEM2', 'COND', 'X_M1', 'X_M2', 'FLOW' do iexg = 1, this%nexg n1 = this%nodem1(iexg) n2 = this%nodem2(iexg) flow = this%simvals(iexg) call this%gwtmodel1%dis%noder_to_string(n1, node1str) call this%gwtmodel2%dis%noder_to_string(n2, node2str) - write(iout, fmtdata) trim(adjustl(node1str)), & - trim(adjustl(node2str)), & - this%cond(iexg), this%gwtmodel1%x(n1), & - this%gwtmodel2%x(n2), flow - enddo - endif + write (iout, fmtdata) trim(adjustl(node1str)), & + trim(adjustl(node2str)), & + this%cond(iexg), this%gwtmodel1%x(n1), & + this%gwtmodel2%x(n2), flow + end do + end if ! !cdl Implement when MVT is ready ! -- Mover budget output ibudfl = 1 - if(this%inmvt > 0) call this%mvt%mvt_ot_bdsummary(ibudfl) + if (this%inmvt > 0) call this%mvt%mvt_ot_bdsummary(ibudfl) ! ! -- OBS output call this%obs%obs_ot() @@ -740,24 +749,24 @@ end subroutine gwt_gwt_ot subroutine read_options(this, iout) ! -- modules use ConstantsModule, only: LINELENGTH, LENAUXNAME, DEM6 - use MemoryManagerModule, only: mem_allocate + use MemoryManagerModule, only: mem_allocate use SimModule, only: store_error, store_error_unit ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType integer(I4B), intent(in) :: iout ! -- local character(len=LINELENGTH) :: keyword logical :: isfound - logical :: endOfBlock + logical :: endOfBlock integer(I4B) :: ierr ! ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + call this%parser%GetBlock('OPTIONS', isfound, ierr, & + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING GWT-GWT EXCHANGE OPTIONS' + write (iout, '(1x,a)') 'PROCESSING GWT-GWT EXCHANGE OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) then @@ -776,12 +785,12 @@ subroutine read_options(this, iout) end if ! unknown option - errmsg = "Unknown GWT-GWT exchange option '" // trim(keyword) // "'." + errmsg = "Unknown GWT-GWT exchange option '"//trim(keyword)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() end do - write(iout,'(1x,a)') 'END OF GWT-GWT EXCHANGE OPTIONS' + write (iout, '(1x,a)') 'END OF GWT-GWT EXCHANGE OPTIONS' end if ! ! -- return @@ -792,11 +801,11 @@ end subroutine read_options !< function parse_option(this, keyword, iout) result(parsed) use InputOutputModule, only: getunit, openfile - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType character(len=LINELENGTH), intent(in) :: keyword !< the option name - integer(I4B), intent(in) :: iout !< for logging - logical(LGP) :: parsed !< true when parsed - ! local + integer(I4B), intent(in) :: iout !< for logging + logical(LGP) :: parsed !< true when parsed + ! local character(len=LINELENGTH) :: fname integer(I4B) :: inobs, ilen character(len=LINELENGTH) :: subkey @@ -808,103 +817,117 @@ function parse_option(this, keyword, iout) result(parsed) call this%parser%GetStringCaps(subkey) ilen = len_trim(subkey) if (ilen > LENMODELNAME) then - write(errmsg, '(4x,a,a)') & - 'INVALID MODEL NAME: ', trim(subkey) + write (errmsg, '(4x,a,a)') & + 'INVALID MODEL NAME: ', trim(subkey) call store_error(errmsg) call this%parser%StoreErrorUnit() end if if (this%gwfmodelname1 /= '') then call store_error('GWFMODELNAME1 has already been set to ' & - // trim(this%gwfmodelname1) // '. Cannot set more than once.') + //trim(this%gwfmodelname1)// & + '. Cannot set more than once.') call this%parser%StoreErrorUnit() end if this%gwfmodelname1 = subkey(1:LENMODELNAME) - write(iout,'(4x,a,a)') & + write (iout, '(4x,a,a)') & 'GWFMODELNAME1 IS SET TO: ', trim(this%gwfmodelname1) case ('GWFMODELNAME2') call this%parser%GetStringCaps(subkey) ilen = len_trim(subkey) if (ilen > LENMODELNAME) then - write(errmsg, '(4x,a,a)') & - 'INVALID MODEL NAME: ', trim(subkey) + write (errmsg, '(4x,a,a)') & + 'INVALID MODEL NAME: ', trim(subkey) call store_error(errmsg) call this%parser%StoreErrorUnit() end if if (this%gwfmodelname2 /= '') then call store_error('GWFMODELNAME2 has already been set to ' & - // trim(this%gwfmodelname2) // '. Cannot set more than once.') + //trim(this%gwfmodelname2)// & + '. Cannot set more than once.') call this%parser%StoreErrorUnit() end if this%gwfmodelname2 = subkey(1:LENMODELNAME) - write(iout,'(4x,a,a)') & + write (iout, '(4x,a,a)') & 'GWFMODELNAME2 IS SET TO: ', trim(this%gwfmodelname2) case ('PRINT_FLOWS') this%iprflow = 1 - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'EXCHANGE FLOWS WILL BE PRINTED TO LIST FILES.' case ('SAVE_FLOWS') this%ipakcb = -1 - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'EXCHANGE FLOWS WILL BE SAVED TO BINARY BUDGET FILES.' case ('MVT6') call this%parser%GetStringCaps(subkey) - if(subkey /= 'FILEIN') then - call store_error('MVT6 KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') + if (subkey /= 'FILEIN') then + call store_error('MVT6 KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetString(fname) - if(fname == '') then + if (fname == '') then call store_error('NO MVT6 FILE SPECIFIED.') call this%parser%StoreErrorUnit() - endif + end if this%inmvt = getunit() call openfile(this%inmvt, iout, fname, 'MVT') - write(iout,'(4x,a)') & + write (iout, '(4x,a)') & 'WATER MOVER TRANSPORT INFORMATION WILL BE READ FROM ', trim(fname) case ('OBS6') call this%parser%GetStringCaps(subkey) - if(subkey /= 'FILEIN') then - call store_error('OBS8 KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') + if (subkey /= 'FILEIN') then + call store_error('OBS8 KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') call this%parser%StoreErrorUnit() - endif + end if this%obs%active = .true. call this%parser%GetString(this%obs%inputFilename) inobs = GetUnit() call openfile(inobs, iout, this%obs%inputFilename, 'OBS') this%obs%inUnitObs = inobs - case ('ADVSCHEME') - !cdl todo: change to ADV_SCHEME? + case ('ADV_SCHEME') call this%parser%GetStringCaps(subkey) - select case(subkey) - case('UPSTREAM') + select case (subkey) + case ('UPSTREAM') this%iAdvScheme = 0 - case('CENTRAL') + case ('CENTRAL') this%iAdvScheme = 1 - case('TVD') + case ('TVD') this%iAdvScheme = 2 case default - errmsg = "Unknown weighting method for advection: '" // trim(subkey) // "'." + errmsg = "Unknown weighting method for advection: '"//trim(subkey)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() end select - write(iout,'(4x,a,a)') & + write (iout, '(4x,a,a)') & 'CELL AVERAGING METHOD HAS BEEN SET TO: ', trim(subkey) - case ('XT3D_OFF') - !cdl todo: change to DSP_XT3D_OFF? + case ('DSP_XT3D_OFF') this%ixt3d = 0 - write(iout, '(4x,a)') 'XT3D FORMULATION HAS BEEN SHUT OFF.' - case ('XT3D_RHS') - !cdl todo: change to DSP_XT3D_RHS? + write (iout, '(4x,a)') 'XT3D FORMULATION HAS BEEN SHUT OFF.' + case ('DSP_XT3D_RHS') this%ixt3d = 2 - write(iout, '(4x,a)') 'XT3D RIGHT-HAND SIDE FORMULATION IS SELECTED.' + write (iout, '(4x,a)') 'XT3D RIGHT-HAND SIDE FORMULATION IS SELECTED.' + case ('ADVSCHEME') + errmsg = 'ADVSCHEME is no longer a valid keyword. Use ADV_SCHEME & + &instead.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + case ('XT3D_OFF') + errmsg = 'XT3D_OFF is no longer a valid keyword. Use DSP_XT3D_OFF & + &instead.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + case ('XT3D_RHS') + errmsg = 'XT3D_RHS is no longer a valid keyword. Use DSP_XT3D_RHS & + &instead.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() case default parsed = .false. end select end function parse_option - + !> @ brief Read mover !! !! Read and process movers @@ -914,13 +937,13 @@ subroutine read_mvt(this, iout) ! -- modules use GwtMvtModule, only: mvt_cr ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType integer(I4B), intent(in) :: iout ! -- local ! ! -- Create and initialize the mover object Here, fmi is set to the one ! for gwtmodel1 so that a call to save flows has an associated dis - ! object. + ! object. call mvt_cr(this%mvt, this%name, this%inmvt, iout, this%gwtmodel1%fmi, & gwfmodelname1=this%gwfmodelname1, & gwfmodelname2=this%gwfmodelname2, & @@ -929,7 +952,7 @@ subroutine read_mvt(this, iout) ! -- Return return end subroutine read_mvt - + !> @ brief Allocate scalars !! !! Allocate scalar variables @@ -940,12 +963,12 @@ subroutine allocate_scalars(this) use MemoryManagerModule, only: mem_allocate use ConstantsModule, only: DZERO ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local ! call this%DisConnExchangeType%allocate_scalars() ! - call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) + call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) call mem_allocate(this%iprflow, 'IPRFLOW', this%memoryPath) call mem_allocate(this%ipakcb, 'IPAKCB', this%memoryPath) call mem_allocate(this%inobs, 'INOBS', this%memoryPath) @@ -973,35 +996,36 @@ subroutine gwt_gwt_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local ! ! -- objects if (this%inmvt > 0) then call this%mvt%mvt_da() - deallocate(this%mvt) - endif + deallocate (this%mvt) + end if call this%obs%obs_da() - deallocate(this%obs) + deallocate (this%obs) ! ! -- arrays - call mem_deallocate(this%cond) + call mem_deallocate(this%cond) call mem_deallocate(this%simvals) + call mem_deallocate(this%gwfsimvals, 'GWFSIMVALS', this%memoryPath) ! linked memory ! ! -- output table objects if (associated(this%outputtab1)) then call this%outputtab1%table_da() - deallocate(this%outputtab1) - nullify(this%outputtab1) + deallocate (this%outputtab1) + nullify (this%outputtab1) end if if (associated(this%outputtab2)) then call this%outputtab2%table_da() - deallocate(this%outputtab2) - nullify(this%outputtab2) + deallocate (this%outputtab2) + nullify (this%outputtab2) end if ! - ! -- scalars - deallocate(this%filename) + ! -- scalars + deallocate (this%filename) call mem_deallocate(this%inewton) call mem_deallocate(this%iprflow) call mem_deallocate(this%ipakcb) @@ -1015,7 +1039,7 @@ subroutine gwt_gwt_da(this) ! -- return return end subroutine gwt_gwt_da - + !> @ brief Allocate arrays !! !! Allocate arrays @@ -1025,13 +1049,13 @@ subroutine allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local character(len=LINELENGTH) :: text integer(I4B) :: ntabcol, i ! call this%DisConnExchangeType%allocate_arrays() - ! + ! call mem_allocate(this%cond, this%nexg, 'COND', this%memoryPath) call mem_allocate(this%simvals, this%nexg, 'SIMVALS', this%memoryPath) ! @@ -1052,7 +1076,7 @@ subroutine allocate_arrays(this) ! -- initialize the output table objects ! outouttab1 call table_cr(this%outputtab1, this%name, ' ') - call this%outputtab1%table_df(this%nexg, ntabcol, this%gwtmodel1%iout, & + call this%outputtab1%table_df(this%nexg, ntabcol, this%gwtmodel1%iout, & transient=.TRUE.) text = 'NUMBER' call this%outputtab1%initialize_column(text, 10, alignment=TABCENTER) @@ -1066,7 +1090,7 @@ subroutine allocate_arrays(this) end if ! outouttab2 call table_cr(this%outputtab2, this%name, ' ') - call this%outputtab2%table_df(this%nexg, ntabcol, this%gwtmodel2%iout, & + call this%outputtab2%table_df(this%nexg, ntabcol, this%gwtmodel2%iout, & transient=.TRUE.) text = 'NUMBER' call this%outputtab2%initialize_column(text, 10, alignment=TABCENTER) @@ -1091,7 +1115,7 @@ end subroutine allocate_arrays !< subroutine gwt_gwt_df_obs(this) ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local integer(I4B) :: indx ! @@ -1103,7 +1127,7 @@ subroutine gwt_gwt_df_obs(this) ! -- return return end subroutine gwt_gwt_df_obs - + !> @ brief Read and prepare observations !! !! Handle observation exchanges exchange-boundary names. @@ -1113,7 +1137,7 @@ subroutine gwt_gwt_rp_obs(this) ! -- modules use ConstantsModule, only: DZERO ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! -- local integer(I4B) :: i integer(I4B) :: j @@ -1121,15 +1145,15 @@ subroutine gwt_gwt_rp_obs(this) character(len=LENBOUNDNAME) :: bname logical :: jfound ! -- formats -10 format('Exchange "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') -20 format('Exchange id "',i0,'" for observation "',a, & - '" is invalid in package "',a,'"') +10 format('Exchange "', a, '" for observation "', a, & + '" is invalid in package "', a, '"') +20 format('Exchange id "', i0, '" for observation "', a, & + '" is invalid in package "', a, '"') ! do i = 1, this%obs%npakobs obsrv => this%obs%pakobs(i)%obsrv ! - ! -- indxbnds needs to be reset each stress period because + ! -- indxbnds needs to be reset each stress period because ! list of boundaries can change each stress period. ! -- Not true for exchanges, but leave this in for now anyway. call obsrv%ResetObsIndex() @@ -1141,18 +1165,18 @@ subroutine gwt_gwt_rp_obs(this) ! Iterate through all boundaries to identify and store ! corresponding index(indices) in bound array. jfound = .false. - do j=1,this%nexg + do j = 1, this%nexg if (this%boundname(j) == bname) then jfound = .true. obsrv%BndFound = .true. obsrv%CurrentTimeStepEndValue = DZERO call obsrv%AddObsIndex(j) - endif - enddo + end if + end do if (.not. jfound) then - write(errmsg, 10) trim(bname), trim(obsrv%ObsTypeId) , trim(this%name) + write (errmsg, 10) trim(bname), trim(obsrv%ObsTypeId), trim(this%name) call store_error(errmsg) - endif + end if else ! -- Observation location is a single exchange number if (obsrv%intPak1 <= this%nexg .and. obsrv%intPak1 > 0) then @@ -1162,23 +1186,23 @@ subroutine gwt_gwt_rp_obs(this) call obsrv%AddObsIndex(obsrv%intPak1) else jfound = .false. - endif + end if if (.not. jfound) then - write(errmsg, 20) obsrv%intPak1, trim(obsrv%ObsTypeId) , trim(this%name) + write (errmsg, 20) obsrv%intPak1, trim(obsrv%ObsTypeId), trim(this%name) call store_error(errmsg) - endif - endif - enddo + end if + end if + end do ! ! -- write summary of error messages if (count_errors() > 0) then call store_error_unit(this%inobs) - endif + end if ! ! -- Return return end subroutine gwt_gwt_rp_obs - + !> @ brief Final processing !! !! Conduct any final processing @@ -1186,40 +1210,52 @@ end subroutine gwt_gwt_rp_obs !< subroutine gwt_gwt_fp(this) ! -- dummy - class(GwtExchangeType) :: this !< GwtExchangeType + class(GwtExchangeType) :: this !< GwtExchangeType ! return end subroutine gwt_gwt_fp - - !> @brief Return true when this exchange provides matrix + + !> @brief Return true when this exchange provides matrix !! coefficients for solving @param model !< function gwt_gwt_connects_model(this, model) result(is_connected) - class(GwtExchangeType) :: this !< GwtExchangeType - class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection - logical(LGP) :: is_connected !< true, when connected + class(GwtExchangeType) :: this !< GwtExchangeType + class(BaseModelType), pointer, intent(in) :: model !< the model to which the exchange might hold a connection + logical(LGP) :: is_connected !< true, when connected is_connected = .false. ! only connected when model is GwtModelType of course - select type(model) - class is (GwtModelType) - if (associated(this%gwtmodel1, model)) then - is_connected = .true. - else if (associated(this%gwtmodel2, model)) then - is_connected = .true. - end if + select type (model) + class is (GwtModelType) + if (associated(this%gwtmodel1, model)) then + is_connected = .true. + else if (associated(this%gwtmodel2, model)) then + is_connected = .true. + end if end select end function gwt_gwt_connects_model !> @brief Should interface model be used for this exchange + !! + !! For now this always returns true, since we do not support + !! a classic-style two-point flux approximation for GWT-GWT. + !! If we ever add logic to support a simpler non-interface + !! model flux calculation, then logic should be added here to + !! set the return accordingly. !< function use_interface_model(this) result(useIM) class(GwtExchangeType) :: this !< GwtExchangeType - logical(LGP) :: useIM !< true when interface model should be used - - useIM = (this%ixt3d > 0) - + logical(LGP) :: useIM !< true when interface model should be used + + ! if support is added in the future for simpler flow calcuation, + ! then set useIM as follows + !useIM = (this%ixt3d > 0) + + ! For now set useIM to .true. since the interface model approach + ! must currently be used for any GWT-GWT exchange. + useIM = .true. + end function !> @ brief Save simulated flow observations @@ -1248,7 +1284,7 @@ subroutine gwt_gwt_save_simvals(this) call this%obs%obs_bd_clear() do i = 1, this%obs%npakobs obsrv => this%obs%pakobs(i)%obsrv - do j = 1, obsrv%indxbnds_count + do j = 1, obsrv%indxbnds_count iexg = obsrv%indxbnds(j) v = DZERO select case (obsrv%ObsTypeId) @@ -1257,15 +1293,15 @@ subroutine gwt_gwt_save_simvals(this) n2 = this%nodem2(iexg) v = this%simvals(iexg) case default - msg = 'Error: Unrecognized observation type: ' // & + msg = 'Error: Unrecognized observation type: '// & trim(obsrv%ObsTypeId) call store_error(msg) call store_error_unit(this%inobs) end select call this%obs%SaveOneSimval(obsrv, v) - enddo - enddo - endif + end do + end do + end if ! return end subroutine gwt_gwt_save_simvals @@ -1282,10 +1318,10 @@ subroutine gwt_gwt_process_obsID(obsrv, dis, inunitobs, iout) use ObserveModule, only: ObserveType use BaseDisModule, only: DisBaseType ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: n, iexg, istat integer(I4B) :: icol, istart, istop @@ -1307,7 +1343,7 @@ subroutine gwt_gwt_process_obsID(obsrv, dis, inunitobs, iout) ! boundaries, so assign intPak1 as a value that indicates observation ! is for a named exchange boundary or group of exchange boundaries. obsrv%intPak1 = NAMEDBOUNDFLAG - endif + end if ! return end subroutine gwt_gwt_process_obsID @@ -1317,7 +1353,7 @@ end subroutine gwt_gwt_process_obsID !! Cast polymorphic object as exchange !! !< - function CastAsGwtExchange(obj) result (res) + function CastAsGwtExchange(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(GwtExchangeType), pointer :: res @@ -1337,12 +1373,12 @@ end function CastAsGwtExchange !! Return an exchange from the list for specified index !! !< - function GetGwtExchangeFromList(list, idx) result (res) + function GetGwtExchangeFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(GwtExchangeType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(GwtExchangeType), pointer :: res ! -- local class(*), pointer :: obj ! @@ -1352,7 +1388,5 @@ function GetGwtExchangeFromList(list, idx) result (res) return end function GetGwtExchangeFromList - - end module GwtGwtExchangeModule diff --git a/src/Exchange/NumericalExchange.f90 b/src/Exchange/NumericalExchange.f90 index bba412b0127..8b9897f86d0 100644 --- a/src/Exchange/NumericalExchange.f90 +++ b/src/Exchange/NumericalExchange.f90 @@ -1,18 +1,18 @@ module NumericalExchangeModule - use KindModule, only: DP, I4B - use BaseModelModule, only: BaseModelType - use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList - use NumericalModelModule, only: NumericalModelType - use ListModule, only: ListType + use KindModule, only: DP, I4B + use BaseModelModule, only: BaseModelType + use BaseExchangeModule, only: BaseExchangeType, AddBaseExchangeToList + use NumericalModelModule, only: NumericalModelType + use ListModule, only: ListType implicit none private - public :: NumericalExchangeType, & + public :: NumericalExchangeType, & AddNumericalExchangeToList, GetNumericalExchangeFromList - type, extends(BaseExchangeType) :: NumericalExchangeType + type, extends(BaseExchangeType) :: NumericalExchangeType character(len=7) :: typename !< name of the type (e.g., 'GWF-GWF') contains procedure :: exg_df @@ -29,7 +29,7 @@ module NumericalExchangeModule procedure :: exg_bd procedure :: exg_ot procedure :: exg_da - procedure :: get_iasym + procedure :: get_iasym end type NumericalExchangeType contains @@ -61,7 +61,7 @@ subroutine exg_ac(this, sparse) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix ! -- dummy class(NumericalExchangeType) :: this type(sparsematrix), intent(inout) :: sparse @@ -80,7 +80,7 @@ subroutine exg_mc(this, iasln, jasln) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- module - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix ! -- dummy class(NumericalExchangeType) :: this integer(I4B), dimension(:), intent(in) :: iasln @@ -120,7 +120,7 @@ subroutine exg_ad(this) ! -- return return end subroutine exg_ad - + subroutine exg_cf(this, kiter) ! ****************************************************************************** ! exg_cf -- Calculate conductance, and for explicit exchanges, set the @@ -132,7 +132,7 @@ subroutine exg_cf(this, kiter) ! -- modules ! -- dummy class(NumericalExchangeType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter ! -- local ! ------------------------------------------------------------------------------ ! @@ -272,7 +272,7 @@ subroutine exg_da(this) return end subroutine exg_da - function get_iasym(this) result (iasym) + function get_iasym(this) result(iasym) class(NumericalExchangeType) :: this integer(I4B) :: iasym @@ -280,7 +280,7 @@ function get_iasym(this) result (iasym) end function get_iasym - function CastAsNumericalExchangeClass(obj) result (res) + function CastAsNumericalExchangeClass(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(NumericalExchangeType), pointer :: res @@ -298,7 +298,7 @@ end function CastAsNumericalExchangeClass subroutine AddNumericalExchangeToList(list, exchange) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(NumericalExchangeType), pointer, intent(in) :: exchange ! -- local class(*), pointer :: obj @@ -309,12 +309,12 @@ subroutine AddNumericalExchangeToList(list, exchange) return end subroutine AddNumericalExchangeToList - function GetNumericalExchangeFromList(list, idx) result (res) + function GetNumericalExchangeFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(NumericalExchangeType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(NumericalExchangeType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Model/BaseModel.f90 b/src/Model/BaseModel.f90 index 65c5b4fdef1..29a71992fd2 100644 --- a/src/Model/BaseModel.f90 +++ b/src/Model/BaseModel.f90 @@ -12,18 +12,17 @@ module BaseModelModule GetBaseModelFromList type :: BaseModelType - character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored + character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored - character(len=LENMODELNAME), pointer :: name => null() !< name of the model - character(len=3), pointer :: macronym => null() !< 3 letter model acronym (GWF, GWT, ...) - integer(I4B), pointer :: idsoln => null() !< id of the solution model is in - integer(I4B), pointer :: id => null() !< model id - integer(I4B), pointer :: iout => null() !< output unit number - integer(I4B), pointer :: inewton => null() !< newton-raphson flag - integer(I4B), pointer :: iprpak => null() !< integer flag to echo input - integer(I4B), pointer :: iprflow => null() !< flag to print simulated flows - integer(I4B), pointer :: ipakcb => null() !< save_flows flag - logical, pointer :: single_model_run => null() !< indicate if it is a single model run + character(len=LENMODELNAME), pointer :: name => null() !< name of the model + character(len=3), pointer :: macronym => null() !< 3 letter model acronym (GWF, GWT, ...) + integer(I4B), pointer :: idsoln => null() !< id of the solution model is in + integer(I4B), pointer :: id => null() !< model id + integer(I4B), pointer :: iout => null() !< output unit number + integer(I4B), pointer :: inewton => null() !< newton-raphson flag + integer(I4B), pointer :: iprpak => null() !< integer flag to echo input + integer(I4B), pointer :: iprflow => null() !< flag to print simulated flows + integer(I4B), pointer :: ipakcb => null() !< save_flows flag contains procedure :: model_df procedure :: model_ar @@ -36,8 +35,8 @@ module BaseModelModule procedure :: model_message end type BaseModelType - contains - +contains + subroutine model_df(this) ! ****************************************************************************** ! modeldf -- Define the model @@ -51,7 +50,7 @@ subroutine model_df(this) ! -- return return end subroutine model_df - + subroutine model_ar(this) ! ****************************************************************************** ! modelar -- Allocate and read @@ -65,7 +64,7 @@ subroutine model_ar(this) ! -- return return end subroutine model_ar - + subroutine model_rp(this) ! ****************************************************************************** ! model_rp -- Read and prepare @@ -79,7 +78,7 @@ subroutine model_rp(this) ! -- return return end subroutine model_rp - + subroutine model_calculate_delt(this) ! ****************************************************************************** ! model_calculate_delt -- Calculate time step length @@ -93,7 +92,7 @@ subroutine model_calculate_delt(this) ! -- return return end subroutine model_calculate_delt - + subroutine model_ot(this) ! ****************************************************************************** ! model_ot -- output results @@ -107,7 +106,7 @@ subroutine model_ot(this) ! -- return return end subroutine model_ot - + subroutine model_message(this, line, fmt) ! ****************************************************************************** ! model_message -- write line to model iout @@ -131,12 +130,12 @@ subroutine model_message(this, line, fmt) end if ! ! -- write line - write(this%iout, trim(cfmt)) trim(line) + write (this%iout, trim(cfmt)) trim(line) ! ! -- return return end subroutine model_message - + subroutine model_fp(this) ! ****************************************************************************** ! model_fp -- Final processing @@ -150,7 +149,7 @@ subroutine model_fp(this) ! -- return return end subroutine model_fp - + subroutine allocate_scalars(this, modelname) ! ****************************************************************************** ! allocate_scalars @@ -162,12 +161,11 @@ subroutine allocate_scalars(this, modelname) use MemoryManagerModule, only: mem_allocate ! -- dummy class(BaseModelType) :: this - character(len=*), intent(in) :: modelname + character(len=*), intent(in) :: modelname ! ------------------------------------------------------------------------------ ! - allocate(this%name) - allocate(this%macronym) - allocate(this%single_model_run) + call mem_allocate(this%name, LENMODELNAME, 'NAME', this%memoryPath) + call mem_allocate(this%macronym, 3, 'MACRONYM', this%memoryPath) call mem_allocate(this%id, 'ID', this%memoryPath) call mem_allocate(this%iout, 'IOUT', this%memoryPath) call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) @@ -185,12 +183,11 @@ subroutine allocate_scalars(this, modelname) this%iprflow = 0 this%ipakcb = 0 this%inewton = 0 !default is standard formulation - this%single_model_run = .false. ! ! -- return return end subroutine allocate_scalars - + subroutine model_da(this) ! ****************************************************************************** ! deallocate @@ -205,11 +202,10 @@ subroutine model_da(this) ! ------------------------------------------------------------------------------ ! ! -- Strings - deallocate(this%name) - deallocate(this%macronym) + call mem_deallocate(this%name, 'NAME', this%memoryPath) + call mem_deallocate(this%macronym, 'MACRONYM', this%memoryPath) ! ! -- Scalars - deallocate(this%single_model_run) call mem_deallocate(this%id) call mem_deallocate(this%iout) call mem_deallocate(this%inewton) @@ -222,7 +218,7 @@ subroutine model_da(this) return end subroutine model_da - function CastAsBaseModelClass(obj) result (res) + function CastAsBaseModelClass(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(BaseModelType), pointer :: res @@ -240,7 +236,7 @@ end function CastAsBaseModelClass subroutine AddBaseModelToList(list, model) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(BaseModelType), pointer, intent(inout) :: model ! -- local class(*), pointer :: obj @@ -250,13 +246,13 @@ subroutine AddBaseModelToList(list, model) ! return end subroutine AddBaseModelToList - - function GetBaseModelFromList(list, idx) result (res) + + function GetBaseModelFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(BaseModelType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(BaseModelType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Model/Connection/CellWithNbrs.f90 b/src/Model/Connection/CellWithNbrs.f90 index 20186bfa4c9..43c28cf4afd 100644 --- a/src/Model/Connection/CellWithNbrs.f90 +++ b/src/Model/Connection/CellWithNbrs.f90 @@ -1,65 +1,68 @@ module CellWithNbrsModule use KindModule, only: I4B, LGP use NumericalModelModule, only: NumericalModelType + use DistributedModelModule, only: DistributedModelType implicit none private integer(I4B), parameter :: defaultCapacity = 6 !> Data structure to hold a global cell identifier, - !! using a pointer to the model and its local cell + !! using a pointer to the model and its local cell !< index type, public :: GlobalCellType - integer(I4B) :: index !< the index on the model grid - class(NumericalModelType), pointer :: model => null() !< the model + integer(I4B) :: index !< the index on the model grid + class(DistributedModelType), pointer :: dmodel => null() !< distributed model end type - + ! a global cell with neighbors type, public :: CellWithNbrsType type(GlobalCellType) :: cell integer(I4B) :: nrOfNbrs = 0 - type(CellWithNbrsType), dimension(:), pointer, contiguous :: neighbors => null() + type(CellWithNbrsType), dimension(:), pointer, & + contiguous :: neighbors => null() contains procedure :: addNbrCell end type - contains +contains - subroutine addNbrCell(this, index, modelToAdd) + subroutine addNbrCell(this, index, dist_model) class(CellWithNbrsType) :: this integer(I4B) :: index - class(NumericalModelType), pointer :: modelToAdd + class(DistributedModelType), pointer :: dist_model ! TODO_MJR: this will replace the model pointer entirely ! local integer(I4B) :: nbrCnt, currentSize, i - type(CellWithNbrsType), dimension(:), pointer, contiguous :: newNeighbors - type(CellWithNbrsType), dimension(:), pointer, contiguous :: oldNeighbors + type(CellWithNbrsType), dimension(:), pointer, contiguous :: newNeighbors + type(CellWithNbrsType), dimension(:), pointer, contiguous :: oldNeighbors if (.not. associated(this%neighbors)) then - allocate(this%neighbors(defaultCapacity)) + allocate (this%neighbors(defaultCapacity)) this%nrOfNbrs = 0 end if - + nbrCnt = this%nrOfNbrs currentSize = size(this%neighbors) if (nbrCnt + 1 > currentSize) then ! inflate oldNeighbors => this%neighbors - allocate(newNeighbors(currentSize + defaultCapacity)) - do i=1, currentSize + allocate (newNeighbors(currentSize + defaultCapacity)) + do i = 1, currentSize newNeighbors(i) = oldNeighbors(i) end do this%neighbors => newNeighbors ! clean up - deallocate(oldNeighbors) - nullify(oldNeighbors) + deallocate (oldNeighbors) + nullify (oldNeighbors) end if - + this%neighbors(nbrCnt + 1)%cell%index = index - this%neighbors(nbrCnt + 1)%cell%model => modelToAdd + this%neighbors(nbrCnt + 1)%cell%dmodel => dist_model + this%nrOfNbrs = nbrCnt + 1 - + end subroutine addNbrCell -end module \ No newline at end of file +end module diff --git a/src/Model/Connection/ConnectionBuilder.f90 b/src/Model/Connection/ConnectionBuilder.f90 index 66f5e2f08ba..df0988b51a8 100644 --- a/src/Model/Connection/ConnectionBuilder.f90 +++ b/src/Model/Connection/ConnectionBuilder.f90 @@ -6,38 +6,38 @@ module ConnectionBuilderModule use BaseSolutionModule, only: BaseSolutionType use NumericalSolutionModule, only: NumericalSolutionType use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList - use DisConnExchangeModule, only: DisConnExchangeType, & - GetDisConnExchangeFromList + use DisConnExchangeModule, only: DisConnExchangeType, & + GetDisConnExchangeFromList use NumericalModelModule, only: NumericalModelType use SpatialModelConnectionModule, only: SpatialModelConnectionType, & - CastAsSpatialModelConnectionClass, & - GetSpatialModelConnectionFromList, & - AddSpatialModelConnectionToList - - implicit none + CastAsSpatialModelConnectionClass, & + GetSpatialModelConnectionFromList, & + AddSpatialModelConnectionToList + + implicit none private - + type, public :: ConnectionBuilderType contains procedure, pass(this) :: processSolution procedure, private, pass(this) :: processExchanges procedure, private, pass(this) :: setConnectionsToSolution procedure, private, pass(this) :: assignExchangesToConnections - end type ConnectionBuilderType - - contains + end type ConnectionBuilderType + +contains !> @brief Process the exchanges in the solution into model connections !! !! This routine processes all exchanges in a solution and, - !! when required, creates model connections of the proper + !! when required, creates model connections of the proper !! type (GWF-GWF, GWT-GWT, ...) for a subset. It removes this !! subset of exchanges from the solution and replaces them with the !! created connections. !< subroutine processSolution(this, solution) - class(ConnectionBuilderType) :: this !< the connection builder object - class(BaseSolutionType), pointer :: solution !< the solution for which the exchanges are processed + class(ConnectionBuilderType) :: this !< the connection builder object + class(BaseSolutionType), pointer :: solution !< the solution for which the exchanges are processed ! local class(NumericalSolutionType), pointer :: numSol type(ListType) :: newConnections @@ -54,10 +54,10 @@ subroutine processSolution(this, solution) call this%processExchanges(numSol%exchangelist, newConnections) if (newConnections%Count() == 0) then return - end if + end if - write(iout,'(1x,a,i0,a,a)') 'Created ', newConnections%Count(), & - ' model connections for solution ', trim(solution%name) + write (iout, '(1x,a,i0,a,a)') 'Created ', newConnections%Count(), & + ' model connections for solution ', trim(solution%name) ! set the global exchanges from this solution to ! the model connections @@ -73,16 +73,16 @@ end subroutine processSolution !> @brief Create connections from exchanges !! - !! If the configuration demands it, this will create connections, + !! If the configuration demands it, this will create connections, !! for the exchanges (one connection per exchange) add them to !! the global list, and return them as @param newConnections !< subroutine processExchanges(this, exchanges, newConnections) use ListsModule, only: baseconnectionlist, baseexchangelist use VersionModule, only: IDEVELOPMODE - class(ConnectionBuilderType) :: this !< the connection builder object - type(ListType), pointer, intent(in) :: exchanges !< the list of exchanges to process - type(ListType), intent(inout) :: newConnections !< the newly created connections + class(ConnectionBuilderType) :: this !< the connection builder object + type(ListType), pointer, intent(in) :: exchanges !< the list of exchanges to process + type(ListType), intent(inout) :: newConnections !< the newly created connections ! local class(DisConnExchangeType), pointer :: conEx class(BaseExchangeType), pointer :: baseEx @@ -96,10 +96,11 @@ subroutine processExchanges(this, exchanges, newConnections) ! Force use of the interface model dev_always_ifmod = .false. if (IDEVELOPMODE == 1) then - call get_environment_variable('DEV_ALWAYS_USE_IFMOD', value=envvar, status=status) + call get_environment_variable('DEV_ALWAYS_USE_IFMOD', & + value=envvar, status=status) if (status == 0 .and. envvar == '1') then dev_always_ifmod = .true. - write(*,'(a,/)') "### Experimental: forcing interface model ###" + write (*, '(a,/)') "### Experimental: forcing interface model ###" end if end if @@ -109,17 +110,17 @@ subroutine processExchanges(this, exchanges, newConnections) ! if it is not DisConnExchangeType, we can skip it continue end if - + ! for now, if we have XT3D on the interface, we use a connection, - ! (this will be more generic in the future) - if (conEx%use_interface_model() .or. conEx%dev_ifmod_on & + ! (this will be more generic in the future) + if (conEx%use_interface_model() .or. conEx%dev_ifmod_on & .or. dev_always_ifmod) then ! we should not get period connections here isPeriodic = associated(conEx%model1, conEx%model2) if (isPeriodic) then - write(*,*) 'Error (which should never happen): interface model '// & - 'does not support periodic boundary condition' + write (*, *) 'Error (which should never happen): interface model '// & + 'does not support periodic boundary condition' call ustop() end if @@ -128,7 +129,7 @@ subroutine processExchanges(this, exchanges, newConnections) call AddSpatialModelConnectionToList(baseconnectionlist, modelConnection) call AddSpatialModelConnectionToList(newConnections, modelConnection) - ! and for model 2, unless periodic + ! and for model 2, unless periodic modelConnection => createModelConnection(conEx%model2, conEx) call AddSpatialModelConnectionToList(baseconnectionlist, modelConnection) call AddSpatialModelConnectionToList(newConnections, modelConnection) @@ -142,7 +143,7 @@ subroutine processExchanges(this, exchanges, newConnections) exit end if end do - + end if end do @@ -158,45 +159,45 @@ function createModelConnection(model, exchange) result(connection) use GwfGwfConnectionModule, only: GwfGwfConnectionType use GwtGwtConnectionModule, only: GwtGwtConnectionType use GwfModule, only: GwfModelType - - class(NumericalModelType), pointer , intent(in) :: model !< the model for which the connection will be created + + class(NumericalModelType), pointer, intent(in) :: model !< the model for which the connection will be created class(DisConnExchangeType), pointer, intent(in) :: exchange !< the type of connection - class(SpatialModelConnectionType), pointer :: connection !< the created connection - + class(SpatialModelConnectionType), pointer :: connection !< the created connection + ! different concrete connection types: class(GwfGwfConnectionType), pointer :: flowConnection => null() class(GwtGwtConnectionType), pointer :: transportConnection => null() - + connection => null() - + ! select on type of connection to create - select case(exchange%typename) - case('GWF-GWF') - allocate(GwfGwfConnectionType :: flowConnection) - call flowConnection%construct(model, exchange) - connection => flowConnection - flowConnection => null() - case('GWT-GWT') - allocate(GwtGwtConnectionType :: transportConnection) - call transportConnection%construct(model, exchange) - connection => transportConnection - transportConnection => null() - case default - write(*,*) 'Error (which should never happen): undefined exchangetype found' - call ustop() - end select - + select case (exchange%typename) + case ('GWF-GWF') + allocate (GwfGwfConnectionType :: flowConnection) + call flowConnection%construct(model, exchange) + connection => flowConnection + flowConnection => null() + case ('GWT-GWT') + allocate (GwtGwtConnectionType :: transportConnection) + call transportConnection%construct(model, exchange) + connection => transportConnection + transportConnection => null() + case default + write (*, *) 'Error (which should never happen): '// & + 'undefined exchangetype found' + call ustop() + end select + end function createModelConnection - - + !> @brief Set connections to the solution !! - !! This adds the connections to the solution and removes + !! This adds the connections to the solution and removes !! those exchanges which are replaced by a connection !< subroutine setConnectionsToSolution(this, connections, solution) - class(ConnectionBuilderType) :: this !< the connection builder object - type(ListType), intent(inout) :: connections !< the connections created for the solution + class(ConnectionBuilderType) :: this !< the connection builder object + type(ListType), intent(inout) :: connections !< the connections created for the solution class(NumericalSolutionType), pointer, intent(in) :: solution !< the solution to which the connections are set ! local type(ListType) :: keepList @@ -211,7 +212,7 @@ subroutine setConnectionsToSolution(this, connections, solution) ! will this exchange be replaced by a connection? keepExchange = .true. do iconn = 1, connections%Count() - conn => GetSpatialModelConnectionFromList(connections,iconn) + conn => GetSpatialModelConnectionFromList(connections, iconn) exPtr2 => conn%primaryExchange if (associated(exPtr2, exPtr)) then ! if so, don't add it to the list @@ -252,9 +253,9 @@ end subroutine setConnectionsToSolution !! connected, through yet another exchange object. !< subroutine assignExchangesToConnections(this, exchanges, connections) - class(ConnectionBuilderType) :: this !< the connection builder object - type(ListType), pointer, intent(in) :: exchanges !< all exchanges in a solution - type(ListType), intent(inout) :: connections !< all connections that are created for this solution + class(ConnectionBuilderType) :: this !< the connection builder object + type(ListType), pointer, intent(in) :: exchanges !< all exchanges in a solution + type(ListType), intent(inout) :: connections !< all connections that are created for this solution ! local integer(I4B) :: iex, iconn class(DisConnExchangeType), pointer :: conEx @@ -284,8 +285,7 @@ subroutine assignExchangesToConnections(this, exchanges, connections) ! clean call keepList%Clear(destroy=.false.) - + end subroutine assignExchangesToConnections - - + end module ConnectionBuilderModule diff --git a/src/Model/Connection/CsrUtils.f90 b/src/Model/Connection/CsrUtils.f90 index 0bd0847cce5..70e72e00845 100644 --- a/src/Model/Connection/CsrUtils.f90 +++ b/src/Model/Connection/CsrUtils.f90 @@ -2,31 +2,31 @@ module CsrUtilsModule implicit none private - + public :: getCSRIndex - + contains - + !> @brief Return index for element i,j in CSR storage, !< returns -1 when not there function getCSRIndex(i, j, ia, ja) result(csrIndex) use KindModule, only: I4B - integer(I4B), intent(in) :: i !< the row index - integer(I4B), intent(in) :: j !< the column index - integer(I4B), dimension(:), intent(in) :: ia !< CSR ia array - integer(I4B), dimension(:), intent(in) :: ja !< CSR ja array - integer(I4B) :: csrIndex !< the CSR ndex of element i,j + integer(I4B), intent(in) :: i !< the row index + integer(I4B), intent(in) :: j !< the column index + integer(I4B), dimension(:), intent(in) :: ia !< CSR ia array + integer(I4B), dimension(:), intent(in) :: ja !< CSR ja array + integer(I4B) :: csrIndex !< the CSR ndex of element i,j ! local integer(I4B) :: idx - + csrIndex = -1 - do idx = ia(i), ia(i+1)-1 + do idx = ia(i), ia(i + 1) - 1 if (ja(idx) == j) then csrIndex = idx return end if end do - - end function -end module \ No newline at end of file + end function + +end module diff --git a/src/Model/Connection/DistributedData.f90 b/src/Model/Connection/DistributedData.f90 new file mode 100644 index 00000000000..2426b722908 --- /dev/null +++ b/src/Model/Connection/DistributedData.f90 @@ -0,0 +1,318 @@ +module DistributedDataModule + use ConstantsModule, only: LENMEMPATH, LENCOMPONENTNAME, LENVARNAME + use KindModule, only: I4B, LGP + use MemoryTypeModule, only: MemoryType + use MemoryHelperModule, only: create_mem_path + use MemoryListModule, only: MemoryListType + use ListModule, only: ListType + use MappedVariableModule, only: MappedVariableType, CastAsMappedVariable + use InterfaceMapModule + + implicit none + private + + ! stages for synchronization + integer(I4B), public, parameter :: BEFORE_AR = 1 + integer(I4B), public, parameter :: AFTER_AR = 2 + integer(I4B), public, parameter :: BEFORE_AD = 3 + integer(I4B), public, parameter :: BEFORE_CF = 4 + integer(I4B), public, parameter :: BEFORE_FC = 5 + + ! types of variables + integer(I4B), public, parameter :: SYNC_SCALAR = 0 + integer(I4B), public, parameter :: SYNC_NODES = 1 + integer(I4B), public, parameter :: SYNC_CONNECTIONS = 2 + integer(I4B), public, parameter :: SYNC_EXCHANGES = 3 + + type, public :: DistVarType + character(len=LENVARNAME) :: var_name !< name of variable, e.g. "K11" + character(len=LENCOMPONENTNAME) :: subcomp_name !< subcomponent, e.g. "NPF" + character(len=LENCOMPONENTNAME) :: comp_name !< component, e.g. the model or exchange name + integer(I4B) :: map_type !< can be 0 = scalar, 1 = node based, 2 = connection based, + !! 3 = exchange based (connections crossing model boundaries) + character(len=LENVARNAME) :: exg_var_name !< needed for exchange variables, e.g. SIMVALS + integer(I4B), dimension(:), allocatable :: sync_stages !< when to sync, e.g. (/ STAGE_AD, STAGE_CF /) + !! which is before AD and CF + end type DistVarType + + type, public :: DistributedDataType + type(MemoryListType) :: remote_memory_list !< all remote data as a list of MemoryType + type(ListType) :: variable_list !< all distributed variables, NB: not necessarily 1-to-1 + !!with list of data items + contains + procedure :: map_variables + procedure :: get_dist_data + procedure :: synchronize + procedure :: destroy + + procedure, private :: map_model_data + procedure, private :: map_exg_data + procedure, private :: map_data + procedure, private :: print_variables + end type DistributedDataType + + ! HACK: global access + type(DistributedDataType), public :: distributed_data + +contains + + subroutine map_variables(this, sol_id, dist_vars, interface_map) + class(DistributedDataType) :: this + integer(I4B) :: sol_id + type(ListType) :: dist_vars + type(InterfaceMapType), pointer :: interface_map + ! local + integer(I4B) :: i, m, e + type(DistVarType), pointer :: distvar + type(IndexMapType), pointer :: idx_map + + ! loop over variables + do i = 1, dist_vars%Count() + distvar => GetDistVarFromList(dist_vars, i) + if (distvar%map_type == SYNC_NODES .or. & + distvar%map_type == SYNC_CONNECTIONS) then + ! map data for all models in this interface + do m = 1, interface_map%nr_models + + ! pick the right index map: connection based or node based + if (distvar%map_type == SYNC_NODES) then + idx_map => interface_map%node_map(m) + else if (distvar%map_type == SYNC_CONNECTIONS) then + idx_map => interface_map%connection_map(m) + end if + + ! and map ... + call distributed_data%map_model_data(sol_id, & + distvar%comp_name, & + distvar%subcomp_name, & + distvar%var_name, & + interface_map%model_names(m), & + idx_map, & + distvar%sync_stages) + end do + else if (distvar%map_type == SYNC_EXCHANGES) then + ! map data from the exchanges to the interface + do e = 1, interface_map%nr_exchanges + call distributed_data%map_exg_data(sol_id, & + distvar%comp_name, & + distvar%subcomp_name, & + distvar%var_name, & + interface_map%exchange_names(e), & + distvar%exg_var_name, & + interface_map%exchange_map(e), & + distvar%sync_stages) + end do + end if + end do + + end subroutine map_variables + + !> @brief Map data from model memory to a target memory entry, + !! with the specified map. The source and target items have + !< the same name and (optionally) subcomponent name. + subroutine map_model_data(this, controller_id, tgt_model_name, & + tgt_subcomp_name, tgt_var_name, src_model_name, & + index_map, stages) + use SimModule, only: ustop + use MemoryManagerModule, only: get_from_memorylist + class(DistributedDataType) :: this + integer(I4B) :: controller_id !< e.g. the numerical solution where synchr. is controlled + character(len=*), intent(in) :: tgt_model_name + character(len=*), intent(in) :: tgt_subcomp_name + character(len=*), intent(in) :: tgt_var_name + character(len=*), intent(in) :: src_model_name + type(IndexMapType), intent(in) :: index_map + integer(I4B), dimension(:), intent(in) :: stages !< array with 1 or multiple stages for synchronization + ! local + character(len=LENVARNAME) :: src_var_name + character(len=LENMEMPATH) :: src_mem_path, tgt_mem_path + + if (len_trim(tgt_subcomp_name) > 0) then + src_mem_path = create_mem_path(src_model_name, tgt_subcomp_name) + tgt_mem_path = create_mem_path(tgt_model_name, tgt_subcomp_name) + else + src_mem_path = create_mem_path(src_model_name) + tgt_mem_path = create_mem_path(tgt_model_name) + end if + + src_var_name = tgt_var_name + call this%map_data(controller_id, & + tgt_var_name, tgt_mem_path, index_map%tgt_idx, & + src_var_name, src_mem_path, index_map%src_idx, & + null(), stages) + + end subroutine map_model_data + + !> @brief Map memory from a Exchange to the specified memory entry, + !< using the index map + subroutine map_exg_data(this, controller_id, tgt_model_name, & + tgt_subcomp_name, tgt_var_name, src_exg_name, & + src_var_name, index_map_sgn, stages) + use SimModule, only: ustop + use MemoryManagerModule, only: get_from_memorylist + class(DistributedDataType) :: this + integer(I4B) :: controller_id !< e.g. the numerical solution where synchr. is controlled + character(len=*), intent(in) :: tgt_model_name + character(len=*), intent(in) :: tgt_subcomp_name + character(len=*), intent(in) :: tgt_var_name + character(len=*), intent(in) :: src_exg_name + character(len=*), intent(in) :: src_var_name + type(IndexMapSgnType), intent(in) :: index_map_sgn + integer(I4B), dimension(:), intent(in) :: stages !< array with 1 or multiple stages for synchronization + ! local + character(len=LENMEMPATH) :: src_mem_path, tgt_mem_path + + src_mem_path = create_mem_path(src_exg_name) + if (len_trim(tgt_subcomp_name) > 0) then + tgt_mem_path = create_mem_path(tgt_model_name, tgt_subcomp_name) + else + tgt_mem_path = create_mem_path(tgt_model_name) + end if + + call this%map_data(controller_id, & + tgt_var_name, tgt_mem_path, index_map_sgn%tgt_idx, & + src_var_name, src_mem_path, index_map_sgn%src_idx, & + index_map_sgn%sign, stages) + + end subroutine map_exg_data + + !> @brief Generic mapping between two variables in memory, using + !! an optional sign conversion + !< + subroutine map_data(this, controller_id, tgt_name, tgt_path, tgt_idx, & + src_name, src_path, src_idx, sign_array, stages) + class(DistributedDataType) :: this + integer(I4B) :: controller_id + character(len=*), intent(in) :: tgt_name + character(len=*), intent(in) :: tgt_path + integer(I4B), dimension(:), pointer :: tgt_idx + character(len=*), intent(in) :: src_name + character(len=*), intent(in) :: src_path + integer(I4B), dimension(:), pointer :: src_idx + integer(I4B), dimension(:), pointer :: sign_array + integer(I4B), dimension(:), intent(in) :: stages + ! local + integer(I4B) :: istage, i + type(MappedVariableType), pointer :: mapped_var + class(*), pointer :: obj + + ! loop and set stage bits + istage = 0 + do i = 1, size(stages) + istage = ibset(istage, stages(i)) + end do + + ! create MappedVariable and add to list + allocate (mapped_var) + mapped_var%controller_id = controller_id + mapped_var%sync_stage = istage + mapped_var%src_name = src_name + mapped_var%src_path = src_path + mapped_var%src => null() + mapped_var%tgt_name = tgt_name + mapped_var%tgt_path = tgt_path + mapped_var%tgt => null() + mapped_var%src_idx => src_idx + mapped_var%tgt_idx => tgt_idx + mapped_var%sign => sign_array + obj => mapped_var + call this%variable_list%Add(obj) + + end subroutine map_data + + function get_dist_data(this) result(dist_data) + class(DistributedDataType) :: this + type(MemoryType), pointer :: dist_data + + ! get from memory list + + end function get_dist_data + + subroutine synchronize(this, controller_id, stage) + class(DistributedDataType) :: this + integer(I4B) :: controller_id + integer(I4B), intent(in) :: stage + ! local + integer(I4B) :: i + class(*), pointer :: obj + class(MappedVariableType), pointer :: var + + ! sync all variables (src => tgt) for a given stage + do i = 1, this%variable_list%Count() + obj => this%variable_list%GetItem(i) + var => CastAsMappedVariable(obj) + if (controller_id > 0 .and. var%controller_id /= controller_id) cycle + if (.not. check_stage(var%sync_stage, stage)) cycle + + ! copy data + call var%sync() + end do + + end subroutine synchronize + + function check_stage(var_stage, current_stage) result(is_sync) + integer(I4B) :: var_stage + integer(I4B) :: current_stage + logical(LGP) :: is_sync + + is_sync = iand(var_stage, ibset(0, current_stage)) == ibset(0, current_stage) + + end function check_stage + + subroutine destroy(this) + class(DistributedDataType) :: this + + !call this%print_variables() + + call this%variable_list%Clear(destroy=.true.) + call this%remote_memory_list%clear() + + end subroutine destroy + + function GetDistVarFromList(list, idx) result(res) + implicit none + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(DistVarType), pointer :: res + ! local + class(*), pointer :: obj + + obj => list%GetItem(idx) + res => CastAsDistVar(obj) + return + + end function GetDistVarFromList + + function CastAsDistVar(obj) result(res) + implicit none + class(*), pointer, intent(inout) :: obj + class(DistVarType), pointer :: res + + res => null() + if (.not. associated(obj)) return + + select type (obj) + class is (DistVarType) + res => obj + end select + return + end function CastAsDistVar + + subroutine print_variables(this) + class(DistributedDataType) :: this + ! local + integer(I4B) :: i + class(*), pointer :: obj + class(MappedVariableType), pointer :: var + + write (*, *) "Debug: print variables..." + do i = 1, this%variable_list%Count() + obj => this%variable_list%GetItem(i) + var => CastAsMappedVariable(obj) + write (*, *) trim(var%src%name), " ", trim(var%src%path), & + " to ", trim(var%tgt%name), " ", trim(var%tgt%path) + end do + + end subroutine print_variables + +end module DistributedDataModule diff --git a/src/Model/Connection/DistributedModel.f90 b/src/Model/Connection/DistributedModel.f90 new file mode 100644 index 00000000000..92a0b39a6d2 --- /dev/null +++ b/src/Model/Connection/DistributedModel.f90 @@ -0,0 +1,244 @@ +module DistributedModelModule + use KindModule, only: I4B, DP, LGP + use ConstantsModule, only: LENMODELNAME, LENCOMPONENTNAME, & + LENVARNAME, LENMEMPATH + use SimModule, only: ustop + use ListModule, only: ListType + use MemoryTypeModule, only: MemoryType + use MemoryManagerModule, only: get_from_memorylist + use MemoryHelperModule, only: create_mem_path + use NumericalModelModule, only: NumericalModelType, GetNumericalModelFromList, & + AddNumericalModelToList + + use ListsModule, only: basemodellist, distmodellist + implicit none + private + + public :: add_dist_model + public :: GetDistModelFromList, AddDistModelToList + + type, public :: DistributedModelType + integer(I4B) :: id !< universal identifier: id of the model + character(len=LENMODELNAME) :: name !< model name + + ! cached variables: + integer(I4B), pointer :: moffset => null() + + ! this is strictly private, use access() instead + class(NumericalModelType), private, pointer :: model !< implementation if local, null otherwise + contains + generic :: create => create_local, create_remote + generic :: load => load_intsclr, load_int1d, load_dblsclr, load_double1d + generic :: operator(==) => equals_dist_model, equals_num_model + procedure :: access + + ! private + procedure, private :: create_local + procedure, private :: create_remote + procedure, private :: load_intsclr + procedure, private :: load_int1d + procedure, private :: load_dblsclr + procedure, private :: load_double1d + procedure, private :: equals_dist_model + procedure, private :: equals_num_model + end type DistributedModelType + +contains + + subroutine add_dist_model(model_index) + integer :: model_index + ! local + class(NumericalModelType), pointer :: num_model + class(DistributedModelType), pointer :: dist_model + + num_model => GetNumericalModelFromList(basemodellist, model_index) + + allocate (dist_model) + call dist_model%create_local(num_model) + call AddDistModelToList(distmodellist, dist_model) + + end subroutine add_dist_model + + subroutine create_local(this, model) + class(DistributedModelType) :: this + class(NumericalModelType), pointer :: model + + this%id = model%id + this%name = model%name + this%model => model + + ! connect cached variables + call this%load(this%moffset, 'MOFFSET') + + end subroutine create_local + + subroutine create_remote(this, m_id) + class(DistributedModelType) :: this + integer(I4B) :: m_id + + this%id = m_id + this%name = 'TBD' + this%model => null() + + ! TODO_MJR: this should prepare a memory space + ! where the remote data can live, and then + ! also connect cache (if we decide to use that) + + end subroutine create_remote + + subroutine load_intsclr(this, intsclr, var_name, subcomp_name) + class(DistributedModelType) :: this + integer(I4B), pointer :: intsclr + character(len=*) :: var_name + character(len=*), optional :: subcomp_name + ! local + type(MemoryType), pointer :: mt + logical(LGP) :: found + character(len=LENMEMPATH) :: mem_path + + if (present(subcomp_name)) then + mem_path = create_mem_path(this%name, subcomp_name) + else + mem_path = create_mem_path(this%name) + end if + + call get_from_memorylist(var_name, mem_path, mt, found) + intsclr => mt%intsclr + + end subroutine load_intsclr + + subroutine load_int1d(this, aint1d, var_name, subcomp_name) + class(DistributedModelType) :: this + integer(I4B), dimension(:), pointer, contiguous :: aint1d + character(len=*) :: var_name + character(len=*), optional :: subcomp_name + ! local + character(len=LENMEMPATH) :: mem_path + type(MemoryType), pointer :: mt + logical(LGP) :: found + + if (present(subcomp_name)) then + mem_path = create_mem_path(this%name, subcomp_name) + else + mem_path = create_mem_path(this%name) + end if + + call get_from_memorylist(var_name, mem_path, mt, found) + aint1d => mt%aint1d + + end subroutine load_int1d + + subroutine load_dblsclr(this, dblsclr, var_name, subcomp_name) + class(DistributedModelType) :: this + real(DP), pointer :: dblsclr + character(len=*) :: var_name + character(len=*), optional :: subcomp_name + ! local + type(MemoryType), pointer :: mt + logical(LGP) :: found + character(len=LENMEMPATH) :: mem_path + + if (present(subcomp_name)) then + mem_path = create_mem_path(this%name, subcomp_name) + else + mem_path = create_mem_path(this%name) + end if + + call get_from_memorylist(var_name, mem_path, mt, found) + dblsclr => mt%dblsclr + + end subroutine load_dblsclr + + subroutine load_double1d(this, adbl1d, var_name, subcomp_name) + class(DistributedModelType) :: this + real(DP), dimension(:), pointer, contiguous :: adbl1d + character(len=*) :: var_name + character(len=*), optional :: subcomp_name + ! local + character(len=LENMEMPATH) :: mem_path + type(MemoryType), pointer :: mt + logical(LGP) :: found + + if (present(subcomp_name)) then + mem_path = create_mem_path(this%name, subcomp_name) + else + mem_path = create_mem_path(this%name) + end if + + call get_from_memorylist(var_name, mem_path, mt, found) + adbl1d => mt%adbl1d + + end subroutine load_double1d + + function equals_dist_model(this, dist_model) result(is_equal) + class(DistributedModelType), intent(in) :: this + class(DistributedModelType), intent(in) :: dist_model + logical(LGP) :: is_equal + + is_equal = (this%id == dist_model%id) + + end function equals_dist_model + + function equals_num_model(this, num_model) result(is_equal) + class(DistributedModelType), intent(in) :: this + class(NumericalModelType), intent(in) :: num_model + logical(LGP) :: is_equal + + is_equal = (this%id == num_model%id) + + end function equals_num_model + + function access(this) result(model) + class(DistributedModelType) :: this + class(NumericalModelType), pointer :: model + + if (associated(this%model)) then + model => this%model + else + write (*, *) 'Error: illegal access to remote memory, abort' + call ustop() + end if + + end function access + + function CastAsDistModelClass(obj) result(res) + class(*), pointer, intent(inout) :: obj + class(DistributedModelType), pointer :: res + + res => null() + if (.not. associated(obj)) return + + select type (obj) + class is (DistributedModelType) + res => obj + end select + return + + end function CastAsDistModelClass + + subroutine AddDistModelToList(list, model) + type(ListType), intent(inout) :: list + class(DistributedModelType), pointer, intent(inout) :: model + ! local + class(*), pointer :: obj + + obj => model + call list%Add(obj) + return + + end subroutine AddDistModelToList + + function GetDistModelFromList(list, idx) result(res) + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(DistributedModelType), pointer :: res + ! local + class(*), pointer :: obj + + obj => list%GetItem(idx) + res => CastAsDistModelClass(obj) + return + + end function GetDistModelFromList + +end module DistributedModelModule diff --git a/src/Model/Connection/GridConnection.f90 b/src/Model/Connection/GridConnection.f90 index 70a915783d0..51c25d1f5ff 100644 --- a/src/Model/Connection/GridConnection.f90 +++ b/src/Model/Connection/GridConnection.f90 @@ -1,25 +1,35 @@ +!> Refactoring issues towards parallel: +!! +!! * remove camelCase +!< module GridConnectionModule use KindModule, only: I4B, DP, LGP use SimModule, only: ustop - use ConstantsModule, only: LENMEMPATH, DZERO, DPIO180 + use ConstantsModule, only: LENMEMPATH, DZERO, DPIO180, LENMODELNAME use MemoryManagerModule, only: mem_allocate, mem_deallocate use MemoryHelperModule, only: create_mem_path use ListModule, only: ListType, isEqualIface, arePointersEqual use NumericalModelModule use GwfDisuModule use DisConnExchangeModule + use DistributedModelModule, only: DistributedModelType, GetDistModelFromList, & + AddDistModelToList use CellWithNbrsModule - use ConnectionsModule + use ConnectionsModule use SparseModule, only: sparsematrix + use InterfaceMapModule + use BaseDisModule, only: dis_transform_xy + use ListsModule, only: distmodellist + use CsrUtilsModule implicit none private - + ! Initial nr of neighbors for sparse matrix allocation integer(I4B), parameter :: InitNrNeighbors = 7 - + !> This class is used to construct the connections object for !! the interface model's spatial discretization/grid. - !! + !! !! It works as follows: !! !! 1: construct basic instance, allocate data structures @@ -47,46 +57,43 @@ module GridConnectionModule integer(I4B) :: internalStencilDepth !< stencil size for the interior integer(I4B) :: exchangeStencilDepth !< stencil size at the interface - class(NumericalModelType), pointer :: model => null() !< the model for which this grid connection exists - - integer(I4B), pointer :: nrOfBoundaryCells => null() !< nr of boundary cells with connection to another model - type(CellWithNbrsType), dimension(:), pointer :: boundaryCells => null() !< cells on our side of the primary connections - type(CellWithNbrsType), dimension(:), pointer :: connectedCells => null() !< cells on the neighbors side of the primary connection - type(ListType) :: exchanges !< all relevant exchanges for this connection, up to - !! the required depth - - integer, dimension(:), pointer :: primConnections => null() !< table mapping the index in the boundaryCells/connectedCells - !< arrays into a connection index for e.g. access to flowja - - integer(I4B), pointer :: nrOfCells => null() !< the total number of cells in the interface - type(GlobalCellType), dimension(:), pointer :: idxToGlobal => null() !< a map from interface index to global coordinate + class(NumericalModelType), pointer :: model => null() !< the model for which this grid connection exists + class(DisConnExchangeType), pointer :: primaryExchange => null() !< pointer to the primary exchange for this interface + + integer(I4B), pointer :: nrOfBoundaryCells => null() !< nr of boundary cells with connection to another model + type(CellWithNbrsType), dimension(:), pointer :: boundaryCells => null() !< cells on our side of the primary connections + type(CellWithNbrsType), dimension(:), pointer :: connectedCells => null() !< cells on the neighbors side of the primary connection + type(ListType) :: exchanges !< all relevant exchanges for this connection, up to the required depth + + integer(I4B), pointer :: nrOfCells => null() !< the total number of cells in the interface + type(GlobalCellType), dimension(:), pointer :: idxToGlobal => null() !< a map from interface index to global coordinate integer(I4B), dimension(:), pointer, contiguous :: idxToGlobalIdx => null() !< a (flat) map from interface index to global index, !! stored in mem. mgr. so can be used for debugging - - integer(I4B), dimension(:), pointer :: regionalToInterfaceIdxMap => null() !< (sparse) mapping from regional index to interface ixd - type(ListType) :: regionalModels !< the models participating in the interface - integer(I4B), dimension(:), pointer :: regionalModelOffset => null() !< the new offset to compactify the range of indices - integer(I4B), pointer :: indexCount => null() !< counts the number of cells in the interface - type(ConnectionsType), pointer :: connections => null() !< sparse matrix with the connections - integer(I4B), dimension(:), pointer :: connectionMask => null() !< to mask out connections from the amat coefficient calculation - + + integer(I4B), dimension(:), pointer :: regionalToInterfaceIdxMap => null() !< (sparse) mapping from regional index to interface ixd + type(ListType) :: regionalModels !< the models participating in the interface + integer(I4B), dimension(:), pointer :: regionalModelOffset => null() !< the new offset to compactify the range of indices + integer(I4B), pointer :: indexCount => null() !< counts the number of cells in the interface + type(ConnectionsType), pointer :: connections => null() !< sparse matrix with the connections + integer(I4B), dimension(:), pointer :: connectionMask => null() !< to mask out connections from the amat coefficient calculation + contains + ! public procedure, pass(this) :: construct procedure, private, pass(this) :: allocateScalars - procedure, public, pass(this) :: destroy - procedure, pass(this) :: connectCell + procedure, pass(this) :: destroy + procedure, pass(this) :: connectPrimaryExchange procedure, pass(this) :: findModelNeighbors procedure, pass(this) :: extendConnection - generic :: getInterfaceIndex => getInterfaceIndexByCell, & - getInterfaceIndexByIndexModel - procedure, pass(this) :: getDiscretization - + procedure, pass(this) :: getInterfaceMap + ! 'protected' procedure, pass(this) :: isPeriodic - + ! private routines + procedure, private, pass(this) :: connectCell procedure, private, pass(this) :: buildConnections procedure, private, pass(this) :: addNeighbors procedure, private, pass(this) :: addNeighborCell @@ -94,6 +101,8 @@ module GridConnectionModule procedure, private, pass(this) :: addModelNeighbors procedure, private, pass(this) :: addToRegionalModels procedure, private, pass(this) :: getRegionalModelOffset + generic, private :: getInterfaceIndex => getInterfaceIndexByCell, & + getInterfaceIndexByIndexModel procedure, private, pass(this) :: getInterfaceIndexByCell procedure, private, pass(this) :: getInterfaceIndexByIndexModel procedure, private, pass(this) :: registerInterfaceCells @@ -107,103 +116,128 @@ module GridConnectionModule procedure, private, pass(this) :: createConnectionMask procedure, private, pass(this) :: maskInternalConnections procedure, private, pass(this) :: setMaskOnConnection - procedure, private, pass(this) :: createLookupTable end type - - contains + +contains !> @brief Construct the GridConnection and allocate !! the data structures for the primary connections !< subroutine construct(this, model, nrOfPrimaries, connectionName) - class(GridConnectionType), intent(inout) :: this !> this instance - class(NumericalModelType), pointer, intent(in) :: model !> the model for which the interface is constructed - integer(I4B) :: nrOfPrimaries !> the number of primary connections between the two models - character(len=*) :: connectionName !> the name, for memory management mostly + class(GridConnectionType), intent(inout) :: this !> this instance + class(NumericalModelType), pointer, intent(in) :: model !> the model for which the interface is constructed + integer(I4B) :: nrOfPrimaries !> the number of primary connections between the two models + character(len=*) :: connectionName !> the name, for memory management mostly ! local + class(DistributedModelType), pointer :: dist_model this%model => model this%memoryPath = create_mem_path(connectionName, 'GC') call this%allocateScalars() - - allocate(this%boundaryCells(nrOfPrimaries)) - allocate(this%connectedCells(nrOfPrimaries)) - allocate(this%primConnections(nrOfPrimaries)) - allocate(this%idxToGlobal(2*nrOfPrimaries)) - - call this%addToRegionalModels(model) - + + allocate (this%boundaryCells(nrOfPrimaries)) + allocate (this%connectedCells(nrOfPrimaries)) + allocate (this%idxToGlobal(2 * nrOfPrimaries)) + + dist_model => GetDistModelFromList(distmodellist, model%id) + call this%addToRegionalModels(dist_model) + this%nrOfBoundaryCells = 0 this%internalStencilDepth = 1 this%exchangeStencilDepth = 1 end subroutine construct - + + !> @brief Make connections for the primary exchange + !< + subroutine connectPrimaryExchange(this, primEx) + class(GridConnectionType) :: this !< this grid connection + class(DisConnExchangeType), pointer :: primEx !< the primary exchange for this connection + ! local + integer(I4B) :: iconn + + ! store the primary exchange + this%primaryExchange => primEx + + ! connect the cells + do iconn = 1, primEx%nexg + call this%connectCell(primEx%nodem1(iconn), primEx%dmodel1, & + primEx%nodem2(iconn), primEx%dmodel2) + end do + + end subroutine connectPrimaryExchange + !> @brief Connect neighboring cells at the interface by !! storing them in the boundary cell and connected cell !! arrays !< - subroutine connectCell(this, idx1, model1, idx2, model2) - class(GridConnectionType), intent(in) :: this !< this grid connection - integer(I4B) :: idx1 !< local index cell 1 - class(NumericalModelType), pointer :: model1 !< model of cell 1 - integer(I4B) :: idx2 !< local index cell 2 - class(NumericalModelType), pointer :: model2 !< model of cell 2 - - this%nrOfBoundaryCells = this%nrOfBoundaryCells + 1 + subroutine connectCell(this, idx1, dist_model1, idx2, dist_model2) + class(GridConnectionType), intent(in) :: this !< this grid connection + integer(I4B) :: idx1 !< local index cell 1 + class(DistributedModelType), pointer :: dist_model1 !< model of cell 1 + integer(I4B) :: idx2 !< local index cell 2 + class(DistributedModelType), pointer :: dist_model2 !< model of cell 2 + ! local + type(GlobalCellType), pointer :: bnd_cell, conn_cell + + this%nrOfBoundaryCells = this%nrOfBoundaryCells + 1 if (this%nrOfBoundaryCells > size(this%boundaryCells)) then - write(*,*) 'Error: nr of cell connections exceeds capacity in grid connection, terminating...' + write (*, *) 'Error: nr of cell connections exceeds '// & + 'capacity in grid connection, terminating...' call ustop() end if - - if (associated(model1, this%model)) then - this%boundaryCells(this%nrOfBoundaryCells)%cell%index = idx1 - this%boundaryCells(this%nrOfBoundaryCells)%cell%model => this%model - - this%connectedCells(this%nrOfBoundaryCells)%cell%index = idx2 - this%connectedCells(this%nrOfBoundaryCells)%cell%model => model2 - else if (associated(model2, this%model)) then - this%boundaryCells(this%nrOfBoundaryCells)%cell%index = idx2 - this%boundaryCells(this%nrOfBoundaryCells)%cell%model => this%model - - this%connectedCells(this%nrOfBoundaryCells)%cell%index = idx1 - this%connectedCells(this%nrOfBoundaryCells)%cell%model => model1 + + bnd_cell => this%boundaryCells(this%nrOfBoundaryCells)%cell + conn_cell => this%connectedCells(this%nrOfBoundaryCells)%cell + if (dist_model1 == this%model) then + bnd_cell%index = idx1 + bnd_cell%dmodel => dist_model1 + conn_cell%index = idx2 + conn_cell%dmodel => dist_model2 + else if (dist_model2 == this%model) then + bnd_cell%index = idx2 + bnd_cell%dmodel => dist_model2 + conn_cell%index = idx1 + conn_cell%dmodel => dist_model1 else - write(*,*) 'Error: unable to connect cells outside the model' + write (*, *) 'Error: unable to connect cells outside the model' call ustop() end if - - end subroutine connectCell + end subroutine connectCell !> @brief Create the tree structure with all model nbrs, nbrs-of-nbrs, !< etc. for this model up to the specified depth subroutine findModelNeighbors(this, globalExchanges, depth) class(GridConnectionType), intent(inout) :: this !< this grid connection type(ListType), intent(inout) :: globalExchanges !< list with global exchanges - integer(I4B) :: depth !< the maximal number of exchanges between - !! any two models in the topology + integer(I4B) :: depth !< the maximal number of exchanges between + !! any two models in the topology + ! local + class(DistributedModelType), pointer :: dist_model - call this%addModelNeighbors(this%model, globalExchanges, depth) + dist_model => GetDistModelFromList(distmodellist, this%model%id) + call this%addModelNeighbors(dist_model, globalExchanges, depth) end subroutine findModelNeighbors - !> @brief Add neighbors and nbrs-of-nbrs to the model tree - !< - recursive subroutine addModelNeighbors(this, model, globalExchanges, depth, mask) - class(GridConnectionType), intent(inout) :: this !< this grid connection - class(NumericalModelType), pointer, intent(inout) :: model !< the model to add neighbors for - type(ListType), intent(inout) :: globalExchanges !< list with all exchanges - integer(I4B) :: depth !< the maximal number of exchanges between - class(NumericalModelType), pointer, optional :: mask !< don't add this one a neighbor + !< + recursive subroutine addModelNeighbors(this, dist_model, & + globalExchanges, & + depth, mask) + class(GridConnectionType), intent(inout) :: this !< this grid connection + class(DistributedModelType), pointer, intent(inout) :: dist_model !< the model to add neighbors for + type(ListType), intent(inout) :: globalExchanges !< list with all exchanges + integer(I4B) :: depth !< the maximal number of exchanges between + class(DistributedModelType), pointer, optional :: mask !< don't add this one as a neighbor ! local integer(I4B) :: i, n class(DisConnExchangeType), pointer :: connEx - class(NumericalModelType), pointer :: neighborModel - class(NumericalModelType), pointer :: modelMask + class(DistributedModelType), pointer :: neighborModel + class(DistributedModelType), pointer :: modelMask type(ListType) :: nbrModels class(*), pointer :: objPtr procedure(isEqualIface), pointer :: areEqualMethod @@ -214,22 +248,25 @@ recursive subroutine addModelNeighbors(this, model, globalExchanges, depth, mask modelMask => mask end if - ! first find all direct neighbors of the model and add them, + ! first find all direct neighbors of the model and add them, ! avoiding duplicates do i = 1, globalExchanges%Count() - neighborModel => null() connEx => GetDisConnExchangeFromList(globalExchanges, i) - if (associated(model, connEx%model1)) then - neighborModel => connEx%model2 - else if (associated(model, connEx%model2)) then - neighborModel => connEx%model1 + if (connEx%dmodel1 == dist_model) then + neighborModel => connEx%dmodel2 + else if (connEx%dmodel2 == dist_model) then + neighborModel => connEx%dmodel1 end if ! check if there is a neighbor, and it is not masked ! (to prevent back-and-forth connections) - if (associated(neighborModel) .and. .not. & - associated(neighborModel, modelMask)) then + if (associated(neighborModel)) then + + ! check if masked + if (associated(modelMask)) then + if (neighborModel == modelMask) cycle + end if ! add to neighbors objPtr => neighborModel @@ -249,14 +286,15 @@ recursive subroutine addModelNeighbors(this, model, globalExchanges, depth, mask end if end do - + ! now recurse on the neighbors up to the specified depth depth = depth - 1 if (depth == 0) return - + do n = 1, nbrModels%Count() - neighborModel => GetNumericalModelFromList(nbrModels, n) - call this%addModelNeighbors(neighborModel, globalExchanges, depth, model) + neighborModel => GetDistModelFromList(nbrModels, n) + call this%addModelNeighbors(neighborModel, globalExchanges, & + depth, dist_model) end do ! clear list @@ -264,25 +302,24 @@ recursive subroutine addModelNeighbors(this, model, globalExchanges, depth, mask end subroutine addModelNeighbors - !> @brief Add a model to a list of all regional models !< subroutine addToRegionalModels(this, modelToAdd) - class(GridConnectionType), intent(inout) :: this !< this grid connection - class(NumericalModelType), pointer :: modelToAdd !< the model to add to the region + class(GridConnectionType), intent(inout) :: this !< this grid connection + class(DistributedModelType), pointer :: modelToAdd !< the model to add to the region ! local - class(*), pointer :: mPtr + class(*), pointer :: mPtr procedure(isEqualIface), pointer :: areEqualMethod mPtr => modelToAdd areEqualMethod => arePointersEqual if (.not. this%regionalModels%ContainsObject(mPtr, areEqualMethod)) then - call AddNumericalModelToList(this%regionalModels, modelToAdd) + call AddDistModelToList(this%regionalModels, modelToAdd) end if - + end subroutine addToRegionalModels - !> @brief Extend the connection topology to deal with + !> @brief Extend the connection topology to deal with !! higher levels of connectivity (neighbors-of-neighbors, etc.) !! !! The following steps are taken: @@ -291,49 +328,51 @@ end subroutine addToRegionalModels !! 3. Allocate a (sparse) mapping table for the region !! 4. Build connection object for the interface grid, and the mask !< - subroutine extendConnection(this) + subroutine extendConnection(this) class(GridConnectionType), intent(inout) :: this !< this grid connection - ! local + ! local integer(I4B) :: remoteDepth, localDepth integer(I4B) :: icell integer(I4B) :: imod, regionSize, offset - class(NumericalModelType), pointer :: numModel - + class(DistributedModelType), pointer :: dist_model + integer(I4B), pointer :: nr_nodes + ! we need (stencildepth-1) extra cells for the interior remoteDepth = this%exchangeStencilDepth - localDepth = 2*this%internalStencilDepth - 1 + localDepth = 2 * this%internalStencilDepth - 1 if (localDepth < remoteDepth) then localDepth = remoteDepth end if - - ! first add the neighbors for the interior + + ! first add the neighbors for the interior ! (possibly extending into other models) do icell = 1, this%nrOfBoundaryCells - call this%addNeighbors(this%boundaryCells(icell), localDepth, & + call this%addNeighbors(this%boundaryCells(icell), localDepth, & this%connectedCells(icell)%cell, .true.) end do ! and for the exterior do icell = 1, this%nrOfBoundaryCells - call this%addNeighbors(this%connectedCells(icell), remoteDepth, & + call this%addNeighbors(this%connectedCells(icell), remoteDepth, & this%boundaryCells(icell)%cell, .false.) end do - + ! set up mapping for the region (models participating in interface model grid) - allocate(this%regionalModelOffset(this%regionalModels%Count())) + allocate (this%regionalModelOffset(this%regionalModels%Count())) regionSize = 0 offset = 0 do imod = 1, this%regionalModels%Count() - numModel => GetNumericalModelFromList(this%regionalModels, imod) - regionSize = regionSize + numModel%dis%nodes + dist_model => GetDistModelFromList(this%regionalModels, imod) + call dist_model%load(nr_nodes, 'NODES', 'DIS') + regionSize = regionSize + nr_nodes this%regionalModelOffset(imod) = offset - offset = offset + numModel%dis%nodes + offset = offset + nr_nodes end do ! init to -1, meaning 'interface index was not assigned yet' - allocate(this%regionalToInterfaceIdxMap(regionSize)) + allocate (this%regionalToInterfaceIdxMap(regionSize)) this%regionalToInterfaceIdxMap = -1 - + call this%buildConnections() - + end subroutine extendConnection !> @brief Builds a sparse matrix holding all cell connections, @@ -343,12 +382,12 @@ subroutine buildConnections(this) ! local integer(I4B) :: icell, iconn integer(I4B), dimension(:), allocatable :: nnz - type(SparseMatrix), pointer :: sparse - integer(I4B) :: ierror + type(SparseMatrix), pointer :: sparse + integer(I4B) :: ierror type(ConnectionsType), pointer :: conn - + ! Recursively generate interface cell indices, fill map to global cells, - ! and add to region lookup table + ! and add to region lookup table this%indexCount = 0 do icell = 1, this%nrOfBoundaryCells call this%registerInterfaceCells(this%boundaryCells(icell)) @@ -363,20 +402,20 @@ subroutine buildConnections(this) ! sort interface indexes such that 'n > m' means 'n below m' call this%sortInterfaceGrid() - + ! allocate a map from interface index to global coordinates - call mem_allocate(this%idxToGlobalIdx, this%nrOfCells, & + call mem_allocate(this%idxToGlobalIdx, this%nrOfCells, & 'IDXTOGLOBALIDX', this%memoryPath) - + ! create sparse data structure, to temporarily hold connections - allocate(sparse) - allocate(nnz(this%nrOfCells)) - nnz = InitNrNeighbors+1 + allocate (sparse) + allocate (nnz(this%nrOfCells)) + nnz = InitNrNeighbors + 1 call sparse%init(this%nrOfCells, this%nrOfCells, nnz) - - ! now (recursively) add connections to sparse, start with + + ! now (recursively) add connections to sparse, start with ! the primary connections (n-m from the exchange files) - call this%makePrimaryConnections(sparse) + call this%makePrimaryConnections(sparse) ! then into own domain do icell = 1, this%nrOfBoundaryCells call this%connectNeighborCells(this%boundaryCells(icell), sparse) @@ -385,163 +424,164 @@ subroutine buildConnections(this) do icell = 1, this%nrOfBoundaryCells call this%connectNeighborCells(this%connectedCells(icell), sparse) end do - - ! create connections object - allocate(this%connections) - conn => this%connections + + ! create connections object + allocate (this%connections) + conn => this%connections call conn%allocate_scalars(this%memoryPath) conn%nodes = this%nrOfCells conn%nja = sparse%nnz - conn%njas = (conn%nja - conn%nodes) / 2 + conn%njas = (conn%nja - conn%nodes) / 2 call conn%allocate_arrays() do iconn = 1, conn%njas conn%anglex(iconn) = -999. end do ! fill connection from sparse - call sparse%filliaja(conn%ia, conn%ja, ierror) + call sparse%filliaja(conn%ia, conn%ja, ierror) if (ierror /= 0) then - write(*,*) 'Error filling ia/ja in GridConnection: terminating...' + write (*, *) 'Error filling ia/ja in GridConnection: terminating...' call ustop() - end if + end if call fillisym(conn%nodes, conn%nja, conn%ia, conn%ja, conn%isym) - call filljas(conn%nodes, conn%nja, conn%ia, conn%ja, conn%isym, conn%jas) + call filljas(conn%nodes, conn%nja, conn%ia, conn%ja, conn%isym, conn%jas) call sparse%destroy() - - ! fill connection data (ihc, cl1, cl2, etc.) using data + + ! fill connection data (ihc, cl1, cl2, etc.) using data ! from models and exchanges - call this%fillConnectionDataInternal() + call this%fillConnectionDataInternal() call this%fillConnectionDataFromExchanges() - + ! set the masks on connections call this%createConnectionMask() - ! create lookup table(s) - call this%createLookupTable() - - end subroutine buildConnections + end subroutine buildConnections - !< @brief Routine for finding neighbors-of-neighbors, recursively !< recursive subroutine addNeighbors(this, cellNbrs, depth, mask, interior) use SimModule, only: ustop - class(GridConnectionType), intent(inout) :: this !< this grid connection - type(CellWithNbrsType), intent(inout) :: cellNbrs !< cell to add to - integer(I4B), intent(inout) :: depth !< current depth (typically decreases in recursion) - type(GlobalCellType), optional :: mask !< mask to excluded back-and-forth connection between cells - logical(LGP) :: interior !< when true, we are adding from the exchange back into the model + class(GridConnectionType), intent(inout) :: this !< this grid connection + type(CellWithNbrsType), intent(inout) :: cellNbrs !< cell to add to + integer(I4B), intent(inout) :: depth !< current depth (typically decreases in recursion) + type(GlobalCellType), optional :: mask !< mask to excluded back-and-forth connection between cells + logical(LGP) :: interior !< when true, we are adding from the exchange back into the model ! local - integer(I4B) :: nbrIdx, ipos, inbr - type(ConnectionsType), pointer :: conn - integer(I4B) :: newDepth - + integer(I4B) :: nbrIdx, ipos, inbr + integer(I4B) :: newDepth + + ! TODO_MJR, is this how we are going to do this? + integer(I4B), dimension(:), pointer, contiguous :: ia + integer(I4B), dimension(:), pointer, contiguous :: ja + ! if depth == 1, then we are not adding neighbors but use ! the boundary and connected cell only if (depth < 2) then return end if newDepth = depth - 1 - - conn => cellNbrs%cell%model%dis%con - + + ! access through dist. model: + call cellNbrs%cell%dmodel%load(ia, 'IA', 'CON') + call cellNbrs%cell%dmodel%load(ja, 'JA', 'CON') + ! find neighbors local to this cell by looping through grid connections - do ipos=conn%ia(cellNbrs%cell%index) + 1, conn%ia(cellNbrs%cell%index+1) - 1 - nbrIdx = conn%ja(ipos) - call this%addNeighborCell(cellNbrs, nbrIdx, cellNbrs%cell%model, mask) + do ipos = ia(cellNbrs%cell%index) + 1, & + ia(cellNbrs%cell%index + 1) - 1 + nbrIdx = ja(ipos) + call this%addNeighborCell(cellNbrs, nbrIdx, cellNbrs%cell%dmodel, mask) end do - + ! add remote nbr using the data from the exchanges call this%addRemoteNeighbors(cellNbrs, mask) - + ! now find nbr-of-nbr - do inbr=1, cellNbrs%nrOfNbrs + do inbr = 1, cellNbrs%nrOfNbrs ! are we leaving the model through another exchange? - if (interior .and. associated(cellNbrs%cell%model, this%model)) then - if (.not. associated(cellNbrs%neighbors(inbr)%cell%model, this%model)) then + if (interior .and. cellNbrs%cell%dmodel == this%model) then + if (.not. cellNbrs%neighbors(inbr)%cell%dmodel == this%model) then ! decrement by 1, because the connection we are crossing is not ! calculated by this interface newDepth = newDepth - 1 - end if + end if end if ! and add neigbors with the new depth - call this%addNeighbors(cellNbrs%neighbors(inbr), newDepth, & + call this%addNeighbors(cellNbrs%neighbors(inbr), newDepth, & cellNbrs%cell, interior) end do - + end subroutine addNeighbors - + !> @brief Add cell neighbors across models using the stored exchange !! data structures subroutine addRemoteNeighbors(this, cellNbrs, mask) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(CellWithNbrsType), intent(inout) :: cellNbrs !< cell to add to - type(GlobalCellType), optional :: mask !< a mask to exclude back-and-forth connections + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(CellWithNbrsType), intent(inout) :: cellNbrs !< cell to add to + type(GlobalCellType), optional :: mask !< a mask to exclude back-and-forth connections ! local integer(I4B) :: ix, iexg type(DisConnExchangeType), pointer :: connEx - - ! loop over all exchanges - do ix = 1, this%exchanges%Count() + + ! loop over all exchanges + do ix = 1, this%exchanges%Count() connEx => GetDisConnExchangeFromList(this%exchanges, ix) ! loop over n-m links in the exchange - if (associated(cellNbrs%cell%model, connEx%model1)) then + if (cellNbrs%cell%dmodel == connEx%dmodel1) then do iexg = 1, connEx%nexg if (connEx%nodem1(iexg) == cellNbrs%cell%index) then ! we have a link, now add foreign neighbor - call this%addNeighborCell(cellNbrs, connEx%nodem2(iexg), & - connEx%model2, mask) + call this%addNeighborCell(cellNbrs, connEx%nodem2(iexg), & + connEx%dmodel2, mask) end if end do end if ! and the reverse - if (associated(cellNbrs%cell%model, connEx%model2)) then + if (cellNbrs%cell%dmodel == connEx%dmodel2) then do iexg = 1, connEx%nexg if (connEx%nodem2(iexg) == cellNbrs%cell%index) then ! we have a link, now add foreign neighbor - call this%addNeighborCell(cellNbrs, connEx%nodem1(iexg), & - connEx%model1, mask) + call this%addNeighborCell(cellNbrs, connEx%nodem1(iexg), & + connEx%dmodel1, mask) end if end do end if - + end do - + end subroutine addRemoteNeighbors - !> @brief Add neighboring cell to tree structure !< - subroutine addNeighborCell(this, cellNbrs, newNbrIdx, nbrModel, mask) - class(GridConnectionType), intent(in) :: this !< this grid connection instance - type(CellWithNbrsType), intent(inout) :: cellNbrs !< the root cell which to add to - integer(I4B), intent(in) :: newNbrIdx !< the neigboring cell's index - class(NumericalModelType), pointer :: nbrModel !< the model where the new neighbor lives - type(GlobalCellType), optional :: mask !< don't add connections to this cell (optional) - ! local - + subroutine addNeighborCell(this, cellNbrs, newNbrIdx, nbr_dist_model, mask) + class(GridConnectionType), intent(in) :: this !< this grid connection instance + type(CellWithNbrsType), intent(inout) :: cellNbrs !< the root cell which to add to + integer(I4B), intent(in) :: newNbrIdx !< the neigboring cell's index + class(DistributedModelType), pointer :: nbr_dist_model !< the model where the new neighbor lives + type(GlobalCellType), optional :: mask !< don't add connections to this cell (optional) + if (present(mask)) then - if (newNbrIdx == mask%index .and. associated(nbrModel, mask%model)) then + if (newNbrIdx == mask%index .and. mask%dmodel == nbr_dist_model) then return end if end if - call cellNbrs%addNbrCell(newNbrIdx, nbrModel) + + call cellNbrs%addNbrCell(newNbrIdx, nbr_dist_model) end subroutine addNeighborCell - + !> @brief Recursively set interface cell indexes and !< add to the region-to-interface loopup table recursive subroutine registerInterfaceCells(this, cellWithNbrs) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(CellWithNbrsType) :: cellWithNbrs !< the cell from where to start registering neighbors + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(CellWithNbrsType) :: cellWithNbrs !< the cell from where to start registering neighbors ! local integer(I4B) :: offset, inbr - integer(I4B) :: regionIdx ! unique idx in the region (all connected models) - integer(I4B) :: ifaceIdx ! unique idx in the interface grid - - offset = this%getRegionalModelOffset(cellWithNbrs%cell%model) + integer(I4B) :: regionIdx ! unique idx in the region (all connected models) + integer(I4B) :: ifaceIdx ! unique idx in the interface grid + + offset = this%getRegionalModelOffset(cellWithNbrs%cell%dmodel) regionIdx = offset + cellWithNbrs%cell%index ifaceIdx = this%getInterfaceIndex(cellWithNbrs%cell) if (ifaceIdx == -1) then @@ -550,20 +590,20 @@ recursive subroutine registerInterfaceCells(this, cellWithNbrs) call this%addToGlobalMap(ifaceIdx, cellWithNbrs%cell) this%regionalToInterfaceIdxMap(regionIdx) = ifaceIdx end if - + ! and also for its neighbors do inbr = 1, cellWithNbrs%nrOfNbrs call this%registerInterfaceCells(cellWithNbrs%neighbors(inbr)) end do - + end subroutine registerInterfaceCells !> @brief Add entry to lookup table, inflating when necessary !< subroutine addToGlobalMap(this, ifaceIdx, cell) class(GridConnectionType), intent(inout) :: this !< this grid connection instance - integer(I4B), intent(in) :: ifaceIdx !< unique idx in the interface grid - type(GlobalCellType), intent(in) :: cell !< the global cell + integer(I4B), intent(in) :: ifaceIdx !< unique idx in the interface grid + type(GlobalCellType), intent(in) :: cell !< the global cell ! local integer(I4B) :: i, currentSize, newSize type(GlobalCellType), dimension(:), pointer :: tempMap @@ -571,13 +611,13 @@ subroutine addToGlobalMap(this, ifaceIdx, cell) ! inflate? currentSize = size(this%idxToGlobal) if (ifaceIdx > currentSize) then - newSize = nint(1.5*currentSize) - allocate(tempMap(newSize)) + newSize = nint(1.5 * currentSize) + allocate (tempMap(newSize)) do i = 1, currentSize tempMap(i) = this%idxToGlobal(i) end do - - deallocate(this%idxToGlobal) + + deallocate (this%idxToGlobal) this%idxToGlobal => tempMap end if @@ -593,12 +633,12 @@ subroutine compressGlobalMap(this) type(GlobalCellType), dimension(:), pointer :: tempMap if (size(this%idxToGlobal) > this%nrOfCells) then - allocate(tempMap(this%nrOfCells)) + allocate (tempMap(this%nrOfCells)) tempMap(1:this%nrOfCells) = this%idxToGlobal(1:this%nrOfCells) - deallocate(this%idxToGlobal) - allocate(this%idxToGlobal(this%nrOfCells)) + deallocate (this%idxToGlobal) + allocate (this%idxToGlobal(this%nrOfCells)) this%idxToGlobal(1:this%nrOfCells) = tempMap(1:this%nrOfCells) - deallocate(tempMap) + deallocate (tempMap) end if end subroutine compressGlobalMap @@ -617,28 +657,28 @@ subroutine sortInterfaceGrid(this) integer(I4B), dimension(:), allocatable :: sortedRegionMap ! sort based on coordinates - newToOldIdx = (/ (i, i=1, size(this%idxToGlobal)) /) + newToOldIdx = (/(i, i=1, size(this%idxToGlobal))/) call quickSortGrid(newToOldIdx, size(newToOldIdx), this%idxToGlobal) - + ! and invert - allocate(oldToNewIdx(size(newToOldIdx))) - do i=1, size(oldToNewIdx) + allocate (oldToNewIdx(size(newToOldIdx))) + do i = 1, size(oldToNewIdx) oldToNewIdx(newToOldIdx(i)) = i end do ! reorder global table - allocate(sortedGlobalMap(size(this%idxToGlobal))) - do i=1, size(newToOldIdx) + allocate (sortedGlobalMap(size(this%idxToGlobal))) + do i = 1, size(newToOldIdx) sortedGlobalMap(i) = this%idxToGlobal(newToOldIdx(i)) end do - do i=1, size(newToOldIdx) + do i = 1, size(newToOldIdx) this%idxToGlobal(i) = sortedGlobalMap(i) end do - deallocate(sortedGlobalMap) + deallocate (sortedGlobalMap) - ! reorder regional lookup table - allocate(sortedRegionMap(size(this%regionalToInterfaceIdxMap))) - do i=1, size(sortedRegionMap) + ! reorder regional lookup table + allocate (sortedRegionMap(size(this%regionalToInterfaceIdxMap))) + do i = 1, size(sortedRegionMap) if (this%regionalToInterfaceIdxMap(i) /= -1) then idxOld = this%regionalToInterfaceIdxMap(i) sortedRegionMap(i) = oldToNewIdx(idxOld) @@ -646,131 +686,146 @@ subroutine sortInterfaceGrid(this) sortedRegionMap(i) = -1 end if end do - do i=1, size(sortedRegionMap) + do i = 1, size(sortedRegionMap) this%regionalToInterfaceIdxMap(i) = sortedRegionMap(i) end do - deallocate(sortedRegionMap) - + deallocate (sortedRegionMap) + end subroutine sortInterfaceGrid - + !> @brief Add primary connections to the sparse data structure !< subroutine makePrimaryConnections(this, sparse) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(SparseMatrix), pointer :: sparse !< the sparse data structure to hold the connections + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(SparseMatrix), pointer :: sparse !< the sparse data structure to hold the connections ! local integer(I4B) :: icell integer(I4B) :: ifaceIdx, ifaceIdxNbr - - do icell = 1, this%nrOfBoundaryCells + + do icell = 1, this%nrOfBoundaryCells ifaceIdx = this%getInterfaceIndex(this%boundaryCells(icell)%cell) ifaceIdxNbr = this%getInterfaceIndex(this%connectedCells(icell)%cell) - + ! add diagonals to sparse call sparse%addconnection(ifaceIdx, ifaceIdx, 1) call sparse%addconnection(ifaceIdxNbr, ifaceIdxNbr, 1) - + ! and cross terms call sparse%addconnection(ifaceIdx, ifaceIdxNbr, 1) call sparse%addconnection(ifaceIdxNbr, ifaceIdx, 1) end do - + end subroutine makePrimaryConnections - + !> @brief Recursively add higher order connections (from !! cells neighoring the primarily connected cells) to the !< sparse data structure recursive subroutine connectNeighborCells(this, cell, sparse) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(CellWithNbrsType) :: cell !< the cell whose connections is to be added - type(SparseMatrix), pointer :: sparse !< the sparse data structure to hold the connections + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(CellWithNbrsType) :: cell !< the cell whose connections is to be added + type(SparseMatrix), pointer :: sparse !< the sparse data structure to hold the connections ! local - integer(I4B) :: ifaceIdx, ifaceIdxNbr ! unique idx in the interface grid + integer(I4B) :: ifaceIdx, ifaceIdxNbr ! unique idx in the interface grid integer(I4B) :: inbr - + ifaceIdx = this%getInterfaceIndex(cell%cell) do inbr = 1, cell%nrOfNbrs ifaceIdxNbr = this%getInterfaceIndex(cell%neighbors(inbr)%cell) - + call sparse%addconnection(ifaceIdxNbr, ifaceIdxNbr, 1) call sparse%addconnection(ifaceIdx, ifaceIdxNbr, 1) call sparse%addconnection(ifaceIdxNbr, ifaceIdx, 1) - + ! recurse call this%connectNeighborCells(cell%neighbors(inbr), sparse) end do - + end subroutine connectNeighborCells - + !> @brief Fill connection data (ihc, cl1, ...) for !< connections between cells within the same model. subroutine fillConnectionDataInternal(this) use ConstantsModule, only: DPI, DTWOPI - class(GridConnectionType), intent(inout) :: this !< this grid connection instance + class(GridConnectionType), intent(inout) :: this !< this grid connection instance ! local - type(ConnectionsType), pointer :: conn, connOrig + type(ConnectionsType), pointer :: conn integer(I4B) :: n, m, ipos, isym, iposOrig, isymOrig type(GlobalCellType), pointer :: ncell, mcell - + integer(I4B), dimension(:), pointer, contiguous :: jas, ihc + real(DP), dimension(:), pointer, contiguous :: hwva, cl1, cl2, anglex + integer(I4B), dimension(:), pointer, contiguous :: ia, ja + conn => this%connections - + do n = 1, conn%nodes - do ipos=conn%ia(n)+1, conn%ia(n+1)-1 + do ipos = conn%ia(n) + 1, conn%ia(n + 1) - 1 m = conn%ja(ipos) if (n > m) cycle - + isym = conn%jas(ipos) ncell => this%idxToGlobal(n) mcell => this%idxToGlobal(m) - if (associated(ncell%model, mcell%model)) then + if (ncell%dmodel == mcell%dmodel) then + ! within same model, straight copy - connOrig => ncell%model%dis%con - iposOrig = connOrig%getjaindex(ncell%index, mcell%index) + call ncell%dmodel%load(ia, 'IA', 'CON') + call ncell%dmodel%load(ja, 'JA', 'CON') + iposOrig = getCSRIndex(ncell%index, mcell%index, ia, ja) + if (iposOrig == 0) then - ! periodic boundary conditions can add connections between cells in + ! periodic boundary conditions can add connections between cells in ! the same model, but they are dealt with through the exchange data if (this%isPeriodic(ncell%index, mcell%index)) cycle - + ! this should not be possible - write(*,*) 'Error: cannot find cell connection in model grid' - call ustop() + write (*, *) 'Error: cannot find cell connection in model grid' + call ustop() end if - - isymOrig = connOrig%jas(iposOrig) - conn%hwva(isym) = connOrig%hwva(isymOrig) - conn%ihc(isym) = connOrig%ihc(isymOrig) + + ! load distributed data from memory + ! TODO_MJR: this should probably be cached at some point... + call ncell%dmodel%load(jas, 'JAS', 'CON') + call ncell%dmodel%load(ihc, 'IHC', 'CON') + call ncell%dmodel%load(hwva, 'HWVA', 'CON') + call ncell%dmodel%load(cl1, 'CL1', 'CON') + call ncell%dmodel%load(cl2, 'CL2', 'CON') + call ncell%dmodel%load(anglex, 'ANGLEX', 'CON') + + isymOrig = jas(iposOrig) + conn%hwva(isym) = hwva(isymOrig) + conn%ihc(isym) = ihc(isymOrig) if (ncell%index < mcell%index) then - conn%cl1(isym) = connOrig%cl1(isymOrig) - conn%cl2(isym) = connOrig%cl2(isymOrig) - conn%anglex(isym) = connOrig%anglex(isymOrig) + conn%cl1(isym) = cl1(isymOrig) + conn%cl2(isym) = cl2(isymOrig) + conn%anglex(isym) = anglex(isymOrig) else - conn%cl1(isym) = connOrig%cl2(isymOrig) - conn%cl2(isym) = connOrig%cl1(isymOrig) - conn%anglex(isym) = mod(connOrig%anglex(isymOrig) + DPI, DTWOPI) + conn%cl1(isym) = cl2(isymOrig) + conn%cl2(isym) = cl1(isymOrig) + conn%anglex(isym) = mod(anglex(isymOrig) + DPI, DTWOPI) end if end if end do end do end subroutine fillConnectionDataInternal - - !> @brief Fill connection data (ihc, cl1, ...) for + + !> @brief Fill connection data (ihc, cl1, ...) for !< all exchanges subroutine fillConnectionDataFromExchanges(this) use ConstantsModule, only: DPI, DTWOPI, DPIO180 - use ArrayHandlersModule, only: ifind - class(GridConnectionType), intent(inout) :: this !< this grid connection instance + use ArrayHandlersModule, only: ifind + class(GridConnectionType), intent(inout) :: this !< this grid connection instance ! local integer(I4B) :: inx, iexg, ivalAngldegx integer(I4B) :: ipos, isym integer(I4B) :: nOffset, mOffset, nIfaceIdx, mIfaceIdx class(DisConnExchangeType), pointer :: connEx type(ConnectionsType), pointer :: conn - + conn => this%connections - + do inx = 1, this%exchanges%Count() - connEx => GetDisConnExchangeFromList(this%exchanges, inx) - + connEx => GetDisConnExchangeFromList(this%exchanges, inx) + ivalAngldegx = -1 if (connEx%naux > 0) then ivalAngldegx = ifind(connEx%auxname, 'ANGLDEGX') @@ -778,50 +833,51 @@ subroutine fillConnectionDataFromExchanges(this) conn%ianglex = 1 end if end if - - nOffset = this%getRegionalModelOffset(connEx%model1) - mOffset = this%getRegionalModelOffset(connEx%model2) + + nOffset = this%getRegionalModelOffset(connEx%dmodel1) + mOffset = this%getRegionalModelOffset(connEx%dmodel2) do iexg = 1, connEx%nexg nIfaceIdx = this%regionalToInterfaceIdxMap(noffset + connEx%nodem1(iexg)) mIfaceIdx = this%regionalToInterfaceIdxMap(moffset + connEx%nodem2(iexg)) - ! not all nodes from the exchanges are part of the interface grid + ! not all nodes from the exchanges are part of the interface grid ! (think of exchanges between neigboring models, and their neighbors) if (nIFaceIdx == -1 .or. mIFaceIdx == -1) then cycle end if - - ipos = conn%getjaindex(nIfaceIdx, mIfaceIdx) - ! (see prev. remark) sometimes the cells are in the interface grid, + + ipos = conn%getjaindex(nIfaceIdx, mIfaceIdx) + ! (see prev. remark) sometimes the cells are in the interface grid, ! but the connection isn't. This can happen for leaf nodes of the grid. if (ipos == 0) then ! no match, safely cycle cycle - end if + end if isym = conn%jas(ipos) - + ! note: cl1 equals L_nm: the length from cell n to the shared ! face with cell m (and cl2 analogously for L_mn) if (nIfaceIdx < mIfaceIdx) then conn%cl1(isym) = connEx%cl1(iexg) conn%cl2(isym) = connEx%cl2(iexg) if (ivalAngldegx > 0) then - conn%anglex(isym) = connEx%auxvar(ivalAngldegx,iexg) * DPIO180 + conn%anglex(isym) = connEx%auxvar(ivalAngldegx, iexg) * DPIO180 end if else conn%cl1(isym) = connEx%cl2(iexg) conn%cl2(isym) = connEx%cl1(iexg) if (ivalAngldegx > 0) then - conn%anglex(isym) = mod(connEx%auxvar(ivalAngldegx,iexg) + 180.0_DP, 360.0_DP) * DPIO180 + conn%anglex(isym) = mod(connEx%auxvar(ivalAngldegx, iexg) + & + 180.0_DP, 360.0_DP) * DPIO180 end if end if conn%hwva(isym) = connEx%hwva(iexg) conn%ihc(isym) = connEx%ihc(iexg) - - end do + + end do end do - - end subroutine fillConnectionDataFromExchanges - + + end subroutine fillConnectionDataFromExchanges + !> @brief Create the connection masks !! !! The level indicates the nr of connections away from @@ -834,117 +890,103 @@ subroutine createConnectionMask(this) integer(I4B) :: icell, inbr, n, ipos integer(I4B) :: level, newMask type(CellWithNbrsType), pointer :: cell, nbrCell - + ! set all masks to zero to begin with do ipos = 1, this%connections%nja - call this%connections%set_mask(ipos, 0) + call this%connections%set_mask(ipos, 0) end do - + ! remote connections remain masked ! now set mask for exchange connections (level == 1) level = 1 - do icell = 1, this%nrOfBoundaryCells - call this%setMaskOnConnection(this%boundaryCells(icell), this%connectedCells(icell), level) + do icell = 1, this%nrOfBoundaryCells + call this%setMaskOnConnection(this%boundaryCells(icell), & + this%connectedCells(icell), level) ! for cross-boundary connections, we need to apply the mask to both n-m and m-n, ! because if the upper triangular one is disabled, its transposed (lower triangular) ! counter part is skipped in the NPF calculation as well. - call this%setMaskOnConnection(this%connectedCells(icell), this%boundaryCells(icell), level) + call this%setMaskOnConnection(this%connectedCells(icell), & + this%boundaryCells(icell), level) end do - + ! now extend mask recursively into the internal domain (level > 1) do icell = 1, this%nrOfBoundaryCells - cell => this%boundaryCells(icell) + cell => this%boundaryCells(icell) do inbr = 1, cell%nrOfNbrs nbrCell => this%boundaryCells(icell)%neighbors(inbr) level = 2 ! this is incremented within the recursion - call this%maskInternalConnections(this%boundaryCells(icell), this%boundaryCells(icell)%neighbors(inbr), level) - end do + call this%maskInternalConnections(this%boundaryCells(icell), & + this%boundaryCells(icell)% & + neighbors(inbr), level) + end do end do - + ! set normalized mask: ! =1 for links with connectivity <= interior stencil depth ! =0 otherwise - do n = 1, this%connections%nodes + do n = 1, this%connections%nodes ! set diagonals to zero call this%connections%set_mask(this%connections%ia(n), 0) - + do ipos = this%connections%ia(n) + 1, this%connections%ia(n + 1) - 1 newMask = 0 if (this%connections%mask(ipos) > 0) then if (this%connections%mask(ipos) < this%internalStencilDepth + 1) then newMask = 1 end if - end if + end if ! set mask on off-diag call this%connections%set_mask(ipos, newMask) - end do + end do end do - + end subroutine createConnectionMask - !> @brief Create lookup tables for efficient access - !< (this needs the connections object to be available) - subroutine createLookupTable(this) - use CsrUtilsModule, only: getCSRIndex - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - ! local - integer(I4B) :: i, n1, n2, ipos - - do i = 1, this%nrOfBoundaryCells - n1 = this%getInterfaceIndexByIndexModel(this%boundaryCells(i)%cell%index, & - this%boundaryCells(i)%cell%model) - n2 = this%getInterfaceIndexByIndexModel(this%connectedCells(i)%cell%index,& - this%connectedCells(i)%cell%model) - - ipos = getCSRIndex(n1, n2, this%connections%ia, this%connections%ja) - this%primConnections(i) = ipos - end do - - end subroutine createLookupTable - !> @brief Recursively mask connections, increasing the level as we go !< recursive subroutine maskInternalConnections(this, cell, nbrCell, level) class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(CellWithNbrsType), intent(inout) :: cell !< cell 1 in the connection to mask + type(CellWithNbrsType), intent(inout) :: cell !< cell 1 in the connection to mask type(CellWithNbrsType), intent(inout) :: nbrCell !< cell 2 in the connection to mask integer(I4B), intent(in) :: level ! local integer(I4B) :: inbr, newLevel - + ! only set the mask for internal connections, leaving the ! others at 0 - if (associated(cell%cell%model, this%model) .and. & - associated(nbrCell%cell%model, this%model)) then + if (cell%cell%dmodel == this%model .and. & + nbrCell%cell%dmodel == this%model) then ! this will set a mask on both diagonal, and both cross terms call this%setMaskOnConnection(cell, nbrCell, level) call this%setMaskOnConnection(nbrCell, cell, level) end if - + ! recurse on nbrs-of-nbrs newLevel = level + 1 - do inbr = 1, nbrCell%nrOfNbrs - call this%maskInternalConnections(nbrCell, nbrCell%neighbors(inbr), newLevel) + do inbr = 1, nbrCell%nrOfNbrs + call this%maskInternalConnections(nbrCell, & + nbrCell%neighbors(inbr), & + newLevel) end do - + end subroutine maskInternalConnections - + !> @brief Set a mask on the connection from a cell to its neighbor, !! (and not the transposed!) not overwriting the current level !< of a connection when it is smaller subroutine setMaskOnConnection(this, cell, nbrCell, level) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(CellWithNbrsType), intent(inout) :: cell !< cell 1 in the connection - type(CellWithNbrsType), intent(inout) :: nbrCell !< cell 2 in the connection - integer(I4B), intent(in) :: level !< the level value to set the mask to + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(CellWithNbrsType), intent(inout) :: cell !< cell 1 in the connection + type(CellWithNbrsType), intent(inout) :: nbrCell !< cell 2 in the connection + integer(I4B), intent(in) :: level !< the level value to set the mask to ! local integer(I4B) :: ifaceIdx, ifaceIdxNbr integer(I4B) :: iposdiag, ipos integer(I4B) :: currentLevel - + ifaceIdx = this%getInterfaceIndex(cell%cell) ifaceIdxNbr = this%getInterfaceIndex(nbrCell%cell) - + ! diagonal iposdiag = this%connections%getjaindex(ifaceIdx, ifaceIdx) currentLevel = this%connections%mask(iposdiag) @@ -957,83 +999,85 @@ subroutine setMaskOnConnection(this, cell, nbrCell, level) if (currentLevel == 0 .or. level < currentLevel) then call this%connections%set_mask(ipos, level) end if - + end subroutine setMaskOnConnection - + !> @brief Get interface index from global cell !< function getInterfaceIndexByCell(this, cell) result(ifaceIdx) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - type(GlobalCellType), intent(in) :: cell !< the global cell to get the interface index for - integer(I4B) :: ifaceIdx !< the index in the interface model + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + type(GlobalCellType), intent(in) :: cell !< the global cell to get the interface index for + integer(I4B) :: ifaceIdx !< the index in the interface model ! local integer(I4B) :: offset, regionIdx - - offset = this%getRegionalModelOffset(cell%model) + + offset = this%getRegionalModelOffset(cell%dmodel) regionIdx = offset + cell%index ifaceIdx = this%regionalToInterfaceIdxMap(regionIdx) end function getInterfaceIndexByCell !> @brief Get interface index from a model pointer and the local index !< - function getInterfaceIndexByIndexModel(this, index, model) result(ifaceIdx) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - integer(I4B) :: index !< the local cell index - class(NumericalModelType), pointer :: model !< the cell's model - integer(I4B) :: ifaceIdx !< the index in the interface model + function getInterfaceIndexByIndexModel(this, index, dist_model) result(ifaceIdx) + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + integer(I4B) :: index !< the local cell index + class(DistributedModelType), pointer :: dist_model !< the cell's model + integer(I4B) :: ifaceIdx !< the index in the interface model ! local integer(I4B) :: offset, regionIdx - - offset = this%getRegionalModelOffset(model) + + offset = this%getRegionalModelOffset(dist_model) regionIdx = offset + index ifaceIdx = this%regionalToInterfaceIdxMap(regionIdx) end function getInterfaceIndexByIndexModel - + !> @brief Get the offset for a regional model !< function getRegionalModelOffset(this, model) result(offset) - class(GridConnectionType), intent(inout) :: this !< this grid connection instance - class(NumericalModelType), pointer :: model !< the model to get the offset for - integer(I4B) :: offset !< the index offset in the regional domain + class(GridConnectionType), intent(inout) :: this !< this grid connection instance + class(DistributedModelType), pointer :: model !< the model to get the offset for + integer(I4B) :: offset !< the index offset in the regional domain ! local integer(I4B) :: im - class(NumericalModelType), pointer :: modelInList + class(DistributedModelType), pointer :: modelInList offset = 0 do im = 1, this%regionalModels%Count() - modelInList => GetNumericalModelFromList(this%regionalModels, im) - if (associated(model, modelInList)) then - offset = this%regionalModelOffset(im) - return - end if + modelInList => GetDistModelFromList(this%regionalModels, im) + if (modelInList == model) then + offset = this%regionalModelOffset(im) + return + end if end do - + end function getRegionalModelOffset - + !> @brief Allocate scalar data !< subroutine allocateScalars(this) use MemoryManagerModule, only: mem_allocate class(GridConnectionType) :: this !< this grid connection instance - + call mem_allocate(this%nrOfBoundaryCells, 'NRBNDCELLS', this%memoryPath) call mem_allocate(this%indexCount, 'IDXCOUNT', this%memoryPath) call mem_allocate(this%nrOfCells, 'NRCELLS', this%memoryPath) - + end subroutine allocateScalars !> @brief Sets the discretization (DISU) after all !! preprocessing by this grid connection has been done, !< this comes after disu_cr - subroutine getDiscretization(this, disu) - use ConnectionsModule + subroutine getDiscretization(this, disu) + use ConnectionsModule use SparseModule, only: sparsematrix - class(GridConnectionType) :: this !< the grid connection - class(GwfDisuType), pointer :: disu !< the target disu object + class(GridConnectionType) :: this !< the grid connection + class(GwfDisuType), pointer :: disu !< the target disu object ! local integer(I4B) :: icell, nrOfCells, idx - type(NumericalModelType), pointer :: model - real(DP) :: x, y, xglo, yglo - + type(DistributedModelType), pointer :: dist_model + real(DP), dimension(:), pointer, contiguous :: dis_xc, dis_yc + real(DP), pointer :: dis_xorigin, dis_yorigin, dis_angrot + real(DP) :: xglo, yglo + ! the following is similar to dis_df nrOfCells = this%nrOfCells disu%nodes = nrOfCells @@ -1041,34 +1085,43 @@ subroutine getDiscretization(this, disu) disu%nja = this%connections%nja call disu%allocate_arrays() - ! these are otherwise allocated in dis%read_dimensions + ! these are otherwise allocated in dis%read_dimensions call disu%allocate_arrays_mem() - + ! fill data do icell = 1, nrOfCells idx = this%idxToGlobal(icell)%index - model => this%idxToGlobal(icell)%model - - disu%top(icell) = model%dis%top(idx) - disu%bot(icell) = model%dis%bot(idx) - disu%area(icell) = model%dis%area(idx) + disu%top(icell) = -huge(1.0_DP) + disu%bot(icell) = -huge(1.0_DP) + disu%area(icell) = -huge(1.0_DP) end do - + ! grid connections follow from GridConnection: disu%con => this%connections - disu%njas = disu%con%njas - + disu%njas = disu%con%njas + ! copy cell x,y do icell = 1, nrOfCells idx = this%idxToGlobal(icell)%index - model => this%idxToGlobal(icell)%model - call model%dis%get_cellxy(idx, x, y) + dist_model => this%idxToGlobal(icell)%dmodel + + call dist_model%load(dis_xc, 'XC', 'DIS') + call dist_model%load(dis_yc, 'YC', 'DIS') + call dist_model%load(dis_xorigin, 'XORIGIN', 'DIS') + call dist_model%load(dis_yorigin, 'YORIGIN', 'DIS') + call dist_model%load(dis_angrot, 'ANGROT', 'DIS') ! we are merging grids with possibly (likely) different origins, - ! transform: - call model%dis%transform_xy(x, y, xglo, yglo) - disu%cellxy(1,icell) = xglo - disu%cellxy(2,icell) = yglo + ! transform to global coordinates: + call dis_transform_xy(dis_xc(idx), dis_yc(idx), & + dis_xorigin, dis_yorigin, & + dis_angrot, xglo, yglo) + + ! NB: usernodes equals internal nodes for interface + disu%cellxy(1, icell) = xglo + disu%xc(icell) = xglo + disu%cellxy(2, icell) = yglo + disu%yc(icell) = yglo end do ! if vertices will be needed, it will look like this: @@ -1079,44 +1132,205 @@ subroutine getDiscretization(this, disu) ! 4. get vertex data per cell, add functions to base ! 5. add vertex (x,y) to list and connectivity to sparse ! 6. generate ia/ja from sparse - + end subroutine getDiscretization - + !> @brief Build interface map object for outside use, + !< (caller owns the memory) + subroutine getInterfaceMap(this, interfaceMap) + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use VectorIntModule + class(GridConnectionType) :: this !< this grid connection + type(InterfaceMapType), pointer :: interfaceMap !< a pointer to the map (not allocated yet) + ! local + integer(I4B) :: i, j, iloc, jloc + integer(I4B) :: im, ix, mid, n + integer(I4B) :: ipos, iposModel + type(VectorInt) :: modelIds + type(VectorInt) :: srcIdxTmp, tgtIdxTmp, signTmp + class(DisConnExchangeType), pointer :: connEx + integer(I4B), dimension(:), pointer, contiguous :: ia, ja + + allocate (interfaceMap) + + ! first get the participating models + call modelIds%init() + do i = 1, this%nrOfCells + if (.not. modelIds%contains(this%idxToGlobal(i)%dmodel%id)) then + call modelIds%push_back(this%idxToGlobal(i)%dmodel%id) + end if + end do + + ! allocate space + interfaceMap%nr_models = modelIds%size + allocate (interfaceMap%model_names(modelIds%size)) + allocate (interfaceMap%node_map(modelIds%size)) + allocate (interfaceMap%connection_map(modelIds%size)) + + ! for each model part of this interface, ... + do im = 1, modelIds%size + mid = modelIds%at(im) + interfaceMap%model_names(im) = get_model_name(mid) + call srcIdxTmp%init() + call tgtIdxTmp%init() + + ! store the node map for this model + do i = 1, this%nrOfCells + if (mid == this%idxToGlobal(i)%dmodel%id) then + call srcIdxTmp%push_back(this%idxToGlobal(i)%index) + call tgtIdxTmp%push_back(i) + end if + end do + + ! and copy into interface map + allocate (interfaceMap%node_map(im)%src_idx(srcIdxTmp%size)) + allocate (interfaceMap%node_map(im)%tgt_idx(tgtIdxTmp%size)) + do i = 1, srcIdxTmp%size + interfaceMap%node_map(im)%src_idx(i) = srcIdxTmp%at(i) + interfaceMap%node_map(im)%tgt_idx(i) = tgtIdxTmp%at(i) + end do + + call srcIdxTmp%destroy() + call tgtIdxTmp%destroy() + + ! and for connections + call srcIdxTmp%init() + call tgtIdxTmp%init() + + ! store the connection map for this model + do i = 1, this%nrOfCells + if (mid /= this%idxToGlobal(i)%dmodel%id) cycle + do ipos = this%connections%ia(i), this%connections%ia(i + 1) - 1 + j = this%connections%ja(ipos) + if (mid /= this%idxToGlobal(j)%dmodel%id) cycle + + ! i and j are now in same model (mid) + iloc = this%idxToGlobal(i)%index + jloc = this%idxToGlobal(j)%index + call this%idxToGlobal(i)%dmodel%load(ia, 'IA', 'CON') + call this%idxToGlobal(i)%dmodel%load(ja, 'JA', 'CON') + iposModel = getCSRIndex(iloc, jloc, ia, ja) + + call srcIdxTmp%push_back(iposModel) + call tgtIdxTmp%push_back(ipos) + end do + end do + + ! copy into interface map + allocate (interfaceMap%connection_map(im)%src_idx(srcIdxTmp%size)) + allocate (interfaceMap%connection_map(im)%tgt_idx(tgtIdxTmp%size)) + do i = 1, srcIdxTmp%size + interfaceMap%connection_map(im)%src_idx(i) = srcIdxTmp%at(i) + interfaceMap%connection_map(im)%tgt_idx(i) = tgtIdxTmp%at(i) + end do + + call srcIdxTmp%destroy() + call tgtIdxTmp%destroy() + + end do + + call modelIds%destroy() + + ! for each exchange that is part of this interface + interfaceMap%nr_exchanges = this%exchanges%Count() + allocate (interfaceMap%exchange_names(interfaceMap%nr_exchanges)) + allocate (interfaceMap%exchange_map(interfaceMap%nr_exchanges)) + do ix = 1, this%exchanges%Count() + + ! all exchanges in this list should have at + ! least one relevant connection for this map + connEx => GetDisConnExchangeFromList(this%exchanges, ix) + interfaceMap%exchange_names(ix) = connEx%name + + call srcIdxTmp%init() + call tgtIdxTmp%init() + call signTmp%init() + + do n = 1, connEx%nexg + i = this%getInterfaceIndex(connEx%nodem1(n), connEx%dmodel1) + j = this%getInterfaceIndex(connEx%nodem2(n), connEx%dmodel2) + if (i == -1 .or. j == -1) cycle ! not all exchange nodes are part of the interface + ipos = this%connections%getjaindex(i, j) + if (ipos == 0) then + ! this can typically happen at corner points for a larger + ! stencil (XT3D), when both i and j are included in the + ! interface grid as leaf nodes, but their connection is not. + ! (c.f. 'test_gwf_ifmod_mult_exg.py') + cycle + end if + call srcIdxTmp%push_back(n) + call tgtIdxTmp%push_back(ipos) + call signTmp%push_back(1) + + ! and the reverse connection: + call srcIdxTmp%push_back(n) + call tgtIdxTmp%push_back(this%connections%isym(ipos)) + call signTmp%push_back(-1) + end do + + allocate (interfaceMap%exchange_map(ix)%src_idx(srcIdxTmp%size)) + allocate (interfaceMap%exchange_map(ix)%tgt_idx(tgtIdxTmp%size)) + allocate (interfaceMap%exchange_map(ix)%sign(signTmp%size)) + do i = 1, srcIdxTmp%size + interfaceMap%exchange_map(ix)%src_idx(i) = srcIdxTmp%at(i) + interfaceMap%exchange_map(ix)%tgt_idx(i) = tgtIdxTmp%at(i) + interfaceMap%exchange_map(ix)%sign(i) = signTmp%at(i) + end do + + call srcIdxTmp%destroy() + call tgtIdxTmp%destroy() + call signTmp%destroy() + + end do + + ! set the primary exchange idx + ! findloc cannot be used until gfortran 9... + interfaceMap%prim_exg_idx = -1 + do i = 1, interfaceMap%nr_exchanges + if (interfaceMap%exchange_names(i) == this%primaryExchange%name) then + interfaceMap%prim_exg_idx = i + exit + end if + end do + + end subroutine getInterfaceMap + !> @brief Deallocate grid connection resources !< subroutine destroy(this) - use MemoryManagerModule, only: mem_deallocate + use MemoryManagerModule, only: mem_deallocate class(GridConnectionType) :: this !< this grid connection instance - + call mem_deallocate(this%nrOfBoundaryCells) call mem_deallocate(this%indexCount) call mem_deallocate(this%nrOfCells) ! arrays - deallocate(this%idxToGlobal) - deallocate(this%boundaryCells) - deallocate(this%connectedCells) - deallocate(this%primConnections) + deallocate (this%idxToGlobal) + deallocate (this%boundaryCells) + deallocate (this%connectedCells) call mem_deallocate(this%idxToGlobalIdx) - + end subroutine destroy - + !> @brief Test if the connection between nodes within !< the same model is periodic function isPeriodic(this, n, m) result(periodic) class(GridConnectionType), intent(in) :: this !< this grid connection instance - integer(I4B), intent(in) :: n !< first node of the connection - integer(I4B), intent(in) :: m !< second node of the connection - logical :: periodic !< true when periodic + integer(I4B), intent(in) :: n !< first node of the connection + integer(I4B), intent(in) :: m !< second node of the connection + logical :: periodic !< true when periodic ! local integer(I4B) :: icell - - periodic = .false. + + periodic = .false. do icell = 1, this%nrOfBoundaryCells - if (.not. associated(this%boundaryCells(icell)%cell%model, this%connectedCells(icell)%cell%model)) cycle - + if (.not. this%boundaryCells(icell)%cell%dmodel == & + this%connectedCells(icell)%cell%dmodel) then + cycle + end if + ! one way if (this%boundaryCells(icell)%cell%index == n) then if (this%connectedCells(icell)%cell%index == m) then @@ -1131,9 +1345,33 @@ function isPeriodic(this, n, m) result(periodic) return end if end if - + end do - + end function - + + !> @brief Helper function to get model names when ids are given + !< + function get_model_name(id) result(name) + use ConstantsModule, only: LENMODELNAME + use ListsModule, only: basemodellist + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use MemoryHelperModule, only: create_mem_path + integer(I4B) :: id + character(len=LENMODELNAME) :: name + ! local + class(BaseModelType), pointer :: model + integer(I4B) :: im + + name = '' + do im = 1, basemodellist%Count() + model => GetBaseModelFromList(basemodellist, im) + if (model%id == id) then + name = model%name + return + end if + end do + + end function get_model_name + end module GridConnectionModule diff --git a/src/Model/Connection/GridSorting.f90 b/src/Model/Connection/GridSorting.f90 index 4c10b28bf84..dd062730a30 100644 --- a/src/Model/Connection/GridSorting.f90 +++ b/src/Model/Connection/GridSorting.f90 @@ -1,8 +1,9 @@ -module GridSorting +module GridSorting use KindModule, only: I4B, DP, LGP use ConstantsModule, only: DHALF use CellWithNbrsModule, only: GlobalCellType use GenericUtilitiesModule, only: is_same + use BaseDisModule, only: dis_transform_xy implicit none private @@ -11,74 +12,102 @@ module GridSorting contains ! Sort an array of integers subroutine quickSortGrid(array, arraySize, idxToGlobal) - integer, intent(inout), dimension(:) :: array - integer, intent(in) :: arraySize - type(GlobalCellType), dimension(:), pointer :: idxToGlobal + integer, intent(inout), dimension(:) :: array + integer, intent(in) :: arraySize + type(GlobalCellType), dimension(:), pointer :: idxToGlobal + ! local + integer :: QSORT_THRESHOLD = 8 + include "qsort_inline.inc" + + contains + subroutine init() + end subroutine init + + ! Compare two grid cells, this doesn't work as + ! smooth for staggered discretizations though... + function lessThan(n, m) result(isLess) + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: m + logical(LGP) :: isLess ! local - integer :: QSORT_THRESHOLD = 8 - include "qsort_inline.inc" - - contains - subroutine init() - end subroutine init - - ! Compare two grid cells, this doesn't work as - ! smooth for staggered discretizations though... - function lessThan(n, m) result(isLess) - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: m - logical(LGP) :: isLess - ! local - type(GlobalCellType), pointer :: gcn, gcm - real(DP) :: xnloc, ynloc, xmloc, ymloc - real(DP) :: xn, yn, zn, xm, ym, zm - - ! get coordinates - gcn => idxToGlobal(array(n)) - gcm => idxToGlobal(array(m)) - - ! convert coordinates - call gcn%model%dis%get_cellxy(gcn%index, xnloc, ynloc) - call gcn%model%dis%transform_xy(xnloc, ynloc, xn, yn) - zn = DHALF*(gcn%model%dis%top(gcn%index) + gcn%model%dis%bot(gcn%index)) - - call gcm%model%dis%get_cellxy(gcm%index, xmloc, ymloc) - call gcm%model%dis%transform_xy(xmloc, ymloc, xm, ym) - zm = DHALF*(gcm%model%dis%top(gcm%index) + gcm%model%dis%bot(gcm%index)) - - ! compare - if (.not. is_same(zn, zm, 10*epsilon(zn))) then - isLess = zn > zm - else if (.not. is_same(yn, ym, 10*epsilon(yn))) then - isLess = yn > ym - else if (.not. is_same(xn, xm, 10*epsilon(xn))) then - isLess = xn < xm - else - isLess = .false. - end if - - end function lessThan - - ! swap indices - subroutine swap(a,b) - integer, intent(in) :: a,b - integer :: hold - - hold=array(a) - array(a)=array(b) - array(b)=hold - - end subroutine swap - - ! circular shift-right by one - subroutine rshift(left,right) - integer, intent(in) :: left, right - integer :: hold - - hold=array(right) - array(left+1:right)=array(left:right-1) - array(left)=hold - - end subroutine rshift + type(GlobalCellType), pointer :: gcn, gcm + real(DP) :: xn, yn, zn, xm, ym, zm + real(DP), dimension(:), pointer, contiguous :: dis_top_n, dis_bot_n, & + dis_top_m, dis_bot_m + real(DP), dimension(:), pointer, contiguous :: dis_xc_n, dis_yc_n, & + dis_xc_m, dis_yc_m + real(DP), pointer :: xorigin_n, yorigin_n, angrot_n, & + xorigin_m, yorigin_m, angrot_m + + ! get coordinates + gcn => idxToGlobal(array(n)) + gcm => idxToGlobal(array(m)) + + ! load model data + ! TODO_MJR: we should probably cache this + ! for n: + call gcn%dmodel%load(dis_top_n, 'TOP', 'DIS') + call gcn%dmodel%load(dis_bot_n, 'BOT', 'DIS') + call gcn%dmodel%load(dis_xc_n, 'XC', 'DIS') + call gcn%dmodel%load(dis_yc_n, 'YC', 'DIS') + call gcn%dmodel%load(xorigin_n, 'XORIGIN', 'DIS') + call gcn%dmodel%load(yorigin_n, 'YORIGIN', 'DIS') + call gcn%dmodel%load(angrot_n, 'ANGROT', 'DIS') + ! for m: + call gcm%dmodel%load(dis_top_m, 'TOP', 'DIS') + call gcm%dmodel%load(dis_bot_m, 'BOT', 'DIS') + call gcm%dmodel%load(dis_xc_m, 'XC', 'DIS') + call gcm%dmodel%load(dis_yc_m, 'YC', 'DIS') + call gcm%dmodel%load(xorigin_m, 'XORIGIN', 'DIS') + call gcm%dmodel%load(yorigin_m, 'YORIGIN', 'DIS') + call gcm%dmodel%load(angrot_m, 'ANGROT', 'DIS') + + ! convert coordinates + call dis_transform_xy(dis_xc_n(gcn%index), dis_yc_n(gcn%index), & + xorigin_n, yorigin_n, angrot_n, & + xn, yn) + zn = DHALF * (dis_top_n(gcn%index) + & + dis_bot_n(gcn%index)) + + call dis_transform_xy(dis_xc_m(gcm%index), dis_yc_m(gcm%index), & + xorigin_m, yorigin_m, angrot_m, & + xm, ym) + zm = DHALF * (dis_top_m(gcm%index) + & + dis_bot_m(gcm%index)) + + ! compare + if (.not. is_same(zn, zm, 10 * epsilon(zn))) then + isLess = zn > zm + else if (.not. is_same(yn, ym, 10 * epsilon(yn))) then + isLess = yn > ym + else if (.not. is_same(xn, xm, 10 * epsilon(xn))) then + isLess = xn < xm + else + isLess = .false. + end if + + end function lessThan + + ! swap indices + subroutine swap(a, b) + integer, intent(in) :: a, b + integer :: hold + + hold = array(a) + array(a) = array(b) + array(b) = hold + + end subroutine swap + + ! circular shift-right by one + subroutine rshift(left, right) + integer, intent(in) :: left, right + integer :: hold + + hold = array(right) + array(left + 1:right) = array(left:right - 1) + array(left) = hold + + end subroutine rshift end subroutine quickSortGrid end module GridSorting diff --git a/src/Model/Connection/GwfGwfConnection.f90 b/src/Model/Connection/GwfGwfConnection.f90 index 90a0c70db6f..625aad620af 100644 --- a/src/Model/Connection/GwfGwfConnection.f90 +++ b/src/Model/Connection/GwfGwfConnection.f90 @@ -1,51 +1,51 @@ module GwfGwfConnectionModule use KindModule, only: I4B, DP, LGP - use ConstantsModule, only: DZERO, DONE, DEM6, LENCOMPONENTNAME, LINELENGTH + use ConstantsModule, only: DZERO, DONE, DEM6, LENVARNAME, & + LENCOMPONENTNAME, LENMEMPATH, LINELENGTH use CsrUtilsModule, only: getCSRIndex - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix use MemoryManagerModule, only: mem_allocate, mem_deallocate use SimModule, only: ustop - use SpatialModelConnectionModule + use SpatialModelConnectionModule use GwfInterfaceModelModule use NumericalModelModule use GwfModule, only: GwfModelType, CastAsGwfModel use DisConnExchangeModule - use GwfGwfExchangeModule, only: GwfExchangeType, GetGwfExchangeFromList, & + use GwfGwfExchangeModule, only: GwfExchangeType, GetGwfExchangeFromList, & CastAsGwfExchange use GwfNpfModule, only: GwfNpfType, hcond, vcond use GwfBuyModule, only: GwfBuyType use BaseDisModule, only: DisBaseType use ConnectionsModule, only: ConnectionsType use CellWithNbrsModule, only: GlobalCellType - + use DistributedDataModule + implicit none private public :: CastAsGwfGwfConnection - !> Connecting a GWF model to other models in space, implements - !! NumericalExchangeType so the solution can used this object to determine + !> Connecting a GWF model to other models in space, implements + !! NumericalExchangeType so the solution can used this object to determine !! the coefficients for the coupling between two adjacent models. !< type, public, extends(SpatialModelConnectionType) :: GwfGwfConnectionType - type(GwfModelType), pointer :: gwfModel => null() !< the model for which this connection exists - type(GwfExchangeType), pointer :: gwfExchange => null() !< the primary exchange, cast to its concrete type - logical(LGP) :: exchangeIsOwned !< there are two connections (in serial) for an exchange, - !! one of them needs to manage/own the exchange (e.g. clean up) - type(GwfInterfaceModelType), pointer :: gwfInterfaceModel => null() !< the interface model - integer(I4B), pointer :: iXt3dOnExchange => null() !< run XT3D on the interface, - !! 0 = don't, 1 = matrix, 2 = rhs - integer(I4B) :: iout = 0 !< the list file for the interface model - - real(DP), dimension(:), pointer, contiguous :: exgflowja => null() !< flowja through exchange faces - - contains + type(GwfModelType), pointer :: gwfModel => null() !< the model for which this connection exists + type(GwfExchangeType), pointer :: gwfExchange => null() !< the primary exchange, cast to its concrete type + logical(LGP) :: exchangeIsOwned !< there are two connections (in serial) for an exchange, + !! one of them needs to manage/own the exchange (e.g. clean up) + type(GwfInterfaceModelType), pointer :: gwfInterfaceModel => null() !< the interface model + integer(I4B), pointer :: iXt3dOnExchange => null() !< run XT3D on the interface, + !! 0 = don't, 1 = matrix, 2 = rhs + integer(I4B) :: iout = 0 !< the list file for the interface model + + contains procedure, pass(this) :: gwfGwfConnection_ctor generic, public :: construct => gwfGwfConnection_ctor - + ! overriding NumericalExchangeType - procedure :: exg_df => gwfgwfcon_df + procedure :: exg_df => gwfgwfcon_df procedure :: exg_ar => gwfgwfcon_ar procedure :: exg_rp => gwfgwfcon_rp procedure :: exg_ad => gwfgwfcon_ad @@ -58,30 +58,27 @@ module GwfGwfConnectionModule ! overriding 'protected' procedure, pass(this) :: validateConnection - + ! local stuff procedure, pass(this), private :: allocateScalars - procedure, pass(this), private :: allocate_arrays procedure, pass(this), private :: setGridExtent - procedure, pass(this), private :: syncInterfaceModel procedure, pass(this), private :: validateGwfExchange procedure, pass(this), private :: setFlowToExchange - procedure, pass(this), private :: saveExchangeFlows procedure, pass(this), private :: setNpfEdgeProps - + end type GwfGwfConnectionType contains - + !> @brief Basic construction of the connection !< subroutine gwfGwfConnection_ctor(this, model, gwfEx) use NumericalModelModule, only: NumericalModelType use InputOutputModule, only: openfile - class(GwfGwfConnectionType) :: this !< the connection - class(NumericalModelType), pointer :: model !< the model owning this connection, - !! this must of course be a GwfModelType - class(DisConnExchangeType), pointer :: gwfEx !< the exchange the interface model is created for + class(GwfGwfConnectionType) :: this !< the connection + class(NumericalModelType), pointer :: model !< the model owning this connection, + !! this must of course be a GwfModelType + class(DisConnExchangeType), pointer :: gwfEx !< the exchange the interface model is created for ! local character(len=LINELENGTH) :: fname character(len=LENCOMPONENTNAME) :: name @@ -94,73 +91,132 @@ subroutine gwfGwfConnection_ctor(this, model, gwfEx) this%gwfExchange => CastAsGwfExchange(objPtr) this%exchangeIsOwned = associated(gwfEx%model1, model) - + if (this%exchangeIsOwned) then - write(name,'(a,i0)') 'GWFCON1_', gwfEx%id + write (name, '(a,i0)') 'GWFCON1_', gwfEx%id else - write(name,'(a,i0)') 'GWFCON2_', gwfEx%id + write (name, '(a,i0)') 'GWFCON2_', gwfEx%id end if ! .lst file for interface model if (write_ifmodel_listfile) then fname = trim(name)//'.im.lst' call openfile(this%iout, 0, fname, 'LIST', filstat_opt='REPLACE') - write(this%iout, '(4a)') 'Creating GWF-GWF connection for model ', & - trim(this%gwfModel%name), ' from exchange ', & - trim(gwfEx%name) + write (this%iout, '(4a)') 'Creating GWF-GWF connection for model ', & + trim(this%gwfModel%name), ' from exchange ', & + trim(gwfEx%name) end if - + ! first call base constructor - call this%SpatialModelConnectionType%spatialConnection_ctor(model, gwfEx, name) - + call this%SpatialModelConnectionType%spatialConnection_ctor(model, & + gwfEx, & + name) + call this%allocateScalars() - + this%typename = 'GWF-GWF' this%iXt3dOnExchange = 0 - - allocate(this%gwfInterfaceModel) + + allocate (this%gwfInterfaceModel) this%interfaceModel => this%gwfInterfaceModel - + end subroutine gwfGwfConnection_ctor - + !> @brief Define the connection - !! - !! This sets up the GridConnection (for creating the - !! interface grid), creates and defines the interface + !! + !! This sets up the GridConnection (for creating the + !! interface grid), creates and defines the interface !< model subroutine gwfgwfcon_df(this) - class(GwfGwfConnectionType) :: this !< this connection + class(GwfGwfConnectionType) :: this !< this connection ! local - character(len=LENCOMPONENTNAME) :: imName !< the interface model's name + character(len=LENCOMPONENTNAME) :: imName !< the interface model's name ! determine the required size of the interface grid call this%setGridExtent() - ! this sets up the GridConnection + ! this sets up the GridConnection call this%spatialcon_df() - + ! Now grid conn is defined, we create the interface model ! here, and the remainder of this routine is define. ! we basically follow the logic that is present in sln_df() - if(this%exchangeIsOwned) then - write(imName,'(a,i0)') 'GWFIM1_', this%gwfExchange%id + if (this%exchangeIsOwned) then + write (imName, '(a,i0)') 'GWFIM1_', this%gwfExchange%id else - write(imName,'(a,i0)') 'GWFIM2_', this%gwfExchange%id + write (imName, '(a,i0)') 'GWFIM2_', this%gwfExchange%id end if call this%gwfInterfaceModel%gwfifm_cr(imName, this%iout, this%gridConnection) - + call this%gwfInterfaceModel%set_idsoln(this%gwfModel%idsoln) this%gwfInterfaceModel%npf%satomega = this%gwfModel%npf%satomega this%gwfInterfaceModel%npf%ixt3d = this%iXt3dOnExchange call this%gwfInterfaceModel%model_df() + ! Take these settings from the owning model, TODO_MJR: + ! what if the owner iangle1 == 0 but the neighbor doesn't? + this%gwfInterfaceModel%npf%ik22 = this%gwfModel%npf%ik22 + this%gwfInterfaceModel%npf%ik33 = this%gwfModel%npf%ik33 + this%gwfInterfaceModel%npf%iwetdry = this%gwfModel%npf%iwetdry + this%gwfInterfaceModel%npf%iangle1 = this%gwfModel%npf%iangle1 + this%gwfInterfaceModel%npf%iangle2 = this%gwfModel%npf%iangle2 + this%gwfInterfaceModel%npf%iangle3 = this%gwfModel%npf%iangle3 + + call this%addDistVar('X', '', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR, BEFORE_AD, BEFORE_CF/)) + call this%addDistVar('IBOUND', '', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR, BEFORE_AD, BEFORE_CF/)) + call this%addDistVar('XOLD', '', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AD, BEFORE_CF/)) + call this%addDistVar('ICELLTYPE', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('K11', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('K22', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('K33', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + if (this%gwfInterfaceModel%npf%iangle1 == 1) then + call this%addDistVar('ANGLE1', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + if (this%gwfInterfaceModel%npf%iangle2 == 1) then + call this%addDistVar('ANGLE2', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + if (this%gwfInterfaceModel%npf%iangle3 == 1) then + call this%addDistVar('ANGLE3', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + if (this%gwfInterfaceModel%npf%iwetdry == 1) then + call this%addDistVar('WETDRY', 'NPF', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + call this%addDistVar('TOP', 'DIS', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('BOT', 'DIS', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('AREA', 'DIS', this%gwfInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%mapVariables() + + if (this%gwfInterfaceModel%npf%ixt3d > 0) then + this%gwfInterfaceModel%npf%iangle1 = 1 + this%gwfInterfaceModel%npf%iangle2 = 1 + this%gwfInterfaceModel%npf%iangle3 = 1 + end if + + ! set defaults + ! TODO_MJR: loop this + this%gwfInterfaceModel%npf%angle1 = 0.0_DP + this%gwfInterfaceModel%npf%angle2 = 0.0_DP + this%gwfInterfaceModel%npf%angle3 = 0.0_DP + ! point X, RHS, IBOUND to connection call this%spatialcon_setmodelptrs() ! connect interface model to spatial connection call this%spatialcon_connect() - call this%allocate_arrays() - end subroutine gwfgwfcon_df !> @brief Set the required size of the interface grid from @@ -169,7 +225,7 @@ subroutine setGridExtent(this) class(GwfGwfConnectionType) :: this !< the connection ! local - this%iXt3dOnExchange = this%gwfExchange%ixt3d + this%iXt3dOnExchange = this%gwfExchange%ixt3d if (this%iXt3dOnExchange > 0) then this%exchangeStencilDepth = 2 if (this%gwfModel%npf%ixt3d > 0) then @@ -178,7 +234,7 @@ subroutine setGridExtent(this) end if end subroutine setGridExtent - + !> @brief allocation of scalars in the connection !< subroutine allocateScalars(this) @@ -190,34 +246,18 @@ subroutine allocateScalars(this) end subroutine allocateScalars - !> @brief allocation of arrays in the connection - !< - subroutine allocate_arrays(this) - use MemoryManagerModule, only: mem_allocate - class(GwfGwfConnectionType) :: this !< the connection - ! local - integer(I4B) :: i - - call mem_allocate(this%exgflowja, this%gridConnection%nrOfBoundaryCells, & - 'EXGFLOWJA', this%memoryPath) - do i = 1, size(this%exgflowja) - this%exgflowja(i) = 0.0_DP - end do - - end subroutine allocate_arrays - !> @brief Allocate and read the connection !< subroutine gwfgwfcon_ar(this) - use GridConnectionModule, only: GridConnectionType + use GridConnectionModule, only: GridConnectionType class(GwfGwfConnectionType) :: this !< this connection - ! local + ! local ! check if we can construct an interface model ! NB: only makes sense after the models' allocate&read have been ! called, which is why we do it here call this%validateConnection() - + ! allocate and read base call this%spatialcon_ar() @@ -240,7 +280,7 @@ end subroutine gwfgwfcon_ar !< subroutine gwfgwfcon_rp(this) class(GwfGwfConnectionType) :: this !< this connection - + ! Call exchange rp routines if (this%exchangeIsOwned) then call this%gwfExchange%exg_rp() @@ -254,12 +294,9 @@ end subroutine gwfgwfcon_rp subroutine gwfgwfcon_ad(this) class(GwfGwfConnectionType) :: this !< this connection - ! copy model data into interface model - call this%syncInterfaceModel() - ! this triggers the BUY density calculation if (this%gwfInterfaceModel%inbuy > 0) call this%gwfInterfaceModel%buy%buy_ad() - + if (this%exchangeIsOwned) then call this%gwfExchange%exg_ad() end if @@ -271,10 +308,10 @@ end subroutine gwfgwfcon_ad !< by the connection of a GWF model with its neigbors subroutine gwfgwfcon_cf(this, kiter) class(GwfGwfConnectionType) :: this !< this connection - integer(I4B), intent(in) :: kiter !< the iteration counter + integer(I4B), intent(in) :: kiter !< the iteration counter ! local integer(I4B) :: i - + ! reset interface system do i = 1, this%nja this%amat(i) = 0.0_DP @@ -282,68 +319,44 @@ subroutine gwfgwfcon_cf(this, kiter) do i = 1, this%neq this%rhs(i) = 0.0_DP end do - - ! copy model data into interface model - ! (when kiter == 1, this is already done in _ad) - if (kiter > 1) call this%syncInterfaceModel() ! calculate (wetting/drying, saturation) call this%gwfInterfaceModel%model_cf(kiter) - + end subroutine gwfgwfcon_cf - - !> @brief Synchronize the interface model - !! Fills interface model data from the - !! contributing GWF models, at the iteration - !< level - subroutine syncInterfaceModel(this) - class(GwfGwfConnectionType) :: this !< this connection - ! local - integer(I4B) :: icell, idx - class(NumericalModelType), pointer :: model - - ! copy head values - do icell = 1, this%gridConnection%nrOfCells - idx = this%gridConnection%idxToGlobal(icell)%index - model => this%gridConnection%idxToGlobal(icell)%model - - this%x(icell) = model%x(idx) - this%gwfInterfaceModel%ibound(icell) = model%ibound(idx) - this%gwfInterfaceModel%xold(icell) = model%xold(idx) - end do - - end subroutine syncInterfaceModel - - !> @brief Write the calculated coefficients into the global + + !> @brief Write the calculated coefficients into the global !< system matrix and the rhs subroutine gwfgwfcon_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) - class(GwfGwfConnectionType) :: this !< this connection - integer(I4B), intent(in) :: kiter !< the iteration counter - integer(I4B), dimension(:), intent(in) :: iasln !< global system's IA array - real(DP), dimension(:), intent(inout) :: amatsln !< global system matrix coefficients - real(DP), dimension(:), intent(inout) ::rhssln !< global right-hand-side - integer(I4B), optional, intent(in) :: inwtflag !< newton-raphson flag + class(GwfGwfConnectionType) :: this !< this connection + integer(I4B), intent(in) :: kiter !< the iteration counter + integer(I4B), dimension(:), intent(in) :: iasln !< global system's IA array + real(DP), dimension(:), intent(inout) :: amatsln !< global system matrix coefficients + real(DP), dimension(:), intent(inout) :: rhssln !< global right-hand-side + integer(I4B), optional, intent(in) :: inwtflag !< newton-raphson flag ! local integer(I4B) :: n, ipos, nglo - + ! fill (and add to...) coefficients for interface call this%gwfInterfaceModel%model_fc(kiter, this%amat, this%nja, inwtflag) - + ! map back to solution matrix do n = 1, this%neq ! we cannot check with the mask here, because cross-terms are not ! necessarily from primary connections. But, we only need the coefficients ! for our own model (i.e. fluxes into cells belonging to this%owner): - if (.not. associated(this%gridConnection%idxToGlobal(n)%model, this%owner)) then + if (.not. this%gridConnection%idxToGlobal(n)%dmodel == this%owner) then ! only add connections for own model to global matrix cycle end if - - nglo = this%gridConnection%idxToGlobal(n)%index + this%gridConnection%idxToGlobal(n)%model%moffset + + nglo = this%gridConnection%idxToGlobal(n)%index + & + this%gridConnection%idxToGlobal(n)%dmodel%moffset rhssln(nglo) = rhssln(nglo) + this%rhs(n) - - do ipos = this%ia(n), this%ia(n+1) - 1 - amatsln(this%mapIdxToSln(ipos)) = amatsln(this%mapIdxToSln(ipos)) + this%amat(ipos) + + do ipos = this%ia(n), this%ia(n + 1) - 1 + amatsln(this%mapIdxToSln(ipos)) = amatsln(this%mapIdxToSln(ipos)) + & + this%amat(ipos) end do end do @@ -358,7 +371,7 @@ subroutine gwfgwfcon_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) end subroutine gwfgwfcon_fc !> @brief Validate this connection - !! This is called before proceeding to construct + !! This is called before proceeding to construct !! the interface model !< subroutine validateConnection(this) @@ -366,14 +379,14 @@ subroutine validateConnection(this) use SimModule, only: count_errors class(GwfGwfConnectionType) :: this !< this connection ! local - + ! base validation (geometry/spatial) call this%SpatialModelConnectionType%validateConnection() call this%validateGwfExchange() ! abort on errors - if(count_errors() > 0) then - write(errmsg, '(1x,a)') 'Errors occurred while processing exchange(s)' + if (count_errors() > 0) then + write (errmsg, '(1x,a)') 'Errors occurred while processing exchange(s)' call ustop() end if @@ -389,7 +402,7 @@ subroutine validateGwfExchange(this) use SimVariablesModule, only: errmsg use SimModule, only: store_error use GwfNpfModule, only: GwfNpfType - class(GwfGwfConnectionType) :: this !< this connection + class(GwfGwfConnectionType) :: this !< this connection ! local class(GwfExchangeType), pointer :: gwfEx class(*), pointer :: modelPtr @@ -406,18 +419,18 @@ subroutine validateGwfExchange(this) ! GNC not allowed if (gwfEx%ingnc /= 0) then - write(errmsg, '(1x,2a)') 'Ghost node correction not supported '// & - 'with interface model for exchange', & - trim(gwfEx%name) + write (errmsg, '(1x,2a)') 'Ghost node correction not supported '// & + 'with interface model for exchange', & + trim(gwfEx%name) call store_error(errmsg) end if - if ((gwfModel1%inbuy > 0 .and. gwfModel2%inbuy == 0) .or. & + if ((gwfModel1%inbuy > 0 .and. gwfModel2%inbuy == 0) .or. & (gwfModel1%inbuy == 0 .and. gwfModel2%inbuy > 0)) then - write(errmsg, '(1x,2a)') 'Buoyancy package should be enabled/disabled '// & - 'simultaneously in models connected with the '// & - 'interface model for exchange ', & - trim(gwfEx%name) + write (errmsg, '(1x,2a)') 'Buoyancy package should be enabled/disabled '// & + 'simultaneously in models connected with the '// & + 'interface model for exchange ', & + trim(gwfEx%name) call store_error(errmsg) end if @@ -425,10 +438,10 @@ subroutine validateGwfExchange(this) if (gwfModel1%inbuy > 0 .and. gwfModel2%inbuy > 0) then ! does not work with XT3D if (this%iXt3dOnExchange > 0) then - write(errmsg, '(1x,2a)') 'Connecting models with BUY package not '// & - 'allowed with XT3D enabled on exchange ', & - trim(gwfEx%name) - call store_error(errmsg) + write (errmsg, '(1x,2a)') 'Connecting models with BUY package not '// & + 'allowed with XT3D enabled on exchange ', & + trim(gwfEx%name) + call store_error(errmsg) end if ! check compatibility of buoyancy @@ -445,12 +458,12 @@ subroutine validateGwfExchange(this) end if if (.not. compatible) then - write(errmsg, '(1x,6a)') 'Buoyancy packages in model ', & - trim(gwfEx%model1%name), ' and ', & - trim(gwfEx%model2%name), & - ' should be equivalent to construct an '// & - ' interface model for exchange ', & - trim(gwfEx%name) + write (errmsg, '(1x,6a)') 'Buoyancy packages in model ', & + trim(gwfEx%model1%name), ' and ', & + trim(gwfEx%model2%name), & + ' should be equivalent to construct an '// & + ' interface model for exchange ', & + trim(gwfEx%name) call store_error(errmsg) end if @@ -460,7 +473,7 @@ end subroutine validateGwfExchange !> @brief Deallocate all resources !< - subroutine gwfgwfcon_da(this) + subroutine gwfgwfcon_da(this) use KindModule, only: LGP class(GwfGwfConnectionType) :: this !< this connection ! local @@ -469,24 +482,21 @@ subroutine gwfgwfcon_da(this) ! scalars call mem_deallocate(this%iXt3dOnExchange) - ! arrays - call mem_deallocate(this%exgflowja) - call this%gwfInterfaceModel%model_da() - deallocate(this%gwfInterfaceModel) - + deallocate (this%gwfInterfaceModel) + call this%spatialcon_da() - inquire(this%iout, opened=isOpen) + inquire (this%iout, opened=isOpen) if (isOpen) then - close(this%iout) + close (this%iout) end if ! we need to deallocate the baseexchange we own: if (this%exchangeIsOwned) then call this%gwfExchange%exg_da() end if - + end subroutine gwfgwfcon_da !> @brief Calculate intra-cell flows @@ -494,22 +504,20 @@ end subroutine gwfgwfcon_da !! model, and then mapped back to real-world cell ids. !< subroutine gwfgwfcon_cq(this, icnvg, isuppress_output, isolnid) - class(GwfGwfConnectionType) :: this !< this connection - integer(I4B), intent(inout) :: icnvg !< convergence flag + class(GwfGwfConnectionType) :: this !< this connection + integer(I4B), intent(inout) :: icnvg !< convergence flag integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 - integer(I4B), intent(in) :: isolnid !< solution id - - call this%gwfInterfaceModel%model_cq(icnvg, isuppress_output) + integer(I4B), intent(in) :: isolnid !< solution id - call this%setFlowToExchange() + call this%gwfInterfaceModel%model_cq(icnvg, isuppress_output) - call this%saveExchangeFlows() + call this%setFlowToExchange() !cdl Could we allow GwfExchange to do this instead, using ! simvals? ! if needed, we add the edge properties to the model's NPF ! package for its spdis calculation: - if (this%gwfModel%npf%icalcspdis == 1) then + if (this%gwfModel%npf%icalcspdis == 1) then call this%setNpfEdgeProps() end if @@ -521,58 +529,32 @@ subroutine gwfgwfcon_cq(this, icnvg, isuppress_output, isolnid) call this%gwfExchange%gwf_gwf_add_to_flowja() end if - end subroutine gwfgwfcon_cq - !> @brief Set the flows (flowja from interface model) to the + !> @brief Set the flows (flowja from interface model) to the !< simvals in the exchange, leaving the budget calcution in there subroutine setFlowToExchange(this) + use InterfaceMapModule class(GwfGwfConnectionType) :: this !< this connection ! local integer(I4B) :: i - integer(I4B) :: nIface, mIface, ipos class(GwfExchangeType), pointer :: gwfEx + type(IndexMapSgnType), pointer :: map - gwfEx => this%gwfExchange - if (this%exchangeIsOwned) then - do i = 1, gwfEx%nexg - gwfEx%simvals(i) = DZERO - - if (gwfEx%gwfmodel1%ibound(gwfEx%nodem1(i)) /= 0 .and. & - gwfEx%gwfmodel2%ibound(gwfEx%nodem2(i)) /= 0) then - - nIface = this%gridConnection%getInterfaceIndex(gwfEx%nodem1(i), gwfEx%model1) - mIface = this%gridConnection%getInterfaceIndex(gwfEx%nodem2(i), gwfEx%model2) - ipos = getCSRIndex(nIface, mIface, this%gwfInterfaceModel%ia, this%gwfInterfaceModel%ja) - gwfEx%simvals(i) = this%gwfInterfaceModel%flowja(ipos) - - end if + if (this%exchangeIsOwned) then + gwfEx => this%gwfExchange + map => this%interfaceMap%exchange_map(this%interfaceMap%prim_exg_idx) + + ! use (half of) the exchange map in reverse: + do i = 1, size(map%src_idx) + if (map%sign(i) < 0) cycle ! simvals is defined from exg%m1 => exg%m2 + gwfEx%simvals(map%src_idx(i)) = & + this%gwfInterfaceModel%flowja(map%tgt_idx(i)) end do end if end subroutine setFlowToExchange - !> @brief Copy interface model flowja between models, to - !< the local buffer for reuse by, e.g., GWT - subroutine saveExchangeFlows(this) - class(GwfGwfConnectionType) :: this !< this connection - ! local - integer(I4B) :: i, n, m, ipos - type(GlobalCellType) :: boundaryCell, connectedCell - - do i = 1, this%gridConnection%nrOfBoundaryCells - boundaryCell = this%gridConnection%boundaryCells(i)%cell - connectedCell = this%gridConnection%connectedCells(i)%cell - n = this%gridConnection%getInterfaceIndex(boundaryCell%index, & - boundaryCell%model) - m = this%gridConnection%getInterfaceIndex(connectedCell%index, & - connectedCell%model) - ipos = getCSRIndex(n, m, this%gwfInterfaceModel%ia, this%gwfInterfaceModel%ja) - this%exgflowja(i) = this%gwfInterfaceModel%flowja(ipos) - end do - - end subroutine saveExchangeFlows - !> @brief Set flowja as edge properties in the model, !< so it can be used for e.g. specific discharge calculation subroutine setNpfEdgeProps(this) @@ -590,9 +572,9 @@ subroutine setNpfEdgeProps(this) real(DP) :: dist real(DP) :: cl logical :: nozee - type(ConnectionsType), pointer :: imCon !< interface model connections - class(GwfNpfType), pointer :: imNpf !< interface model npf package - class(DisBaseType), pointer :: imDis !< interface model discretization + type(ConnectionsType), pointer :: imCon !< interface model connections + class(GwfNpfType), pointer :: imNpf !< interface model npf package + class(DisBaseType), pointer :: imDis !< interface model discretization type(GlobalCellType), dimension(:), pointer :: toGlobal !< map interface index to global cell ! for readability @@ -610,33 +592,33 @@ subroutine setNpfEdgeProps(this) ! for flows crossing the boundary, and set flowja for internal ! flows affected by the connection. do n = 1, this%neq - if (.not. associated(toGlobal(n)%model, this%owner)) then + if (.not. toGlobal(n)%dmodel == this%owner) then ! only add flows to own model cycle end if nLoc = toGlobal(n)%index - do ipos = imCon%ia(n)+1, imCon%ia(n+1) - 1 + do ipos = imCon%ia(n) + 1, imCon%ia(n + 1) - 1 if (imCon%mask(ipos) < 1) then ! skip this connection, it's masked so not determined by us cycle end if m = imCon%ja(ipos) - mLoc = toGlobal(m)%index + mLoc = toGlobal(m)%index - if (.not. associated(toGlobal(m)%model, this%owner)) then + if (.not. toGlobal(m)%dmodel == this%owner) then ! boundary connection, set edge properties isym = imCon%jas(ipos) ihc = imCon%ihc(isym) - area = imCon%hwva(isym) + area = imCon%hwva(isym) satThick = imNpf%calcSatThickness(n, m, ihc) rrate = this%gwfInterfaceModel%flowja(ipos) - call imDis%connection_normal(n, m, ihc, nx, ny, nz, ipos) + call imDis%connection_normal(n, m, ihc, nx, ny, nz, ipos) call imDis%connection_vector(n, m, nozee, imNpf%sat(n), imNpf%sat(m), & - ihc, cx, cy, cz, conLen) + ihc, cx, cy, cz, conLen) if (ihc == 0) then ! check if n is below m @@ -650,8 +632,8 @@ subroutine setNpfEdgeProps(this) cl = imCon%cl2(isym) end if dist = conLen * cl / (imCon%cl1(isym) + imCon%cl2(isym)) - call this%gwfModel%npf%set_edge_properties(nLoc, ihc, rrate, area, & - nx, ny, dist) + call this%gwfModel%npf%set_edge_properties(nLoc, ihc, rrate, area, & + nx, ny, dist) else ! internal, need to set flowja for n-m ! TODO_MJR: should we mask the flowja calculation in the model? @@ -668,10 +650,10 @@ end subroutine setNpfEdgeProps !> @brief Calculate the budget terms for this connection, this is !! dispatched to the GWF-GWF exchange subroutine gwfgwfcon_bd(this, icnvg, isuppress_output, isolnid) - class(GwfGwfConnectionType) :: this !< this connection - integer(I4B), intent(inout) :: icnvg !< convergence flag - integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 - integer(I4B), intent(in) :: isolnid !< solution id + class(GwfGwfConnectionType) :: this !< this connection + integer(I4B), intent(inout) :: icnvg !< convergence flag + integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 + integer(I4B), intent(in) :: isolnid !< solution id ! local ! call exchange budget routine, also calls bd @@ -679,15 +661,15 @@ subroutine gwfgwfcon_bd(this, icnvg, isuppress_output, isolnid) if (this%exchangeIsOwned) then call this%gwfExchange%exg_bd(icnvg, isuppress_output, isolnid) end if - + end subroutine gwfgwfcon_bd !> @brief Write output for exchange (and calls !< save on the budget) subroutine gwfgwfcon_ot(this) - class(GwfGwfConnectionType) :: this !< this connection + class(GwfGwfConnectionType) :: this !< this connection ! local - + ! Call exg_ot() here as it handles all output processing ! based on gwfExchange%simvals(:), which was correctly ! filled from gwfgwfcon @@ -699,14 +681,14 @@ end subroutine gwfgwfcon_ot !> @brief Cast to GwfGwfConnectionType !< - function CastAsGwfGwfConnection(obj) result (res) + function CastAsGwfGwfConnection(obj) result(res) implicit none - class(*), pointer, intent(inout) :: obj !< object to be cast + class(*), pointer, intent(inout) :: obj !< object to be cast class(GwfGwfConnectionType), pointer :: res !< the GwfGwfConnection - + res => null() if (.not. associated(obj)) return - + select type (obj) class is (GwfGwfConnectionType) res => obj diff --git a/src/Model/Connection/GwfInterfaceModel.f90 b/src/Model/Connection/GwfInterfaceModel.f90 index 1fa930292dd..b8f71e6cdb3 100644 --- a/src/Model/Connection/GwfInterfaceModel.f90 +++ b/src/Model/Connection/GwfInterfaceModel.f90 @@ -1,6 +1,6 @@ module GwfInterfaceModelModule use KindModule, only: I4B, DP - use ConstantsModule, only: DZERO + use ConstantsModule, only: DZERO use MemoryManagerModule, only: mem_allocate use MemoryHelperModule, only: create_mem_path use NumericalModelModule, only: NumericalModelType, GetNumericalModelFromList @@ -12,72 +12,70 @@ module GwfInterfaceModelModule use GwfDisuModule use GwfNpfModule use GwfNpfOptionsModule - use GwfNpfGridDataModule use GwfBuyInputDataModule use GwfOcModule implicit none private !> The GWF Interface Model is a utility to calculate the solution's - !! exchange coefficients from the interface between a GWF model and - !! its GWF neighbors. The interface model itself will not be part - !! of the solution, it is not being solved. + !! exchange coefficients from the interface between a GWF model and + !! its GWF neighbors. The interface model itself will not be part + !! of the solution, it is not being solved. !! Patching (a part of the) discretizations of two GWF models in a - !! general way, e.g. DIS+DIS with refinement, requires the resulting + !! general way, e.g. DIS+DIS with refinement, requires the resulting !< discretization to be of type DISU. type, public, extends(GwfModelType) :: GwfInterfaceModelType - class(GridConnectionType), pointer :: gridConnection => null() !< The grid connection class will provide the interface grid - class(GwfModelType), private, pointer :: owner => null() !< the real GWF model for which the exchange coefficients - !! are calculated with this interface model + class(GridConnectionType), pointer :: gridConnection => null() !< The grid connection class will provide the interface grid + class(GwfModelType), private, pointer :: owner => null() !< the real GWF model for which the exchange coefficients + !! are calculated with this interface model contains procedure, pass(this) :: gwfifm_cr procedure :: model_df => gwfifm_df procedure :: model_ar => gwfifm_ar - procedure :: model_da => gwfifm_da + procedure :: model_da => gwfifm_da ! private procedure, private, pass(this) :: setNpfOptions - procedure, private, pass(this) :: setNpfGridData procedure, private, pass(this) :: setBuyData end type - + contains - - !> @brief set up the interface model, analogously to what + + !> @brief set up the interface model, analogously to what !< happens in gwf_cr subroutine gwfifm_cr(this, name, iout, gridConn) - class(GwfInterfaceModelType) :: this !< the GWF interface model - character(len=*), intent(in) :: name !< the interface model's name - integer(I4B), intent(in) :: iout !< the output unit + class(GwfInterfaceModelType) :: this !< the GWF interface model + character(len=*), intent(in) :: name !< the interface model's name + integer(I4B), intent(in) :: iout !< the output unit class(GridConnectionType), pointer, intent(in) :: gridConn !< the grid connection for creating a DISU ! local class(*), pointer :: modPtr - + this%memoryPath = create_mem_path(name) call this%allocate_scalars(name) - - this%iout = iout + + this%iout = iout this%gridConnection => gridConn modPtr => this%gridConnection%model this%owner => CastAsGwfModel(modPtr) - + this%innpf = huge(1_I4B) this%inewton = this%owner%inewton this%inewtonur = this%owner%inewtonur - + if (this%owner%inbuy > 0) then this%inbuy = huge(1_I4B) end if - + ! create discretization and packages call disu_cr(this%dis, this%name, -1, this%iout) - call npf_cr(this%npf, this%name, this%innpf, this%iout) - call xt3d_cr(this%xt3d, this%name, this%innpf, this%iout) + call npf_cr(this%npf, this%name, -this%innpf, this%iout) + call xt3d_cr(this%xt3d, this%name, -this%innpf, this%iout) call buy_cr(this%buy, this%name, this%inbuy, this%iout) - + end subroutine gwfifm_cr - + !> @brief Define, mostly DISU and the NPF package !< for this interface model subroutine gwfifm_df(this) @@ -96,7 +94,7 @@ subroutine gwfifm_df(this) ! define NPF package call npfOptions%construct() call this%setNpfOptions(npfOptions) - call this%npf%npf_df(this%dis, this%xt3d, 0, npfOptions) + call this%npf%npf_df(this%dis, this%xt3d, 0, 0, npfOptions) call npfOptions%destroy() ! define BUY package @@ -106,39 +104,32 @@ subroutine gwfifm_df(this) call this%buy%buy_df(this%dis, buyData) call buyData%destruct() end if - + this%neq = this%dis%nodes this%nja = this%dis%nja - this%ia => this%dis%con%ia - this%ja => this%dis%con%ja - + this%ia => this%dis%con%ia + this%ja => this%dis%con%ja + call this%allocate_arrays() - + end subroutine gwfifm_df - + !> @brief allocate and read the packages !< subroutine gwfifm_ar(this) class(GwfInterfaceModelType) :: this !< the GWF interface model - ! local - type(GwfNpfGridDataType) :: npfGridData - - call npfGridData%construct(this%dis%nodes) - call this%setNpfGridData(npfGridData) - call this%npf%npf_ar(this%ic, this%ibound, this%x, npfGridData) - call npfGridData%destroy() + call this%npf%npf_ar(this%ic, this%vsc, this%ibound, this%x) if (this%inbuy > 0) call this%buy%buy_ar(this%npf, this%ibound) - + end subroutine gwfifm_ar - !> @brief Clean up !< subroutine gwfifm_da(this) - use MemoryManagerModule, only: mem_deallocate + use MemoryManagerModule, only: mem_deallocate class(GwfInterfaceModelType) :: this !< the GWF interface model - + ! -- Internal flow packages deallocate call this%dis%dis_da() call this%npf%npf_da() @@ -146,9 +137,9 @@ subroutine gwfifm_da(this) call this%buy%buy_da() ! ! -- Internal package objects - deallocate(this%dis) - deallocate(this%npf) - deallocate(this%xt3d) + deallocate (this%dis) + deallocate (this%npf) + deallocate (this%xt3d) ! ! -- Scalars call mem_deallocate(this%inic) @@ -156,6 +147,7 @@ subroutine gwfifm_da(this) call mem_deallocate(this%inobs) call mem_deallocate(this%innpf) call mem_deallocate(this%inbuy) + call mem_deallocate(this%invsc) call mem_deallocate(this%insto) call mem_deallocate(this%incsub) call mem_deallocate(this%inmvr) @@ -166,14 +158,14 @@ subroutine gwfifm_da(this) ! ! -- NumericalModelType call this%NumericalModelType%model_da() - + end subroutine - + !> @brief Copy NPF options from the model owning !! the interface to the data structure !< subroutine setNpfOptions(this, npfOptions) - class(GwfInterfaceModelType) :: this !< the GWF interface model + class(GwfInterfaceModelType) :: this !< the GWF interface model type(GwfNpfOptionsType) :: npfOptions !< the options data to be filled ! for now, assuming full homogeneity, so just take @@ -190,80 +182,8 @@ subroutine setNpfOptions(this, npfOptions) end subroutine setNpfOptions - !> @brief Loop over the interface grid and fill the structure - !! with NPF grid data, copied from the models that participate - !! in this interface - !< - subroutine setNpfGridData(this, npfGridData) - class(GwfInterfaceModelType) :: this !< the interface model - type(GwfNpfGridDataType) :: npfGridData !< grid data to be set - ! local - integer(I4B) :: icell, idx - class(*), pointer :: modelPtr - class(GwfModelType), pointer :: gwfModel - - ! TODO_MJR: deal with inhomogeneity, for now, we assume - ! that we can just take the owning model's settings... - npfGridData%ik22 = this%owner%npf%ik22 - npfGridData%ik33 = this%owner%npf%ik33 - npfGridData%iwetdry = this%owner%npf%iwetdry - npfGridData%iangle1 = this%owner%npf%iangle1 - npfGridData%iangle2 = this%owner%npf%iangle2 - npfGridData%iangle3 = this%owner%npf%iangle3 - if (this%npf%ixt3d > 0) then - npfGridData%iangle1 = 1 - npfGridData%iangle2 = 1 - npfGridData%iangle3 = 1 - end if - - do icell = 1, this%gridConnection%nrOfCells - idx = this%gridConnection%idxToGlobal(icell)%index - modelPtr => this%gridConnection%idxToGlobal(icell)%model - gwfModel => CastAsGwfModel(modelPtr) - - npfGridData%icelltype(icell) = gwfModel%npf%icelltype(idx) - npfGridData%k11(icell) = gwfModel%npf%k11(idx) - npfGridData%k22(icell) = gwfModel%npf%k22(idx) - npfGridData%k33(icell) = gwfModel%npf%k33(idx) - - ! the K rotation angles, or default (0.0) - if (npfGridData%iangle1 == 1) then - if (gwfModel%npf%iangle1 == 1) then - npfGridData%angle1(icell) = gwfModel%npf%angle1(idx) - else - npfGridData%angle1(icell) = DZERO - end if - end if - if (npfGridData%iangle2 == 1) then - if (gwfModel%npf%iangle2 == 1) then - npfGridData%angle2(icell) = gwfModel%npf%angle2(idx) - else - npfGridData%angle2(icell) = DZERO - end if - end if - if (npfGridData%iangle3 == 1) then - if (gwfModel%npf%iangle3 == 1) then - npfGridData%angle3(icell) = gwfModel%npf%angle3(idx) - else - npfGridData%angle3(icell) = DZERO - end if - end if - - ! wetdry parameter, TODO_MJR: where is it ever set to 1?? - if (npfGridData%iwetdry == 1) then - if (gwfModel%npf%iwetdry == 1) then - npfGridData%wetdry(icell) = gwfModel%npf%wetdry(idx) - else - npfGridData%wetdry(icell) = DZERO - end if - end if - - end do - - end subroutine setNpfGridData - - !> @brief Sets the BUY input data from the models that - !! make up this interface. We adopt everything from the + !> @brief Sets the BUY input data from the models that + !! make up this interface. We adopt everything from the !! owning model, but during validation it should be !< checked that the models are compatible. subroutine setBuyData(this, buyData) @@ -284,5 +204,5 @@ subroutine setBuyData(this, buyData) end do end subroutine setBuyData - + end module GwfInterfaceModelModule diff --git a/src/Model/Connection/GwtGwtConnection.f90 b/src/Model/Connection/GwtGwtConnection.f90 index fb9cef32314..8c0e9ec1efa 100644 --- a/src/Model/Connection/GwtGwtConnection.f90 +++ b/src/Model/Connection/GwtGwtConnection.f90 @@ -1,9 +1,9 @@ module GwtGwtConnectionModule use KindModule, only: I4B, DP, LGP - use ConstantsModule, only: LINELENGTH, LENCOMPONENTNAME, DZERO, LENBUDTXT + use ConstantsModule, only: LINELENGTH, LENCOMPONENTNAME, DZERO, LENBUDTXT use CsrUtilsModule, only: getCSRIndex use SimModule, only: ustop - use MemoryManagerModule, only: mem_allocate, mem_deallocate + use MemoryManagerModule, only: mem_allocate, mem_deallocate, mem_checkin use SpatialModelConnectionModule use NumericalModelModule use GwtModule @@ -13,6 +13,7 @@ module GwtGwtConnectionModule use SparseModule, only: sparsematrix use ConnectionsModule, only: ConnectionsType use CellWithNbrsModule, only: GlobalCellType + use DistributedDataModule implicit none private @@ -25,28 +26,27 @@ module GwtGwtConnectionModule !< type, public, extends(SpatialModelConnectionType) :: GwtGwtConnectionType - type(GwtModelType), pointer :: gwtModel => null() !< the model for which this connection exists - type(GwtExchangeType), pointer :: gwtExchange => null() !< the primary exchange, cast to GWT-GWT - logical(LGP) :: exchangeIsOwned !< there are two connections (in serial) for an exchange, - !! one of them needs to manage/own the exchange (e.g. clean up) - type(GwtInterfaceModelType), pointer :: gwtInterfaceModel => null() !< the interface model - integer(I4B), pointer :: iIfaceAdvScheme => null() !< the advection scheme at the interface: - !! 0 = upstream, 1 = central, 2 = TVD - integer(I4B), pointer :: iIfaceXt3d => null() !< XT3D in the interface DSP package: 0 = no, 1 = lhs, 2 = rhs - real(DP), dimension(:), pointer, contiguous :: exgflowja => null() !< intercell flows at the interface, coming from GWF interface model - integer(I4B), pointer :: exgflowSign => null() !< indicates the flow direction of exgflowja + type(GwtModelType), pointer :: gwtModel => null() !< the model for which this connection exists + type(GwtExchangeType), pointer :: gwtExchange => null() !< the primary exchange, cast to GWT-GWT + logical(LGP) :: exchangeIsOwned !< there are two connections (in serial) for an exchange, + !! one of them needs to manage/own the exchange (e.g. clean up) + type(GwtInterfaceModelType), pointer :: gwtInterfaceModel => null() !< the interface model + integer(I4B), pointer :: iIfaceAdvScheme => null() !< the advection scheme at the interface: + !! 0 = upstream, 1 = central, 2 = TVD + integer(I4B), pointer :: iIfaceXt3d => null() !< XT3D in the interface DSP package: 0 = no, 1 = lhs, 2 = rhs + integer(I4B), pointer :: exgflowSign => null() !< indicates the flow direction of exgflowja real(DP), dimension(:), pointer, contiguous :: exgflowjaGwt => null() !< gwt-flowja at the interface (this is a subset of the GWT !! interface model flowja's) - - real(DP), dimension(:), pointer, contiguous :: gwfflowja => null() !< gwfflowja for the interface model - real(DP), dimension(:), pointer, contiguous :: gwfsat => null() !< gwfsat for the interface model - real(DP), dimension(:), pointer, contiguous :: gwfhead => null() !< gwfhead for the interface model - real(DP), dimension(:,:), pointer, contiguous :: gwfspdis => null() !< gwfspdis for the interface model - real(DP), dimension(:), pointer, contiguous :: conc => null() !< pointer to concentration array - integer(I4B), dimension(:), pointer, contiguous :: icbound => null() !< store pointer to gwt ibound array - - integer(I4B) :: iout = 0 !< the list file for the interface model + real(DP), dimension(:), pointer, contiguous :: gwfflowja => null() !< gwfflowja for the interface model + real(DP), dimension(:), pointer, contiguous :: gwfsat => null() !< gwfsat for the interface model + real(DP), dimension(:), pointer, contiguous :: gwfhead => null() !< gwfhead for the interface model + real(DP), dimension(:, :), pointer, contiguous :: gwfspdis => null() !< gwfspdis for the interface model + + real(DP), dimension(:), pointer, contiguous :: conc => null() !< pointer to concentration array + integer(I4B), dimension(:), pointer, contiguous :: icbound => null() !< store pointer to gwt ibound array + + integer(I4B) :: iout = 0 !< the list file for the interface model contains @@ -71,7 +71,6 @@ module GwtGwtConnectionModule ! local stuff procedure, pass(this), private :: allocate_scalars procedure, pass(this), private :: allocate_arrays - procedure, pass(this), private :: syncInterfaceModel procedure, pass(this), private :: setGridExtent procedure, pass(this), private :: setFlowToExchange @@ -79,551 +78,483 @@ module GwtGwtConnectionModule contains -!> @brief Basic construction of the connection -!< -subroutine gwtGwtConnection_ctor(this, model, gwtEx) - use InputOutputModule, only: openfile - class(GwtGwtConnectionType) :: this !< the connection - class(NumericalModelType), pointer :: model !< the model owning this connection, - !! this must be a GwtModelType - class(DisConnExchangeType), pointer :: gwtEx !< the GWT-GWT exchange the interface model is created for - ! local - character(len=LINELENGTH) :: fname - character(len=LENCOMPONENTNAME) :: name - class(*), pointer :: objPtr - logical(LGP) :: write_ifmodel_listfile = .false. - - objPtr => model - this%gwtModel => CastAsGwtModel(objPtr) - objPtr => gwtEx - this%gwtExchange => CastAsGwtExchange(objPtr) - - this%exchangeIsOwned = associated(model, gwtEx%model1) - - if (this%exchangeIsOwned) then - write(name,'(a,i0)') 'GWTCON1_', gwtEx%id - else - write(name,'(a,i0)') 'GWTCON2_', gwtEx%id - end if - - ! .lst file for interface model - if (write_ifmodel_listfile) then - fname = trim(name)//'.im.lst' - call openfile(this%iout, 0, fname, 'LIST', filstat_opt='REPLACE') - write(this%iout, '(4a)') 'Creating GWT-GWT connection for model ', & - trim(this%gwtModel%name), 'from exchange ', & - trim(gwtEx%name) - end if - - ! first call base constructor - call this%SpatialModelConnectionType%spatialConnection_ctor(model, gwtEx, name) - - call this%allocate_scalars() - this%typename = 'GWT-GWT' - this%iIfaceAdvScheme = 0 - this%iIfaceXt3d = 1 - this%exgflowSign = 1 - - allocate(this%gwtInterfaceModel) - this%interfaceModel => this%gwtInterfaceModel - -end subroutine gwtGwtConnection_ctor - -!> @brief Allocate scalar variables for this connection -!< -subroutine allocate_scalars(this) - class(GwtGwtConnectionType) :: this !< the connection - - call mem_allocate(this%iIfaceAdvScheme, 'IADVSCHEME', this%memoryPath) - call mem_allocate(this%iIfaceXt3d, 'IXT3D', this%memoryPath) - call mem_allocate(this%exgflowSign, 'EXGFLOWSIGN', this%memoryPath) - -end subroutine allocate_scalars - -!> @brief Allocate array variables for this connection -!< -subroutine allocate_arrays(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - integer(I4B) :: i - - call mem_allocate(this%gwfflowja, this%interfaceModel%nja, 'GWFFLOWJA', & - this%memoryPath) - call mem_allocate(this%gwfsat, this%neq, 'GWFSAT', this%memoryPath) - call mem_allocate(this%gwfhead, this%neq, 'GWFHEAD', this%memoryPath) - call mem_allocate(this%gwfspdis, 3, this%neq, 'GWFSPDIS', this%memoryPath) - - call mem_allocate(this%exgflowjaGwt, this%gridConnection%nrOfBoundaryCells, & - 'EXGFLOWJAGWT', this%memoryPath) - - do i = 1, size(this%gwfflowja) - this%gwfflowja = 0.0_DP - end do - - do i = 1, this%neq - this%gwfsat = 0.0_DP - end do - -end subroutine allocate_arrays - -!> @brief define the GWT-GWT connection -!< -subroutine gwtgwtcon_df(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - character(len=LENCOMPONENTNAME) :: imName - - ! determine advection scheme (the GWT-GWT exchange - ! has been read at this point) - this%iIfaceAdvScheme = this%gwtExchange%iAdvScheme - - ! determine xt3d setting on interface - this%iIfaceXt3d = this%gwtExchange%ixt3d - - ! determine the required size of the interface model grid - call this%setGridExtent() - - ! now set up the GridConnection - call this%spatialcon_df() - - ! we have to 'catch up' and create the interface model - ! here, then the remainder of this routine will be define - if (this%exchangeIsOwned) then - write(imName,'(a,i0)') 'GWTIM1_', this%gwtExchange%id - else - write(imName,'(a,i0)') 'GWTIM2_', this%gwtExchange%id - end if - call this%gwtInterfaceModel%gwtifmod_cr(imName, this%iout, this%gridConnection) - this%gwtInterfaceModel%iAdvScheme = this%iIfaceAdvScheme - this%gwtInterfaceModel%ixt3d = this%iIfaceXt3d - call this%gwtInterfaceModel%model_df() - - call this%allocate_arrays() - - ! connect X, RHS, IBOUND, and flowja - call this%spatialcon_setmodelptrs() - - this%gwtInterfaceModel%fmi%gwfflowja => this%gwfflowja - this%gwtInterfaceModel%fmi%gwfsat => this%gwfsat - this%gwtInterfaceModel%fmi%gwfhead => this%gwfhead - this%gwtInterfaceModel%fmi%gwfspdis => this%gwfspdis - - ! connect pointers (used by BUY) - this%conc => this%gwtInterfaceModel%x - this%icbound => this%gwtInterfaceModel%ibound - - ! add connections from the interface model to solution matrix - call this%spatialcon_connect() - -end subroutine gwtgwtcon_df - -!> @brief Set required extent of the interface grid from -!< the configuration -subroutine setGridExtent(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - logical(LGP) :: hasAdv, hasDsp - - hasAdv = this%gwtModel%inadv > 0 - hasDsp = this%gwtModel%indsp > 0 - - if (hasAdv) then - if (this%iIfaceAdvScheme == 2) then - this%exchangeStencilDepth = 2 - if (this%gwtModel%adv%iadvwt == 2) then - this%internalStencilDepth = 2 + !> @brief Basic construction of the connection + !< + subroutine gwtGwtConnection_ctor(this, model, gwtEx) + use InputOutputModule, only: openfile + class(GwtGwtConnectionType) :: this !< the connection + class(NumericalModelType), pointer :: model !< the model owning this connection, + !! this must be a GwtModelType + class(DisConnExchangeType), pointer :: gwtEx !< the GWT-GWT exchange the interface model is created for + ! local + character(len=LINELENGTH) :: fname + character(len=LENCOMPONENTNAME) :: name + class(*), pointer :: objPtr + logical(LGP) :: write_ifmodel_listfile = .false. + + objPtr => model + this%gwtModel => CastAsGwtModel(objPtr) + objPtr => gwtEx + this%gwtExchange => CastAsGwtExchange(objPtr) + + this%exchangeIsOwned = associated(model, gwtEx%model1) + + if (this%exchangeIsOwned) then + write (name, '(a,i0)') 'GWTCON1_', gwtEx%id + else + write (name, '(a,i0)') 'GWTCON2_', gwtEx%id + end if + + ! .lst file for interface model + if (write_ifmodel_listfile) then + fname = trim(name)//'.im.lst' + call openfile(this%iout, 0, fname, 'LIST', filstat_opt='REPLACE') + write (this%iout, '(4a)') 'Creating GWT-GWT connection for model ', & + trim(this%gwtModel%name), 'from exchange ', & + trim(gwtEx%name) + end if + + ! first call base constructor + call this%SpatialModelConnectionType%spatialConnection_ctor(model, & + gwtEx, & + name) + + call this%allocate_scalars() + this%typename = 'GWT-GWT' + this%iIfaceAdvScheme = 0 + this%iIfaceXt3d = 1 + this%exgflowSign = 1 + + allocate (this%gwtInterfaceModel) + this%interfaceModel => this%gwtInterfaceModel + + end subroutine gwtGwtConnection_ctor + + !> @brief Allocate scalar variables for this connection + !< + subroutine allocate_scalars(this) + class(GwtGwtConnectionType) :: this !< the connection + + call mem_allocate(this%iIfaceAdvScheme, 'IADVSCHEME', this%memoryPath) + call mem_allocate(this%iIfaceXt3d, 'IXT3D', this%memoryPath) + call mem_allocate(this%exgflowSign, 'EXGFLOWSIGN', this%memoryPath) + + end subroutine allocate_scalars + + !> @brief define the GWT-GWT connection + !< + subroutine gwtgwtcon_df(this) + class(GwtGwtConnectionType) :: this !< the connection + ! local + character(len=LENCOMPONENTNAME) :: imName + + ! determine advection scheme (the GWT-GWT exchange + ! has been read at this point) + this%iIfaceAdvScheme = this%gwtExchange%iAdvScheme + + ! determine xt3d setting on interface + this%iIfaceXt3d = this%gwtExchange%ixt3d + + ! determine the required size of the interface model grid + call this%setGridExtent() + + ! now set up the GridConnection + call this%spatialcon_df() + + ! we have to 'catch up' and create the interface model + ! here, then the remainder of this routine will be define + if (this%exchangeIsOwned) then + write (imName, '(a,i0)') 'GWTIM1_', this%gwtExchange%id + else + write (imName, '(a,i0)') 'GWTIM2_', this%gwtExchange%id + end if + call this%gwtInterfaceModel%gwtifmod_cr(imName, & + this%iout, & + this%gridConnection) + call this%gwtInterfaceModel%set_idsoln(this%gwtModel%idsoln) + this%gwtInterfaceModel%iAdvScheme = this%iIfaceAdvScheme + this%gwtInterfaceModel%ixt3d = this%iIfaceXt3d + call this%gwtInterfaceModel%model_df() + + call this%addDistVar('X', '', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR, BEFORE_AD, BEFORE_CF/)) + call this%addDistVar('IBOUND', '', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('TOP', 'DIS', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('BOT', 'DIS', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('AREA', 'DIS', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + if (this%gwtInterfaceModel%dsp%idiffc > 0) then + call this%addDistVar('DIFFC', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + if (this%gwtInterfaceModel%dsp%idisp > 0) then + call this%addDistVar('ALH', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('ALV', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('ATH1', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('ATH2', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + call this%addDistVar('ATV', 'DSP', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AR/)) + end if + call this%addDistVar('GWFHEAD', 'FMI', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AD/)) + call this%addDistVar('GWFSAT', 'FMI', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AD/)) + call this%addDistVar('GWFSPDIS', 'FMI', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/BEFORE_AD/)) + call this%addDistVar('GWFFLOWJA', 'FMI', this%gwtInterfaceModel%name, & + SYNC_CONNECTIONS, '', (/BEFORE_AD/)) + call this%addDistVar('GWFFLOWJA', 'FMI', this%gwtInterfaceModel%name, & + SYNC_EXCHANGES, 'GWFSIMVALS', (/BEFORE_AD/)) + ! fill porosity from mst packages, needed for dsp + if (this%gwtModel%indsp > 0 .and. this%gwtModel%inmst > 0) then + call this%addDistVar('POROSITY', 'MST', this%gwtInterfaceModel%name, & + SYNC_NODES, '', (/AFTER_AR/)) + end if + call this%mapVariables() + + call this%allocate_arrays() + call this%gwtInterfaceModel%allocate_fmi() + + ! connect X, RHS, IBOUND, and flowja + call this%spatialcon_setmodelptrs() + + ! connect pointers (used by BUY) + this%conc => this%gwtInterfaceModel%x + this%icbound => this%gwtInterfaceModel%ibound + + ! add connections from the interface model to solution matrix + call this%spatialcon_connect() + + end subroutine gwtgwtcon_df + + !> @brief Allocate array variables for this connection + !< + subroutine allocate_arrays(this) + class(GwtGwtConnectionType) :: this !< the connection + + call mem_allocate(this%exgflowjaGwt, this%gridConnection%nrOfBoundaryCells, & + 'EXGFLOWJAGWT', this%memoryPath) + + end subroutine allocate_arrays + + !> @brief Set required extent of the interface grid from + !< the configuration + subroutine setGridExtent(this) + class(GwtGwtConnectionType) :: this !< the connection + ! local + logical(LGP) :: hasAdv, hasDsp + + hasAdv = this%gwtModel%inadv > 0 + hasDsp = this%gwtModel%indsp > 0 + + if (hasAdv) then + if (this%iIfaceAdvScheme == 2) then + this%exchangeStencilDepth = 2 + if (this%gwtModel%adv%iadvwt == 2) then + this%internalStencilDepth = 2 + end if end if end if - end if - if (hasDsp) then - if (this%iIfaceXt3d > 0) then - this%exchangeStencilDepth = 2 - if (this%gwtModel%dsp%ixt3d > 0) then - this%internalStencilDepth = 2 + if (hasDsp) then + if (this%iIfaceXt3d > 0) then + this%exchangeStencilDepth = 2 + if (this%gwtModel%dsp%ixt3d > 0) then + this%internalStencilDepth = 2 + end if end if end if - end if - -end subroutine setGridExtent - -!> @brief allocate and read/set the connection's data structures -!< -subroutine gwtgwtcon_ar(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - integer(I4B) :: i, idx - class(GwtModelType), pointer :: gwtModel - class(*), pointer :: modelPtr - - ! check if we can construct an interface model - ! NB: only makes sense after the models' allocate&read have been - ! called, which is why we do it here - call this%validateConnection() - - ! fill porosity from mst packages, needed for dsp - if (this%gwtModel%inmst > 0) then - do i = 1, this%neq - modelPtr => this%gridConnection%idxToGlobal(i)%model - gwtModel => CastAsGwtModel(modelPtr) - idx = this%gridConnection%idxToGlobal(i)%index - this%gwtInterfaceModel%porosity(i) = gwtModel%mst%porosity(idx) + + end subroutine setGridExtent + + !> @brief allocate and read/set the connection's data structures + !< + subroutine gwtgwtcon_ar(this) + class(GwtGwtConnectionType) :: this !< the connection + + ! check if we can construct an interface model + ! NB: only makes sense after the models' allocate&read have been + ! called, which is why we do it here + call this%validateConnection() + + ! allocate and read base + call this%spatialcon_ar() + + ! ... and now the interface model + call this%gwtInterfaceModel%model_ar() + + ! AR the movers and obs through the exchange + if (this%exchangeIsOwned) then + !cdl implement this when MVT is ready + !cdl if (this%gwtExchange%inmvt > 0) then + !cdl call this%gwtExchange%mvt%mvt_ar() + !cdl end if + if (this%gwtExchange%inobs > 0) then + call this%gwtExchange%obs%obs_ar() + end if + end if + + end subroutine gwtgwtcon_ar + + !> @brief validate this connection prior to constructing + !< the interface model + subroutine validateConnection(this) + use SimVariablesModule, only: errmsg + use SimModule, only: count_errors, store_error + class(GwtGwtConnectionType) :: this !< this connection + + ! base validation, the spatial/geometry part + call this%SpatialModelConnectionType%validateConnection() + + ! GWT related matters + if ((this%gwtExchange%gwtmodel1%inadv > 0 .and. & + this%gwtExchange%gwtmodel2%inadv == 0) .or. & + (this%gwtExchange%gwtmodel2%inadv > 0 .and. & + this%gwtExchange%gwtmodel1%inadv == 0)) then + write (errmsg, '(1x,a,a,a)') 'Cannot connect GWT models in exchange ', & + trim(this%gwtExchange%name), ' because one model is configured with ADV & + &and the other one is not' + call store_error(errmsg) + end if + + if ((this%gwtExchange%gwtmodel1%indsp > 0 .and. & + this%gwtExchange%gwtmodel2%indsp == 0) .or. & + (this%gwtExchange%gwtmodel2%indsp > 0 .and. & + this%gwtExchange%gwtmodel1%indsp == 0)) then + write (errmsg, '(1x,a,a,a)') 'Cannot connect GWT models in exchange ', & + trim(this%gwtExchange%name), ' because one model is configured with DSP & + &and the other one is not' + call store_error(errmsg) + end if + + ! abort on errors + if (count_errors() > 0) then + write (errmsg, '(1x,a)') 'Errors occurred while processing exchange(s)' + call ustop() + end if + + end subroutine validateConnection + + !> @brief add connections to the global system for + !< this connection + subroutine gwtgwtcon_ac(this, sparse) + class(GwtGwtConnectionType) :: this !< this connection + type(sparsematrix), intent(inout) :: sparse !< sparse matrix to store the connections + ! local + integer(I4B) :: ic, iglo, jglo + type(GlobalCellType) :: boundaryCell, connectedCell + + ! connections to other models + do ic = 1, this%gridConnection%nrOfBoundaryCells + boundaryCell = this%gridConnection%boundaryCells(ic)%cell + connectedCell = this%gridConnection%connectedCells(ic)%cell + iglo = boundaryCell%index + boundaryCell%dmodel%moffset + jglo = connectedCell%index + connectedCell%dmodel%moffset + call sparse%addconnection(iglo, jglo, 1) + call sparse%addconnection(jglo, iglo, 1) end do - end if - - ! allocate and read base - call this%spatialcon_ar() - - ! ... and now the interface model - call this%gwtInterfaceModel%model_ar() - - ! AR the movers and obs through the exchange - if (this%exchangeIsOwned) then - !cdl implement this when MVT is ready - !cdl if (this%gwtExchange%inmvt > 0) then - !cdl call this%gwtExchange%mvt%mvt_ar() - !cdl end if - if (this%gwtExchange%inobs > 0) then - call this%gwtExchange%obs%obs_ar() + + ! and internal connections + call this%spatialcon_ac(sparse) + + end subroutine gwtgwtcon_ac + + subroutine gwtgwtcon_rp(this) + class(GwtGwtConnectionType) :: this !< the connection + + ! Call exchange rp routines + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_rp() end if - end if - -end subroutine gwtgwtcon_ar - -!> @brief validate this connection prior to constructing -!< the interface model -subroutine validateConnection(this) - use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error - class(GwtGwtConnectionType) :: this !< this connection - - ! base validation, the spatial/geometry part - call this%SpatialModelConnectionType%validateConnection() - - ! GWT related matters - if ((this%gwtExchange%gwtmodel1%inadv > 0 .and. this%gwtExchange%gwtmodel2%inadv == 0) .or. & - (this%gwtExchange%gwtmodel2%inadv > 0 .and. this%gwtExchange%gwtmodel1%inadv == 0)) then - write(errmsg, '(1x,a,a,a)') 'Cannot connect GWT models in exchange ', & - trim(this%gwtExchange%name), ' because one model is configured with ADV & - &and the other one is not' - call store_error(errmsg) - end if - - if ((this%gwtExchange%gwtmodel1%indsp > 0 .and. this%gwtExchange%gwtmodel2%indsp == 0) .or. & - (this%gwtExchange%gwtmodel2%indsp > 0 .and. this%gwtExchange%gwtmodel1%indsp == 0)) then - write(errmsg, '(1x,a,a,a)') 'Cannot connect GWT models in exchange ', & - trim(this%gwtExchange%name), ' because one model is configured with DSP & - &and the other one is not' - call store_error(errmsg) - end if - - ! abort on errors - if(count_errors() > 0) then - write(errmsg, '(1x,a)') 'Errors occurred while processing exchange(s)' - call ustop() - end if - -end subroutine validateConnection - - -!> @brief add connections to the global system for -!< this connection -subroutine gwtgwtcon_ac(this, sparse) - class(GwtGwtConnectionType) :: this !< this connection - type(sparsematrix), intent(inout) :: sparse !< sparse matrix to store the connections - ! local - integer(I4B) :: ic, iglo, jglo - type(GlobalCellType) :: boundaryCell, connectedCell - - ! connections to other models - do ic = 1, this%gridConnection%nrOfBoundaryCells - boundaryCell = this%gridConnection%boundaryCells(ic)%cell - connectedCell = this%gridConnection%connectedCells(ic)%cell - iglo = boundaryCell%index + boundaryCell%model%moffset - jglo = connectedCell%index + connectedCell%model%moffset - call sparse%addconnection(iglo, jglo, 1) - call sparse%addconnection(jglo, iglo, 1) - end do - - ! and internal connections - call this%spatialcon_ac(sparse) - -end subroutine gwtgwtcon_ac - -subroutine gwtgwtcon_rp(this) - class(GwtGwtConnectionType) :: this !< the connection - - ! Call exchange rp routines - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_rp() - end if - -end subroutine gwtgwtcon_rp - - -!> @brief Advance this connection + + end subroutine gwtgwtcon_rp + + !> @brief Advance this connection !< -subroutine gwtgwtcon_ad(this) - class(GwtGwtConnectionType) :: this !< this connection - - ! copy model data into interface model - call this%syncInterfaceModel() - - ! recalculate dispersion ellipse - if (this%gwtInterfaceModel%indsp > 0) call this%gwtInterfaceModel%dsp%dsp_ad() - - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_ad() - end if - -end subroutine gwtgwtcon_ad - - -subroutine gwtgwtcon_cf(this, kiter) - class(GwtGwtConnectionType) :: this !< the connection - integer(I4B), intent(in) :: kiter !< the iteration counter - ! local - integer(I4B) :: i - - ! copy model data into interface model - ! (when kiter == 1, this is already done in _ad) - if (kiter > 1) call this%syncInterfaceModel() - - ! reset interface system - do i = 1, this%nja - this%amat(i) = 0.0_DP - end do - do i = 1, this%neq - this%rhs(i) = 0.0_DP - end do - - call this%gwtInterfaceModel%model_cf(kiter) - -end subroutine gwtgwtcon_cf - - -!> @brief called during advance (*_ad), to copy the data -!! from the models into the connection's placeholder arrays -!< -subroutine syncInterfaceModel(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - integer(I4B) :: i, n, m, ipos, iposLoc, idx - type(ConnectionsType), pointer :: imCon !< interface model connections - type(GlobalCellType), dimension(:), pointer :: toGlobal !< map interface index to global cell - type(GlobalCellType), pointer :: boundaryCell, connectedCell - class(GwtModelType), pointer :: gwtModel - class(*), pointer :: modelPtr - - ! for readability - imCon => this%gwtInterfaceModel%dis%con - toGlobal => this%gridConnection%idxToGlobal - - ! loop over connections in interface - do n = 1, this%neq - do ipos = imCon%ia(n) + 1, imCon%ia(n+1) - 1 - m = imCon%ja(ipos) - if (associated(toGlobal(n)%model, toGlobal(m)%model)) then - ! internal connection for a model, copy from its flowja - iposLoc = getCSRIndex(toGlobal(n)%index, toGlobal(m)%index, & - toGlobal(n)%model%ia, toGlobal(n)%model%ja) - modelPtr => toGlobal(n)%model - gwtModel => CastAsGwtModel(modelPtr) - this%gwfflowja(ipos) = gwtModel%fmi%gwfflowja(iposLoc) - end if - end do - end do - - ! the flowja for exchange cells - do i = 1, this%gridConnection%nrOfBoundaryCells - boundaryCell => this%gridConnection%boundaryCells(i)%cell - connectedCell => this%gridConnection%connectedCells(i)%cell - n = this%gridConnection%getInterfaceIndex(boundaryCell%index, & - boundaryCell%model) - m = this%gridConnection%getInterfaceIndex(connectedCell%index, & - connectedCell%model) - ipos = getCSRIndex(n, m, imCon%ia, imCon%ja) - this%gwfflowja(ipos) = this%exgflowja(i) * this%exgflowSign - ipos = getCSRIndex(m, n, imCon%ia, imCon%ja) - this%gwfflowja(ipos) = -this%exgflowja(i) * this%exgflowSign - end do - - ! copy concentrations - do i = 1, this%gridConnection%nrOfCells - idx = this%gridConnection%idxToGlobal(i)%index - this%x(i) = this%gridConnection%idxToGlobal(i)%model%x(idx) - this%gwtInterfaceModel%xold(i) = this%gridConnection%idxToGlobal(i)%model%xold(idx) - end do - - ! copy fmi - do i = 1, this%gridConnection%nrOfCells - idx = this%gridConnection%idxToGlobal(i)%index - modelPtr => this%gridConnection%idxToGlobal(i)%model - gwtModel => CastAsGwtModel(modelPtr) - - this%gwfsat(i) = gwtModel%fmi%gwfsat(idx) - this%gwfhead(i) = gwtModel%fmi%gwfhead(idx) - this%gwfspdis(1, i) = gwtModel%fmi%gwfspdis(1, idx) - this%gwfspdis(2, i) = gwtModel%fmi%gwfspdis(2, idx) - this%gwfspdis(3, i) = gwtModel%fmi%gwfspdis(3, idx) - end do - -end subroutine syncInterfaceModel - - -subroutine gwtgwtcon_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) - class(GwtGwtConnectionType) :: this !< the connection - integer(I4B), intent(in) :: kiter !< the iteration counter - integer(I4B), dimension(:), intent(in) :: iasln !< global system's IA array - real(DP), dimension(:), intent(inout) :: amatsln !< global system matrix coefficients - real(DP), dimension(:), intent(inout) ::rhssln !< global right-hand-side - integer(I4B), optional, intent(in) :: inwtflag !< newton-raphson flag - ! local - integer(I4B) :: n, nglo, ipos - - call this%gwtInterfaceModel%model_fc(kiter, this%amat, this%nja, inwtflag) - - ! map back to solution matrix - do n = 1, this%neq - ! We only need the coefficients for our own model - ! (i.e. rows in the matrix that belong to this%owner): - if (.not. associated(this%gridConnection%idxToGlobal(n)%model, this%owner)) then - cycle + subroutine gwtgwtcon_ad(this) + class(GwtGwtConnectionType) :: this !< this connection + + ! recalculate dispersion ellipse + if (this%gwtInterfaceModel%indsp > 0) call this%gwtInterfaceModel%dsp%dsp_ad() + + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_ad() end if - - nglo = this%gridConnection%idxToGlobal(n)%index + this%gridConnection%idxToGlobal(n)%model%moffset - rhssln(nglo) = rhssln(nglo) + this%rhs(n) - - do ipos = this%ia(n), this%ia(n+1) - 1 - amatsln(this%mapIdxToSln(ipos)) = amatsln(this%mapIdxToSln(ipos)) + this%amat(ipos) + + end subroutine gwtgwtcon_ad + + subroutine gwtgwtcon_cf(this, kiter) + class(GwtGwtConnectionType) :: this !< the connection + integer(I4B), intent(in) :: kiter !< the iteration counter + ! local + integer(I4B) :: i + + ! reset interface system + do i = 1, this%nja + this%amat(i) = 0.0_DP + end do + do i = 1, this%neq + this%rhs(i) = 0.0_DP + end do + + call this%gwtInterfaceModel%model_cf(kiter) + + end subroutine gwtgwtcon_cf + + subroutine gwtgwtcon_fc(this, kiter, iasln, amatsln, rhssln, inwtflag) + class(GwtGwtConnectionType) :: this !< the connection + integer(I4B), intent(in) :: kiter !< the iteration counter + integer(I4B), dimension(:), intent(in) :: iasln !< global system's IA array + real(DP), dimension(:), intent(inout) :: amatsln !< global system matrix coefficients + real(DP), dimension(:), intent(inout) :: rhssln !< global right-hand-side + integer(I4B), optional, intent(in) :: inwtflag !< newton-raphson flag + ! local + integer(I4B) :: n, nglo, ipos + + call this%gwtInterfaceModel%model_fc(kiter, this%amat, this%nja, inwtflag) + + ! map back to solution matrix + do n = 1, this%neq + ! We only need the coefficients for our own model + ! (i.e. rows in the matrix that belong to this%owner): + if (.not. this%gridConnection%idxToGlobal(n)%dmodel == this%owner) then + cycle + end if + + nglo = this%gridConnection%idxToGlobal(n)%index + & + this%gridConnection%idxToGlobal(n)%dmodel%moffset + rhssln(nglo) = rhssln(nglo) + this%rhs(n) + + do ipos = this%ia(n), this%ia(n + 1) - 1 + amatsln(this%mapIdxToSln(ipos)) = amatsln(this%mapIdxToSln(ipos)) + & + this%amat(ipos) + end do end do - end do - ! FC the movers through the exchange; we can call - ! exg_fc() directly because it only handles mover terms (unlike in GwfExchange%exg_fc) - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_fc(kiter, iasln, amatsln, rhssln, inwtflag) - end if + ! FC the movers through the exchange; we can call + ! exg_fc() directly because it only handles mover terms (unlike in GwfExchange%exg_fc) + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_fc(kiter, iasln, amatsln, rhssln, inwtflag) + end if -end subroutine gwtgwtcon_fc + end subroutine gwtgwtcon_fc -subroutine gwtgwtcon_cq(this, icnvg, isuppress_output, isolnid) - class(GwtGwtConnectionType) :: this !< the connection - integer(I4B), intent(inout) :: icnvg !< convergence flag - integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 - integer(I4B), intent(in) :: isolnid !< solution id + subroutine gwtgwtcon_cq(this, icnvg, isuppress_output, isolnid) + class(GwtGwtConnectionType) :: this !< the connection + integer(I4B), intent(inout) :: icnvg !< convergence flag + integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 + integer(I4B), intent(in) :: isolnid !< solution id - call this%gwtInterfaceModel%model_cq(icnvg, isuppress_output) - call this%setFlowToExchange() + call this%gwtInterfaceModel%model_cq(icnvg, isuppress_output) + call this%setFlowToExchange() -end subroutine gwtgwtcon_cq + end subroutine gwtgwtcon_cq - !> @brief Set the flows (flowja from interface model) to the + !> @brief Set the flows (flowja from interface model) to the !< simvals in the exchange, leaving the budget calcution in there subroutine setFlowToExchange(this) + use InterfaceMapModule class(GwtGwtConnectionType) :: this !< this connection ! local integer(I4B) :: i - integer(I4B) :: nIface, mIface, ipos class(GwtExchangeType), pointer :: gwtEx + type(IndexMapSgnType), pointer :: map - gwtEx => this%gwtExchange - if (this%exchangeIsOwned) then - do i = 1, gwtEx%nexg - gwtEx%simvals(i) = DZERO - - if (gwtEx%gwtmodel1%ibound(gwtEx%nodem1(i)) /= 0 .and. & - gwtEx%gwtmodel2%ibound(gwtEx%nodem2(i)) /= 0) then + if (this%exchangeIsOwned) then + gwtEx => this%gwtExchange + map => this%interfaceMap%exchange_map(this%interfaceMap%prim_exg_idx) - nIface = this%gridConnection%getInterfaceIndex(gwtEx%nodem1(i), gwtEx%model1) - mIface = this%gridConnection%getInterfaceIndex(gwtEx%nodem2(i), gwtEx%model2) - ipos = getCSRIndex(nIface, mIface, this%gwtInterfaceModel%ia, this%gwtInterfaceModel%ja) - gwtEx%simvals(i) = this%gwtInterfaceModel%flowja(ipos) - - end if + ! use (half of) the exchange map in reverse: + do i = 1, size(map%src_idx) + if (map%sign(i) < 0) cycle ! simvals is defined from exg%m1 => exg%m2 + gwtEx%simvals(map%src_idx(i)) = & + this%gwtInterfaceModel%flowja(map%tgt_idx(i)) end do end if end subroutine setFlowToExchange -subroutine gwtgwtcon_bd(this, icnvg, isuppress_output, isolnid) - use BudgetModule, only: rate_accumulator - class(GwtGwtConnectionType) :: this !< the connection - integer(I4B), intent(inout) :: icnvg !< convergence flag - integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 - integer(I4B), intent(in) :: isolnid !< solution id - - ! call exchange budget routine, also calls bd - ! for movers. - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_bd(icnvg, isuppress_output, isolnid) - end if - -end subroutine gwtgwtcon_bd - -subroutine gwtgwtcon_ot(this) - class(GwtGwtConnectionType) :: this !< the connection - - ! Call exg_ot() here as it handles all output processing - ! based on gwtExchange%simvals(:), which was correctly - ! filled from gwtgwtcon - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_ot() - end if - -end subroutine gwtgwtcon_ot - -subroutine gwtgwtcon_da(this) - class(GwtGwtConnectionType) :: this !< the connection - ! local - logical(LGP) :: isOpen - - ! scalars - call mem_deallocate(this%iIfaceAdvScheme) - call mem_deallocate(this%iIfaceXt3d) - call mem_deallocate(this%exgflowSign) - - ! arrays - call mem_deallocate(this%gwfflowja) - call mem_deallocate(this%gwfsat) - call mem_deallocate(this%gwfhead) - call mem_deallocate(this%gwfspdis) - call mem_deallocate(this%exgflowjaGwt) - - ! interface model - call this%gwtInterfaceModel%model_da() - deallocate(this%gwtInterfaceModel) - - ! dealloc base - call this%spatialcon_da() - - inquire(this%iout, opened=isOpen) + subroutine gwtgwtcon_bd(this, icnvg, isuppress_output, isolnid) + use BudgetModule, only: rate_accumulator + class(GwtGwtConnectionType) :: this !< the connection + integer(I4B), intent(inout) :: icnvg !< convergence flag + integer(I4B), intent(in) :: isuppress_output !< suppress output when =1 + integer(I4B), intent(in) :: isolnid !< solution id + + ! call exchange budget routine, also calls bd + ! for movers. + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_bd(icnvg, isuppress_output, isolnid) + end if + + end subroutine gwtgwtcon_bd + + subroutine gwtgwtcon_ot(this) + class(GwtGwtConnectionType) :: this !< the connection + + ! Call exg_ot() here as it handles all output processing + ! based on gwtExchange%simvals(:), which was correctly + ! filled from gwtgwtcon + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_ot() + end if + + end subroutine gwtgwtcon_ot + + subroutine gwtgwtcon_da(this) + class(GwtGwtConnectionType) :: this !< the connection + ! local + logical(LGP) :: isOpen + + ! scalars + call mem_deallocate(this%iIfaceAdvScheme) + call mem_deallocate(this%iIfaceXt3d) + call mem_deallocate(this%exgflowSign) + + ! arrays + call mem_deallocate(this%exgflowjaGwt) + + ! interface model + call this%gwtInterfaceModel%model_da() + deallocate (this%gwtInterfaceModel) + + ! dealloc base + call this%spatialcon_da() + + inquire (this%iout, opened=isOpen) if (isOpen) then - close(this%iout) + close (this%iout) end if - ! we need to deallocate the exchange we own: - if (this%exchangeIsOwned) then - call this%gwtExchange%exg_da() - end if + ! we need to deallocate the exchange we own: + if (this%exchangeIsOwned) then + call this%gwtExchange%exg_da() + end if -end subroutine gwtgwtcon_da + end subroutine gwtgwtcon_da -!> @brief Cast to GwtGwtConnectionType -!< -function CastAsGwtGwtConnection(obj) result (res) - implicit none - class(*), pointer, intent(inout) :: obj !< object to be cast - class(GwtGwtConnectionType), pointer :: res !< the GwtGwtConnection - - res => null() - if (.not. associated(obj)) return - - select type (obj) - class is (GwtGwtConnectionType) - res => obj - end select - return -end function CastAsGwtGwtConnection - -end module \ No newline at end of file + !> @brief Cast to GwtGwtConnectionType + !< + function CastAsGwtGwtConnection(obj) result(res) + implicit none + class(*), pointer, intent(inout) :: obj !< object to be cast + class(GwtGwtConnectionType), pointer :: res !< the GwtGwtConnection + + res => null() + if (.not. associated(obj)) return + + select type (obj) + class is (GwtGwtConnectionType) + res => obj + end select + return + end function CastAsGwtGwtConnection + +end module diff --git a/src/Model/Connection/GwtInterfaceModel.f90 b/src/Model/Connection/GwtInterfaceModel.f90 index 0e6f3423cb7..472a63e980e 100644 --- a/src/Model/Connection/GwtInterfaceModel.f90 +++ b/src/Model/Connection/GwtInterfaceModel.f90 @@ -1,6 +1,6 @@ module GwtInterfaceModelModule - use KindModule, only: I4B, DP - use MemoryManagerModule, only: mem_allocate, mem_deallocate + use KindModule, only: I4B, DP + use MemoryManagerModule, only: mem_allocate, mem_deallocate, mem_reallocate use MemoryHelperModule, only: create_mem_path use NumericalModelModule, only: NumericalModelType use GwtModule, only: GwtModelType, CastAsGwtModel @@ -10,7 +10,7 @@ module GwtInterfaceModelModule use GwtAdvOptionsModule, only: GwtAdvOptionsType use GwtDspModule, only: dsp_cr, GwtDspType use GwtDspOptionsModule, only: GwtDspOptionsType - use GwtDspGridDataModule, only: GwtDspGridDataType + use GwtMstModule, only: mst_cr use GwtObsModule, only: gwt_obs_cr use GridConnectionModule @@ -18,222 +18,211 @@ module GwtInterfaceModelModule private !> The GWT Interface Model is a utility to calculate the solution's - !! exchange coefficients from the interface between a GWT model and - !! its GWT neighbors. The interface model itself will not be part - !! of the solution, it is not being solved. + !! exchange coefficients from the interface between a GWT model and + !! its GWT neighbors. The interface model itself will not be part + !! of the solution, it is not being solved. type, public, extends(GwtModelType) :: GwtInterfaceModelType - integer(i4B), pointer :: iAdvScheme => null() !< the advection scheme: 0 = up, 1 = central, 2 = tvd - integer(i4B), pointer :: ixt3d => null() !< xt3d setting: 0 = off, 1 = lhs, 2 = rhs + integer(i4B), pointer :: iAdvScheme => null() !< the advection scheme: 0 = up, 1 = central, 2 = tvd + integer(i4B), pointer :: ixt3d => null() !< xt3d setting: 0 = off, 1 = lhs, 2 = rhs - class(GridConnectionType), pointer :: gridConnection => null() !< The grid connection class will provide the interface grid - class(GwtModelType), private, pointer :: owner => null() !< the real GWT model for which the exchange coefficients - !! are calculated with this interface model - - real(DP), dimension(:), pointer, contiguous :: porosity => null() !< to be filled with MST porosity + class(GridConnectionType), pointer :: gridConnection => null() !< The grid connection class will provide the interface grid + class(GwtModelType), private, pointer :: owner => null() !< the real GWT model for which the exchange coefficients + !! are calculated with this interface model contains procedure, pass(this) :: gwtifmod_cr procedure :: model_df => gwtifmod_df procedure :: model_ar => gwtifmod_ar procedure :: model_da => gwtifmod_da + procedure, public :: allocate_fmi procedure :: allocate_scalars - procedure :: setDspGridData end type GwtInterfaceModelType contains -!> @brief Create the interface model, analogously to what -!< happens in gwt_cr -subroutine gwtifmod_cr(this, name, iout, gridConn) - class(GwtInterfaceModelType) :: this !< the GWT interface model - character(len=*), intent(in) :: name !< the interface model's name - integer(I4B), intent(in) :: iout !< the output unit - class(GridConnectionType), pointer, intent(in) :: gridConn !< the grid connection data for creating a DISU - ! local - class(*), pointer :: modelPtr - integer(I4B), target :: inobs - integer(I4B) :: adv_unit, dsp_unit - - this%memoryPath = create_mem_path(name) - call this%allocate_scalars(name) - - ! defaults - this%iAdvScheme = 0 - this%ixt3d = 0 - - this%iout = iout - this%gridConnection => gridConn - modelPtr => gridConn%model - this%owner => CastAsGwtModel(modelPtr) - - inobs = 0 - adv_unit = 0 - dsp_unit = 0 - if (this%owner%inadv > 0) then - this%inadv = huge(1_I4B) - adv_unit = huge(1_I4B) - end if - if (this%owner%indsp > 0) then - this%indsp = huge(1_I4B) - dsp_unit = huge(1_I4B) - end if - - ! create dis and packages - call disu_cr(this%dis, this%name, -1, this%iout) - call fmi_cr(this%fmi, this%name, 0, this%iout) - call adv_cr(this%adv, this%name, adv_unit, this%iout, this%fmi) - call dsp_cr(this%dsp, this%name, dsp_unit, this%iout, this%fmi) - call gwt_obs_cr(this%obs, inobs) - -end subroutine gwtifmod_cr - -subroutine allocate_scalars(this, modelname) - class(GwtInterfaceModelType) :: this !< the GWT interface model - character(len=*), intent(in) :: modelname !< the model name - - call this%GwtModelType%allocate_scalars(modelname) - - call mem_allocate(this%iAdvScheme, 'ADVSCHEME', this%memoryPath) - call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) - -end subroutine allocate_scalars - -!> @brief Define the GWT interface model -!< -subroutine gwtifmod_df(this) - class(GwtInterfaceModelType) :: this !< the GWT interface model - ! local - class(*), pointer :: disPtr - type(GwtAdvOptionsType) :: adv_options - type(GwtDspOptionsType) :: dsp_options - integer(I4B) :: i - - this%moffset = 0 - adv_options%iAdvScheme = this%iAdvScheme - dsp_options%ixt3d = this%ixt3d - - ! define DISU - disPtr => this%dis - call this%gridConnection%getDiscretization(CastAsDisuType(disPtr)) - call this%fmi%fmi_df(this%dis, 0) - - if (this%inadv > 0) then - call this%adv%adv_df(adv_options) - end if - if (this%indsp > 0) then - call this%dsp%dsp_df(this%dis, dsp_options) - end if - - ! assign or point model members to dis members - this%neq = this%dis%nodes - this%nja = this%dis%nja - this%ia => this%dis%con%ia - this%ja => this%dis%con%ja - ! - ! allocate model arrays, now that neq and nja are assigned - call this%allocate_arrays() - call mem_allocate(this%porosity, this%neq, 'POROSITY', this%memoryPath) - - do i = 1, size(this%flowja) - this%flowja = 0.0_DP - end do - do i = 1, this%neq - this%porosity = 0.0_DP - end do - -end subroutine gwtifmod_df - - -!> @brief Override allocate and read the GWT interface model and its -!! packages so that we can create stuff from memory instead of input -!< files -subroutine gwtifmod_ar(this) - class(GwtInterfaceModelType) :: this !< the GWT interface model - ! local - type(GwtDspGridDataType) :: dspGridData - - call this%fmi%fmi_ar(this%ibound) - if (this%inadv > 0) then - call this%adv%adv_ar(this%dis, this%ibound) - end if - if (this%indsp > 0) then - this%dsp%idiffc = this%owner%dsp%idiffc - this%dsp%idisp = this%owner%dsp%idisp - call dspGridData%construct(this%neq) - call this%setDspGridData(dspGridData) - call this%dsp%dsp_ar(this%ibound, this%porosity, dspGridData) - end if - -end subroutine gwtifmod_ar - - -!> @brief set dsp grid data from models -!< -subroutine setDspGridData(this, gridData) - class(GwtInterfaceModelType) :: this !< the GWT interface model - type(GwtDspGridDataType) :: gridData !< the dsp grid data to be set - ! local - integer(I4B) :: i, idx - class(GwtModelType), pointer :: gwtModel - class(*), pointer :: modelPtr - - do i = 1, this%neq - modelPtr => this%gridConnection%idxToGlobal(i)%model - gwtModel => CastAsGwtModel(modelPtr) - idx = this%gridConnection%idxToGlobal(i)%index - - if (this%dsp%idiffc > 0) then - gridData%diffc(i) = gwtModel%dsp%diffc(idx) + !> @brief Create the interface model, analogously to what + !< happens in gwt_cr + subroutine gwtifmod_cr(this, name, iout, gridConn) + class(GwtInterfaceModelType) :: this !< the GWT interface model + character(len=*), intent(in) :: name !< the interface model's name + integer(I4B), intent(in) :: iout !< the output unit + class(GridConnectionType), pointer, intent(in) :: gridConn !< the grid connection data for creating a DISU + ! local + class(*), pointer :: modelPtr + integer(I4B), target :: inobs + integer(I4B) :: adv_unit, dsp_unit + + this%memoryPath = create_mem_path(name) + call this%allocate_scalars(name) + + ! defaults + this%iAdvScheme = 0 + this%ixt3d = 0 + + this%iout = iout + this%gridConnection => gridConn + modelPtr => gridConn%model + this%owner => CastAsGwtModel(modelPtr) + + inobs = 0 + adv_unit = 0 + dsp_unit = 0 + if (this%owner%inadv > 0) then + this%inadv = huge(1_I4B) + adv_unit = huge(1_I4B) + end if + if (this%owner%indsp > 0) then + this%indsp = huge(1_I4B) + dsp_unit = huge(1_I4B) end if - if (this%dsp%idisp > 0) then - gridData%alh(i) = gwtModel%dsp%alh(idx) - gridData%alv(i) = gwtModel%dsp%alv(idx) - gridData%ath1(i) = gwtModel%dsp%ath1(idx) - gridData%ath2(i) = gwtModel%dsp%ath2(idx) - gridData%atv(i) = gwtModel%dsp%atv(idx) + + ! create dis and packages + call disu_cr(this%dis, this%name, -1, this%iout) + call fmi_cr(this%fmi, this%name, 0, this%iout) + call adv_cr(this%adv, this%name, adv_unit, this%iout, this%fmi) + call dsp_cr(this%dsp, this%name, -dsp_unit, this%iout, this%fmi) + call gwt_obs_cr(this%obs, inobs) + + end subroutine gwtifmod_cr + + subroutine allocate_scalars(this, modelname) + class(GwtInterfaceModelType) :: this !< the GWT interface model + character(len=*), intent(in) :: modelname !< the model name + + call this%GwtModelType%allocate_scalars(modelname) + + call mem_allocate(this%iAdvScheme, 'ADVSCHEME', this%memoryPath) + call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) + + end subroutine allocate_scalars + + subroutine allocate_fmi(this) + class(GwtInterfaceModelType) :: this !< the GWT interface model + + call mem_allocate(this%fmi%gwfflowja, this%nja, 'GWFFLOWJA', & + this%fmi%memoryPath) + call mem_allocate(this%fmi%gwfhead, this%neq, 'GWFHEAD', & + this%fmi%memoryPath) + call mem_allocate(this%fmi%gwfsat, this%neq, 'GWFSAT', & + this%fmi%memoryPath) + call mem_allocate(this%fmi%gwfspdis, 3, this%neq, 'GWFSPDIS', & + this%fmi%memoryPath) + + end subroutine allocate_fmi + + !> @brief Define the GWT interface model + !< + subroutine gwtifmod_df(this) + class(GwtInterfaceModelType) :: this !< the GWT interface model + ! local + class(*), pointer :: disPtr + type(GwtAdvOptionsType) :: adv_options + type(GwtDspOptionsType) :: dsp_options + + this%moffset = 0 + adv_options%iAdvScheme = this%iAdvScheme + dsp_options%ixt3d = this%ixt3d + + ! define DISU + disPtr => this%dis + call this%gridConnection%getDiscretization(CastAsDisuType(disPtr)) + call this%fmi%fmi_df(this%dis, 0) + + if (this%inadv > 0) then + call this%adv%adv_df(adv_options) end if + if (this%indsp > 0) then + this%dsp%idiffc = this%owner%dsp%idiffc + this%dsp%idisp = this%owner%dsp%idisp + call this%dsp%dsp_df(this%dis, dsp_options) + if (this%dsp%idiffc > 0) then + call mem_reallocate(this%dsp%diffc, this%dis%nodes, 'DIFFC', & + trim(this%dsp%memoryPath)) + end if + if (this%dsp%idisp > 0) then + call mem_reallocate(this%dsp%alh, this%dis%nodes, 'ALH', & + trim(this%dsp%memoryPath)) + call mem_reallocate(this%dsp%alv, this%dis%nodes, 'ALV', & + trim(this%dsp%memoryPath)) + call mem_reallocate(this%dsp%ath1, this%dis%nodes, 'ATH1', & + trim(this%dsp%memoryPath)) + call mem_reallocate(this%dsp%ath2, this%dis%nodes, 'ATH2', & + trim(this%dsp%memoryPath)) + call mem_reallocate(this%dsp%atv, this%dis%nodes, 'ATV', & + trim(this%dsp%memoryPath)) + end if + allocate (this%mst) + call mem_allocate(this%mst%porosity, this%dis%nodes, & + 'POROSITY', create_mem_path(this%name, 'MST')) + end if + + ! assign or point model members to dis members + this%neq = this%dis%nodes + this%nja = this%dis%nja + this%ia => this%dis%con%ia + this%ja => this%dis%con%ja + ! + ! allocate model arrays, now that neq and nja are assigned + call this%allocate_arrays() + + end subroutine gwtifmod_df + + !> @brief Override allocate and read the GWT interface model and its + !! packages so that we can create stuff from memory instead of input + !< files + subroutine gwtifmod_ar(this) + class(GwtInterfaceModelType) :: this !< the GWT interface model + + call this%fmi%fmi_ar(this%ibound) + if (this%inadv > 0) then + call this%adv%adv_ar(this%dis, this%ibound) + end if + if (this%indsp > 0) then + call this%dsp%dsp_ar(this%ibound, this%mst%porosity) + end if + + end subroutine gwtifmod_ar + + !> @brief Clean up resources + !< + subroutine gwtifmod_da(this) + class(GwtInterfaceModelType) :: this !< the GWT interface model + + ! this + call mem_deallocate(this%iAdvScheme) + call mem_deallocate(this%ixt3d) + + ! gwt packages + call this%dis%dis_da() + call this%fmi%fmi_da() + call this%adv%adv_da() + call this%dsp%dsp_da() + + deallocate (this%dis) + deallocate (this%fmi) + deallocate (this%adv) + deallocate (this%dsp) + + if (associated(this%mst)) then + call mem_deallocate(this%mst%porosity) + deallocate (this%mst) + end if + + ! gwt scalars + call mem_deallocate(this%inic) + call mem_deallocate(this%infmi) + call mem_deallocate(this%inadv) + call mem_deallocate(this%indsp) + call mem_deallocate(this%inssm) + call mem_deallocate(this%inmst) + call mem_deallocate(this%inmvt) + call mem_deallocate(this%inoc) + call mem_deallocate(this%inobs) + + ! base + call this%NumericalModelType%model_da() + + end subroutine gwtifmod_da - end do - -end subroutine setDspGridData - -!> @brief Clean up resources -!< -subroutine gwtifmod_da(this) - class(GwtInterfaceModelType) :: this !< the GWT interface model - - ! this - call mem_deallocate(this%iAdvScheme) - call mem_deallocate(this%ixt3d) - call mem_deallocate(this%porosity) - - ! gwt packages - call this%dis%dis_da() - call this%fmi%fmi_da() - call this%adv%adv_da() - call this%dsp%dsp_da() - - deallocate(this%dis) - deallocate(this%fmi) - deallocate(this%adv) - deallocate(this%dsp) - - ! gwt scalars - call mem_deallocate(this%inic) - call mem_deallocate(this%infmi) - call mem_deallocate(this%inadv) - call mem_deallocate(this%indsp) - call mem_deallocate(this%inssm) - call mem_deallocate(this%inmst) - call mem_deallocate(this%inmvt) - call mem_deallocate(this%inoc) - call mem_deallocate(this%inobs) - - ! base - call this%NumericalModelType%model_da() - -end subroutine gwtifmod_da - - -end module GwtInterfaceModelModule \ No newline at end of file +end module GwtInterfaceModelModule diff --git a/src/Model/Connection/InterfaceMap.f90 b/src/Model/Connection/InterfaceMap.f90 new file mode 100644 index 00000000000..bd4b599fb65 --- /dev/null +++ b/src/Model/Connection/InterfaceMap.f90 @@ -0,0 +1,30 @@ +module InterfaceMapModule + use KindModule, only: I4B + use ConstantsModule, only: LENMODELNAME, LENEXCHANGENAME + + implicit none + private + + type, public :: IndexMapType + integer(I4B), dimension(:), pointer :: src_idx + integer(I4B), dimension(:), pointer :: tgt_idx + end type IndexMapType + + type, public :: IndexMapSgnType + integer(I4B), dimension(:), pointer :: src_idx + integer(I4B), dimension(:), pointer :: tgt_idx + integer(I4B), dimension(:), pointer :: sign + end type IndexMapSgnType + + type, public :: InterfaceMapType + integer(I4B) :: nr_models + character(len=LENMODELNAME), dimension(:), pointer :: model_names + integer(I4B) :: nr_exchanges + integer(I4B) :: prim_exg_idx + character(len=LENEXCHANGENAME), dimension(:), pointer :: exchange_names + type(IndexMapType), dimension(:), pointer :: node_map + type(IndexMapType), dimension(:), pointer :: connection_map + type(IndexMapSgnType), dimension(:), pointer :: exchange_map + end type InterfaceMapType + +end module InterfaceMapModule diff --git a/src/Model/Connection/MappedVariable.f90 b/src/Model/Connection/MappedVariable.f90 new file mode 100644 index 00000000000..7f0a3abc574 --- /dev/null +++ b/src/Model/Connection/MappedVariable.f90 @@ -0,0 +1,166 @@ +module MappedVariableModule + use KindModule, only: I4B, LGP + use ConstantsModule, only: LENMEMPATH, LENVARNAME + use MemoryTypeModule, only: MemoryType + use MemoryManagerModule, only: get_from_memorylist + + implicit none + private + + public :: CastAsMappedVariable + public :: MappedVariableType + + type :: MappedVariableType + integer(I4B) :: controller_id + integer(I4B) :: sync_stage + character(len=LENVARNAME) :: src_name + character(len=LENMEMPATH) :: src_path + type(MemoryType), pointer :: src !< cached memory item + character(len=LENVARNAME) :: tgt_name + character(len=LENMEMPATH) :: tgt_path + type(MemoryType), pointer :: tgt !< cached memory item + integer(I4B), dimension(:), pointer :: src_idx !< source indexes to copy from + integer(I4B), dimension(:), pointer :: tgt_idx !< target indexes to copy to + integer(I4B), dimension(:), pointer :: sign !< optional sign (or null) to negate copied value + contains + procedure :: sync + procedure :: skip_sync !< possibility to skip synchronization, e.g. when src variable not allocated and should remain at default + ! private stuff + procedure, private :: sync_int1d + procedure, private :: apply_sgn_int1d + procedure, private :: sync_dbl1d + procedure, private :: apply_sgn_dbl1d + procedure, private :: sync_dbl2d + procedure, private :: apply_sgn_dbl2d + + end type MappedVariableType + +contains + + subroutine sync(this) + class(MappedVariableType) :: this + ! local + logical(LGP) :: found + + if (.not. associated(this%src)) then + ! cache + call get_from_memorylist(this%src_name, this%src_path, this%src, found) + call get_from_memorylist(this%tgt_name, this%tgt_path, this%tgt, found) + end if + + if (this%skip_sync()) return + + if (associated(this%tgt%aint1d)) call this%sync_int1d() + if (associated(this%tgt%adbl1d)) call this%sync_dbl1d() + if (associated(this%tgt%adbl2d)) call this%sync_dbl2d() + + if (associated(this%sign)) then + if (associated(this%tgt%aint1d)) call this%apply_sgn_int1d() + if (associated(this%tgt%adbl1d)) call this%apply_sgn_dbl1d() + if (associated(this%tgt%adbl2d)) call this%apply_sgn_dbl2d() + end if + + end subroutine sync + + function skip_sync(this) result(skip) + class(MappedVariableType) :: this + logical(LGP) :: skip + + skip = (this%src%isize == 0) + + end function skip_sync + + !> @brief Copy 1d integer array with map. + !< TODO_MJR: should this maybe move to the memory manager for more convenient maintenance? + subroutine sync_int1d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i + + do i = 1, size(this%tgt_idx) + this%tgt%aint1d(this%tgt_idx(i)) = this%src%aint1d(this%src_idx(i)) + end do + + end subroutine sync_int1d + + subroutine apply_sgn_int1d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i + + do i = 1, size(this%tgt_idx) + this%tgt%aint1d(this%tgt_idx(i)) = this%tgt%aint1d(this%tgt_idx(i)) * & + this%sign(i) + end do + + end subroutine apply_sgn_int1d + + !> @brief Copy 1d double array with map. + !< + subroutine sync_dbl1d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i + + do i = 1, size(this%tgt_idx) + this%tgt%adbl1d(this%tgt_idx(i)) = this%src%adbl1d(this%src_idx(i)) + end do + + end subroutine sync_dbl1d + + subroutine apply_sgn_dbl1d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i + + do i = 1, size(this%tgt_idx) + this%tgt%adbl1d(this%tgt_idx(i)) = this%tgt%adbl1d(this%tgt_idx(i)) * & + this%sign(i) + end do + + end subroutine apply_sgn_dbl1d + + !> @brief Copy 2d double array with map. + !< NB: only dim=2 is mapped. + subroutine sync_dbl2d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i, k + + do i = 1, size(this%tgt_idx) + do k = 1, size(this%src%adbl2d, dim=1) + this%tgt%adbl2d(k, this%tgt_idx(i)) = this%src%adbl2d(k, this%src_idx(i)) + end do + end do + + end subroutine sync_dbl2d + + subroutine apply_sgn_dbl2d(this) + class(MappedVariableType) :: this + ! local + integer(I4B) :: i, k + + do i = 1, size(this%tgt_idx) + do k = 1, size(this%src%adbl2d, dim=1) + this%tgt%adbl2d(k, this%tgt_idx(i)) = & + this%tgt%adbl2d(k, this%tgt_idx(i)) * this%sign(i) + end do + end do + + end subroutine apply_sgn_dbl2d + + function CastAsMappedVariable(obj) result(res) + implicit none + class(*), pointer, intent(inout) :: obj + class(MappedVariableType), pointer :: res + + res => null() + + select type (obj) + class is (MappedVariableType) + res => obj + end select + + end function CastAsMappedVariable + +end module MappedVariableModule diff --git a/src/Model/Connection/SpatialModelConnection.f90 b/src/Model/Connection/SpatialModelConnection.f90 index 19f1ba3c486..c06bcdeb7e4 100644 --- a/src/Model/Connection/SpatialModelConnection.f90 +++ b/src/Model/Connection/SpatialModelConnection.f90 @@ -1,6 +1,6 @@ module SpatialModelConnectionModule use KindModule, only: I4B, DP, LGP - use SparseModule, only:sparsematrix + use SparseModule, only: sparsematrix use ConnectionsModule, only: ConnectionsType use CsrUtilsModule, only: getCSRIndex use SimModule, only: ustop @@ -10,102 +10,106 @@ module SpatialModelConnectionModule use MemoryManagerModule, only: mem_allocate, mem_deallocate, mem_checkin use MemoryHelperModule, only: create_mem_path use GridConnectionModule, only: GridConnectionType + use InterfaceMapModule + use DistributedDataModule use ListModule, only: ListType - + implicit none private public :: CastAsSpatialModelConnectionClass public :: AddSpatialModelConnectionToList public :: GetSpatialModelConnectionFromList - !> Class to manage spatial connection of a model to one - !! or more models of the same type. Spatial connection here - !! means that the model domains (spatial discretization) are + !> Class to manage spatial connection of a model to one + !! or more models of the same type. Spatial connection here + !! means that the model domains (spatial discretization) are !! adjacent and connected via DisConnExchangeType object(s). - !! The connection itself is a Numerical Exchange as well, + !! The connection itself is a Numerical Exchange as well, !! and part of a Numerical Solution providing the amat and rhs !< values for the exchange. type, public, extends(NumericalExchangeType) :: SpatialModelConnectionType - class(NumericalModelType), pointer :: owner => null() !< the model whose connection this is - class(NumericalModelType), pointer :: interfaceModel => null() !< the interface model - integer(I4B), pointer :: nrOfConnections => null() !< total nr. of connected cells (primary) - - class(DisConnExchangeType), pointer :: primaryExchange => null() !< the exchange for which the interface model is created - type(ListType) :: globalExchanges !< all exchanges in the same solution - integer(I4B), pointer :: internalStencilDepth => null() !< size of the computational stencil for the interior - !! default = 1, xt3d = 2, ... - integer(I4B), pointer :: exchangeStencilDepth => null() !< size of the computational stencil at the interface - !! default = 1, xt3d = 2, ... - - + class(NumericalModelType), pointer :: owner => null() !< the model whose connection this is + class(NumericalModelType), pointer :: interfaceModel => null() !< the interface model + integer(I4B), pointer :: nrOfConnections => null() !< total nr. of connected cells (primary) + + class(DisConnExchangeType), pointer :: primaryExchange => null() !< the exchange for which the interface model is created + type(ListType) :: globalExchanges !< all exchanges in the same solution + integer(I4B), pointer :: internalStencilDepth => null() !< size of the computational stencil for the interior + !! default = 1, xt3d = 2, ... + integer(I4B), pointer :: exchangeStencilDepth => null() !< size of the computational stencil at the interface + !! default = 1, xt3d = 2, ... + ! The following variables are equivalent to those in Numerical Solution: - integer(I4B), pointer :: neq => null() !< nr. of equations in matrix system - integer(I4B), pointer :: nja => null() !< nr. of nonzero matrix elements - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< sparse indexing IA - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< sparse indexing JA - real(DP), dimension(:), pointer, contiguous :: amat => null() !< matrix coefficients - real(DP), dimension(:), pointer, contiguous :: rhs => null() !< rhs of interface system - real(DP), dimension(:), pointer, contiguous :: x => null() !< dependent variable of interface system - integer(I4B), dimension(:), pointer, contiguous :: active => null() !< cell status (c.f. ibound) of interface system - + integer(I4B), pointer :: neq => null() !< nr. of equations in matrix system + integer(I4B), pointer :: nja => null() !< nr. of nonzero matrix elements + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< sparse indexing IA + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< sparse indexing JA + real(DP), dimension(:), pointer, contiguous :: amat => null() !< matrix coefficients + real(DP), dimension(:), pointer, contiguous :: rhs => null() !< rhs of interface system + real(DP), dimension(:), pointer, contiguous :: x => null() !< dependent variable of interface system + integer(I4B), dimension(:), pointer, contiguous :: active => null() !< cell status (c.f. ibound) of interface system + ! these are not in the memory manager class(GridConnectionType), pointer :: gridConnection => null() !< facility to build the interface grid connection structure - integer(I4B), dimension(:), pointer :: mapIdxToSln => null() !< mapping between interface matrix and the solution matrix - + integer(I4B), dimension(:), pointer :: mapIdxToSln => null() !< mapping between interface matrix and the solution matrix + type(ListType) :: distVarList !< list with distributed variables + type(InterfaceMapType), pointer :: interfaceMap => null() !< a map of the interface into models and exchanges + contains - + ! public procedure, pass(this) :: spatialConnection_ctor generic :: construct => spatialConnection_ctor ! partly overriding NumericalExchangeType: - procedure :: exg_df => spatialcon_df + procedure :: exg_df => spatialcon_df procedure :: exg_ar => spatialcon_ar procedure :: exg_ac => spatialcon_ac procedure :: exg_mc => spatialcon_mc procedure :: exg_da => spatialcon_da - + ! protected - procedure, pass(this) :: spatialcon_df + procedure, pass(this) :: spatialcon_df procedure, pass(this) :: spatialcon_ar procedure, pass(this) :: spatialcon_ac procedure, pass(this) :: spatialcon_da procedure, pass(this) :: spatialcon_setmodelptrs procedure, pass(this) :: spatialcon_connect procedure, pass(this) :: validateConnection + procedure, pass(this) :: addDistVar + procedure, pass(this) :: mapVariables ! private procedure, private, pass(this) :: setupGridConnection - procedure, private, pass(this) :: setExchangeConnections - procedure, private, pass(this) :: getNrOfConnections + procedure, private, pass(this) :: getNrOfConnections procedure, private, pass(this) :: allocateScalars - procedure, private, pass(this) :: allocateArrays - procedure, private, pass(this) :: createCoefficientMatrix + procedure, private, pass(this) :: allocateArrays + procedure, private, pass(this) :: createCoefficientMatrix procedure, private, pass(this) :: maskOwnerConnections - + end type SpatialModelConnectionType contains ! module procedures - + !> @brief Construct the spatial connection base !! !! This constructor is typically called from a derived class. !< subroutine spatialConnection_ctor(this, model, exchange, name) - class(SpatialModelConnectionType) :: this !< the connection - class(NumericalModelType), intent(in), pointer :: model !< the model that owns the connection - class(DisConnExchangeType), intent(in), pointer :: exchange !< the primary exchange from which + class(SpatialModelConnectionType) :: this !< the connection + class(NumericalModelType), intent(in), pointer :: model !< the model that owns the connection + class(DisConnExchangeType), intent(in), pointer :: exchange !< the primary exchange from which !! the connection is created - character(len=*), intent(in) :: name !< the connection name (for memory management mostly) - + character(len=*), intent(in) :: name !< the connection name (for memory management mostly) + this%name = name this%memoryPath = create_mem_path(this%name) this%owner => model this%primaryExchange => exchange - allocate(this%gridConnection) + allocate (this%gridConnection) call this%allocateScalars() this%internalStencilDepth = 1 @@ -114,70 +118,81 @@ subroutine spatialConnection_ctor(this, model, exchange, name) ! this should be set in derived ctor this%interfaceModel => null() - + end subroutine spatialConnection_ctor - - + !> @brief Define this connection, mostly sets up the grid !< connection, allocates arrays, and links x,rhs, and ibound subroutine spatialcon_df(this) class(SpatialModelConnectionType) :: this !< this connection - + ! create the grid connection data structure this%nrOfConnections = this%getNrOfConnections() - call this%gridConnection%construct(this%owner, this%nrOfConnections, this%name) + call this%gridConnection%construct(this%owner, & + this%nrOfConnections, & + this%name) this%gridConnection%internalStencilDepth = this%internalStencilDepth this%gridConnection%exchangeStencilDepth = this%exchangeStencilDepth call this%setupGridConnection() - + this%neq = this%gridConnection%nrOfCells call this%allocateArrays() - + end subroutine spatialcon_df - !> @brief Allocate the connection, + !> @brief Allocate the connection, !< subroutine spatialcon_ar(this) class(SpatialModelConnectionType) :: this !< this connection ! local - integer(I4B) :: icell, idx, localIdx + integer(I4B) :: iface_idx class(GridConnectionType), pointer :: gc - class(NumericalModelType), pointer :: model - - ! init x and ibound with model data - gc => this%gridConnection - do icell = 1, gc%nrOfCells - idx = gc%idxToGlobal(icell)%index - model => gc%idxToGlobal(icell)%model - this%interfaceModel%x(icell) = model%x(idx) - this%interfaceModel%ibound(icell) = model%ibound(idx) - end do ! fill mapping to global index (which can be ! done now because moffset is set in sln_df) - do localIdx = 1, gc%nrOfCells - gc%idxToGlobalIdx(localIdx) = gc%idxToGlobal(localIdx)%index + & - gc%idxToGlobal(localIdx)%model%moffset + gc => this%gridConnection + do iface_idx = 1, gc%nrOfCells + gc%idxToGlobalIdx(iface_idx) = gc%idxToGlobal(iface_idx)%index + & + gc%idxToGlobal(iface_idx)%dmodel%moffset end do end subroutine spatialcon_ar - !> @brief set model pointers to connection + !> @brief Map interface variables to the specified + !< source data + subroutine mapVariables(this) + class(SpatialModelConnectionType) :: this !< this connection + + ! map distributed model variables for synchronization + call this%gridConnection%getInterfaceMap(this%interfaceMap) + call distributed_data%map_variables(this%interfaceModel%idsoln, & + this%distVarList, & + this%interfaceMap) + + end subroutine mapVariables + + !> @brief set model pointers to connection !< subroutine spatialcon_setmodelptrs(this) class(SpatialModelConnectionType) :: this !< this connection - + ! point x, ibound, and rhs to connection this%interfaceModel%x => this%x - call mem_checkin(this%interfaceModel%x, 'X', this%interfaceModel%memoryPath, 'X', this%memoryPath) + call mem_checkin(this%interfaceModel%x, 'X', & + this%interfaceModel%memoryPath, 'X', & + this%memoryPath) this%interfaceModel%rhs => this%rhs - call mem_checkin(this%interfaceModel%rhs, 'RHS', this%interfaceModel%memoryPath, 'RHS', this%memoryPath) + call mem_checkin(this%interfaceModel%rhs, 'RHS', & + this%interfaceModel%memoryPath, 'RHS', & + this%memoryPath) this%interfaceModel%ibound => this%active - call mem_checkin(this%interfaceModel%ibound, 'IBOUND', this%interfaceModel%memoryPath, 'IBOUND', this%memoryPath) + call mem_checkin(this%interfaceModel%ibound, 'IBOUND', & + this%interfaceModel%memoryPath, 'IBOUND', & + this%memoryPath) end subroutine spatialcon_setmodelptrs - !> @brief map interface model connections to our sparse matrix, + !> @brief map interface model connections to our sparse matrix, !< analogously to what happens in sln_connect. subroutine spatialcon_connect(this) class(SpatialModelConnectionType) :: this !< this connection @@ -186,21 +201,20 @@ subroutine spatialcon_connect(this) call sparse%init(this%neq, this%neq, 7) call this%interfaceModel%model_ac(sparse) - + ! create amat from sparse call this%createCoefficientMatrix(sparse) call sparse%destroy() - + ! map connections call this%interfaceModel%model_mc(this%ia, this%ja) call this%maskOwnerConnections() end subroutine spatialcon_connect - !> @brief Mask the owner's connections !! - !! Determine which connections are handled by the interface model + !! Determine which connections are handled by the interface model !! (using the connections object in its discretization) and !< set their mask to zero for the owning model. subroutine maskOwnerConnections(this) @@ -209,113 +223,117 @@ subroutine maskOwnerConnections(this) ! local integer(I4B) :: ipos, n, m, nloc, mloc, csrIdx type(ConnectionsType), pointer :: conn - + ! set the mask on connections that are calculated by the interface model conn => this%interfaceModel%dis%con do n = 1, conn%nodes ! only for connections internal to the owning model - if (.not. associated(this%gridConnection%idxToGlobal(n)%model, this%owner)) then + if (.not. this%gridConnection%idxToGlobal(n)%dmodel == this%owner) then cycle end if nloc = this%gridConnection%idxToGlobal(n)%index - + do ipos = conn%ia(n) + 1, conn%ia(n + 1) - 1 m = conn%ja(ipos) - if (.not. associated(this%gridConnection%idxToGlobal(m)%model, this%owner)) then - cycle + if (.not. this%gridConnection%idxToGlobal(m)%dmodel == this%owner) then + cycle end if mloc = this%gridConnection%idxToGlobal(m)%index - + if (conn%mask(ipos) > 0) then ! calculated by interface model, set local model's mask to zero - csrIdx = getCSRIndex(nloc, mloc, this%owner%ia, this%owner%ja) + csrIdx = getCSRIndex(nloc, mloc, this%owner%ia, this%owner%ja) if (csrIdx == -1) then - ! this can only happen with periodic boundary conditions, + ! this can only happen with periodic boundary conditions, ! then there is no need to set the mask if (this%gridConnection%isPeriodic(nloc, mloc)) cycle - - write(*,*) 'Error: cannot find cell connection in global system' + + write (*, *) 'Error: cannot find cell connection in global system' call ustop() - end if + end if if (this%owner%dis%con%mask(csrIdx) > 0) then call this%owner%dis%con%set_mask(csrIdx, 0) else ! edge case, someone will be calculating this connection ! so we ignore it here (TODO_MJR: add name) - write(*,*) 'Debug: overlap detected, ignoring connection ', & - nloc, ':', mloc, ' for model ', trim(this%owner%name), & - ' in Exchange ???' + write (*, *) 'Debug: overlap detected, ignoring connection ', & + nloc, ':', mloc, ' for model ', trim(this%owner%name), & + ' in Exchange ???' call conn%set_mask(ipos, 0) end if end if end do end do - + end subroutine maskOwnerConnections !> @brief Add connections, handled by the interface model, !< to the global system's sparse - subroutine spatialcon_ac(this, sparse) - class(SpatialModelConnectionType) :: this !< this connection + subroutine spatialcon_ac(this, sparse) + class(SpatialModelConnectionType) :: this !< this connection type(sparsematrix), intent(inout) :: sparse !< sparse matrix to store the connections ! local integer(I4B) :: n, m, ipos integer(I4B) :: nglo, mglo - + do n = 1, this%neq - if (.not. associated(this%gridConnection%idxToGlobal(n)%model, this%owner)) then + if (.not. this%gridConnection%idxToGlobal(n)%dmodel == this%owner) then ! only add connections for own model to global matrix cycle end if - nglo = this%gridConnection%idxToGlobal(n)%index + this%gridConnection%idxToGlobal(n)%model%moffset - do ipos = this%ia(n) + 1, this%ia(n+1) - 1 + nglo = this%gridConnection%idxToGlobal(n)%index + & + this%gridConnection%idxToGlobal(n)%dmodel%moffset + do ipos = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ipos) - mglo = this%gridConnection%idxToGlobal(m)%index + this%gridConnection%idxToGlobal(m)%model%moffset - + mglo = this%gridConnection%idxToGlobal(m)%index + & + this%gridConnection%idxToGlobal(m)%dmodel%moffset + call sparse%addconnection(nglo, mglo, 1) end do end do - + end subroutine spatialcon_ac - !> @brief Creates the mapping from the local system + !> @brief Creates the mapping from the local system !< matrix to the global one subroutine spatialcon_mc(this, iasln, jasln) use SimModule, only: ustop - class(SpatialModelConnectionType) :: this !< this connection + class(SpatialModelConnectionType) :: this !< this connection integer(I4B), dimension(:), intent(in) :: iasln !< global IA array integer(I4B), dimension(:), intent(in) :: jasln !< global JA array ! local integer(I4B) :: m, n, mglo, nglo, ipos, csrIdx - logical(LGP) :: isOwnedConnection - - allocate(this%mapIdxToSln(this%nja)) - - do n = 1, this%neq - isOwnedConnection = associated(this%gridConnection%idxToGlobal(n)%model, this%owner) - do ipos = this%ia(n), this%ia(n+1)-1 - m = this%ja(ipos) - nglo = this%gridConnection%idxToGlobal(n)%index + this%gridConnection%idxToGlobal(n)%model%moffset - mglo = this%gridConnection%idxToGlobal(m)%index + this%gridConnection%idxToGlobal(m)%model%moffset + logical(LGP) :: isOwned + + allocate (this%mapIdxToSln(this%nja)) + + do n = 1, this%neq + isOwned = (this%gridConnection%idxToGlobal(n)%dmodel == this%owner) + do ipos = this%ia(n), this%ia(n + 1) - 1 + m = this%ja(ipos) + nglo = this%gridConnection%idxToGlobal(n)%index + & + this%gridConnection%idxToGlobal(n)%dmodel%moffset + mglo = this%gridConnection%idxToGlobal(m)%index + & + this%gridConnection%idxToGlobal(m)%dmodel%moffset csrIdx = getCSRIndex(nglo, mglo, iasln, jasln) - if (csrIdx == -1 .and. isOwnedConnection) then + if (csrIdx == -1 .and. isOwned) then ! this should not be possible - write(*,*) 'Error: cannot find cell connection in global system' + write (*, *) 'Error: cannot find cell connection in global system' call ustop() end if - + this%mapIdxToSln(ipos) = csrIdx end do end do - + end subroutine spatialcon_mc - + !> @brief Deallocation !< subroutine spatialcon_da(this) class(SpatialModelConnectionType) :: this !< this connection - + call mem_deallocate(this%neq) call mem_deallocate(this%nja) call mem_deallocate(this%internalStencilDepth) @@ -325,73 +343,57 @@ subroutine spatialcon_da(this) call mem_deallocate(this%ia) call mem_deallocate(this%ja) call mem_deallocate(this%amat) - + call mem_deallocate(this%x) call mem_deallocate(this%rhs) call mem_deallocate(this%active) - + call this%gridConnection%destroy() - deallocate(this%gridConnection) - deallocate(this%mapIdxToSln) - + call this%distVarList%Clear(destroy=.true.) + deallocate (this%gridConnection) + deallocate (this%interfaceMap) + deallocate (this%mapIdxToSln) + end subroutine spatialcon_da - + !> @brief Set up the grid connection !! !! This works in three steps: !! 1. set the primary connections - !! 2. create the topology of connected models, finding + !! 2. create the topology of connected models, finding !! neighbors of neighboring models when required !! 3. extend the interface grid, using that information !< subroutine setupGridConnection(this) class(SpatialModelConnectionType) :: this !< this connection ! local - - ! set boundary cells - call this%setExchangeConnections() - + + ! connect cells from primary exchange + call this%gridConnection%connectPrimaryExchange(this%primaryExchange) + ! create topology of models - call this%gridConnection%findModelNeighbors(this%globalExchanges, & + call this%gridConnection%findModelNeighbors(this%globalExchanges, & this%exchangeStencilDepth) - - ! now scan for nbr-of-nbrs and create final data structures + + ! now scan for nbr-of-nbrs and create final data structures call this%gridConnection%extendConnection() - + end subroutine setupGridConnection - - !> @brief Set the primary connections from the exchange data - !< - subroutine setExchangeConnections(this) - class(SpatialModelConnectionType) :: this !< this connection - ! local - integer(I4B) :: iconn - type(DisConnExchangeType), pointer :: connEx - - ! set boundary cells - connEx => this%primaryExchange - do iconn=1, connEx%nexg - call this%gridConnection%connectCell(connEx%nodem1(iconn), connEx%model1, & - connEx%nodem2(iconn), connEx%model2) - end do - - end subroutine setExchangeConnections - !> @brief Allocation of scalars !< subroutine allocateScalars(this) use MemoryManagerModule, only: mem_allocate class(SpatialModelConnectionType) :: this !< this connection - + call mem_allocate(this%neq, 'NEQ', this%memoryPath) call mem_allocate(this%nja, 'NJA', this%memoryPath) call mem_allocate(this%internalStencilDepth, 'INTSTDEPTH', this%memoryPath) call mem_allocate(this%exchangeStencilDepth, 'EXGSTDEPTH', this%memoryPath) call mem_allocate(this%nrOfConnections, 'NROFCONNS', this%memoryPath) - + end subroutine allocateScalars - + !> @brief Allocation of arrays !< subroutine allocateArrays(this) @@ -400,40 +402,40 @@ subroutine allocateArrays(this) class(SpatialModelConnectionType) :: this !< this connection ! local integer(I4B) :: i - + call mem_allocate(this%x, this%neq, 'X', this%memoryPath) call mem_allocate(this%rhs, this%neq, 'RHS', this%memoryPath) call mem_allocate(this%active, this%neq, 'IACTIVE', this%memoryPath) - + ! c.f. NumericalSolution do i = 1, this%neq this%x(i) = DZERO this%active(i) = 1 ! default is active this%rhs(i) = DZERO - enddo - + end do + end subroutine allocateArrays - + !> @brief Returns total nr. of primary connections !< function getNrOfConnections(this) result(nrConns) class(SpatialModelConnectionType) :: this !< this connection - integer(I4B) :: nrConns + integer(I4B) :: nrConns !local - + nrConns = this%primaryExchange%nexg - + end function getNrOfConnections - + !> @brief Create connection's matrix (ia,ja,amat) from sparse !< subroutine createCoefficientMatrix(this, sparse) use SimModule, only: ustop - class(SpatialModelConnectionType) :: this !< this connection + class(SpatialModelConnectionType) :: this !< this connection type(sparsematrix), intent(inout) :: sparse !< the sparse matrix with the cell connections ! local integer(I4B) :: ierror - + this%nja = sparse%nnz call mem_allocate(this%ia, this%neq + 1, 'IA', this%memoryPath) call mem_allocate(this%ja, this%nja, 'JA', this%memoryPath) @@ -443,10 +445,10 @@ subroutine createCoefficientMatrix(this, sparse) call sparse%filliaja(this%ia, this%ja, ierror) if (ierror /= 0) then - write(*,*) 'Error: cannot fill ia/ja for model connection' + write (*, *) 'Error: cannot fill ia/ja for model connection' call ustop() end if - + end subroutine createCoefficientMatrix !> @brief Validate this connection @@ -459,31 +461,58 @@ subroutine validateConnection(this) class(DisConnExchangeType), pointer :: conEx => null() conEx => this%primaryExchange - if (conEx%ixt3d > 0) then + if (conEx%ixt3d > 0) then ! if XT3D, we need these angles: if (conEx%model1%dis%con%ianglex == 0) then - write(errmsg, '(1x,a,a,a,a,a)') 'XT3D configured on the exchange ', & - trim(conEx%name), ' but the discretization in model ', & - trim(conEx%model1%name), ' has no ANGLDEGX specified' + write (errmsg, '(1x,a,a,a,a,a)') 'XT3D configured on the exchange ', & + trim(conEx%name), ' but the discretization in model ', & + trim(conEx%model1%name), ' has no ANGLDEGX specified' call store_error(errmsg) end if if (conEx%model2%dis%con%ianglex == 0) then - write(errmsg, '(1x,a,a,a,a,a)') 'XT3D configured on the exchange ', & - trim(conEx%name), ' but the discretization in model ', & - trim(conEx%model2%name), ' has no ANGLDEGX specified' + write (errmsg, '(1x,a,a,a,a,a)') 'XT3D configured on the exchange ', & + trim(conEx%name), ' but the discretization in model ', & + trim(conEx%model2%name), ' has no ANGLDEGX specified' call store_error(errmsg) end if end if end subroutine validateConnection + subroutine addDistVar(this, var_name, subcomp_name, comp_name, & + map_type, exg_var_name, sync_stages) + class(SpatialModelConnectionType) :: this !< this connection + character(len=*) :: var_name !< name of variable, e.g. "K11" + character(len=*) :: subcomp_name !< subcomponent, e.g. "NPF" + character(len=*) :: comp_name !< component, e.g. the model or exchange name + integer(I4B) :: map_type !< can be 0 = scalar, 1 = node based, 2 = connection based, + !! 3 = exchange based (connections crossing model boundaries) + character(len=*) :: exg_var_name !< needed for exchange variables, e.g. SIMVALS + integer(I4B), dimension(:) :: sync_stages !< when to sync, e.g. (/ STAGE_AD, STAGE_CF /) + !! which is before AD and CF + ! local + type(DistVarType), pointer :: distVar => null() + class(*), pointer :: obj + + allocate (distVar) + distVar%var_name = var_name + distVar%subcomp_name = subcomp_name + distVar%comp_name = comp_name + distVar%map_type = map_type + distVar%exg_var_name = exg_var_name + distVar%sync_stages = sync_stages + + obj => distVar + call this%distVarList%Add(obj) + + end subroutine addDistVar !> @brief Cast to SpatialModelConnectionType !< - function CastAsSpatialModelConnectionClass(obj) result (res) + function CastAsSpatialModelConnectionClass(obj) result(res) implicit none - class(*), pointer, intent(inout) :: obj !< object to be cast - class(SpatialModelConnectionType), pointer :: res !< the instance of SpatialModelConnectionType + class(*), pointer, intent(inout) :: obj !< object to be cast + class(SpatialModelConnectionType), pointer :: res !< the instance of SpatialModelConnectionType ! res => null() if (.not. associated(obj)) return @@ -500,8 +529,8 @@ end function CastAsSpatialModelConnectionClass subroutine AddSpatialModelConnectionToList(list, conn) implicit none ! -- dummy - type(ListType), intent(inout) :: list !< the list - class(SpatialModelConnectionType), pointer, intent(in) :: conn !< the connection + type(ListType), intent(inout) :: list !< the list + class(SpatialModelConnectionType), pointer, intent(in) :: conn !< the connection ! -- local class(*), pointer :: obj ! @@ -514,16 +543,16 @@ end subroutine AddSpatialModelConnectionToList !> @brief Get the connection from a list !< function GetSpatialModelConnectionFromList(list, idx) result(res) - type(ListType), intent(inout) :: list !< the list - integer(I4B), intent(in) :: idx !< the index of the connection + type(ListType), intent(inout) :: list !< the list + integer(I4B), intent(in) :: idx !< the index of the connection class(SpatialModelConnectionType), pointer :: res !< the returned connection - + ! local class(*), pointer :: obj obj => list%GetItem(idx) res => CastAsSpatialModelConnectionClass(obj) ! return - end function GetSpatialModelConnectionFromList - + end function GetSpatialModelConnectionFromList + end module SpatialModelConnectionModule diff --git a/src/Model/Geometry/BaseGeometry.f90 b/src/Model/Geometry/BaseGeometry.f90 index 39bc2be3d4e..0216abb793f 100644 --- a/src/Model/Geometry/BaseGeometry.f90 +++ b/src/Model/Geometry/BaseGeometry.f90 @@ -1,13 +1,13 @@ module BaseGeometryModule - + use KindModule, only: DP, I4B - + implicit none private public BaseGeometryType - + integer(I4B), parameter :: GEONAMELEN = 20 - + type :: BaseGeometryType character(len=20) :: geo_type = 'UNDEFINED' integer(I4B) :: id = 0 @@ -21,8 +21,8 @@ module BaseGeometryModule procedure :: print_attributes end type BaseGeometryType - contains - +contains + function area_sat(this) ! -- return real(DP) :: area_sat @@ -32,8 +32,8 @@ function area_sat(this) ! -- return return end function area_sat - - function perimeter_sat(this) + + function perimeter_sat(this) ! -- return real(DP) :: perimeter_sat ! -- dummy @@ -42,29 +42,29 @@ function perimeter_sat(this) ! -- return return end function perimeter_sat - + function area_wet(this, depth) ! -- return real(DP) :: area_wet ! -- dummy class(BaseGeometryType) :: this - real(DP), intent(in) :: depth + real(DP), intent(in) :: depth area_wet = 0.d0 ! -- return return end function area_wet - + function perimeter_wet(this, depth) ! -- return real(DP) :: perimeter_wet ! -- dummy class(BaseGeometryType) :: this - real(DP), intent(in) :: depth + real(DP), intent(in) :: depth perimeter_wet = 0.d0 ! -- return return end function perimeter_wet - + subroutine set_attribute(this, line) ! -- dummy class(BaseGeometryType) :: this @@ -72,7 +72,7 @@ subroutine set_attribute(this, line) ! -- return return end subroutine set_attribute - + subroutine print_attributes(this, iout) ! ****************************************************************************** ! print_attributes -- print the attributes for this object @@ -89,13 +89,12 @@ subroutine print_attributes(this, iout) character(len=*), parameter :: fmtnm = "(4x,a,a)" ! ------------------------------------------------------------------------------ ! - write(iout, fmtid) 'ID = ', this%id - write(iout, fmtnm) 'NAME = ', trim(adjustl(this%name)) - write(iout, fmtnm) 'GEOMETRY TYPE = ', trim(adjustl(this%geo_type)) + write (iout, fmtid) 'ID = ', this%id + write (iout, fmtnm) 'NAME = ', trim(adjustl(this%name)) + write (iout, fmtnm) 'GEOMETRY TYPE = ', trim(adjustl(this%geo_type)) ! ! -- return return end subroutine print_attributes - - -end module BaseGeometryModule \ No newline at end of file + +end module BaseGeometryModule diff --git a/src/Model/Geometry/CircularGeometry.f90 b/src/Model/Geometry/CircularGeometry.f90 index b2c8cfcef5e..c49f4179e14 100644 --- a/src/Model/Geometry/CircularGeometry.f90 +++ b/src/Model/Geometry/CircularGeometry.f90 @@ -7,7 +7,7 @@ module CircularGeometryModule private public :: CircularGeometryType - + type, extends(BaseGeometryType) :: CircularGeometryType real(DP) :: radius = DZERO contains @@ -18,9 +18,9 @@ module CircularGeometryModule procedure :: set_attribute procedure :: print_attributes end type CircularGeometryType - - contains - + +contains + function area_sat(this) ! ****************************************************************************** ! area_sat -- return area as if geometry is fully saturated @@ -37,12 +37,12 @@ function area_sat(this) ! ------------------------------------------------------------------------------ ! ! -- Calculate area - area_sat = DPI * this%radius ** DTWO + area_sat = DPI * this%radius**DTWO ! ! -- Return return end function area_sat - + function perimeter_sat(this) ! ****************************************************************************** ! perimeter_sat -- return perimeter as if geometry is fully saturated @@ -64,7 +64,7 @@ function perimeter_sat(this) ! -- return return end function perimeter_sat - + function area_wet(this, depth) ! ****************************************************************************** ! area_wet -- return wetted area @@ -82,25 +82,26 @@ function area_wet(this, depth) ! ------------------------------------------------------------------------------ ! ! -- Calculate area - if(depth <= DZERO) then - area_wet = DZERO - elseif(depth <= this%radius) then - area_wet = this%radius * this%radius * & - acos((this%radius - depth) / this%radius) - & - (this%radius - depth) * sqrt(this%radius * this%radius - & - (this%radius - depth) ** DTWO) - elseif(depth <= DTWO * this%radius) then - area_wet = this%radius * this%radius * (DPI - acos((depth - this%radius) & - / this%radius)) - (this%radius - depth) * sqrt(this%radius * & - this%radius - (this%radius - depth) ** DTWO) + if (depth <= DZERO) then + area_wet = DZERO + elseif (depth <= this%radius) then + area_wet = this%radius * this%radius * & + acos((this%radius - depth) / this%radius) - & + (this%radius - depth) * & + sqrt(this%radius * this%radius - (this%radius - depth)**DTWO) + elseif (depth <= DTWO * this%radius) then + area_wet = this%radius * this%radius * & + (DPI - acos((depth - this%radius) / this%radius)) - & + (this%radius - depth) * & + sqrt(this%radius * this%radius - (this%radius - depth)**DTWO) else area_wet = DPI * this%radius * this%radius - endif + end if ! ! -- Return return end function area_wet - + function perimeter_wet(this, depth) ! ****************************************************************************** ! perimeter_wet -- return wetted perimeter @@ -118,22 +119,22 @@ function perimeter_wet(this, depth) ! ------------------------------------------------------------------------------ ! ! -- Calculate area - if(depth <= DZERO) then - perimeter_wet = DZERO - elseif(depth <= this%radius) then - perimeter_wet = DTWO * this%radius * acos((this%radius - depth) / & - this%radius) - elseif(depth <= DTWO * this%radius) then + if (depth <= DZERO) then + perimeter_wet = DZERO + elseif (depth <= this%radius) then + perimeter_wet = DTWO * this%radius * acos((this%radius - depth) / & + this%radius) + elseif (depth <= DTWO * this%radius) then perimeter_wet = DTWO * this%radius * (DPI - acos((depth - this%radius) / & - this%radius)) + this%radius)) else perimeter_wet = DTWO * DPI * this%radius - endif + end if ! ! -- return return end function perimeter_wet - + subroutine set_attribute(this, line) ! ****************************************************************************** ! set_attribute -- set a parameter for this circular object @@ -153,23 +154,23 @@ subroutine set_attribute(this, line) integer(I4B) :: lloc, istart, istop, ival real(DP) :: rval ! ------------------------------------------------------------------------------ - ! + ! ! -- should change this and set id if uninitialized or store it - lloc=1 + lloc = 1 call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0) this%id = ival - + ! -- Parse the attribute call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) - select case(line(istart:istop)) - case('NAME') + select case (line(istart:istop)) + case ('NAME') call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) this%name = line(istart:istop) - case('RADIUS') + case ('RADIUS') call urword(line, lloc, istart, istop, 3, ival, rval, 0, 0) - this%radius = rval + this%radius = rval case default - write(errmsg,'(4x,a,a)') & + write (errmsg, '(4x,a,a)') & 'Unknown circular geometry attribute: ', line(istart:istop) call store_error(errmsg, terminate=.TRUE.) end select @@ -198,12 +199,12 @@ subroutine print_attributes(this, iout) call this%BaseGeometryType%print_attributes(iout) ! ! -- Print specifics of this geometry type - write(iout, fmttd) 'RADIUS = ', this%radius - write(iout, fmttd) 'SATURATED AREA = ', this%area_sat() - write(iout, fmttd) 'SATURATED WETTED PERIMETER = ', this%perimeter_sat() + write (iout, fmttd) 'RADIUS = ', this%radius + write (iout, fmttd) 'SATURATED AREA = ', this%area_sat() + write (iout, fmttd) 'SATURATED WETTED PERIMETER = ', this%perimeter_sat() ! ! -- return return end subroutine print_attributes - -end module CircularGeometryModule \ No newline at end of file + +end module CircularGeometryModule diff --git a/src/Model/Geometry/RectangularGeometry.f90 b/src/Model/Geometry/RectangularGeometry.f90 index 59caca65127..dfe89ac50b4 100644 --- a/src/Model/Geometry/RectangularGeometry.f90 +++ b/src/Model/Geometry/RectangularGeometry.f90 @@ -5,10 +5,10 @@ module RectangularGeometryModule implicit none private public :: RectangularGeometryType - + type, extends(BaseGeometryType) :: RectangularGeometryType real(DP) :: height = DZERO - real(DP) :: width = DZERO + real(DP) :: width = DZERO contains procedure :: area_sat procedure :: perimeter_sat @@ -17,9 +17,9 @@ module RectangularGeometryModule procedure :: set_attribute procedure :: print_attributes end type RectangularGeometryType - - contains - + +contains + function area_sat(this) ! ****************************************************************************** ! area_sat -- return saturated area @@ -41,7 +41,7 @@ function area_sat(this) ! -- Return return end function area_sat - + function perimeter_sat(this) ! ****************************************************************************** ! perimeter_sat -- return saturated perimeter @@ -63,7 +63,7 @@ function perimeter_sat(this) ! -- return return end function perimeter_sat - + function area_wet(this, depth) ! ****************************************************************************** ! area_wet -- return wetted area @@ -81,18 +81,18 @@ function area_wet(this, depth) ! ------------------------------------------------------------------------------ ! ! -- Calculate area - if(depth <= DZERO) then - area_wet = DZERO - elseif(depth <= this%height) then + if (depth <= DZERO) then + area_wet = DZERO + elseif (depth <= this%height) then area_wet = depth * this%width else area_wet = this%width * this%height - endif + end if ! ! -- Return return end function area_wet - + function perimeter_wet(this, depth) ! ****************************************************************************** ! perimeter_wet -- return wetted perimeter @@ -110,18 +110,18 @@ function perimeter_wet(this, depth) ! ------------------------------------------------------------------------------ ! ! -- Calculate area - if(depth <= DZERO) then - perimeter_wet = DZERO - elseif(depth <= this%height) then + if (depth <= DZERO) then + perimeter_wet = DZERO + elseif (depth <= this%height) then perimeter_wet = DTWO * (depth + this%width) else perimeter_wet = DTWO * (this%height + this%width) - endif + end if ! ! -- return return end function perimeter_wet - + subroutine set_attribute(this, line) ! ****************************************************************************** ! set_attribute -- set a parameter for this rectangular object @@ -141,26 +141,26 @@ subroutine set_attribute(this, line) integer(I4B) :: lloc, istart, istop, ival real(DP) :: rval ! ------------------------------------------------------------------------------ - ! + ! ! -- should change this and set id if uninitialized or store it - lloc=1 + lloc = 1 call urword(line, lloc, istart, istop, 2, ival, rval, 0, 0) this%id = ival - + ! -- Parse the attribute call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) - select case(line(istart:istop)) - case('NAME') + select case (line(istart:istop)) + case ('NAME') call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) this%name = line(istart:istop) - case('HEIGHT') + case ('HEIGHT') call urword(line, lloc, istart, istop, 3, ival, rval, 0, 0) - this%height = rval - case('WIDTH') + this%height = rval + case ('WIDTH') call urword(line, lloc, istart, istop, 3, ival, rval, 0, 0) - this%width = rval + this%width = rval case default - write(errmsg,'(4x,a,a)') & + write (errmsg, '(4x,a,a)') & 'Unknown rectangular geometry attribute: ', line(istart:istop) call store_error(errmsg, terminate=.TRUE.) end select @@ -189,13 +189,13 @@ subroutine print_attributes(this, iout) call this%BaseGeometryType%print_attributes(iout) ! ! -- Print specifics of this geometry type - write(iout, fmttd) 'HEIGHT = ', this%height - write(iout, fmttd) 'WIDTH = ', this%width - write(iout, fmttd) 'SATURATED AREA = ', this%area_sat() - write(iout, fmttd) 'SATURATED WETTED PERIMETER = ', this%perimeter_sat() + write (iout, fmttd) 'HEIGHT = ', this%height + write (iout, fmttd) 'WIDTH = ', this%width + write (iout, fmttd) 'SATURATED AREA = ', this%area_sat() + write (iout, fmttd) 'SATURATED WETTED PERIMETER = ', this%perimeter_sat() ! ! -- return return end subroutine print_attributes - -end module RectangularGeometryModule \ No newline at end of file + +end module RectangularGeometryModule diff --git a/src/Model/GroundWaterFlow/gwf3.f90 b/src/Model/GroundWaterFlow/gwf3.f90 index f3a28da225b..0961b2e81c8 100644 --- a/src/Model/GroundWaterFlow/gwf3.f90 +++ b/src/Model/GroundWaterFlow/gwf3.f90 @@ -1,26 +1,27 @@ module GwfModule - use KindModule, only: DP, I4B - use InputOutputModule, only: ParseLine, upcase - use ConstantsModule, only: LENFTYPE, LENPAKLOC, DZERO, DEM1, DTEN, DEP20 - use VersionModule, only: write_listfile_header - use NumericalModelModule, only: NumericalModelType - use BaseDisModule, only: DisBaseType - use BndModule, only: BndType, AddBndToList, GetBndFromList - use GwfIcModule, only: GwfIcType - use GwfNpfModule, only: GwfNpfType - use Xt3dModule, only: Xt3dType - use GwfBuyModule, only: GwfBuyType - use GwfHfbModule, only: GwfHfbType - use GwfStoModule, only: GwfStoType - use GwfCsubModule, only: GwfCsubType - use GwfMvrModule, only: GwfMvrType - use BudgetModule, only: BudgetType - use GwfOcModule, only: GwfOcType - use GhostNodeModule, only: GhostNodeType, gnc_cr - use GwfObsModule, only: GwfObsType, gwf_obs_cr - use SimModule, only: count_errors, store_error - use BaseModelModule, only: BaseModelType + use KindModule, only: DP, I4B + use InputOutputModule, only: ParseLine, upcase + use ConstantsModule, only: LENFTYPE, LENPAKLOC, DZERO, DEM1, DTEN, DEP20 + use VersionModule, only: write_listfile_header + use NumericalModelModule, only: NumericalModelType + use BaseDisModule, only: DisBaseType + use BndModule, only: BndType, AddBndToList, GetBndFromList + use GwfIcModule, only: GwfIcType + use GwfNpfModule, only: GwfNpfType + use Xt3dModule, only: Xt3dType + use GwfBuyModule, only: GwfBuyType + use GwfVscModule, only: GwfVscType + use GwfHfbModule, only: GwfHfbType + use GwfStoModule, only: GwfStoType + use GwfCsubModule, only: GwfCsubType + use GwfMvrModule, only: GwfMvrType + use BudgetModule, only: BudgetType + use GwfOcModule, only: GwfOcType + use GhostNodeModule, only: GhostNodeType, gnc_cr + use GwfObsModule, only: GwfObsType, gwf_obs_cr + use SimModule, only: count_errors, store_error + use BaseModelModule, only: BaseModelType implicit none @@ -31,52 +32,54 @@ module GwfModule type, extends(NumericalModelType) :: GwfModelType - type(GwfIcType), pointer :: ic => null() ! initial conditions package - type(GwfNpfType), pointer :: npf => null() ! node property flow package - type(Xt3dType), pointer :: xt3d => null() ! xt3d option for npf - type(GwfBuyType), pointer :: buy => null() ! buoyancy package - type(GwfStoType), pointer :: sto => null() ! storage package - type(GwfCsubType), pointer :: csub => null() ! subsidence package - type(GwfOcType), pointer :: oc => null() ! output control package - type(GhostNodeType), pointer :: gnc => null() ! ghost node correction package - type(GwfHfbType), pointer :: hfb => null() ! horizontal flow barrier package - type(GwfMvrType), pointer :: mvr => null() ! water mover package - type(GwfObsType), pointer :: obs => null() ! observation package - type(BudgetType), pointer :: budget => null() ! budget object - integer(I4B), pointer :: inic => null() ! unit number IC - integer(I4B), pointer :: inoc => null() ! unit number OC - integer(I4B), pointer :: innpf => null() ! unit number NPF - integer(I4B), pointer :: inbuy => null() ! unit number BUY - integer(I4B), pointer :: insto => null() ! unit number STO - integer(I4B), pointer :: incsub => null() ! unit number CSUB - integer(I4B), pointer :: inmvr => null() ! unit number MVR - integer(I4B), pointer :: inhfb => null() ! unit number HFB - integer(I4B), pointer :: ingnc => null() ! unit number GNC - integer(I4B), pointer :: inobs => null() ! unit number OBS - integer(I4B), pointer :: iss => null() ! steady state flag - integer(I4B), pointer :: inewtonur => null() ! newton under relaxation flag + type(GwfIcType), pointer :: ic => null() ! initial conditions package + type(GwfNpfType), pointer :: npf => null() ! node property flow package + type(Xt3dType), pointer :: xt3d => null() ! xt3d option for npf + type(GwfBuyType), pointer :: buy => null() ! buoyancy package + type(GwfVscType), pointer :: vsc => null() ! viscosity package + type(GwfStoType), pointer :: sto => null() ! storage package + type(GwfCsubType), pointer :: csub => null() ! subsidence package + type(GwfOcType), pointer :: oc => null() ! output control package + type(GhostNodeType), pointer :: gnc => null() ! ghost node correction package + type(GwfHfbType), pointer :: hfb => null() ! horizontal flow barrier package + type(GwfMvrType), pointer :: mvr => null() ! water mover package + type(GwfObsType), pointer :: obs => null() ! observation package + type(BudgetType), pointer :: budget => null() ! budget object + integer(I4B), pointer :: inic => null() ! unit number IC + integer(I4B), pointer :: inoc => null() ! unit number OC + integer(I4B), pointer :: innpf => null() ! unit number NPF + integer(I4B), pointer :: inbuy => null() ! unit number BUY + integer(I4B), pointer :: invsc => null() ! unit number VSC + integer(I4B), pointer :: insto => null() ! unit number STO + integer(I4B), pointer :: incsub => null() ! unit number CSUB + integer(I4B), pointer :: inmvr => null() ! unit number MVR + integer(I4B), pointer :: inhfb => null() ! unit number HFB + integer(I4B), pointer :: ingnc => null() ! unit number GNC + integer(I4B), pointer :: inobs => null() ! unit number OBS + integer(I4B), pointer :: iss => null() ! steady state flag + integer(I4B), pointer :: inewtonur => null() ! newton under relaxation flag contains - procedure :: model_df => gwf_df - procedure :: model_ac => gwf_ac - procedure :: model_mc => gwf_mc - procedure :: model_ar => gwf_ar - procedure :: model_rp => gwf_rp - procedure :: model_ad => gwf_ad - procedure :: model_cf => gwf_cf - procedure :: model_fc => gwf_fc - procedure :: model_cc => gwf_cc - procedure :: model_ptcchk => gwf_ptcchk - procedure :: model_ptc => gwf_ptc - procedure :: model_nur => gwf_nur - procedure :: model_cq => gwf_cq - procedure :: model_bd => gwf_bd - procedure :: model_ot => gwf_ot - procedure :: model_fp => gwf_fp - procedure :: model_da => gwf_da - procedure :: model_bdentry => gwf_bdentry - procedure :: get_iasym => gwf_get_iasym + procedure :: model_df => gwf_df + procedure :: model_ac => gwf_ac + procedure :: model_mc => gwf_mc + procedure :: model_ar => gwf_ar + procedure :: model_rp => gwf_rp + procedure :: model_ad => gwf_ad + procedure :: model_cf => gwf_cf + procedure :: model_fc => gwf_fc + procedure :: model_cc => gwf_cc + procedure :: model_ptcchk => gwf_ptcchk + procedure :: model_ptc => gwf_ptc + procedure :: model_nur => gwf_nur + procedure :: model_cq => gwf_cq + procedure :: model_bd => gwf_bd + procedure :: model_ot => gwf_ot + procedure :: model_fp => gwf_fp + procedure :: model_da => gwf_da + procedure :: model_bdentry => gwf_bdentry + procedure :: get_iasym => gwf_get_iasym ! -- private procedure :: allocate_scalars procedure :: package_create @@ -89,67 +92,67 @@ module GwfModule end type GwfModelType ! -- Module variables constant for simulation - integer(I4B), parameter :: NIUNIT=100 + integer(I4B), parameter :: NIUNIT = 100 character(len=LENFTYPE), dimension(NIUNIT) :: cunit - data cunit/ 'IC6 ', 'DIS6 ', 'DISU6', 'OC6 ', 'NPF6 ', & ! 5 - 'STO6 ', 'HFB6 ', 'WEL6 ', 'DRN6 ', 'RIV6 ', & ! 10 - 'GHB6 ', 'RCH6 ', 'EVT6 ', 'OBS6 ', 'GNC6 ', & ! 15 - 'API6 ', 'CHD6 ', ' ', ' ', ' ', & ! 20 - ' ', 'MAW6 ', 'SFR6 ', 'LAK6 ', 'UZF6 ', & ! 25 - 'DISV6', 'MVR6 ', 'CSUB6', 'BUY6 ', ' ', & ! 30 - 70 * ' '/ + data cunit/'IC6 ', 'DIS6 ', 'DISU6', 'OC6 ', 'NPF6 ', & ! 5 + &'STO6 ', 'HFB6 ', 'WEL6 ', 'DRN6 ', 'RIV6 ', & ! 10 + &'GHB6 ', 'RCH6 ', 'EVT6 ', 'OBS6 ', 'GNC6 ', & ! 15 + &'API6 ', 'CHD6 ', ' ', ' ', ' ', & ! 20 + &' ', 'MAW6 ', 'SFR6 ', 'LAK6 ', 'UZF6 ', & ! 25 + &'DISV6', 'MVR6 ', 'CSUB6', 'BUY6 ', 'VSC6 ', & ! 30 + &70*' '/ - contains +contains !> @brief Create a new groundwater flow model object !! !! (1) creates model object and add to modellist !! (2) assign values !! - !< - subroutine gwf_cr(filename, id, modelname, smr) - ! -- modules - use ListsModule, only: basemodellist - use MemoryHelperModule, only: create_mem_path - use BaseModelModule, only: AddBaseModelToList - use SimModule, only: store_error, count_errors - use GenericUtilitiesModule, only: write_centered - use ConstantsModule, only: LINELENGTH, LENPACKAGENAME - use MemoryManagerModule, only: mem_allocate - use GwfDisModule, only: dis_cr - use GwfDisvModule, only: disv_cr - use GwfDisuModule, only: disu_cr - use GwfNpfModule, only: npf_cr - use Xt3dModule, only: xt3d_cr - use GwfBuyModule, only: buy_cr - use GwfStoModule, only: sto_cr - use GwfCsubModule, only: csub_cr - use GwfMvrModule, only: mvr_cr - use GwfHfbModule, only: hfb_cr - use GwfIcModule, only: ic_cr - use GwfOcModule, only: oc_cr - use BudgetModule, only: budget_cr - use NameFileModule, only: NameFileType + !< + subroutine gwf_cr(filename, id, modelname) + ! -- modules + use ListsModule, only: basemodellist + use MemoryHelperModule, only: create_mem_path + use BaseModelModule, only: AddBaseModelToList + use SimModule, only: store_error, count_errors + use GenericUtilitiesModule, only: write_centered + use ConstantsModule, only: LINELENGTH, LENPACKAGENAME + use MemoryManagerModule, only: mem_allocate + use GwfDisModule, only: dis_cr + use GwfDisvModule, only: disv_cr + use GwfDisuModule, only: disu_cr + use GwfNpfModule, only: npf_cr + use Xt3dModule, only: xt3d_cr + use GwfBuyModule, only: buy_cr + use GwfVscModule, only: vsc_cr + use GwfStoModule, only: sto_cr + use GwfCsubModule, only: csub_cr + use GwfMvrModule, only: mvr_cr + use GwfHfbModule, only: hfb_cr + use GwfIcModule, only: ic_cr + use GwfOcModule, only: oc_cr + use BudgetModule, only: budget_cr + use NameFileModule, only: NameFileType ! -- dummy - character(len=*), intent(in) :: filename - integer(I4B), intent(in) :: id - character(len=*), intent(in) :: modelname - logical, optional, intent(in) :: smr + character(len=*), intent(in) :: filename + integer(I4B), intent(in) :: id + character(len=*), intent(in) :: modelname ! -- local integer(I4B) :: indis, indis6, indisu6, indisv6 integer(I4B) :: ipakid, i, j, iu, ipaknum character(len=LINELENGTH) :: errmsg character(len=LENPACKAGENAME) :: pakname type(NameFileType) :: namefile_obj - type(GwfModelType), pointer :: this - class(BaseModelType), pointer :: model + type(GwfModelType), pointer :: this + class(BaseModelType), pointer :: model integer(I4B) :: nwords character(len=LINELENGTH), allocatable, dimension(:) :: words ! -- format ! ------------------------------------------------------------------------------ ! ! -- Allocate a new GWF Model (this) and add it to basemodellist - allocate(this) + allocate (this) ! ! -- Set memory path before allocation in memory manager can be done this%memoryPath = create_mem_path(modelname) @@ -163,7 +166,6 @@ subroutine gwf_cr(filename, id, modelname, smr) this%name = modelname this%macronym = 'GWF' this%id = id - if(present(smr)) this%single_model_run = smr ! ! -- Open namefile and set iout call namefile_obj%init(this%filename, 0) @@ -178,45 +180,45 @@ subroutine gwf_cr(filename, id, modelname, smr) ! ! -- GWF options if (size(namefile_obj%opts) > 0) then - write(this%iout, '(1x,a)') 'NAMEFILE OPTIONS:' + write (this%iout, '(1x,a)') 'NAMEFILE OPTIONS:' end if ! ! -- Parse options in the GWF name file do i = 1, size(namefile_obj%opts) call ParseLine(namefile_obj%opts(i), nwords, words) call upcase(words(1)) - select case(words(1)) - case('NEWTON') - this%inewton = 1 - write(this%iout, '(4x,a)') & - 'NEWTON-RAPHSON method enabled for the model.' - if (nwords > 1) then - call upcase(words(2)) - if (words(2) == 'UNDER_RELAXATION') then - this%inewtonur = 1 - write(this%iout, '(4x,a,a)') & - 'NEWTON-RAPHSON UNDER-RELAXATION based on the bottom ', & - 'elevation of the model will be applied to the model.' - end if + select case (words(1)) + case ('NEWTON') + this%inewton = 1 + write (this%iout, '(4x,a)') & + 'NEWTON-RAPHSON method enabled for the model.' + if (nwords > 1) then + call upcase(words(2)) + if (words(2) == 'UNDER_RELAXATION') then + this%inewtonur = 1 + write (this%iout, '(4x,a,a)') & + 'NEWTON-RAPHSON UNDER-RELAXATION based on the bottom ', & + 'elevation of the model will be applied to the model.' end if - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'STRESS PACKAGE INPUT WILL BE PRINTED '// & - 'FOR ALL MODEL STRESS PACKAGES' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') 'PACKAGE FLOWS WILL BE PRINTED '// & - 'FOR ALL MODEL PACKAGES' - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, '(4x,a)') & - 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL' - case default - write(errmsg,'(4x,a,a,a,a)') & - 'Unknown GWF namefile (', & - trim(adjustl(this%filename)), ') option: ', & - trim(adjustl(namefile_obj%opts(i))) - call store_error(errmsg, terminate=.TRUE.) + end if + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') 'STRESS PACKAGE INPUT WILL BE PRINTED '// & + 'FOR ALL MODEL STRESS PACKAGES' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') 'PACKAGE FLOWS WILL BE PRINTED '// & + 'FOR ALL MODEL PACKAGES' + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, '(4x,a)') & + 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL' + case default + write (errmsg, '(4x,a,a,a,a)') & + 'Unknown GWF namefile (', & + trim(adjustl(this%filename)), ') option: ', & + trim(adjustl(namefile_obj%opts(i))) + call store_error(errmsg, terminate=.TRUE.) end select end do ! @@ -228,15 +230,16 @@ subroutine gwf_cr(filename, id, modelname, smr) indisu6 = 0 indisv6 = 0 call namefile_obj%get_unitnumber('DIS6', indis6, 1) - if(indis6 > 0) indis = indis6 - if(indis <= 0) call namefile_obj%get_unitnumber('DISU6', indisu6, 1) - if(indisu6 > 0) indis = indisu6 - if(indis <= 0) call namefile_obj%get_unitnumber('DISV6', indisv6, 1) - if(indisv6 > 0) indis = indisv6 - call namefile_obj%get_unitnumber('IC6', this%inic, 1) - call namefile_obj%get_unitnumber('OC6', this%inoc, 1) + if (indis6 > 0) indis = indis6 + if (indis <= 0) call namefile_obj%get_unitnumber('DISU6', indisu6, 1) + if (indisu6 > 0) indis = indisu6 + if (indis <= 0) call namefile_obj%get_unitnumber('DISV6', indisv6, 1) + if (indisv6 > 0) indis = indisv6 + call namefile_obj%get_unitnumber('IC6', this%inic, 1) + call namefile_obj%get_unitnumber('OC6', this%inoc, 1) call namefile_obj%get_unitnumber('NPF6', this%innpf, 1) call namefile_obj%get_unitnumber('BUY6', this%inbuy, 1) + call namefile_obj%get_unitnumber('VSC6', this%invsc, 1) call namefile_obj%get_unitnumber('STO6', this%insto, 1) call namefile_obj%get_unitnumber('CSUB6', this%incsub, 1) call namefile_obj%get_unitnumber('MVR6', this%inmvr, 1) @@ -248,13 +251,13 @@ subroutine gwf_cr(filename, id, modelname, smr) call this%ftype_check(namefile_obj, indis) ! ! -- Create discretization object - if(indis6 > 0) then + if (indis6 > 0) then call dis_cr(this%dis, this%name, indis, this%iout) - elseif(indisu6 > 0) then + elseif (indisu6 > 0) then call disu_cr(this%dis, this%name, indis, this%iout) - elseif(indisv6 > 0) then + elseif (indisv6 > 0) then call disv_cr(this%dis, this%name, indis, this%iout) - endif + end if ! ! -- Create utility objects call budget_cr(this%budget, this%name) @@ -263,10 +266,11 @@ subroutine gwf_cr(filename, id, modelname, smr) call npf_cr(this%npf, this%name, this%innpf, this%iout) call xt3d_cr(this%xt3d, this%name, this%innpf, this%iout) call buy_cr(this%buy, this%name, this%inbuy, this%iout) + call vsc_cr(this%vsc, this%name, this%invsc, this%iout) call gnc_cr(this%gnc, this%name, this%ingnc, this%iout) call hfb_cr(this%hfb, this%name, this%inhfb, this%iout) call sto_cr(this%sto, this%name, this%insto, this%iout) - call csub_cr(this%csub, this%name, this%insto, this%sto%packName, & + call csub_cr(this%csub, this%name, this%insto, this%sto%packName, & this%incsub, this%iout) call ic_cr(this%ic, this%name, this%inic, this%iout, this%dis) call mvr_cr(this%mvr, this%name, this%inmvr, this%iout, this%dis) @@ -280,19 +284,19 @@ subroutine gwf_cr(filename, id, modelname, smr) do j = 1, namefile_obj%get_nval_for_row(i) iu = namefile_obj%get_unitnumber_rowcol(i, j) call namefile_obj%get_pakname(i, j, pakname) - call this%package_create(cunit(i), ipakid, ipaknum, pakname, iu, & - this%iout) + call this%package_create(cunit(i), ipakid, ipaknum, pakname, iu, & + this%iout) ipaknum = ipaknum + 1 ipakid = ipakid + 1 - enddo - enddo + end do + end do ! ! -- return return end subroutine gwf_cr !> @brief Define packages of the model - !! + !! !! (1) call df routines for each package !! (2) set gwf variables and pointers !! @@ -308,18 +312,19 @@ subroutine gwf_df(this) ! ! -- Define packages and utility objects call this%dis%dis_df() - call this%npf%npf_df(this%dis, this%xt3d, this%ingnc) + call this%npf%npf_df(this%dis, this%xt3d, this%ingnc, this%invsc) call this%oc%oc_df() call this%budget%budget_df(niunit, 'VOLUME', 'L**3') if (this%inbuy > 0) call this%buy%buy_df(this%dis) + if (this%invsc > 0) call this%vsc%vsc_df(this%dis) if (this%ingnc > 0) call this%gnc%gnc_df(this) ! ! -- Assign or point model members to dis members ! this%neq will be incremented if packages add additional unknowns this%neq = this%dis%nodes this%nja = this%dis%nja - this%ia => this%dis%con%ia - this%ja => this%dis%con%ja + this%ia => this%dis%con%ia + this%ja => this%dis%con%ja ! ! -- Allocate model arrays, now that neq and nja are known call this%allocate_arrays() @@ -328,7 +333,7 @@ subroutine gwf_df(this) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_df(this%neq, this%dis) - enddo + end do ! ! -- Store information needed for observations call this%obs%obs_df(this%iout, this%name, 'GWF', this%dis) @@ -353,16 +358,16 @@ subroutine gwf_ac(this, sparse) call this%dis%dis_ac(this%moffset, sparse) ! ! -- Add any additional connections that NPF may need - if(this%innpf > 0) call this%npf%npf_ac(this%moffset, sparse) + if (this%innpf > 0) call this%npf%npf_ac(this%moffset, sparse) ! ! -- Add any package connections do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ac(this%moffset, sparse) - enddo + end do ! ! -- If GNC is active, then add the gnc connections to sparse - if(this%ingnc > 0) call this%gnc%gnc_ac(sparse) + if (this%ingnc > 0) call this%gnc%gnc_ac(sparse) ! ! -- return return @@ -386,17 +391,17 @@ subroutine gwf_mc(this, iasln, jasln) call this%dis%dis_mc(this%moffset, this%idxglo, iasln, jasln) ! ! -- Map any additional connections that NPF may need - if(this%innpf > 0) call this%npf%npf_mc(this%moffset, iasln, jasln) + if (this%innpf > 0) call this%npf%npf_mc(this%moffset, iasln, jasln) ! ! -- Map any package connections - do ip=1,this%bndlist%Count() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_mc(this%moffset, iasln, jasln) - enddo + end do ! ! -- For implicit gnc, need to store positions of gnc connections ! in solution matrix connection - if(this%ingnc > 0) call this%gnc%gnc_mc(iasln, jasln) + if (this%ingnc > 0) call this%gnc%gnc_mc(iasln, jasln) ! ! -- return return @@ -405,7 +410,7 @@ end subroutine gwf_mc !> @brief GroundWater Flow Model Allocate and Read !! !! (1) allocates and reads packages part of this model, - !! (2) allocates memory for arrays part of this model object + !! (2) allocates memory for arrays part of this model object !! !< subroutine gwf_ar(this) @@ -417,14 +422,17 @@ subroutine gwf_ar(this) ! ------------------------------------------------------------------------------ ! ! -- Allocate and read modules attached to model - if(this%inic > 0) call this%ic%ic_ar(this%x) - if(this%innpf > 0) call this%npf%npf_ar(this%ic, this%ibound, this%x) - if(this%inbuy > 0) call this%buy%buy_ar(this%npf, this%ibound) - if(this%inhfb > 0) call this%hfb%hfb_ar(this%ibound, this%xt3d, this%dis) - if(this%insto > 0) call this%sto%sto_ar(this%dis, this%ibound) - if(this%incsub > 0) call this%csub%csub_ar(this%dis, this%ibound) - if(this%inmvr > 0) call this%mvr%mvr_ar() - if(this%inobs > 0) call this%obs%gwf_obs_ar(this%ic, this%x, this%flowja) + if (this%inic > 0) call this%ic%ic_ar(this%x) + if (this%innpf > 0) call this%npf%npf_ar(this%ic, this%vsc, this%ibound, & + this%x) + if (this%invsc > 0) call this%vsc%vsc_ar(this%ibound) + if (this%inbuy > 0) call this%buy%buy_ar(this%npf, this%ibound) + if (this%inhfb > 0) call this%hfb%hfb_ar(this%ibound, this%xt3d, this%dis, & + this%invsc, this%vsc) + if (this%insto > 0) call this%sto%sto_ar(this%dis, this%ibound) + if (this%incsub > 0) call this%csub%csub_ar(this%dis, this%ibound) + if (this%inmvr > 0) call this%mvr%mvr_ar() + if (this%inobs > 0) call this%obs%gwf_obs_ar(this%ic, this%x, this%flowja) ! ! -- Call dis_ar to write binary grid file call this%dis%dis_ar(this%npf%icelltype) @@ -434,24 +442,25 @@ subroutine gwf_ar(this) call this%budget%set_ibudcsv(this%oc%ibudcsv) ! ! -- Package input files now open, so allocate and read - do ip = 1,this%bndlist%Count() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) - call packobj%set_pointers(this%dis%nodes, this%ibound, this%x, & + call packobj%set_pointers(this%dis%nodes, this%ibound, this%x, & this%xold, this%flowja) ! -- Read and allocate package call packobj%bnd_ar() if (this%inbuy > 0) call this%buy%buy_ar_bnd(packobj, this%x) - enddo + if (this%invsc > 0) call this%vsc%vsc_ar_bnd(packobj) + end do ! ! -- return return end subroutine gwf_ar !> @brief GroundWater Flow Model Read and Prepare - !! - !! (1) calls package read and prepare routines !! - !< + !! (1) calls package read and prepare routines + !! + !< subroutine gwf_rp(this) ! -- modules use TdisModule, only: readnewdata @@ -466,18 +475,19 @@ subroutine gwf_rp(this) if (.not. readnewdata) return ! ! -- Read and prepare - if(this%innpf > 0) call this%npf%npf_rp() - if(this%inbuy > 0) call this%buy%buy_rp() - if(this%inhfb > 0) call this%hfb%hfb_rp() - if(this%inoc > 0) call this%oc%oc_rp() - if(this%insto > 0) call this%sto%sto_rp() - if(this%incsub > 0) call this%csub%csub_rp() - if(this%inmvr > 0) call this%mvr%mvr_rp() + if (this%innpf > 0) call this%npf%npf_rp() + if (this%inbuy > 0) call this%buy%buy_rp() + if (this%invsc > 0) call this%vsc%vsc_rp() + if (this%inhfb > 0) call this%hfb%hfb_rp() + if (this%inoc > 0) call this%oc%oc_rp() + if (this%insto > 0) call this%sto%sto_rp() + if (this%incsub > 0) call this%csub%csub_rp() + if (this%inmvr > 0) call this%mvr%mvr_rp() do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_rp() call packobj%bnd_rp_obs() - enddo + end do ! ! -- Return return @@ -507,29 +517,31 @@ subroutine gwf_ad(this) ! -- copy x into xold do n = 1, this%dis%nodes this%xold(n) = this%x(n) - enddo + end do else ! ! -- copy xold into x if this time step is a redo do n = 1, this%dis%nodes this%x(n) = this%xold(n) - enddo + end do end if ! ! -- Advance - if(this%innpf > 0) call this%npf%npf_ad(this%dis%nodes, this%xold, & - this%x, irestore) - if(this%insto > 0) call this%sto%sto_ad() - if(this%incsub > 0) call this%csub%csub_ad(this%dis%nodes, this%x) - if(this%inbuy > 0) call this%buy%buy_ad() - if(this%inmvr > 0) call this%mvr%mvr_ad() - do ip=1,this%bndlist%Count() + if (this%invsc > 0) call this%vsc%vsc_ad() + if (this%innpf > 0) call this%npf%npf_ad(this%dis%nodes, this%xold, & + this%x, irestore) + if (this%insto > 0) call this%sto%sto_ad() + if (this%incsub > 0) call this%csub%csub_ad(this%dis%nodes, this%x) + if (this%inbuy > 0) call this%buy%buy_ad() + if (this%inmvr > 0) call this%mvr%mvr_ad() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ad() + if (this%invsc > 0) call this%vsc%vsc_ad_bnd(packobj, this%x) if (isimcheck > 0) then call packobj%bnd_ck() end if - enddo + end do ! ! -- Push simulated values to preceding time/subtime step call this%obs%obs_ad() @@ -542,20 +554,20 @@ end subroutine gwf_ad subroutine gwf_cf(this, kiter) ! -- dummy class(GwfModelType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter ! -- local class(BndType), pointer :: packobj integer(I4B) :: ip ! ------------------------------------------------------------------------------ ! ! -- Call package cf routines - if(this%innpf > 0) call this%npf%npf_cf(kiter, this%dis%nodes, this%x) - if(this%inbuy > 0) call this%buy%buy_cf(kiter) + if (this%innpf > 0) call this%npf%npf_cf(kiter, this%dis%nodes, this%x) + if (this%inbuy > 0) call this%buy%buy_cf(kiter) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_cf() if (this%inbuy > 0) call this%buy%buy_cf_bnd(packobj, this%x) - enddo + end do ! ! -- return return @@ -577,70 +589,70 @@ subroutine gwf_fc(this, kiter, amatsln, njasln, inwtflag) ! ! -- newton flags inwt = inwtflag - if(inwtflag == 1) inwt = this%npf%inewton + if (inwtflag == 1) inwt = this%npf%inewton inwtsto = inwtflag - if(this%insto > 0) then - if(inwtflag == 1) inwtsto = this%sto%inewton - endif + if (this%insto > 0) then + if (inwtflag == 1) inwtsto = this%sto%inewton + end if inwtcsub = inwtflag - if(this%incsub > 0) then - if(inwtflag == 1) inwtcsub = this%csub%inewton - endif + if (this%incsub > 0) then + if (inwtflag == 1) inwtcsub = this%csub%inewton + end if ! ! -- Fill standard conductance terms - if(this%innpf > 0) call this%npf%npf_fc(kiter, njasln, amatsln, & - this%idxglo, this%rhs, this%x) - if(this%inbuy > 0) call this%buy%buy_fc(kiter, njasln, amatsln, & - this%idxglo, this%rhs, this%x) - if(this%inhfb > 0) call this%hfb%hfb_fc(kiter, njasln, amatsln, & - this%idxglo, this%rhs, this%x) - if(this%ingnc > 0) call this%gnc%gnc_fc(kiter, amatsln) + if (this%innpf > 0) call this%npf%npf_fc(kiter, njasln, amatsln, & + this%idxglo, this%rhs, this%x) + if (this%inbuy > 0) call this%buy%buy_fc(kiter, njasln, amatsln, & + this%idxglo, this%rhs, this%x) + if (this%inhfb > 0) call this%hfb%hfb_fc(kiter, njasln, amatsln, & + this%idxglo, this%rhs, this%x) + if (this%ingnc > 0) call this%gnc%gnc_fc(kiter, amatsln) ! -- storage - if(this%insto > 0) then - call this%sto%sto_fc(kiter, this%xold, this%x, njasln, amatsln, & + if (this%insto > 0) then + call this%sto%sto_fc(kiter, this%xold, this%x, njasln, amatsln, & this%idxglo, this%rhs) end if - ! -- skeletal storage, compaction, and land subsidence - if(this%incsub > 0) then - call this%csub%csub_fc(kiter, this%xold, this%x, njasln, amatsln, & + ! -- skeletal storage, compaction, and land subsidence + if (this%incsub > 0) then + call this%csub%csub_fc(kiter, this%xold, this%x, njasln, amatsln, & this%idxglo, this%rhs) end if - if(this%inmvr > 0) call this%mvr%mvr_fc() + if (this%inmvr > 0) call this%mvr%mvr_fc() do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_fc(this%rhs, this%ia, this%idxglo, amatsln) - enddo + end do ! !--Fill newton terms - if(this%innpf > 0) then - if(inwt /= 0) then - call this%npf%npf_fn(kiter, njasln, amatsln, this%idxglo, this%rhs, & + if (this%innpf > 0) then + if (inwt /= 0) then + call this%npf%npf_fn(kiter, njasln, amatsln, this%idxglo, this%rhs, & this%x) - endif - endif + end if + end if ! ! -- Fill newton terms for ghost nodes - if(this%ingnc > 0) then - if(inwt /= 0) then - call this%gnc%gnc_fn(kiter, njasln, amatsln, this%npf%condsat, & - ivarcv_opt=this%npf%ivarcv, & - ictm1_opt=this%npf%icelltype, & - ictm2_opt=this%npf%icelltype) - endif - endif + if (this%ingnc > 0) then + if (inwt /= 0) then + call this%gnc%gnc_fn(kiter, njasln, amatsln, this%npf%condsat, & + ivarcv_opt=this%npf%ivarcv, & + ictm1_opt=this%npf%icelltype, & + ictm2_opt=this%npf%icelltype) + end if + end if ! ! -- Fill newton terms for storage - if(this%insto > 0) then + if (this%insto > 0) then if (inwtsto /= 0) then - call this%sto%sto_fn(kiter, this%xold, this%x, njasln, amatsln, & + call this%sto%sto_fn(kiter, this%xold, this%x, njasln, amatsln, & this%idxglo, this%rhs) end if end if ! - ! -- Fill newton terms for skeletal storage, compaction, and land subsidence - if(this%incsub > 0) then + ! -- Fill newton terms for skeletal storage, compaction, and land subsidence + if (this%incsub > 0) then if (inwtcsub /= 0) then - call this%csub%csub_fn(kiter, this%xold, this%x, njasln, amatsln, & + call this%csub%csub_fn(kiter, this%xold, this%x, njasln, amatsln, & this%idxglo, this%rhs) end if end if @@ -649,11 +661,11 @@ subroutine gwf_fc(this, kiter, amatsln, njasln, inwtflag) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) inwtpak = inwtflag - if(inwtflag == 1) inwtpak = packobj%inewton + if (inwtflag == 1) inwtpak = packobj%inewton if (inwtpak /= 0) then call packobj%bnd_fn(this%rhs, this%ia, this%idxglo, amatsln) end if - enddo + end do ! ! -- return return @@ -662,15 +674,15 @@ end subroutine gwf_fc !> @brief GroundWater Flow Model Final Convergence Check for Boundary Packages !! !! (1) calls package cc routines - !! + !! !< subroutine gwf_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! -- dummy class(GwfModelType) :: this - integer(I4B),intent(in) :: innertot - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: iend - integer(I4B),intent(in) :: icnvgmod + integer(I4B), intent(in) :: innertot + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: iend + integer(I4B), intent(in) :: icnvgmod character(len=LENPAKLOC), intent(inout) :: cpak integer(I4B), intent(inout) :: ipak real(DP), intent(inout) :: dpak @@ -687,8 +699,8 @@ subroutine gwf_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! ! -- csub convergence check if (this%incsub > 0) then - call this%csub%csub_cc(innertot, kiter, iend, icnvgmod, & - this%dis%nodes, this%x, this%xold, & + call this%csub%csub_cc(innertot, kiter, iend, icnvgmod, & + this%dis%nodes, this%x, this%xold, & cpak, ipak, dpak) end if ! @@ -696,12 +708,12 @@ subroutine gwf_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_cc(innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) - enddo + end do ! ! -- return return end subroutine gwf_cc - + !> @brief check if pseudo-transient continuation factor should be used !! !! (1) Check if pseudo-transient continuation factor should be used @@ -712,7 +724,7 @@ subroutine gwf_ptcchk(this, iptc) class(GwfModelType) :: this integer(I4B), intent(inout) :: iptc ! ------------------------------------------------------------------------------ - ! -- determine if pseudo-transient continuation should be applied to this + ! -- determine if pseudo-transient continuation should be applied to this ! model - pseudo-transient continuation only applied to problems that ! use the Newton-Raphson formulation during steady-state stress periods iptc = 0 @@ -734,22 +746,22 @@ end subroutine gwf_ptcchk !! for the current outer iteration !! !< - subroutine gwf_ptc(this, kiter, neqsln, njasln, ia, ja, & + subroutine gwf_ptc(this, kiter, neqsln, njasln, ia, ja, & x, rhs, amatsln, iptc, ptcf) ! modules use ConstantsModule, only: DONE, DP9 ! -- dummy class(GwfModelType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter integer(I4B), intent(in) :: neqsln - integer(I4B),intent(in) :: njasln - integer(I4B), dimension(neqsln+1), intent(in) :: ia - integer(I4B),dimension(njasln),intent(in) :: ja + integer(I4B), intent(in) :: njasln + integer(I4B), dimension(neqsln + 1), intent(in) :: ia + integer(I4B), dimension(njasln), intent(in) :: ja real(DP), dimension(neqsln), intent(in) :: x real(DP), dimension(neqsln), intent(in) :: rhs - real(DP),dimension(njasln),intent(in) :: amatsln + real(DP), dimension(njasln), intent(in) :: amatsln integer(I4B), intent(inout) :: iptc - real(DP),intent(inout) :: ptcf + real(DP), intent(inout) :: ptcf ! -- local integer(I4B) :: iptct integer(I4B) :: n @@ -766,7 +778,7 @@ subroutine gwf_ptc(this, kiter, neqsln, njasln, ia, ja, & ! -- set temporary flag indicating if pseudo-transient continuation should ! be used for this model and time step iptct = 0 - ! -- only apply pseudo-transient continuation to problems using the + ! -- only apply pseudo-transient continuation to problems using the ! Newton-Raphson formulations for steady-state stress periods if (this%iss > 0) then if (this%inewton > 0) then @@ -785,12 +797,12 @@ subroutine gwf_ptc(this, kiter, neqsln, njasln, ia, ja, & if (this%npf%ibound(n) < 1) cycle jcol = n + this%moffset ! - ! get the maximum volume of the cell (head at top of cell) + ! get the maximum volume of the cell (head at top of cell) v = this%dis%get_cell_volume(n, this%dis%top(n)) ! ! -- calculate the residual for the cell resid = DZERO - do j = ia(jcol), ia(jcol+1)-1 + do j = ia(jcol), ia(jcol + 1) - 1 jj = ja(j) resid = resid + amatsln(j) * x(jcol) end do @@ -801,8 +813,8 @@ subroutine gwf_ptc(this, kiter, neqsln, njasln, ia, ja, & ptcdelem1 = abs(resid) / v ! ! -- set ptcf if the reciprocal of the pseudo-time step - ! exceeds the current value (equivalent to using the - ! smallest pseudo-time step) + ! exceeds the current value (equivalent to using the + ! smallest pseudo-time step) if (ptcdelem1 > ptcf) ptcf = ptcdelem1 ! ! -- determine minimum and maximum diagonal entries @@ -880,7 +892,7 @@ subroutine gwf_nur(this, neqmod, x, xtemp, dx, inewtonur, dxmax, locmax) dx(i0:i1), inewtonur, dxmax, locmax) i0 = i1 + 1 end if - enddo + end do end if ! ! -- return @@ -911,14 +923,14 @@ subroutine gwf_cq(this, icnvg, isuppress_output) ! its flow to this diagonal position. do i = 1, this%nja this%flowja(i) = DZERO - enddo - if(this%innpf > 0) call this%npf%npf_cq(this%x, this%flowja) - if(this%inbuy > 0) call this%buy%buy_cq(this%x, this%flowja) - if(this%inhfb > 0) call this%hfb%hfb_cq(this%x, this%flowja) - if(this%ingnc > 0) call this%gnc%gnc_cq(this%flowja) - if(this%insto > 0) call this%sto%sto_cq(this%flowja, this%x, this%xold) - if(this%incsub > 0) call this%csub%csub_cq(this%dis%nodes, this%x, & - this%xold, isuppress_output, & + end do + if (this%innpf > 0) call this%npf%npf_cq(this%x, this%flowja) + if (this%inbuy > 0) call this%buy%buy_cq(this%x, this%flowja) + if (this%inhfb > 0) call this%hfb%hfb_cq(this%x, this%flowja) + if (this%ingnc > 0) call this%gnc%gnc_cq(this%flowja) + if (this%insto > 0) call this%sto%sto_cq(this%flowja, this%x, this%xold) + if (this%incsub > 0) call this%csub%csub_cq(this%dis%nodes, this%x, & + this%xold, isuppress_output, & this%flowja) ! ! -- Go through packages and call cq routines. cf() routines are called @@ -929,12 +941,12 @@ subroutine gwf_cq(this, icnvg, isuppress_output) call packobj%bnd_cf(reset_mover=.false.) if (this%inbuy > 0) call this%buy%buy_cf_bnd(packobj, this%x) call packobj%bnd_cq(this%x, this%flowja) - enddo + end do ! ! -- Return return end subroutine gwf_cq - + !> @brief GroundWater Flow Model Budget !! !! (1) Calculate stress package contributions to model budget @@ -965,13 +977,13 @@ subroutine gwf_bd(this, icnvg, isuppress_output) ! should be added here to this%budget. In a subsequent exchange call, ! exchange flows might also be added. call this%budget%reset() - if(this%insto > 0) call this%sto%sto_bd(isuppress_output, this%budget) - if(this%incsub > 0) call this%csub%csub_bd(isuppress_output, this%budget) - if(this%inmvr > 0) call this%mvr%mvr_bd() + if (this%insto > 0) call this%sto%sto_bd(isuppress_output, this%budget) + if (this%incsub > 0) call this%csub%csub_bd(isuppress_output, this%budget) + if (this%inmvr > 0) call this%mvr%mvr_bd() do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_bd(this%budget) - enddo + end do ! ! -- npf velocities have to be calculated here, after gwf-gwf exchanges ! have passed in their contributions from exg_cq() @@ -999,7 +1011,7 @@ subroutine gwf_ot(this) integer(I4B) :: ibudfl integer(I4B) :: ipflag ! -- formats - character(len=*),parameter :: fmtnocnvg = & + character(len=*), parameter :: fmtnocnvg = & "(1X,/9X,'****FAILED TO MEET SOLVER CONVERGENCE CRITERIA IN TIME STEP ', & &I0,' OF STRESS PERIOD ',I0,'****')" ! ------------------------------------------------------------------------------ @@ -1009,10 +1021,10 @@ subroutine gwf_ot(this) idvprint = 0 icbcfl = 0 ibudfl = 0 - if(this%oc%oc_save('HEAD')) idvsave = 1 - if(this%oc%oc_print('HEAD')) idvprint = 1 - if(this%oc%oc_save('BUDGET')) icbcfl = 1 - if(this%oc%oc_print('BUDGET')) ibudfl = 1 + if (this%oc%oc_save('HEAD')) idvsave = 1 + if (this%oc%oc_print('HEAD')) idvprint = 1 + if (this%oc%oc_save('BUDGET')) icbcfl = 1 + if (this%oc%oc_print('BUDGET')) ibudfl = 1 icbcun = this%oc%oc_save_unit('BUDGET') ! ! -- Override ibudfl and idvprint flags for nonconvergence @@ -1022,38 +1034,38 @@ subroutine gwf_ot(this) ! ! Calculate and save observations call this%gwf_ot_obs() - ! + ! ! Save and print flows call this%gwf_ot_flow(icbcfl, ibudfl, icbcun) - ! + ! ! Save and print dependent variables call this%gwf_ot_dv(idvsave, idvprint, ipflag) - ! + ! ! Print budget summaries call this%gwf_ot_bdsummary(ibudfl, ipflag) ! ! -- Timing Output; if any dependendent variables or budgets ! are printed, then ipflag is set to 1. - if(ipflag == 1) call tdis_ot(this%iout) + if (ipflag == 1) call tdis_ot(this%iout) ! ! -- Write non-convergence message - if(this%icnvg == 0) then - write(this%iout, fmtnocnvg) kstp, kper - endif + if (this%icnvg == 0) then + write (this%iout, fmtnocnvg) kstp, kper + end if ! ! -- Return return end subroutine gwf_ot - + subroutine gwf_ot_obs(this) class(GwfModelType) :: this class(BndType), pointer :: packobj integer(I4B) :: ip - + ! -- Calculate and save GWF observations call this%obs%obs_bd() call this%obs%obs_ot() - + ! -- Calculate and save csub observations if (this%incsub > 0) then call this%csub%csub_bd_obs() @@ -1066,9 +1078,9 @@ subroutine gwf_ot_obs(this) call packobj%bnd_bd_obs() call packobj%bnd_ot_obs() end do - + end subroutine gwf_ot_obs - + subroutine gwf_ot_flow(this, icbcfl, ibudfl, icbcun) class(GwfModelType) :: this integer(I4B), intent(in) :: icbcfl @@ -1078,46 +1090,46 @@ subroutine gwf_ot_flow(this, icbcfl, ibudfl, icbcun) integer(I4B) :: ip ! -- Save GWF flows - if(this%insto > 0) then + if (this%insto > 0) then call this%sto%sto_save_model_flows(icbcfl, icbcun) - endif - if(this%innpf > 0) then + end if + if (this%innpf > 0) then call this%npf%npf_save_model_flows(this%flowja, icbcfl, icbcun) - endif - if(this%incsub > 0) call this%csub%csub_save_model_flows(icbcfl, icbcun) + end if + if (this%incsub > 0) call this%csub%csub_save_model_flows(icbcfl, icbcun) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_model_flows(icbcfl=icbcfl, ibudfl=0, icbcun=icbcun) end do - + ! -- Save advanced package flows do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_package_flows(icbcfl=icbcfl, ibudfl=0) end do - if(this%inmvr > 0) then + if (this%inmvr > 0) then call this%mvr%mvr_ot_saveflow(icbcfl, ibudfl) end if ! -- Print GWF flows - if(this%innpf > 0) call this%npf%npf_print_model_flows(ibudfl, this%flowja) - if(this%ingnc > 0) call this%gnc%gnc_ot(ibudfl) + if (this%innpf > 0) call this%npf%npf_print_model_flows(ibudfl, this%flowja) + if (this%ingnc > 0) call this%gnc%gnc_ot(ibudfl) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_model_flows(icbcfl=icbcfl, ibudfl=ibudfl, icbcun=0) end do - + ! -- Print advanced package flows do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_package_flows(icbcfl=0, ibudfl=ibudfl) end do - if(this%inmvr > 0) then + if (this%inmvr > 0) then call this%mvr%mvr_ot_printflow(icbcfl, ibudfl) end if - + end subroutine gwf_ot_flow - + subroutine gwf_ot_dv(this, idvsave, idvprint, ipflag) class(GwfModelType) :: this integer(I4B), intent(in) :: idvsave @@ -1125,26 +1137,33 @@ subroutine gwf_ot_dv(this, idvsave, idvprint, ipflag) integer(I4B), intent(inout) :: ipflag class(BndType), pointer :: packobj integer(I4B) :: ip - + ! ! -- Save compaction to binary file - if(this%incsub > 0) call this%csub%csub_ot_dv(idvsave, idvprint) - + if (this%incsub > 0) call this%csub%csub_ot_dv(idvsave, idvprint) + ! ! -- save density to binary file if (this%inbuy > 0) then call this%buy%buy_ot_dv(idvsave) end if - + ! + ! -- save viscosity to binary file + if (this%invsc > 0) then + call this%vsc%vsc_ot_dv(idvsave) + end if + ! ! -- Print advanced package dependent variables do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_dv(idvsave, idvprint) end do - + ! ! -- save head and print head call this%oc%oc_ot(ipflag) - + ! + ! -- Return + return end subroutine gwf_ot_dv - + subroutine gwf_ot_bdsummary(this, ibudfl, ipflag) use TdisModule, only: kstp, kper, totim class(GwfModelType) :: this @@ -1158,24 +1177,24 @@ subroutine gwf_ot_bdsummary(this, ibudfl, ipflag) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_bdsummary(kstp, kper, this%iout, ibudfl) - enddo - + end do + ! -- mover budget summary - if(this%inmvr > 0) then + if (this%inmvr > 0) then call this%mvr%mvr_ot_bdsummary(ibudfl) end if - + ! -- model budget summary if (ibudfl /= 0) then ipflag = 1 call this%budget%budget_ot(kstp, kper, this%iout) end if - + ! -- Write to budget csv every time step call this%budget%writecsv(totim) - + end subroutine gwf_ot_bdsummary - + !> @brief Final processing subroutine gwf_fp(this) ! -- modules @@ -1200,7 +1219,7 @@ subroutine gwf_da(this) class(GwfModelType) :: this ! -- local integer(I4B) :: ip - class(BndType),pointer :: packobj + class(BndType), pointer :: packobj ! ------------------------------------------------------------------------------ ! ! -- Internal flow packages deallocate @@ -1209,6 +1228,7 @@ subroutine gwf_da(this) call this%npf%npf_da() call this%xt3d%xt3d_da() call this%buy%buy_da() + call this%vsc%vsc_da() call this%gnc%gnc_da() call this%sto%sto_da() call this%csub%csub_da() @@ -1219,26 +1239,27 @@ subroutine gwf_da(this) call this%obs%obs_da() ! ! -- Internal package objects - deallocate(this%dis) - deallocate(this%ic) - deallocate(this%npf) - deallocate(this%xt3d) - deallocate(this%buy) - deallocate(this%gnc) - deallocate(this%sto) - deallocate(this%csub) - deallocate(this%budget) - deallocate(this%hfb) - deallocate(this%mvr) - deallocate(this%obs) - deallocate(this%oc) + deallocate (this%dis) + deallocate (this%ic) + deallocate (this%npf) + deallocate (this%xt3d) + deallocate (this%buy) + deallocate (this%vsc) + deallocate (this%gnc) + deallocate (this%sto) + deallocate (this%csub) + deallocate (this%budget) + deallocate (this%hfb) + deallocate (this%mvr) + deallocate (this%obs) + deallocate (this%oc) ! ! -- Boundary packages do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_da() - deallocate(packobj) - enddo + deallocate (packobj) + end do ! ! -- Scalars call mem_deallocate(this%inic) @@ -1246,6 +1267,7 @@ subroutine gwf_da(this) call mem_deallocate(this%inobs) call mem_deallocate(this%innpf) call mem_deallocate(this%inbuy) + call mem_deallocate(this%invsc) call mem_deallocate(this%insto) call mem_deallocate(this%incsub) call mem_deallocate(this%inmvr) @@ -1272,7 +1294,7 @@ end subroutine gwf_da subroutine gwf_bdentry(this, budterm, budtxt, rowlabel) ! -- modules use ConstantsModule, only: LENBUDTXT - use TdisModule, only:delt + use TdisModule, only: delt ! -- dummy class(GwfModelType) :: this real(DP), dimension(:, :), intent(in) :: budterm @@ -1288,8 +1310,8 @@ end subroutine gwf_bdentry !> @brief return 1 if any package causes the matrix to be asymmetric. !! Otherwise return 0. - !< - function gwf_get_iasym(this) result (iasym) + !< + function gwf_get_iasym(this) result(iasym) class(GwfModelType) :: this ! -- local integer(I4B) :: iasym @@ -1304,18 +1326,18 @@ function gwf_get_iasym(this) result (iasym) if (this%innpf > 0) then if (this%npf%iasym /= 0) iasym = 1 if (this%npf%ixt3d /= 0) iasym = 1 - endif + end if ! ! -- GNC if (this%ingnc > 0) then if (this%gnc%iasym /= 0) iasym = 1 - endif + end if ! ! -- Check for any packages that introduce matrix asymmetry - do ip=1,this%bndlist%Count() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) if (packobj%iasym /= 0) iasym = 1 - enddo + end do ! ! -- return return @@ -1327,37 +1349,39 @@ subroutine allocate_scalars(this, modelname) use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwfModelType) :: this - character(len=*), intent(in) :: modelname + character(len=*), intent(in) :: modelname ! ------------------------------------------------------------------------------ ! ! -- allocate members from parent class call this%NumericalModelType%allocate_scalars(modelname) ! ! -- allocate members that are part of model class - call mem_allocate(this%inic, 'INIC', this%memoryPath) - call mem_allocate(this%inoc, 'INOC', this%memoryPath) + call mem_allocate(this%inic, 'INIC', this%memoryPath) + call mem_allocate(this%inoc, 'INOC', this%memoryPath) call mem_allocate(this%innpf, 'INNPF', this%memoryPath) call mem_allocate(this%inbuy, 'INBUY', this%memoryPath) + call mem_allocate(this%invsc, 'INVSC', this%memoryPath) call mem_allocate(this%insto, 'INSTO', this%memoryPath) call mem_allocate(this%incsub, 'INCSUB', this%memoryPath) call mem_allocate(this%inmvr, 'INMVR', this%memoryPath) call mem_allocate(this%inhfb, 'INHFB', this%memoryPath) call mem_allocate(this%ingnc, 'INGNC', this%memoryPath) call mem_allocate(this%inobs, 'INOBS', this%memoryPath) - call mem_allocate(this%iss, 'ISS', this%memoryPath) + call mem_allocate(this%iss, 'ISS', this%memoryPath) call mem_allocate(this%inewtonur, 'INEWTONUR', this%memoryPath) ! this%inic = 0 this%inoc = 0 this%innpf = 0 this%inbuy = 0 + this%invsc = 0 this%insto = 0 this%incsub = 0 this%inmvr = 0 this%inhfb = 0 this%ingnc = 0 this%inobs = 0 - this%iss = 1 !default is steady-state (i.e., no STO package) + this%iss = 1 !default is steady-state (i.e., no STO package) this%inewtonur = 0 !default is to not use newton bottom head dampening ! ! -- return @@ -1370,7 +1394,7 @@ end subroutine allocate_scalars !! (2) add a pointer to the package !! !< - subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & + subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & iout) ! -- modules use ConstantsModule, only: LINELENGTH @@ -1389,13 +1413,13 @@ subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & use ApiModule, only: api_create ! -- dummy class(GwfModelType) :: this - character(len=*),intent(in) :: filtyp + character(len=*), intent(in) :: filtyp character(len=LINELENGTH) :: errmsg - integer(I4B),intent(in) :: ipakid - integer(I4B),intent(in) :: ipaknum + integer(I4B), intent(in) :: ipakid + integer(I4B), intent(in) :: ipaknum character(len=*), intent(in) :: pakname - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout ! -- local class(BndType), pointer :: packobj class(BndType), pointer :: packobj2 @@ -1403,33 +1427,33 @@ subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & ! ------------------------------------------------------------------------------ ! ! -- This part creates the package object - select case(filtyp) - case('CHD6') + select case (filtyp) + case ('CHD6') call chd_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('WEL6') + case ('WEL6') call wel_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('DRN6') + case ('DRN6') call drn_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('RIV6') + case ('RIV6') call riv_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('GHB6') + case ('GHB6') call ghb_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('RCH6') + case ('RCH6') call rch_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('EVT6') + case ('EVT6') call evt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('MAW6') + case ('MAW6') call maw_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('SFR6') + case ('SFR6') call sfr_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('LAK6') + case ('LAK6') call lak_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('UZF6') + case ('UZF6') call uzf_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('API6') + case ('API6') call api_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) case default - write(errmsg, *) 'Invalid package type: ', filtyp + write (errmsg, *) 'Invalid package type: ', filtyp call store_error(errmsg, terminate=.TRUE.) end select ! @@ -1437,12 +1461,12 @@ subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & ! pointer to the package in the model bndlist do ip = 1, this%bndlist%Count() packobj2 => GetBndFromList(this%bndlist, ip) - if(packobj2%packName == pakname) then - write(errmsg, '(a,a)') 'Cannot create package. Package name ' // & + if (packobj2%packName == pakname) then + write (errmsg, '(a,a)') 'Cannot create package. Package name '// & 'already exists: ', trim(pakname) call store_error(errmsg, terminate=.TRUE.) - endif - enddo + end if + end do call AddBndToList(this%bndlist, packobj) ! ! -- return @@ -1452,9 +1476,9 @@ end subroutine package_create !> @brief Check to make sure required input files have been specified subroutine ftype_check(this, namefile_obj, indis) ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, count_errors - use NameFileModule, only: NameFileType + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error, count_errors + use NameFileModule, only: NameFileType ! -- dummy class(GwfModelType) :: this type(NameFileType), intent(in) :: namefile_obj @@ -1462,90 +1486,61 @@ subroutine ftype_check(this, namefile_obj, indis) ! -- local character(len=LINELENGTH) :: errmsg integer(I4B) :: i, iu - character(len=LENFTYPE), dimension(11) :: nodupftype = & - (/'DIS6 ', 'DISU6', 'DISV6', 'IC6 ', 'OC6 ', 'NPF6 ', 'STO6 ', & - 'MVR6 ', 'HFB6 ', 'GNC6 ', 'OBS6 '/) + character(len=LENFTYPE), dimension(13) :: nodupftype = & + (/'DIS6 ', 'DISU6', 'DISV6', & + 'IC6 ', 'OC6 ', 'NPF6 ', & + 'STO6 ', 'MVR6 ', 'HFB6 ', & + 'GNC6 ', 'BUY6 ', 'VSC6 ', & + 'OBS6 '/) ! ------------------------------------------------------------------------------ - ! - if(this%single_model_run) then - ! - ! -- Ensure TDIS6 is present - call namefile_obj%get_unitnumber('TDIS6', iu, 1) - if(iu == 0) then - call store_error('TDIS6 ftype not specified in name file.') - endif - ! - ! -- Ensure IMS6 is present - call namefile_obj%get_unitnumber('IMS6', iu, 1) - if(iu == 0) then - call store_error('IMS6 ftype not specified in name file.') - endif - ! - else - ! - ! -- Warn if TDIS6 is present - call namefile_obj%get_unitnumber('TDIS6', iu, 1) - if(iu > 0) then - write(this%iout, '(/a)') 'Warning TDIS6 detected in GWF name file.' - write(this%iout, *) 'Simulation TDIS file will be used instead.' - close(iu) - endif - ! - ! -- Warn if SMS8 is present - call namefile_obj%get_unitnumber('IMS6', iu, 1) - if(iu > 0) then - write(this%iout, '(/a)') 'Warning IMS6 detected in GWF name file.' - write(this%iout, *) 'Simulation IMS6 file will be used instead.' - close(iu) - endif - endif ! ! -- Check for IC8, DIS(u), and NPF. Stop if not present. - if(this%inic==0) then - write(errmsg, '(1x,a)') 'ERROR. INITIAL CONDITIONS (IC6) PACKAGE NOT SPECIFIED.' + if (this%inic == 0) then + write (errmsg, '(1x,a)') & + 'Initial Conditions (IC6) package not specified.' call store_error(errmsg) - endif - if(indis==0) then - write(errmsg, '(1x,a)') & - 'ERROR. DISCRETIZATION (DIS6, DISV6, or DISU6) PACKAGE NOT SPECIFIED.' + end if + if (indis == 0) then + write (errmsg, '(1x,a)') & + 'Discretization (DIS6, DISV6, or DISU6) Package not specified.' call store_error(errmsg) - endif - if(this%innpf==0) then - write(errmsg, '(1x,a)') & - 'ERROR. NODE PROPERTY FLOW (NPF6) PACKAGE NOT SPECIFIED.' + end if + if (this%innpf == 0) then + write (errmsg, '(1x,a)') & + 'Node Property Flow (NPF6) Package not specified.' call store_error(errmsg) - endif - if(count_errors() > 0) then - write(errmsg,'(1x,a)') 'ERROR. REQUIRED PACKAGE(S) NOT SPECIFIED.' + end if + if (count_errors() > 0) then + write (errmsg, '(1x,a)') 'One or more required package(s) not specified.' call store_error(errmsg) - endif + end if ! ! -- Check to make sure that some GWF packages are not specified more ! than once do i = 1, size(nodupftype) call namefile_obj%get_unitnumber(trim(nodupftype(i)), iu, 0) if (iu > 0) then - write(errmsg,'(1x, a, a, a)') & - 'DUPLICATE ENTRIES FOR FTYPE ', trim(nodupftype(i)), & - ' NOT ALLOWED FOR GWF MODEL.' + write (errmsg, '(1x, a, a, a)') & + 'Duplicate entries for FTYPE ', trim(nodupftype(i)), & + ' not allowed for GWF Model.' call store_error(errmsg) - endif - enddo + end if + end do ! ! -- Stop if errors - if(count_errors() > 0) then - write(errmsg, '(a, a)') 'Error occurred while reading file: ', & + if (count_errors() > 0) then + write (errmsg, '(a, a)') 'Error occurred while reading file: ', & trim(namefile_obj%filename) call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- return return end subroutine ftype_check - + !> @brief Cast to GWF model !< - function CastAsGwfModel(model) result (gwfModel) + function CastAsGwfModel(model) result(gwfModel) implicit none class(*), pointer, intent(inout) :: model class(GwfModelType), pointer :: gwfModel @@ -1554,11 +1549,10 @@ function CastAsGwfModel(model) result (gwfModel) if (.not. associated(model)) return select type (model) class is (GwfModelType) - gwfModel => model + gwfModel => model end select return - + end function CastAsGwfModel - end module GwfModule diff --git a/src/Model/GroundWaterFlow/gwf3api8.f90 b/src/Model/GroundWaterFlow/gwf3api8.f90 index 6ac2ee1c39e..2e381f14149 100644 --- a/src/Model/GroundWaterFlow/gwf3api8.f90 +++ b/src/Model/GroundWaterFlow/gwf3api8.f90 @@ -2,10 +2,10 @@ !! !! This module contains the overridden methods from the base model package !! class for the API package. The API package is designed to be used with the -!! shared object and have period data specified using the MODFLOW API. Several -!! methods need to be overridden since no period data are specified in the +!! shared object and have period data specified using the MODFLOW API. Several +!! methods need to be overridden since no period data are specified in the !! API input file. Overridden methods include: -!! - bnd_rp no period data is specified +!! - bnd_rp no period data is specified !! - bnd_fc BOUND array is not filled. hcof and rhs are specified dierctly !! !< @@ -24,7 +24,7 @@ module apimodule public :: api_create public :: ApiType ! - character(len=LENFTYPE) :: ftype = 'API' + character(len=LENFTYPE) :: ftype = 'API' character(len=LENPACKAGENAME) :: text = ' API' ! type, extends(BndType) :: ApiType @@ -46,13 +46,13 @@ module apimodule !< subroutine api_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! -- dummy variables - class(BndType), pointer :: packobj !< pointer to default package type - integer(I4B), intent(in) :: id !< package id - integer(I4B), intent(in) :: ibcnum !< boundary condition number - integer(I4B), intent(in) :: inunit !< unit number of USR package input file - integer(I4B), intent(in) :: iout !< unit number of model listing file - character(len=*), intent(in) :: namemodel !< model name - character(len=*), intent(in) :: pakname !< package name + class(BndType), pointer :: packobj !< pointer to default package type + integer(I4B), intent(in) :: id !< package id + integer(I4B), intent(in) :: ibcnum !< boundary condition number + integer(I4B), intent(in) :: inunit !< unit number of USR package input file + integer(I4B), intent(in) :: iout !< unit number of model listing file + character(len=*), intent(in) :: namemodel !< model name + character(len=*), intent(in) :: pakname !< package name ! -- local variables type(ApiType), pointer :: apiobj ! @@ -133,10 +133,10 @@ end subroutine api_rp subroutine api_fc(this, rhs, ia, idxglo, amatsln) ! -- dummy variables class(ApiType) :: this - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector - integer(I4B), dimension(:), intent(in) :: ia !< pointer to the rows in A matrix - integer(I4B), dimension(:), intent(in) :: idxglo !< position of entries in A matrix - real(DP), dimension(:), intent(inout) :: amatsln !< A matrix for solution + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector + integer(I4B), dimension(:), intent(in) :: ia !< pointer to the rows in A matrix + integer(I4B), dimension(:), intent(in) :: idxglo !< position of entries in A matrix + real(DP), dimension(:), intent(inout) :: amatsln !< A matrix for solution ! -- local variables integer(I4B) :: i integer(I4B) :: n @@ -157,7 +157,7 @@ subroutine api_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active and this boundary is discharging, ! store available water (as positive value). - qusr = this%rhs(i) - this%hcof(i)*this%xnew(n) + qusr = this%rhs(i) - this%hcof(i) * this%xnew(n) if (this%imover == 1 .and. qusr > DZERO) then call this%pakmvrobj%accumulate_qformvr(i, qusr) end if diff --git a/src/Model/GroundWaterFlow/gwf3buy8.f90 b/src/Model/GroundWaterFlow/gwf3buy8.f90 index 563612f203b..835f09f2d40 100644 --- a/src/Model/GroundWaterFlow/gwf3buy8.f90 +++ b/src/Model/GroundWaterFlow/gwf3buy8.f90 @@ -1,54 +1,53 @@ ! Buoyancy Package for representing variable-density groundwater flow ! The BUY Package does not work yet with the NPF XT3D option - module GwfBuyModule - - use KindModule, only: DP, I4B - use SimModule, only: store_error, count_errors - use MemoryManagerModule, only: mem_allocate, mem_reallocate, & - mem_deallocate - use ConstantsModule, only: DHALF, DZERO, DONE, LENMODELNAME, & - LENAUXNAME, DHNOFLO, MAXCHARLEN, LINELENGTH + + use KindModule, only: DP, I4B + use SimModule, only: store_error, count_errors + use MemoryManagerModule, only: mem_allocate, mem_reallocate, & + mem_deallocate + use ConstantsModule, only: DHALF, DZERO, DONE, LENMODELNAME, & + LENAUXNAME, DHNOFLO, MAXCHARLEN, LINELENGTH use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use GwfNpfModule, only: GwfNpfType - use GwfBuyInputDataModule, only: GwfBuyInputDataType - + use BaseDisModule, only: DisBaseType + use GwfNpfModule, only: GwfNpfType + use GwfBuyInputDataModule, only: GwfBuyInputDataType + implicit none private public :: GwfBuyType public :: buy_cr - + type :: ConcentrationPointer - real(DP), dimension(:), pointer :: conc => null() ! pointer to concentration array - integer(I4B), dimension(:), pointer :: icbund => null() ! store pointer to gwt ibound array + real(DP), dimension(:), pointer :: conc => null() ! pointer to concentration array + integer(I4B), dimension(:), pointer :: icbund => null() ! store pointer to gwt ibound array end type ConcentrationPointer type, extends(NumericalPackageType) :: GwfBuyType - type(GwfNpfType), pointer :: npf => null() ! npf object - integer(I4B), pointer :: ioutdense => null() ! unit number for saving density - integer(I4B), pointer :: iform => null() ! formulation: 0 freshwater head, 1 hh rhs, 2 hydraulic head - integer(I4B), pointer :: ireadelev => null() ! if 1 then elev has been allocated and filled - integer(I4B), pointer :: ireadconcbuy => null() ! if 1 then dense has been read from this buy input file - integer(I4B), pointer :: iconcset => null() ! if 1 then conc is pointed to a gwt model%x - real(DP), pointer :: denseref => null() ! reference fluid density - real(DP), dimension(:), pointer, contiguous :: dense => null() ! density - real(DP), dimension(:), pointer, contiguous :: concbuy => null() ! concentration array if specified in buy package - real(DP), dimension(:), pointer, contiguous :: elev => null() ! cell center elevation (optional; if not specified, hten use (top+bot)/2) - integer(I4B), dimension(:), pointer :: ibound => null() ! store pointer to ibound - - integer(I4B), pointer :: nrhospecies => null() ! number of species used in equation of state to calculate density - real(DP), dimension(:), pointer, contiguous :: drhodc => null() ! change in density with change in concentration - real(DP), dimension(:), pointer, contiguous :: crhoref => null() ! reference concentration used in equation of state - real(DP), dimension(:), pointer, contiguous :: ctemp => null() ! temporary array of size (nrhospec) to pass to calcdens - character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname ! names of gwt models used in equation of state - character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname ! names of gwt models used in equation of state + type(GwfNpfType), pointer :: npf => null() ! npf object + integer(I4B), pointer :: ioutdense => null() ! unit number for saving density + integer(I4B), pointer :: iform => null() ! formulation: 0 freshwater head, 1 hh rhs, 2 hydraulic head + integer(I4B), pointer :: ireadelev => null() ! if 1 then elev has been allocated and filled + integer(I4B), pointer :: ireadconcbuy => null() ! if 1 then dense has been read from this buy input file + integer(I4B), pointer :: iconcset => null() ! if 1 then conc is pointed to a gwt model%x + real(DP), pointer :: denseref => null() ! reference fluid density + real(DP), dimension(:), pointer, contiguous :: dense => null() ! density + real(DP), dimension(:), pointer, contiguous :: concbuy => null() ! concentration array if specified in buy package + real(DP), dimension(:), pointer, contiguous :: elev => null() ! cell center elevation (optional; if not specified, hten use (top+bot)/2) + integer(I4B), dimension(:), pointer :: ibound => null() ! store pointer to ibound - type(ConcentrationPointer), allocatable, dimension(:) :: modelconc ! concentration pointer for each transport model - - contains + integer(I4B), pointer :: nrhospecies => null() ! number of species used in equation of state to calculate density + real(DP), dimension(:), pointer, contiguous :: drhodc => null() ! change in density with change in concentration + real(DP), dimension(:), pointer, contiguous :: crhoref => null() ! reference concentration used in equation of state + real(DP), dimension(:), pointer, contiguous :: ctemp => null() ! temporary array of size (nrhospec) to pass to calcdens + character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname ! names of gwt models used in equation of state + character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname ! names of gwt models used in equation of state + + type(ConcentrationPointer), allocatable, dimension(:) :: modelconc ! concentration pointer for each transport model + + contains procedure :: buy_df procedure :: buy_ar procedure :: buy_ar_bnd @@ -67,15 +66,15 @@ module GwfBuyModule procedure :: allocate_scalars procedure, private :: allocate_arrays procedure, private :: read_options - procedure, private :: set_options + procedure, private :: set_options procedure, private :: read_dimensions procedure, private :: read_packagedata procedure, private :: set_packagedata procedure :: set_concentration_pointer end type GwfBuyType - - contains - + +contains + function calcdens(denseref, drhodc, crhoref, conc) result(dense) ! ****************************************************************************** ! calcdens -- generic function to calculate fluid density from concentration @@ -120,7 +119,7 @@ subroutine buy_cr(buyobj, name_model, inunit, iout) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(buyobj) + allocate (buyobj) ! ! -- create name and memory path call buyobj%set_names(1, name_model, 'BUY', 'BUY') @@ -140,7 +139,7 @@ subroutine buy_cr(buyobj, name_model, inunit, iout) end subroutine buy_cr !> @brief Read options and package data, or set from argument - !< + !< subroutine buy_df(this, dis, buy_input) ! ****************************************************************************** ! buy_df -- Allocate and Read @@ -150,18 +149,18 @@ subroutine buy_df(this, dis, buy_input) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(GwfBuyType) :: this !< this buoyancy package - class(DisBaseType), pointer, intent(in) :: dis !< pointer to discretization + class(GwfBuyType) :: this !< this buoyancy package + class(DisBaseType), pointer, intent(in) :: dis !< pointer to discretization type(GwfBuyInputDataType), optional, intent(in) :: buy_input !< optional buy input data, otherwise read from file ! -- local ! -- formats - character(len=*), parameter :: fmtbuy = & - "(1x,/1x,'BUY -- BUOYANCY PACKAGE, VERSION 1, 5/16/2018', & - &' INPUT READ FROM UNIT ', i0, //)" + character(len=*), parameter :: fmtbuy = & + "(1x,/1x,'BUY -- Buoyancy Package, Version 1, 5/16/2018', & + &' input read from unit ', i0, //)" ! ------------------------------------------------------------------------------ ! ! --print a message identifying the buoyancy package. - write(this%iout, fmtbuy) this%inunit + write (this%iout, fmtbuy) this%inunit ! ! -- store pointers to arguments that were passed in this%dis => dis @@ -212,15 +211,15 @@ subroutine buy_ar(this, npf, ibound) ! ------------------------------------------------------------------------------ ! ! -- store pointers to arguments that were passed in - this%npf => npf - this%ibound => ibound + this%npf => npf + this%ibound => ibound ! ! -- Ensure NPF XT3D is not on if (this%npf%ixt3d /= 0) then - call store_error('Error in model ' // trim(this%name_model) // & - '. The XT3D option cannot be used with the BUY Package.') + call store_error('Error in model '//trim(this%name_model)// & + '. The XT3D option cannot be used with the BUY Package.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Calculate cell elevations call this%buy_calcelev() @@ -251,39 +250,39 @@ subroutine buy_ar_bnd(this, packobj, hnew) ! ! -- Add density terms based on boundary package type select case (packobj%filtyp) - case('LAK') - ! - ! -- activate density for lake package - select type(packobj) - type is (LakType) - call packobj%lak_activate_density() - end select - - case('SFR') - ! - ! -- activate density for sfr package - select type(packobj) - type is (SfrType) - call packobj%sfr_activate_density() - end select - - case('MAW') - ! - ! -- activate density for maw package - select type(packobj) - type is (MawType) - call packobj%maw_activate_density() - end select - - case default - ! - ! -- nothing + case ('LAK') + ! + ! -- activate density for lake package + select type (packobj) + type is (LakType) + call packobj%lak_activate_density() + end select + + case ('SFR') + ! + ! -- activate density for sfr package + select type (packobj) + type is (SfrType) + call packobj%sfr_activate_density() + end select + + case ('MAW') + ! + ! -- activate density for maw package + select type (packobj) + type is (MawType) + call packobj%maw_activate_density() + end select + + case default + ! + ! -- nothing end select ! ! -- Return return end subroutine buy_ar_bnd - + subroutine buy_rp(this) ! ****************************************************************************** ! buy_rp -- Check for new buy period data @@ -299,18 +298,18 @@ subroutine buy_rp(this) character(len=LINELENGTH) :: errmsg integer(I4B) :: i ! -- formats - character(len=*),parameter :: fmtc = & - "('BUOYANCY PACKAGE DOES NOT HAVE HAVE A CONCENTRATION SET & - &FOR SPECIES ',i0,'. ONE OR MORE MODEL NAMES MAY BE SPECIFIED & - &INCORRECTLY IN THE PACKAGEDATA BLOCK OR A GWF-GWT EXCHANGE MAY NEED & - &TO BE ACTIVATED.')" + character(len=*), parameter :: fmtc = & + "('Buoyancy Package does not have have a concentration set & + &for species ',i0,'. One or more model names may be specified & + &incorrectly in the PACKAGEDATA block or a gwf-gwt exchange may need & + &to be activated.')" ! ------------------------------------------------------------------------------ ! ! -- Check to make sure all concentration pointers have been set if (kstp * kper == 1) then do i = 1, this%nrhospecies if (.not. associated(this%modelconc(i)%conc)) then - write(errmsg, fmtc) i + write (errmsg, fmtc) i call store_error(errmsg) end if end do @@ -341,7 +340,7 @@ subroutine buy_ad(this) ! -- Return return end subroutine buy_ad - + subroutine buy_cf(this, kiter) ! ****************************************************************************** ! buy_cf -- Fill coefficients @@ -365,7 +364,7 @@ subroutine buy_cf(this, kiter) ! -- Return return end subroutine buy_cf - + subroutine buy_cf_bnd(this, packobj, hnew) !, hcof, rhs, auxnam, auxvar) ! ****************************************************************************** ! buy_cf_bnd -- Fill coefficients @@ -392,7 +391,7 @@ subroutine buy_cf_bnd(this, packobj, hnew) !, hcof, rhs, auxnam, auxvar) ! -- initialize locdense = 0 locelev = 0 - allocate(locconc(this%nrhospecies)) + allocate (locconc(this%nrhospecies)) locconc(:) = 0 ! ! -- Add buoyancy terms for head-dependent boundaries @@ -422,54 +421,54 @@ subroutine buy_cf_bnd(this, packobj, hnew) !, hcof, rhs, auxnam, auxvar) ! ! -- Add density terms based on boundary package type select case (packobj%filtyp) - case('GHB') - ! - ! -- general head boundary - call buy_cf_ghb(packobj, hnew, this%dense, this%elev, this%denseref, & - locelev, locdense, locconc, this%drhodc, this%crhoref, & - this%ctemp, this%iform) - case('RIV') - ! - ! -- river - call buy_cf_riv(packobj, hnew, this%dense, this%elev, this%denseref, & - locelev, locdense, locconc, this%drhodc, this%crhoref, & - this%ctemp, this%iform) - case('DRN') - ! - ! -- drain - call buy_cf_drn(packobj, hnew, this%dense, this%denseref) - case('LAK') - ! - ! -- lake - call buy_cf_lak(packobj, hnew, this%dense, this%elev, this%denseref, & - locdense, locconc, this%drhodc, this%crhoref, & - this%ctemp, this%iform) - case('SFR') - ! - ! -- sfr - call buy_cf_sfr(packobj, hnew, this%dense, this%elev, this%denseref, & - locdense, locconc, this%drhodc, this%crhoref, & - this%ctemp, this%iform) - case('MAW') - ! - ! -- maw - call buy_cf_maw(packobj, hnew, this%dense, this%elev, this%denseref, & - locdense, locconc, this%drhodc, this%crhoref, & - this%ctemp, this%iform) - case default - ! - ! -- nothing + case ('GHB') + ! + ! -- general head boundary + call buy_cf_ghb(packobj, hnew, this%dense, this%elev, this%denseref, & + locelev, locdense, locconc, this%drhodc, this%crhoref, & + this%ctemp, this%iform) + case ('RIV') + ! + ! -- river + call buy_cf_riv(packobj, hnew, this%dense, this%elev, this%denseref, & + locelev, locdense, locconc, this%drhodc, this%crhoref, & + this%ctemp, this%iform) + case ('DRN') + ! + ! -- drain + call buy_cf_drn(packobj, hnew, this%dense, this%denseref) + case ('LAK') + ! + ! -- lake + call buy_cf_lak(packobj, hnew, this%dense, this%elev, this%denseref, & + locdense, locconc, this%drhodc, this%crhoref, & + this%ctemp, this%iform) + case ('SFR') + ! + ! -- sfr + call buy_cf_sfr(packobj, hnew, this%dense, this%elev, this%denseref, & + locdense, locconc, this%drhodc, this%crhoref, & + this%ctemp, this%iform) + case ('MAW') + ! + ! -- maw + call buy_cf_maw(packobj, hnew, this%dense, this%elev, this%denseref, & + locdense, locconc, this%drhodc, this%crhoref, & + this%ctemp, this%iform) + case default + ! + ! -- nothing end select ! ! -- deallocate - deallocate(locconc) + deallocate (locconc) ! ! -- Return return end subroutine buy_cf_bnd - - function get_bnd_density(n, locdense, locconc, denseref, drhodc, crhoref, & - ctemp, auxvar) result (densebnd) + + function get_bnd_density(n, locdense, locconc, denseref, drhodc, crhoref, & + ctemp, auxvar) result(densebnd) ! ****************************************************************************** ! get_bnd_density -- Return the density of the boundary package using one of ! several different options in the following order of priority: @@ -517,9 +516,9 @@ function get_bnd_density(n, locdense, locconc, denseref, drhodc, crhoref, & ! -- return return end function get_bnd_density - - subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, & - locdense, locconc, drhodc, crhoref, ctemp, & + + subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, & + locdense, locconc, drhodc, crhoref, ctemp, & iform) ! ****************************************************************************** ! buy_cf_ghb -- Fill ghb coefficients @@ -559,7 +558,7 @@ subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, & ! ! -- density denseghb = get_bnd_density(n, locdense, locconc, denseref, & - drhodc, crhoref, ctemp, packobj%auxvar) + drhodc, crhoref, ctemp, packobj%auxvar) ! ! -- elevation elevghb = elev(node) @@ -570,9 +569,9 @@ subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, & cond = packobj%bound(2, n) ! ! -- calculate HCOF and RHS terms - call calc_ghb_hcof_rhs_terms(denseref, denseghb, dense(node), & - elevghb, elev(node), hghb, hnew(node), & - cond, iform, rhsterm, hcofterm) + call calc_ghb_hcof_rhs_terms(denseref, denseghb, dense(node), & + elevghb, elev(node), hghb, hnew(node), & + cond, iform, rhsterm, hcofterm) packobj%hcof(n) = packobj%hcof(n) + hcofterm packobj%rhs(n) = packobj%rhs(n) - rhsterm ! @@ -581,12 +580,12 @@ subroutine buy_cf_ghb(packobj, hnew, dense, elev, denseref, locelev, & ! -- Return return end subroutine buy_cf_ghb - + subroutine calc_ghb_hcof_rhs_terms(denseref, denseghb, densenode, & elevghb, elevnode, hghb, hnode, & cond, iform, rhsterm, hcofterm) ! ****************************************************************************** -! calc_ghb_hcof_rhs_terms -- Calculate density hcof and rhs terms for ghb +! calc_ghb_hcof_rhs_terms -- Calculate density hcof and rhs terms for ghb ! conditions ! ****************************************************************************** ! @@ -636,9 +635,9 @@ subroutine calc_ghb_hcof_rhs_terms(denseref, denseghb, densenode, & ! -- return return end subroutine calc_ghb_hcof_rhs_terms - - subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, & - locdense, locconc, drhodc, crhoref, ctemp, & + + subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, & + locdense, locconc, drhodc, crhoref, ctemp, & iform) ! ****************************************************************************** ! buy_cf_riv -- Fill riv coefficients @@ -680,7 +679,7 @@ subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, & ! ! -- density denseriv = get_bnd_density(n, locdense, locconc, denseref, & - drhodc, crhoref, ctemp, packobj%auxvar) + drhodc, crhoref, ctemp, packobj%auxvar) ! ! -- elevation elevriv = elev(node) @@ -695,9 +694,9 @@ subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, & if (hnew(node) > rbot) then ! ! --calculate HCOF and RHS terms, similar to GHB in this case - call calc_ghb_hcof_rhs_terms(denseref, denseriv, dense(node), & - elevriv, elev(node), hriv, hnew(node), & - cond, iform, rhsterm, hcofterm) + call calc_ghb_hcof_rhs_terms(denseref, denseriv, dense(node), & + elevriv, elev(node), hriv, hnew(node), & + cond, iform, rhsterm, hcofterm) else hcofterm = DZERO rhsterm = cond * (denseriv / denseref - DONE) * (hriv - rbot) @@ -711,7 +710,7 @@ subroutine buy_cf_riv(packobj, hnew, dense, elev, denseref, locelev, & ! -- Return return end subroutine buy_cf_riv - + subroutine buy_cf_drn(packobj, hnew, dense, denseref) ! ****************************************************************************** ! buy_cf_drn -- Fill drn coefficients @@ -744,7 +743,7 @@ subroutine buy_cf_drn(packobj, hnew, dense, denseref) hbnd = packobj%bound(1, n) cond = packobj%bound(2, n) if (hnew(node) > hbnd) then - hcofterm = - cond * (rho / denseref - DONE) + hcofterm = -cond * (rho / denseref - DONE) rhsterm = hcofterm * hbnd packobj%hcof(n) = packobj%hcof(n) + hcofterm packobj%rhs(n) = packobj%rhs(n) + rhsterm @@ -754,8 +753,8 @@ subroutine buy_cf_drn(packobj, hnew, dense, denseref) ! -- Return return end subroutine buy_cf_drn - - subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, & + + subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, & locconc, drhodc, crhoref, ctemp, iform) ! ****************************************************************************** ! buy_cf_lak -- Pass density information into lak package; density terms are @@ -788,7 +787,7 @@ subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, & ! ! -- Insert the lake and gwf relative densities into col 1 and 2 and the ! gwf elevation into col 3 of the lake package denseterms array - select type(packobj) + select type (packobj) type is (LakType) do n = 1, packobj%nbound ! @@ -815,8 +814,8 @@ subroutine buy_cf_lak(packobj, hnew, dense, elev, denseref, locdense, & ! -- Return return end subroutine buy_cf_lak - - subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, & + + subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, & locconc, drhodc, crhoref, ctemp, iform) ! ****************************************************************************** ! buy_cf_sfr -- Pass density information into sfr package; density terms are @@ -849,7 +848,7 @@ subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, & ! ! -- Insert the sfr and gwf relative densities into col 1 and 2 and the ! gwf elevation into col 3 of the sfr package denseterms array - select type(packobj) + select type (packobj) type is (SfrType) do n = 1, packobj%nbound ! @@ -876,8 +875,8 @@ subroutine buy_cf_sfr(packobj, hnew, dense, elev, denseref, locdense, & ! -- Return return end subroutine buy_cf_sfr - - subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, & + + subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, & locconc, drhodc, crhoref, ctemp, iform) ! ****************************************************************************** ! buy_cf_maw -- Pass density information into maw package; density terms are @@ -910,7 +909,7 @@ subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, & ! ! -- Insert the maw and gwf relative densities into col 1 and 2 and the ! gwf elevation into col 3 of the maw package denseterms array - select type(packobj) + select type (packobj) type is (MawType) do n = 1, packobj%nbound ! @@ -937,7 +936,7 @@ subroutine buy_cf_maw(packobj, hnew, dense, elev, denseref, locdense, & ! -- Return return end subroutine buy_cf_maw - + subroutine buy_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! ****************************************************************************** ! buy_fc -- Fill coefficients @@ -948,7 +947,7 @@ subroutine buy_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! -- dummy class(GwfBuyType) :: this integer(I4B) :: kiter - integer,intent(in) :: njasln + integer, intent(in) :: njasln real(DP), dimension(njasln), intent(inout) :: amat integer(I4B), intent(in), dimension(:) :: idxglo real(DP), dimension(:), intent(inout) :: rhs @@ -963,24 +962,24 @@ subroutine buy_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! ! -- fill buoyancy flow term do n = 1, this%dis%nodes - if(this%ibound(n) == 0) cycle + if (this%ibound(n) == 0) cycle idiag = this%dis%con%ia(n) do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ipos) - if(this%ibound(m) == 0) cycle - if(this%iform == 0) then + if (this%ibound(m) == 0) cycle + if (this%iform == 0) then call this%calcbuy(n, m, ipos, hnew(n), hnew(m), rhsterm) else - call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, & + call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, & amatnn, amatnm) - endif + end if ! ! -- Add terms to rhs, diagonal, and off diagonal rhs(n) = rhs(n) - rhsterm amat(idxglo(idiag)) = amat(idxglo(idiag)) - amatnn amat(idxglo(ipos)) = amat(idxglo(ipos)) + amatnm - enddo - enddo + end do + end do ! ! -- Return return @@ -997,7 +996,7 @@ subroutine buy_ot_dv(this, idvfl) class(GwfBuyType) :: this integer(I4B), intent(in) :: idvfl ! -- local - character(len=1) :: cdatafmp=' ', editdesc=' ' + character(len=1) :: cdatafmp = ' ', editdesc = ' ' integer(I4B) :: ibinun integer(I4B) :: iprint integer(I4B) :: nvaluesp @@ -1006,12 +1005,12 @@ subroutine buy_ot_dv(this, idvfl) ! ------------------------------------------------------------------------------ ! ! -- Set unit number for density output - if(this%ioutdense /= 0) then + if (this%ioutdense /= 0) then ibinun = 1 else ibinun = 0 - endif - if(idvfl == 0) ibinun = 0 + end if + if (idvfl == 0) ibinun = 0 ! ! -- save density array if (ibinun /= 0) then @@ -1021,12 +1020,12 @@ subroutine buy_ot_dv(this, idvfl) ! -- write density to binary file if (this%ioutdense /= 0) then ibinun = this%ioutdense - call this%dis%record_array(this%dense, this%iout, iprint, ibinun, & - ' DENSITY', cdatafmp, nvaluesp, & + call this%dis%record_array(this%dense, this%iout, iprint, ibinun, & + ' DENSITY', cdatafmp, nvaluesp, & nwidthp, editdesc, dinact) end if end if - + ! ! -- Return return @@ -1041,37 +1040,37 @@ subroutine buy_cq(this, hnew, flowja) ! ------------------------------------------------------------------------------ implicit none class(GwfBuyType) :: this - real(DP),intent(in),dimension(:) :: hnew - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(in), dimension(:) :: hnew + real(DP), intent(inout), dimension(:) :: flowja integer(I4B) :: n, m, ipos real(DP) :: deltaQ real(DP) :: rhsterm, amatnn, amatnm ! ------------------------------------------------------------------------------ ! ! -- Calculate the flow across each cell face and store in flowja - do n=1,this%dis%nodes + do n = 1, this%dis%nodes do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ipos) - if(m < n) cycle - if(this%iform == 0) then + if (m < n) cycle + if (this%iform == 0) then ! -- equivalent freshwater head formulation call this%calcbuy(n, m, ipos, hnew(n), hnew(m), deltaQ) else ! -- hydraulic head formulation - call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, & + call this%calchhterms(n, m, ipos, hnew(n), hnew(m), rhsterm, & amatnn, amatnm) deltaQ = amatnm * hnew(m) - amatnn * hnew(n) + rhsterm - endif + end if flowja(ipos) = flowja(ipos) + deltaQ - flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - & - deltaQ - enddo - enddo + flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - & + deltaQ + end do + end do ! ! -- Return return end subroutine buy_cq - + subroutine buy_da(this) ! ****************************************************************************** ! buy_da -- Deallocate @@ -1085,17 +1084,17 @@ subroutine buy_da(this) ! ------------------------------------------------------------------------------ ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then call mem_deallocate(this%elev) call mem_deallocate(this%dense) call mem_deallocate(this%concbuy) call mem_deallocate(this%drhodc) call mem_deallocate(this%crhoref) call mem_deallocate(this%ctemp) - deallocate(this%cmodelname) - deallocate(this%cauxspeciesname) - deallocate(this%modelconc) - endif + deallocate (this%cmodelname) + deallocate (this%cauxspeciesname) + deallocate (this%modelconc) + end if ! ! -- Scalars call mem_deallocate(this%ioutdense) @@ -1104,7 +1103,7 @@ subroutine buy_da(this) call mem_deallocate(this%ireadconcbuy) call mem_deallocate(this%iconcset) call mem_deallocate(this%denseref) - + call mem_deallocate(this%nrhospecies) ! ! -- deallocate parent @@ -1123,9 +1122,9 @@ subroutine read_dimensions(this) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(GwfBuyType),intent(inout) :: this + class(GwfBuyType), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: errmsg, keyword + character(len=LINELENGTH) :: errmsg, keyword integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- format @@ -1137,33 +1136,33 @@ subroutine read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING BUY DIMENSIONS' + write (this%iout, '(/1x,a)') 'Processing BUY DIMENSIONS block' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('NRHOSPECIES') - this%nrhospecies = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)')'NRHOSPECIES = ', this%nrhospecies - case default - write(errmsg,'(4x,a,a)') & - 'UNKNOWN BUY DIMENSION: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('NRHOSPECIES') + this%nrhospecies = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NRHOSPECIES = ', this%nrhospecies + case default + write (errmsg, '(4x,a,a)') & + 'Unknown BUY dimension: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF BUY DIMENSIONS' + write (this%iout, '(1x,a)') 'End of BUY DIMENSIONS block' else - call store_error('REQUIRED BUY DIMENSIONS BLOCK NOT FOUND.') + call store_error('Required BUY DIMENSIONS block not found.') call this%parser%StoreErrorUnit() end if ! ! -- check dimension if (this%nrhospecies < 1) then - call store_error('NRHOSPECIES MUST BE GREATER THAN ZERO.') + call store_error('NRHOSPECIES must be greater than zero.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -1190,35 +1189,35 @@ subroutine read_packagedata(this) character(len=10) :: c10 character(len=16) :: c16 ! -- format - character(len=*),parameter :: fmterr = & - "('INVALID VALUE FOR IRHOSPEC (',i0,') DETECTED IN BUY PACKAGE. & - &IRHOSPEC MUST BE > 0 AND <= NRHOSPECIES, AND DUPLICATE VALUES & - &ARE NOT ALLOWED.')" + character(len=*), parameter :: fmterr = & + "('Invalid value for IRHOSPEC (',i0,') detected in BUY Package. & + &IRHOSPEC must be > 0 and <= NRHOSPECIES, and duplicate values & + &are not allowed.')" ! ------------------------------------------------------------------------------ ! ! -- initialize - allocate(itemp(this%nrhospecies)) + allocate (itemp(this%nrhospecies)) itemp(:) = 0 ! ! -- get packagedata block blockrequired = .true. - call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & - blockRequired=blockRequired, & + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + blockRequired=blockRequired, & supportOpenClose=.true.) ! ! -- parse packagedata block if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING BUY PACKAGEDATA' + write (this%iout, '(1x,a)') 'Processing BUY PACKAGEDATA block' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit irhospec = this%parser%GetInteger() if (irhospec < 1 .or. irhospec > this%nrhospecies) then - write(errmsg, fmterr) irhospec + write (errmsg, fmterr) irhospec call store_error(errmsg) end if if (itemp(irhospec) /= 0) then - write(errmsg, fmterr) irhospec + write (errmsg, fmterr) irhospec call store_error(errmsg) end if itemp(irhospec) = 1 @@ -1227,7 +1226,10 @@ subroutine read_packagedata(this) call this%parser%GetStringCaps(this%cmodelname(irhospec)) call this%parser%GetStringCaps(this%cauxspeciesname(irhospec)) end do - write(this%iout,'(1x,a)') 'END OF BUY PACKAGEDATA' + write (this%iout, '(1x,a)') 'End of BUY PACKAGEDATA block' + else + call store_error('Required BUY PACKAGEDATA block not found.') + call this%parser%StoreErrorUnit() end if ! ! -- Check for errors. @@ -1236,26 +1238,26 @@ subroutine read_packagedata(this) end if ! ! -- write packagedata information - write(this%iout, '(/,a)') 'SUMMARY OF SPECIES INFORMATION IN BUY PACKAGE' - write(this%iout, '(1a11, 4a17)') & - 'SPECIES', 'DRHODC', 'CRHOREF', 'MODEL', & - 'AUXSPECIESNAME' + write (this%iout, '(/,a)') 'Summary of species information in BUY Package' + write (this%iout, '(1a11, 4a17)') & + 'SPECIES', 'DRHODC', 'CRHOREF', 'MODEL', & + 'AUXSPECIESNAME' do irhospec = 1, this%nrhospecies - write(c10, '(i0)') irhospec - line = ' ' // adjustr(c10) - write(c16, '(g15.6)') this%drhodc(irhospec) - line = trim(line) // ' ' // adjustr(c16) - write(c16, '(g15.6)') this%crhoref(irhospec) - line = trim(line) // ' ' // adjustr(c16) - write(c16, '(a)') this%cmodelname(irhospec) - line = trim(line) // ' ' // adjustr(c16) - write(c16, '(a)') this%cauxspeciesname(irhospec) - line = trim(line) // ' ' // adjustr(c16) - write(this%iout, '(a)') trim(line) + write (c10, '(i0)') irhospec + line = ' '//adjustr(c10) + write (c16, '(g15.6)') this%drhodc(irhospec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(g15.6)') this%crhoref(irhospec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(a)') this%cmodelname(irhospec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(a)') this%cauxspeciesname(irhospec) + line = trim(line)//' '//adjustr(c16) + write (this%iout, '(a)') trim(line) end do ! ! -- deallocate - deallocate(itemp) + deallocate (itemp) ! ! -- return return @@ -1264,7 +1266,7 @@ end subroutine read_packagedata !> @brief Sets package data instead of reading from file !< subroutine set_packagedata(this, input_data) - class(GwfBuyType) :: this !< this buyoancy pkg + class(GwfBuyType) :: this !< this buyoancy pkg type(GwfBuyInputDataType), intent(in) :: input_data !< the input data to be set ! local integer(I4B) :: ispec @@ -1276,9 +1278,8 @@ subroutine set_packagedata(this, input_data) this%cauxspeciesname(ispec) = input_data%cauxspeciesname(ispec) end do - end subroutine set_packagedata - + subroutine calcbuy(this, n, m, icon, hn, hm, buy) ! ****************************************************************************** ! calcbuy -- Calculate buyancy term for this connection @@ -1299,7 +1300,7 @@ subroutine calcbuy(this, n, m, icon, hn, hm, buy) ! -- local integer(I4B) :: ihc real(DP) :: densen, densem, cl1, cl2, avgdense, wt, elevn, elevm, & - cond, tp, bt + cond, tp, bt real(DP) :: hyn real(DP) :: hym ! ------------------------------------------------------------------------------ @@ -1314,11 +1315,11 @@ subroutine calcbuy(this, n, m, icon, hn, hm, buy) cl1 = this%dis%con%cl2(this%dis%con%jas(icon)) cl2 = this%dis%con%cl1(this%dis%con%jas(icon)) end if - wt = cl1 / (cl1 + cl2) + wt = cl1 / (cl1 + cl2) avgdense = wt * densen + (DONE - wt) * densem ! ! -- Elevations - if(this%ireadelev == 0) then + if (this%ireadelev == 0) then tp = this%dis%top(n) bt = this%dis%bot(n) elevn = bt + DHALF * this%npf%sat(n) * (tp - bt) @@ -1328,40 +1329,40 @@ subroutine calcbuy(this, n, m, icon, hn, hm, buy) else elevn = this%elev(n) elevm = this%elev(m) - endif + end if ! ihc = this%dis%con%ihc(this%dis%con%jas(icon)) hyn = this%npf%hy_eff(n, m, ihc, ipos=icon) hym = this%npf%hy_eff(m, n, ihc, ipos=icon) ! ! -- Conductance - if(this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then - cond = vcond(this%ibound(n), this%ibound(m), & - this%npf%icelltype(n), this%npf%icelltype(m), & - this%npf%inewton, & - this%npf%ivarcv, this%npf%idewatcv, & - this%npf%condsat(this%dis%con%jas(icon)), hn, hm, & - hyn, hym, & - this%npf%sat(n), this%npf%sat(m), & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%hwva(this%dis%con%jas(icon))) + if (this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then + cond = vcond(this%ibound(n), this%ibound(m), & + this%npf%icelltype(n), this%npf%icelltype(m), & + this%npf%inewton, & + this%npf%ivarcv, this%npf%idewatcv, & + this%npf%condsat(this%dis%con%jas(icon)), hn, hm, & + hyn, hym, & + this%npf%sat(n), this%npf%sat(m), & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%hwva(this%dis%con%jas(icon))) else - cond = hcond(this%ibound(n), this%ibound(m), & - this%npf%icelltype(n), this%npf%icelltype(m), & - this%npf%inewton, this%npf%inewton, & - this%dis%con%ihc(this%dis%con%jas(icon)), & - this%npf%icellavg, this%npf%iusgnrhc, this%npf%inwtupw, & - this%npf%condsat(this%dis%con%jas(icon)), & - hn, hm, this%npf%sat(n), this%npf%sat(m), & - hyn, hym, & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%cl1(this%dis%con%jas(icon)), & - this%dis%con%cl2(this%dis%con%jas(icon)), & - this%dis%con%hwva(this%dis%con%jas(icon)), & - this%npf%satomega, this%npf%satmin) - endif + cond = hcond(this%ibound(n), this%ibound(m), & + this%npf%icelltype(n), this%npf%icelltype(m), & + this%npf%inewton, this%npf%inewton, & + this%dis%con%ihc(this%dis%con%jas(icon)), & + this%npf%icellavg, this%npf%iusgnrhc, this%npf%inwtupw, & + this%npf%condsat(this%dis%con%jas(icon)), & + hn, hm, this%npf%sat(n), this%npf%sat(m), & + hyn, hym, & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%cl1(this%dis%con%jas(icon)), & + this%dis%con%cl2(this%dis%con%jas(icon)), & + this%dis%con%hwva(this%dis%con%jas(icon)), & + this%npf%satomega, this%npf%satmin) + end if ! ! -- Calculate buoyancy term buy = cond * (avgdense - this%denseref) / this%denseref * (elevm - elevn) @@ -1370,7 +1371,6 @@ subroutine calcbuy(this, n, m, icon, hn, hm, buy) return end subroutine calcbuy - subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm) ! ****************************************************************************** ! calchhterms -- Calculate hydraulic head term for this connection @@ -1411,7 +1411,7 @@ subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm) cl1 = this%dis%con%cl2(this%dis%con%jas(icon)) cl2 = this%dis%con%cl1(this%dis%con%jas(icon)) end if - wt = cl1 / (cl1 + cl2) + wt = cl1 / (cl1 + cl2) avgdense = wt * densen + (1.0 - wt) * densem ! ! -- Elevations @@ -1424,33 +1424,33 @@ subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm) hym = this%npf%hy_eff(m, n, ihc, ipos=icon) ! ! -- Conductance - if(ihc == 0) then - cond = vcond(this%ibound(n), this%ibound(m), & - this%npf%icelltype(n), this%npf%icelltype(m), & - this%npf%inewton, & - this%npf%ivarcv, this%npf%idewatcv, & - this%npf%condsat(this%dis%con%jas(icon)), hn, hm, & - hyn, hym, & - this%npf%sat(n), this%npf%sat(m), & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%hwva(this%dis%con%jas(icon))) + if (ihc == 0) then + cond = vcond(this%ibound(n), this%ibound(m), & + this%npf%icelltype(n), this%npf%icelltype(m), & + this%npf%inewton, & + this%npf%ivarcv, this%npf%idewatcv, & + this%npf%condsat(this%dis%con%jas(icon)), hn, hm, & + hyn, hym, & + this%npf%sat(n), this%npf%sat(m), & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%hwva(this%dis%con%jas(icon))) else - cond = hcond(this%ibound(n), this%ibound(m), & - this%npf%icelltype(n), this%npf%icelltype(m), & - this%npf%inewton, this%npf%inewton, & - this%dis%con%ihc(this%dis%con%jas(icon)), & - this%npf%icellavg, this%npf%iusgnrhc, this%npf%inwtupw, & - this%npf%condsat(this%dis%con%jas(icon)), & - hn, hm, this%npf%sat(n), this%npf%sat(m), & - hyn, hym, & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%cl1(this%dis%con%jas(icon)), & - this%dis%con%cl2(this%dis%con%jas(icon)), & - this%dis%con%hwva(this%dis%con%jas(icon)), & - this%npf%satomega, this%npf%satmin) - endif + cond = hcond(this%ibound(n), this%ibound(m), & + this%npf%icelltype(n), this%npf%icelltype(m), & + this%npf%inewton, this%npf%inewton, & + this%dis%con%ihc(this%dis%con%jas(icon)), & + this%npf%icellavg, this%npf%iusgnrhc, this%npf%inwtupw, & + this%npf%condsat(this%dis%con%jas(icon)), & + hn, hm, this%npf%sat(n), this%npf%sat(m), & + hyn, hym, & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%cl1(this%dis%con%jas(icon)), & + this%dis%con%cl2(this%dis%con%jas(icon)), & + this%dis%con%hwva(this%dis%con%jas(icon)), & + this%npf%satomega, this%npf%satmin) + end if ! ! -- Calculate terms rhonormn = densen / this%denseref @@ -1467,7 +1467,7 @@ subroutine calchhterms(this, n, m, icon, hn, hm, rhsterm, amatnn, amatnm) ! -- lhs, results in asymmetric matrix due to weight term amatnn = amatnn - cond * (DONE - wt) * (rhonormm - rhonormn) amatnm = amatnm + cond * wt * (rhonormm - rhonormn) - endif + end if ! ! -- Return return @@ -1482,7 +1482,7 @@ subroutine buy_calcdens(this) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfBuyType) :: this - + ! -- local integer(I4B) :: n integer(I4B) :: i @@ -1491,7 +1491,7 @@ subroutine buy_calcdens(this) ! -- Calculate the density using the specified concentration array do n = 1, this%dis%nodes do i = 1, this%nrhospecies - if(this%modelconc(i)%icbund(n) == 0) then + if (this%modelconc(i)%icbund(n) == 0) then this%ctemp = DZERO else this%ctemp(i) = this%modelconc(i)%conc(n) @@ -1499,12 +1499,12 @@ subroutine buy_calcdens(this) end do this%dense(n) = calcdens(this%denseref, this%drhodc, this%crhoref, & this%ctemp) - enddo + end do ! ! -- Return return end subroutine buy_calcdens - + subroutine buy_calcelev(this) ! ****************************************************************************** ! buy_calcelev -- Calculate cell elevations to use in density flow equations @@ -1530,7 +1530,7 @@ subroutine buy_calcelev(this) ! -- Return return end subroutine buy_calcelev - + subroutine allocate_scalars(this) ! ****************************************************************************** ! allocate_scalars @@ -1557,7 +1557,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%denseref, 'DENSEREF', this%memoryPath) call mem_allocate(this%nrhospecies, 'NRHOSPECIES', this%memoryPath) - + ! ! -- Initialize this%ioutdense = 0 @@ -1565,9 +1565,9 @@ subroutine allocate_scalars(this) this%iconcset = 0 this%ireadconcbuy = 0 this%denseref = 1000.d0 - + this%nrhospecies = 0 - + ! ! -- Initialize default to LHS implementation of hydraulic head formulation this%iform = 2 @@ -1599,15 +1599,15 @@ subroutine allocate_arrays(this, nodes) call mem_allocate(this%drhodc, this%nrhospecies, 'DRHODC', this%memoryPath) call mem_allocate(this%crhoref, this%nrhospecies, 'CRHOREF', this%memoryPath) call mem_allocate(this%ctemp, this%nrhospecies, 'CTEMP', this%memoryPath) - allocate(this%cmodelname(this%nrhospecies)) - allocate(this%cauxspeciesname(this%nrhospecies)) - allocate(this%modelconc(this%nrhospecies)) + allocate (this%cmodelname(this%nrhospecies)) + allocate (this%cauxspeciesname(this%nrhospecies)) + allocate (this%modelconc(this%nrhospecies)) ! ! -- Initialize do i = 1, nodes this%dense(i) = this%denseref this%elev(i) = DZERO - enddo + end do ! ! -- Initialize nrhospecies arrays do i = 1, this%nrhospecies @@ -1640,8 +1640,9 @@ subroutine read_options(this) integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*),parameter :: fmtfileout = & - "(4x, 'BUY ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + character(len=*), parameter :: fmtfileout = & + "(4x, 'BUY ', 1x, a, 1x, ' will be saved to file: ', & + &a, /4x, 'opened on unit: ', I7)" ! ------------------------------------------------------------------------------ ! ! -- get options block @@ -1650,50 +1651,50 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING BUY OPTIONS' + write (this%iout, '(1x,a)') 'Processing BUY OPTIONS block' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('HHFORMULATION_RHS') - this%iform = 1 - this%iasym = 0 - write(this%iout,'(4x,a)') & - 'HYDDRAULIC HEAD FORMULATION SET TO RIGHT-HAND SIDE' - case ('DENSEREF') - this%denseref = this%parser%GetDouble() - write(this%iout, '(4x,a,1pg15.6)') & - 'REFERENCE DENSITY HAS BEEN SET TO: ', & - this%denseref - case ('DEV_EFH_FORMULATION') - call this%parser%DevOpt() - this%iform = 0 - this%iasym = 0 - write(this%iout,'(4x,a)') & - 'FORMULATION SET TO EQUIVALENT FRESHWATER HEAD' - case ('DENSITY') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ioutdense = getunit() - call openfile(this%ioutdense, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE') - write(this%iout,fmtfileout) & - 'DENSITY', fname, this%ioutdense - else - errmsg = 'OPTIONAL DENSITY KEYWORD MUST BE ' // & - 'FOLLOWED BY FILEOUT' - call store_error(errmsg) - end if - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN BUY OPTION: ', & - trim(keyword) + case ('HHFORMULATION_RHS') + this%iform = 1 + this%iasym = 0 + write (this%iout, '(4x,a)') & + 'Hydraulic head formulation set to right-hand side' + case ('DENSEREF') + this%denseref = this%parser%GetDouble() + write (this%iout, '(4x,a,1pg15.6)') & + 'Reference density has been set to: ', & + this%denseref + case ('DEV_EFH_FORMULATION') + call this%parser%DevOpt() + this%iform = 0 + this%iasym = 0 + write (this%iout, '(4x,a)') & + 'Formulation set to equivalent freshwater head' + case ('DENSITY') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ioutdense = getunit() + call openfile(this%ioutdense, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtfileout) & + 'DENSITY', fname, this%ioutdense + else + errmsg = 'Optional density keyword must be '// & + 'followed by FILEOUT' call store_error(errmsg) - call this%parser%StoreErrorUnit() + end if + case default + write (errmsg, '(4x,a,a)') '****Error. Unknown BUY option: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF BUY OPTIONS' + write (this%iout, '(1x,a)') 'End of BUY OPTIONS block' end if ! ! -- Return @@ -1710,7 +1711,7 @@ subroutine set_options(this, input_data) this%denseref = input_data%denseref ! derived option: - ! if not iform==2, there is no asymmetry + ! if not iform==2, there is no asymmetry if (this%iform == 0 .or. this%iform == 1) then this%iasym = 0 end if @@ -1720,7 +1721,7 @@ end subroutine set_options subroutine set_concentration_pointer(this, modelname, conc, icbund) ! ****************************************************************************** ! set_concentration_pointer -- pass in a gwt model name, concentration array -! and ibound, and store a pointer to these in the BUY package so that +! and ibound, and store a pointer to these in the BUY package so that ! density can be calculated from them. ! This routine is called from the gwfgwt exchange in the exg_ar() method. ! ****************************************************************************** @@ -1752,5 +1753,5 @@ subroutine set_concentration_pointer(this, modelname, conc, icbund) ! -- Return return end subroutine set_concentration_pointer - -end module GwfBuyModule \ No newline at end of file + +end module GwfBuyModule diff --git a/src/Model/GroundWaterFlow/gwf3chd8.f90 b/src/Model/GroundWaterFlow/gwf3chd8.f90 index 63287e0bd4d..e65e95789d9 100644 --- a/src/Model/GroundWaterFlow/gwf3chd8.f90 +++ b/src/Model/GroundWaterFlow/gwf3chd8.f90 @@ -1,12 +1,12 @@ module ChdModule ! - use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DONE, NAMEDBOUNDFLAG, LENFTYPE, & - LINELENGTH, LENPACKAGENAME - use MemoryHelperModule, only: create_mem_path - use ObsModule, only: DefaultObsIdProcessor - use BndModule, only: BndType - use ObserveModule, only: ObserveType + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, DONE, NAMEDBOUNDFLAG, LENFTYPE, & + LINELENGTH, LENPACKAGENAME + use MemoryHelperModule, only: create_mem_path + use ObsModule, only: DefaultObsIdProcessor + use BndModule, only: BndType + use ObserveModule, only: ObserveType use TimeSeriesLinkModule, only: TimeSeriesLinkType, & GetTimeSeriesLinkFromList ! @@ -15,27 +15,27 @@ module ChdModule private public :: chd_create, ChdType ! - character(len=LENFTYPE) :: ftype = 'CHD' - character(len=LENPACKAGENAME) :: text = ' CHD' + character(len=LENFTYPE) :: ftype = 'CHD' + character(len=LENPACKAGENAME) :: text = ' CHD' ! type, extends(BndType) :: ChdType - real(DP), dimension(:), pointer, contiguous :: ratechdin => null() !simulated flows into constant head (excluding other chds) - real(DP), dimension(:), pointer, contiguous :: ratechdout => null() !simulated flows out of constant head (excluding to other chds) - contains - procedure :: bnd_rp => chd_rp - procedure :: bnd_ad => chd_ad - procedure :: bnd_ck => chd_ck - procedure :: bnd_fc => chd_fc - procedure :: bnd_cq => chd_cq - procedure :: bnd_bd => chd_bd - procedure :: bnd_da => chd_da - procedure :: allocate_arrays => chd_allocate_arrays - procedure :: define_listlabel - ! -- methods for observations - procedure, public :: bnd_obs_supported => chd_obs_supported - procedure, public :: bnd_df_obs => chd_df_obs - ! -- method for time series - procedure, public :: bnd_rp_ts => chd_rp_ts + real(DP), dimension(:), pointer, contiguous :: ratechdin => null() !simulated flows into constant head (excluding other chds) + real(DP), dimension(:), pointer, contiguous :: ratechdout => null() !simulated flows out of constant head (excluding to other chds) + contains + procedure :: bnd_rp => chd_rp + procedure :: bnd_ad => chd_ad + procedure :: bnd_ck => chd_ck + procedure :: bnd_fc => chd_fc + procedure :: bnd_cq => chd_cq + procedure :: bnd_bd => chd_bd + procedure :: bnd_da => chd_da + procedure :: allocate_arrays => chd_allocate_arrays + procedure :: define_listlabel + ! -- methods for observations + procedure, public :: bnd_obs_supported => chd_obs_supported + procedure, public :: bnd_df_obs => chd_df_obs + ! -- method for time series + procedure, public :: bnd_rp_ts => chd_rp_ts end type ChdType contains @@ -51,10 +51,10 @@ subroutine chd_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -62,7 +62,7 @@ subroutine chd_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(chdobj) + allocate (chdobj) packobj => chdobj ! ! -- create name and memory path @@ -82,7 +82,7 @@ subroutine chd_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%ibcnum = ibcnum packobj%ncolbnd = 1 packobj%iscloc = 1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return @@ -110,7 +110,8 @@ subroutine chd_allocate_arrays(this, nodelist, auxvar) ! ! -- allocate ratechdex call mem_allocate(this%ratechdin, this%maxbound, 'RATECHDIN', this%memoryPath) - call mem_allocate(this%ratechdout, this%maxbound, 'RATECHDOUT', this%memoryPath) + call mem_allocate(this%ratechdout, this%maxbound, 'RATECHDOUT', & + this%memoryPath) do i = 1, this%maxbound this%ratechdin(i) = DZERO this%ratechdout(i) = DZERO @@ -119,7 +120,7 @@ subroutine chd_allocate_arrays(this, nodelist, auxvar) ! -- return return end subroutine chd_allocate_arrays - + subroutine chd_rp(this) ! ****************************************************************************** ! chd_rp -- Read and prepare @@ -137,34 +138,34 @@ subroutine chd_rp(this) ! ------------------------------------------------------------------------------ ! ! -- Reset previous CHDs to active cell - do i=1,this%nbound - node = this%nodelist(i) - this%ibound(node) = this%ibcnum - enddo + do i = 1, this%nbound + node = this%nodelist(i) + this%ibound(node) = this%ibcnum + end do ! ! -- Call the parent class read and prepare call this%BndType%bnd_rp() ! ! -- Set ibound to -(ibcnum + 1) for constant head cells ierr = 0 - do i=1,this%nbound + do i = 1, this%nbound node = this%nodelist(i) ibd = this%ibound(node) - if(ibd < 0) then + if (ibd < 0) then call this%dis%noder_to_string(node, nodestr) - write(errmsg, '(3a)') & + write (errmsg, '(3a)') & 'Cell is already a constant head (', trim(adjustl(nodestr)), ').' call store_error(errmsg) ierr = ierr + 1 else this%ibound(node) = -this%ibcnum - endif - enddo + end if + end do ! ! -- Stop if errors detected - if(ierr > 0) then + if (ierr > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -195,7 +196,7 @@ subroutine chd_ad(this) hb = this%bound(1, i) this%xnew(node) = hb this%xold(node) = this%xnew(node) - enddo + end do ! ! -- For each observation, push simulated value and corresponding ! simulation time from "current" to "preceding" and reset @@ -217,7 +218,7 @@ subroutine chd_ck(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors ! -- dummy - class(ChdType),intent(inout) :: this + class(ChdType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg character(len=30) :: nodestr @@ -226,20 +227,20 @@ subroutine chd_ck(this) real(DP) :: bt ! -- formats character(len=*), parameter :: fmtchderr = & - "('CHD BOUNDARY ',i0,' HEAD (',g0,') IS LESS THAN CELL " // & - "BOTTOM (',g0,')',' FOR CELL ',a)" + "('CHD BOUNDARY ',i0,' HEAD (',g0,') IS LESS THAN CELL & + &BOTTOM (',g0,')',' FOR CELL ',a)" ! ------------------------------------------------------------------------------ ! ! -- check stress period data - do i=1,this%nbound - node=this%nodelist(i) - bt = this%dis%bot(node) - ! -- accumulate errors - if (this%bound(1,i) < bt .and. this%icelltype(node) /= 0) then - call this%dis%noder_to_string(node, nodestr) - write(errmsg, fmt=fmtchderr) i, this%bound(1,i), bt, trim(nodestr) - call store_error(errmsg) - end if + do i = 1, this%nbound + node = this%nodelist(i) + bt = this%dis%bot(node) + ! -- accumulate errors + if (this%bound(1, i) < bt .and. this%icelltype(node) /= 0) then + call this%dis%noder_to_string(node, nodestr) + write (errmsg, fmt=fmtchderr) i, this%bound(1, i), bt, trim(nodestr) + call store_error(errmsg) + end if end do ! !write summary of chd package error messages @@ -296,7 +297,7 @@ subroutine chd_cq(this, x, flowja, iadv) ! ------------------------------------------------------------------------------ ! ! -- If no boundaries, skip flow calculations. - if(this%nbound > 0) then + if (this%nbound > 0) then ! ! -- Loop through each boundary calculating flow. do i = 1, this%nbound @@ -308,7 +309,7 @@ subroutine chd_cq(this, x, flowja, iadv) ! ! -- Calculate the flow rate into the cell. do ipos = this%dis%con%ia(node) + 1, & - this%dis%con%ia(node + 1) - 1 + this%dis%con%ia(node + 1) - 1 q = flowja(ipos) rate = rate - q ! -- only accumulate chin and chout for active @@ -323,7 +324,7 @@ subroutine chd_cq(this, x, flowja, iadv) end if end do ! - ! -- For chd, store total flow in rhs so it is available for other + ! -- For chd, store total flow in rhs so it is available for other ! calculations this%rhs(i) = -rate this%hcof(i) = DZERO @@ -355,7 +356,7 @@ subroutine chd_bd(this, model_budget) isuppress_output = 0 call rate_accumulator(this%ratechdin(1:this%nbound), ratin, dum) call rate_accumulator(this%ratechdout(1:this%nbound), ratout, dum) - call model_budget%addentry(ratin, ratout, delt, this%text, & + call model_budget%addentry(ratin, ratout, delt, this%text, & isuppress_output, this%packName) end subroutine chd_bd @@ -395,21 +396,21 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'HEAD' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'HEAD' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -417,7 +418,7 @@ end subroutine define_listlabel ! -- Procedures related to observations -logical function chd_obs_supported(this) + logical function chd_obs_supported(this) ! ****************************************************************************** ! chd_obs_supported ! -- Return true because CHD package supports observations. @@ -426,14 +427,14 @@ logical function chd_obs_supported(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - implicit none - class(ChdType) :: this + implicit none + class(ChdType) :: this ! ------------------------------------------------------------------------------ - chd_obs_supported = .true. - return -end function chd_obs_supported + chd_obs_supported = .true. + return + end function chd_obs_supported -subroutine chd_df_obs(this) + subroutine chd_df_obs(this) ! ****************************************************************************** ! chd_df_obs (implements bnd_df_obs) ! -- Store observation type supported by CHD package. @@ -442,16 +443,16 @@ subroutine chd_df_obs(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - implicit none - ! -- dummy - class(ChdType) :: this - ! -- local - integer(I4B) :: indx + implicit none + ! -- dummy + class(ChdType) :: this + ! -- local + integer(I4B) :: indx ! ------------------------------------------------------------------------------ - call this%obs%StoreObsType('chd', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor - return -end subroutine chd_df_obs + call this%obs%StoreObsType('chd', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor + return + end subroutine chd_df_obs ! -- Procedure related to time series @@ -467,15 +468,15 @@ subroutine chd_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) case (1) tslink%Text = 'HEAD' end select - endif - enddo + end if + end do ! return end subroutine chd_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3csub8.f90 b/src/Model/GroundWaterFlow/gwf3csub8.f90 index 7590ba92aa2..e03f2623b3c 100644 --- a/src/Model/GroundWaterFlow/gwf3csub8.f90 +++ b/src/Model/GroundWaterFlow/gwf3csub8.f90 @@ -1,7 +1,7 @@ !> @brief This module contains the CSUB package methods !! -!! This module contains the methods used to add the effects of elastic -!! skeletal storage, compaction, and subsidence on the groundwater flow +!! This module contains the methods used to add the effects of elastic +!! skeletal storage, compaction, and subsidence on the groundwater flow !! equation. The contribution of elastic skelatal, inelastic and elastic !! interbed storage and water compressibility can be represented. !! @@ -41,6 +41,8 @@ module GwfCsubModule use ListModule, only: ListType use TableModule, only: TableType, table_cr ! + use IMSLinearMisc, only: ims_misc_thomas + ! implicit none ! private @@ -49,174 +51,179 @@ module GwfCsubModule ! character(len=LENBUDTXT), dimension(4) :: budtxt = & !< text labels for budget terms [' CSUB-CGELASTIC', & - ' CSUB-ELASTIC', ' CSUB-INELASTIC', & + ' CSUB-ELASTIC', & + ' CSUB-INELASTIC', & ' CSUB-WATERCOMP'] character(len=LENBUDTXT), dimension(6) :: comptxt = & !< text labels for compaction terms - ['CSUB-COMPACTION', ' CSUB-INELASTIC', ' CSUB-ELASTIC', & - ' CSUB-INTERBED', ' CSUB-COARSE', ' CSUB-ZDISPLACE'] + ['CSUB-COMPACTION', & + ' CSUB-INELASTIC', & + ' CSUB-ELASTIC', & + ' CSUB-INTERBED', & + ' CSUB-COARSE', & + ' CSUB-ZDISPLACE'] ! ! -- local parameter - real(DP), parameter :: dlog10es = 0.4342942_DP !< derivative of the log of effective stress + real(DP), parameter :: dlog10es = 0.4342942_DP !< derivative of the log of effective stress ! ! CSUB type type, extends(NumericalPackageType) :: GwfCsubType ! -- characters scalars - character(len=LENLISTLABEL), pointer :: listlabel => null() !< title of table written for RP - character(len=LENMEMPATH), pointer :: stoMemPath => null() !< memory path of storage package + character(len=LENLISTLABEL), pointer :: listlabel => null() !< title of table written for RP + character(len=LENMEMPATH), pointer :: stoMemPath => null() !< memory path of storage package ! -- character arrays character(len=LENBOUNDNAME), dimension(:), & - pointer, contiguous :: boundname => null() !< vector of boundnames + pointer, contiguous :: boundname => null() !< vector of boundnames character(len=LENAUXNAME), dimension(:), & - pointer, contiguous :: auxname => null() !< vector of auxname + pointer, contiguous :: auxname => null() !< vector of auxname ! -- logical scalars - logical, pointer :: lhead_based => null() !< logical variable indicating if head-based solution + logical, pointer :: lhead_based => null() !< logical variable indicating if head-based solution ! -- integer scalars - integer(I4B), pointer :: istounit => null() !< unit number of storage package - integer(I4B), pointer :: istrainib => null() !< unit number of interbed strain output - integer(I4B), pointer :: istrainsk => null() !< unit number of coarse-grained strain output - integer(I4B), pointer :: ioutcomp => null() !< unit number for cell-by-cell compaction output - integer(I4B), pointer :: ioutcompi => null() !< unit number for cell-by-cell inelastic compaction output - integer(I4B), pointer :: ioutcompe => null() !< unit number for cell-by-cell elastic compaction output - integer(I4B), pointer :: ioutcompib => null() !< unit number for cell-by-cell interbed compaction output - integer(I4B), pointer :: ioutcomps => null() !< unit number for cell-by-cell coarse-grained compaction output - integer(I4B), pointer :: ioutzdisp => null() !< unit number for z-displacement output - integer(I4B), pointer :: ipakcsv => null() !< unit number for csv output - integer(I4B), pointer :: iupdatematprop => null() !< flag indicating if material properties will be updated - integer(I4B), pointer :: istoragec => null() !< flag indicating specific storage coefficient will be specified - integer(I4B), pointer :: icellf => null() !< flag indicating cell fractions will be specified - integer(I4B), pointer :: ispecified_pcs => null() !< flag indicating preconsolidation state is specified (not relative) - integer(I4B), pointer :: ispecified_dbh => null() !< flag indicating delay bed head is specified (not relative) - integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames - integer(I4B), pointer :: iconvchk => null() !< flag indicating if a final convergence check will be made - integer(I4B), pointer :: naux => null() !< number of auxiliary variables - integer(I4B), pointer :: ninterbeds => null() !< number of interbeds - integer(I4B), pointer :: maxsig0 => null() !< maximum number of cells with specified sig0 values - integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period - integer(I4B), pointer :: iscloc => null() !< bound column to scale with SFAC - integer(I4B), pointer :: iauxmultcol => null() !< column to use as multiplier for column iscloc - integer(I4B), pointer :: ndelaycells => null() !< number of cells in delay interbeds - integer(I4B), pointer :: ndelaybeds => null() !< number of delay interbeds - integer(I4B), pointer :: initialized => null() !< flag indicating if the initial stresses have been initialized - integer(I4B), pointer :: ieslag => null() !< flag indicating if the effective stress is lagged - integer(I4B), pointer :: ipch => null() !< flag indicating if initial precosolidation value is a head - integer(I4B), pointer :: iupdatestress => null() !< flag indicating if the geostatic stress is active + integer(I4B), pointer :: istounit => null() !< unit number of storage package + integer(I4B), pointer :: istrainib => null() !< unit number of interbed strain output + integer(I4B), pointer :: istrainsk => null() !< unit number of coarse-grained strain output + integer(I4B), pointer :: ioutcomp => null() !< unit number for cell-by-cell compaction output + integer(I4B), pointer :: ioutcompi => null() !< unit number for cell-by-cell inelastic compaction output + integer(I4B), pointer :: ioutcompe => null() !< unit number for cell-by-cell elastic compaction output + integer(I4B), pointer :: ioutcompib => null() !< unit number for cell-by-cell interbed compaction output + integer(I4B), pointer :: ioutcomps => null() !< unit number for cell-by-cell coarse-grained compaction output + integer(I4B), pointer :: ioutzdisp => null() !< unit number for z-displacement output + integer(I4B), pointer :: ipakcsv => null() !< unit number for csv output + integer(I4B), pointer :: iupdatematprop => null() !< flag indicating if material properties will be updated + integer(I4B), pointer :: istoragec => null() !< flag indicating specific storage coefficient will be specified + integer(I4B), pointer :: icellf => null() !< flag indicating cell fractions will be specified + integer(I4B), pointer :: ispecified_pcs => null() !< flag indicating preconsolidation state is specified (not relative) + integer(I4B), pointer :: ispecified_dbh => null() !< flag indicating delay bed head is specified (not relative) + integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames + integer(I4B), pointer :: iconvchk => null() !< flag indicating if a final convergence check will be made + integer(I4B), pointer :: naux => null() !< number of auxiliary variables + integer(I4B), pointer :: ninterbeds => null() !< number of interbeds + integer(I4B), pointer :: maxsig0 => null() !< maximum number of cells with specified sig0 values + integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period + integer(I4B), pointer :: iscloc => null() !< bound column to scale with SFAC + integer(I4B), pointer :: iauxmultcol => null() !< column to use as multiplier for column iscloc + integer(I4B), pointer :: ndelaycells => null() !< number of cells in delay interbeds + integer(I4B), pointer :: ndelaybeds => null() !< number of delay interbeds + integer(I4B), pointer :: initialized => null() !< flag indicating if the initial stresses have been initialized + integer(I4B), pointer :: ieslag => null() !< flag indicating if the effective stress is lagged + integer(I4B), pointer :: ipch => null() !< flag indicating if initial precosolidation value is a head + integer(I4B), pointer :: iupdatestress => null() !< flag indicating if the geostatic stress is active ! -- real scalars - real(DP), pointer :: epsilon => null() !< epsilon for stress smoothing - real(DP), pointer :: cc_crit => null() !< convergence criteria for csub-gwf convergence check - real(DP), pointer :: gammaw => null() !< product of fluid density, and gravity - real(DP), pointer :: beta => null() !< water compressibility - real(DP), pointer :: brg => null() !< product of gammaw and water compressibility - real(DP), pointer :: satomega => null() !< newton-raphson saturation omega + real(DP), pointer :: epsilon => null() !< epsilon for stress smoothing + real(DP), pointer :: cc_crit => null() !< convergence criteria for csub-gwf convergence check + real(DP), pointer :: gammaw => null() !< product of fluid density, and gravity + real(DP), pointer :: beta => null() !< water compressibility + real(DP), pointer :: brg => null() !< product of gammaw and water compressibility + real(DP), pointer :: satomega => null() !< newton-raphson saturation omega ! -- integer pointer to storage package variables - integer(I4B), pointer :: gwfiss => NULL() !< pointer to model iss flag - integer(I4B), pointer :: gwfiss0 => NULL() !< iss flag for last stress period + integer(I4B), pointer :: gwfiss => NULL() !< pointer to model iss flag + integer(I4B), pointer :: gwfiss0 => NULL() !< iss flag for last stress period ! -- integer arrays - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - integer(I4B), dimension(:), pointer, contiguous :: stoiconv => null() !< pointer to iconvert in storage + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + integer(I4B), dimension(:), pointer, contiguous :: stoiconv => null() !< pointer to iconvert in storage ! -- real arrays - real(DP), dimension(:), pointer, contiguous :: stoss => null() !< pointer to ss in storage - real(DP), dimension(:), pointer, contiguous :: buff => null() !< buff array - real(DP), dimension(:), pointer, contiguous :: buffusr => null() !< buffusr array - integer, dimension(:), pointer, contiguous :: nodelist => null() !< reduced node that the interbed is attached to - integer, dimension(:), pointer, contiguous :: unodelist => null() !< user node that the interbed is attached to + real(DP), dimension(:), pointer, contiguous :: stoss => null() !< pointer to ss in storage + real(DP), dimension(:), pointer, contiguous :: buff => null() !< buff array + real(DP), dimension(:), pointer, contiguous :: buffusr => null() !< buffusr array + integer, dimension(:), pointer, contiguous :: nodelist => null() !< reduced node that the interbed is attached to + integer, dimension(:), pointer, contiguous :: unodelist => null() !< user node that the interbed is attached to ! ! -- coarse-grained storage variables - real(DP), dimension(:), pointer, contiguous :: sgm => null() !< specific gravity moist sediments - real(DP), dimension(:), pointer, contiguous :: sgs => null() !< specific gravity saturated sediments - real(DP), dimension(:), pointer, contiguous :: cg_ske_cr => null() !< coarse-grained specified storage - real(DP), dimension(:), pointer, contiguous :: cg_gs => null() !< geostatic stress for a cell - real(DP), dimension(:), pointer, contiguous :: cg_es => null() !< coarse-grained (aquifer) effective stress - real(DP), dimension(:), pointer, contiguous :: cg_es0 => null() !< coarse-grained (aquifer) effective stress for the previous time step - real(DP), dimension(:), pointer, contiguous :: cg_pcs => null() !< coarse-grained (aquifer) preconsolidation stress - real(DP), dimension(:), pointer, contiguous :: cg_comp => null() !< coarse-grained (aquifer) incremental compaction - real(DP), dimension(:), pointer, contiguous :: cg_tcomp => null() !< coarse-grained (aquifer) total compaction - real(DP), dimension(:), pointer, contiguous :: cg_stor => null() !< coarse-grained (aquifer) storage - real(DP), dimension(:), pointer, contiguous :: cg_ske => null() !< coarse-grained (aquifer) elastic storage coefficient - real(DP), dimension(:), pointer, contiguous :: cg_sk => null() !< coarse-grained (aquifer) first storage coefficient - real(DP), dimension(:), pointer, contiguous :: cg_thickini => null() !< initial coarse-grained (aquifer) thickness - real(DP), dimension(:), pointer, contiguous :: cg_thetaini => null() !< initial coarse-grained (aquifer) porosity - real(DP), dimension(:), pointer, contiguous :: cg_thick => null() !< current coarse-grained (aquifer) thickness - real(DP), dimension(:), pointer, contiguous :: cg_thick0 => null() !< previous coarse-grained (aquifer) thickness - real(DP), dimension(:), pointer, contiguous :: cg_theta => null() !< current coarse-grained (aquifer) porosity - real(DP), dimension(:), pointer, contiguous :: cg_theta0 => null() !< previous coarse-grained (aquifer) porosity + real(DP), dimension(:), pointer, contiguous :: sgm => null() !< specific gravity moist sediments + real(DP), dimension(:), pointer, contiguous :: sgs => null() !< specific gravity saturated sediments + real(DP), dimension(:), pointer, contiguous :: cg_ske_cr => null() !< coarse-grained specified storage + real(DP), dimension(:), pointer, contiguous :: cg_gs => null() !< geostatic stress for a cell + real(DP), dimension(:), pointer, contiguous :: cg_es => null() !< coarse-grained (aquifer) effective stress + real(DP), dimension(:), pointer, contiguous :: cg_es0 => null() !< coarse-grained (aquifer) effective stress for the previous time step + real(DP), dimension(:), pointer, contiguous :: cg_pcs => null() !< coarse-grained (aquifer) preconsolidation stress + real(DP), dimension(:), pointer, contiguous :: cg_comp => null() !< coarse-grained (aquifer) incremental compaction + real(DP), dimension(:), pointer, contiguous :: cg_tcomp => null() !< coarse-grained (aquifer) total compaction + real(DP), dimension(:), pointer, contiguous :: cg_stor => null() !< coarse-grained (aquifer) storage + real(DP), dimension(:), pointer, contiguous :: cg_ske => null() !< coarse-grained (aquifer) elastic storage coefficient + real(DP), dimension(:), pointer, contiguous :: cg_sk => null() !< coarse-grained (aquifer) first storage coefficient + real(DP), dimension(:), pointer, contiguous :: cg_thickini => null() !< initial coarse-grained (aquifer) thickness + real(DP), dimension(:), pointer, contiguous :: cg_thetaini => null() !< initial coarse-grained (aquifer) porosity + real(DP), dimension(:), pointer, contiguous :: cg_thick => null() !< current coarse-grained (aquifer) thickness + real(DP), dimension(:), pointer, contiguous :: cg_thick0 => null() !< previous coarse-grained (aquifer) thickness + real(DP), dimension(:), pointer, contiguous :: cg_theta => null() !< current coarse-grained (aquifer) porosity + real(DP), dimension(:), pointer, contiguous :: cg_theta0 => null() !< previous coarse-grained (aquifer) porosity ! ! -- cell storage variables - real(DP), dimension(:), pointer, contiguous :: cell_wcstor => null() !< cell water compressibility storage - real(DP), dimension(:), pointer, contiguous :: cell_thick => null() !< cell compressible material thickness + real(DP), dimension(:), pointer, contiguous :: cell_wcstor => null() !< cell water compressibility storage + real(DP), dimension(:), pointer, contiguous :: cell_thick => null() !< cell compressible material thickness ! ! -- interbed variables - integer(I4B), dimension(:), pointer, contiguous :: idelay => null() !< delay interbed flag - 0 = nodelay, > 0 = delay - integer(I4B), dimension(:), pointer, contiguous :: ielastic => null() !< elastic interbed equation - 0 = inelastic and elastic, > 0 = elastic - integer(I4B), dimension(:), pointer, contiguous :: iconvert => null() !< convertible cell flag - 0 = elastic, > 0 = inelastic - real(DP), dimension(:), pointer, contiguous :: ci => null() !< compression index - real(DP), dimension(:), pointer, contiguous :: rci => null() !< recompression index - real(DP), dimension(:), pointer, contiguous :: pcs => null() !< preconsolidation stress - real(DP), dimension(:), pointer, contiguous :: rnb => null() !< interbed system material factor - real(DP), dimension(:), pointer, contiguous :: kv => null() !< vertical hydraulic conductivity of interbed - real(DP), dimension(:), pointer, contiguous :: h0 => null() !< initial head in interbed - real(DP), dimension(:), pointer, contiguous :: comp => null() !< interbed incremental compaction - real(DP), dimension(:), pointer, contiguous :: tcomp => null() !< total interbed compaction - real(DP), dimension(:), pointer, contiguous :: tcompi => null() !< total inelastic interbed compaction - real(DP), dimension(:), pointer, contiguous :: tcompe => null() !< total elastic interbed compaction - real(DP), dimension(:), pointer, contiguous :: storagee => null() !< elastic storage - real(DP), dimension(:), pointer, contiguous :: storagei => null() !< inelastic storage - real(DP), dimension(:), pointer, contiguous :: ske => null() !< elastic storage coefficient - real(DP), dimension(:), pointer, contiguous :: sk => null() !< first storage coefficient - real(DP), dimension(:), pointer, contiguous :: thickini => null() !< initial interbed thickness - real(DP), dimension(:), pointer, contiguous :: thetaini => null() !< initial interbed theta - real(DP), dimension(:), pointer, contiguous :: thick => null() !< current interbed thickness - real(DP), dimension(:), pointer, contiguous :: thick0 => null() !< previous interbed thickness - real(DP), dimension(:), pointer, contiguous :: theta => null() !< current interbed porosity - real(DP), dimension(:), pointer, contiguous :: theta0 => null() !< previous interbed porosity - real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< auxiliary variable array + integer(I4B), dimension(:), pointer, contiguous :: idelay => null() !< delay interbed flag - 0 = nodelay, > 0 = delay + integer(I4B), dimension(:), pointer, contiguous :: ielastic => null() !< elastic interbed equation - 0 = inelastic and elastic, > 0 = elastic + integer(I4B), dimension(:), pointer, contiguous :: iconvert => null() !< convertible cell flag - 0 = elastic, > 0 = inelastic + real(DP), dimension(:), pointer, contiguous :: ci => null() !< compression index + real(DP), dimension(:), pointer, contiguous :: rci => null() !< recompression index + real(DP), dimension(:), pointer, contiguous :: pcs => null() !< preconsolidation stress + real(DP), dimension(:), pointer, contiguous :: rnb => null() !< interbed system material factor + real(DP), dimension(:), pointer, contiguous :: kv => null() !< vertical hydraulic conductivity of interbed + real(DP), dimension(:), pointer, contiguous :: h0 => null() !< initial head in interbed + real(DP), dimension(:), pointer, contiguous :: comp => null() !< interbed incremental compaction + real(DP), dimension(:), pointer, contiguous :: tcomp => null() !< total interbed compaction + real(DP), dimension(:), pointer, contiguous :: tcompi => null() !< total inelastic interbed compaction + real(DP), dimension(:), pointer, contiguous :: tcompe => null() !< total elastic interbed compaction + real(DP), dimension(:), pointer, contiguous :: storagee => null() !< elastic storage + real(DP), dimension(:), pointer, contiguous :: storagei => null() !< inelastic storage + real(DP), dimension(:), pointer, contiguous :: ske => null() !< elastic storage coefficient + real(DP), dimension(:), pointer, contiguous :: sk => null() !< first storage coefficient + real(DP), dimension(:), pointer, contiguous :: thickini => null() !< initial interbed thickness + real(DP), dimension(:), pointer, contiguous :: thetaini => null() !< initial interbed theta + real(DP), dimension(:), pointer, contiguous :: thick => null() !< current interbed thickness + real(DP), dimension(:), pointer, contiguous :: thick0 => null() !< previous interbed thickness + real(DP), dimension(:), pointer, contiguous :: theta => null() !< current interbed porosity + real(DP), dimension(:), pointer, contiguous :: theta0 => null() !< previous interbed porosity + real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< auxiliary variable array ! ! -- delay interbed integer(I4B), dimension(:), pointer, contiguous :: idb_nconv_count => null() !< non-convertible count of interbeds with heads below delay cell top - integer(I4B), dimension(:, :), pointer, contiguous :: idbconvert => null() !0 = elastic, > 0 = inelastic - real(DP), dimension(:), pointer, contiguous :: dbdhmax => null() !< delay bed maximum head change - real(DP), dimension(:, :), pointer, contiguous :: dbz => null() !< delay bed cell z - real(DP), dimension(:, :), pointer, contiguous :: dbrelz => null() !< delay bed cell z relative to znode - real(DP), dimension(:, :), pointer, contiguous :: dbh => null() !< delay bed cell h - real(DP), dimension(:, :), pointer, contiguous :: dbh0 => null() !< delay bed cell previous h - real(DP), dimension(:, :), pointer, contiguous :: dbgeo => null() !< delay bed cell geostatic stress - real(DP), dimension(:, :), pointer, contiguous :: dbes => null() !< delay bed cell effective stress - real(DP), dimension(:, :), pointer, contiguous :: dbes0 => null() !< delay bed cell previous effective stress - real(DP), dimension(:, :), pointer, contiguous :: dbpcs => null() !< delay bed cell preconsolidation stress - real(DP), dimension(:), pointer, contiguous :: dbflowtop => null() !< delay bed flow through interbed top - real(DP), dimension(:), pointer, contiguous :: dbflowbot => null() !< delay bed flow through interbed bottom - real(DP), dimension(:, :), pointer, contiguous :: dbdzini => null() !< initial delay bed cell thickness - real(DP), dimension(:, :), pointer, contiguous :: dbthetaini => null() !< initial delay bed cell porosity - real(DP), dimension(:, :), pointer, contiguous :: dbdz => null() !< delay bed dz - real(DP), dimension(:, :), pointer, contiguous :: dbdz0 => null() !< delay bed previous dz - real(DP), dimension(:, :), pointer, contiguous :: dbtheta => null() !< delay bed cell porosity - real(DP), dimension(:, :), pointer, contiguous :: dbtheta0 => null() !< delay bed cell previous porosity - real(DP), dimension(:, :), pointer, contiguous :: dbcomp => null() !< delay bed incremental compaction - real(DP), dimension(:, :), pointer, contiguous :: dbtcomp => null() !< delay bed total interbed compaction + integer(I4B), dimension(:, :), pointer, contiguous :: idbconvert => null() !0 = elastic, > 0 = inelastic + real(DP), dimension(:), pointer, contiguous :: dbdhmax => null() !< delay bed maximum head change + real(DP), dimension(:, :), pointer, contiguous :: dbz => null() !< delay bed cell z + real(DP), dimension(:, :), pointer, contiguous :: dbrelz => null() !< delay bed cell z relative to znode + real(DP), dimension(:, :), pointer, contiguous :: dbh => null() !< delay bed cell h + real(DP), dimension(:, :), pointer, contiguous :: dbh0 => null() !< delay bed cell previous h + real(DP), dimension(:, :), pointer, contiguous :: dbgeo => null() !< delay bed cell geostatic stress + real(DP), dimension(:, :), pointer, contiguous :: dbes => null() !< delay bed cell effective stress + real(DP), dimension(:, :), pointer, contiguous :: dbes0 => null() !< delay bed cell previous effective stress + real(DP), dimension(:, :), pointer, contiguous :: dbpcs => null() !< delay bed cell preconsolidation stress + real(DP), dimension(:), pointer, contiguous :: dbflowtop => null() !< delay bed flow through interbed top + real(DP), dimension(:), pointer, contiguous :: dbflowbot => null() !< delay bed flow through interbed bottom + real(DP), dimension(:, :), pointer, contiguous :: dbdzini => null() !< initial delay bed cell thickness + real(DP), dimension(:, :), pointer, contiguous :: dbthetaini => null() !< initial delay bed cell porosity + real(DP), dimension(:, :), pointer, contiguous :: dbdz => null() !< delay bed dz + real(DP), dimension(:, :), pointer, contiguous :: dbdz0 => null() !< delay bed previous dz + real(DP), dimension(:, :), pointer, contiguous :: dbtheta => null() !< delay bed cell porosity + real(DP), dimension(:, :), pointer, contiguous :: dbtheta0 => null() !< delay bed cell previous porosity + real(DP), dimension(:, :), pointer, contiguous :: dbcomp => null() !< delay bed incremental compaction + real(DP), dimension(:, :), pointer, contiguous :: dbtcomp => null() !< delay bed total interbed compaction ! ! -- delay interbed solution arrays - real(DP), dimension(:), pointer, contiguous :: dbal => null() !< delay bed lower diagonal - real(DP), dimension(:), pointer, contiguous :: dbad => null() !< delay bed diagonal - real(DP), dimension(:), pointer, contiguous :: dbau => null() !< delay bed upper diagonal - real(DP), dimension(:), pointer, contiguous :: dbrhs => null() !< delay bed right hand side - real(DP), dimension(:), pointer, contiguous :: dbdh => null() !< delay bed dh - real(DP), dimension(:), pointer, contiguous :: dbaw => null() !< delay bed work vector + real(DP), dimension(:), pointer, contiguous :: dbal => null() !< delay bed lower diagonal + real(DP), dimension(:), pointer, contiguous :: dbad => null() !< delay bed diagonal + real(DP), dimension(:), pointer, contiguous :: dbau => null() !< delay bed upper diagonal + real(DP), dimension(:), pointer, contiguous :: dbrhs => null() !< delay bed right hand side + real(DP), dimension(:), pointer, contiguous :: dbdh => null() !< delay bed dh + real(DP), dimension(:), pointer, contiguous :: dbaw => null() !< delay bed work vector ! ! -- period data - integer(I4B), dimension(:), pointer, contiguous :: nodelistsig0 => null() !< vector of reduced node numbers - real(DP), dimension(:), pointer, contiguous :: sig0 => null() !< array of package specific boundary numbers + integer(I4B), dimension(:), pointer, contiguous :: nodelistsig0 => null() !< vector of reduced node numbers + real(DP), dimension(:), pointer, contiguous :: sig0 => null() !< array of package specific boundary numbers ! ! -- timeseries - type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager + type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager ! ! -- observation data - integer(I4B), pointer :: inobspkg => null() !< unit number for obs package - type(ObsType), pointer :: obs => null() !< observation package + integer(I4B), pointer :: inobspkg => null() !< unit number for obs package + type(ObsType), pointer :: obs => null() !< observation package ! ! -- table objects - type(TableType), pointer :: inputtab => null() !< table for input variables - type(TableType), pointer :: outputtab => null() !< table for output variables - type(TableType), pointer :: pakcsvtab => null() !< table for csv output + type(TableType), pointer :: inputtab => null() !< table for input variables + type(TableType), pointer :: outputtab => null() !< table for output variables + type(TableType), pointer :: pakcsvtab => null() !< table for csv output contains procedure :: define_listlabel @@ -310,12 +317,12 @@ module GwfCsubModule !< subroutine csub_cr(csubobj, name_model, istounit, stoPckName, inunit, iout) ! -- dummy variables - type(GwfCsubType), pointer :: csubobj !< pointer to default package type - character(len=*), intent(in) :: name_model !< model name - integer(I4B), intent(in) :: inunit !< unit number of csub input file - integer(I4B), intent(in) :: istounit !< unit number of storage package - character(len=*), intent(in) :: stoPckName !< name of the storage package - integer(I4B), intent(in) :: iout !< unit number of lst output file + type(GwfCsubType), pointer :: csubobj !< pointer to default package type + character(len=*), intent(in) :: name_model !< model name + integer(I4B), intent(in) :: inunit !< unit number of csub input file + integer(I4B), intent(in) :: istounit !< unit number of storage package + character(len=*), intent(in) :: stoPckName !< name of the storage package + integer(I4B), intent(in) :: iout !< unit number of lst output file ! -- local variables ! ! -- allocate the object and assign values to object variables @@ -354,8 +361,8 @@ subroutine csub_ar(this, dis, ibound) use KindModule, only: I4B ! -- dummy variables class(GwfCsubType), intent(inout) :: this - class(DisBaseType), pointer, intent(in) :: dis !< model discretization - integer(I4B), dimension(:), pointer, contiguous :: ibound !< model ibound array + class(DisBaseType), pointer, intent(in) :: dis !< model discretization + integer(I4B), dimension(:), pointer, contiguous :: ibound !< model ibound array ! -- local variables logical :: isfound, endOfBlock character(len=:), allocatable :: line @@ -381,7 +388,7 @@ subroutine csub_ar(this, dis, ibound) real(DP) :: v ! -- format character(len=*), parameter :: fmtcsub = & - "(1x,/1x,'CSUB -- COMPACTION PACKAGE, VERSION 1, 12/15/2019', & + "(1x,/1x,'CSUB -- COMPACTION PACKAGE, VERSION 1, 12/15/2019', & &' INPUT READ FROM UNIT ', i0, //)" ! ! --print a message identifying the csub package. @@ -520,7 +527,8 @@ subroutine csub_ar(this, dis, ibound) if (istoerr /= 0) then write (errmsg, '(a,3(1x,a))') & 'Specific storage values in the storage (STO) package must', & - 'be zero in all active cells when using the', trim(adjustl(this%packName)), & + 'be zero in all active cells when using the', & + trim(adjustl(this%packName)), & 'package.' call store_error(errmsg) end if @@ -545,7 +553,7 @@ subroutine csub_ar(this, dis, ibound) if (idelay == 0) then v = this%thickini(ib) else - v = this%rnb(ib)*this%thickini(ib) + v = this%rnb(ib) * this%thickini(ib) end if this%cg_thickini(node) = this%cg_thickini(node) - v end do @@ -589,7 +597,7 @@ end subroutine csub_ar subroutine read_options(this) ! -- modules use ConstantsModule, only: MAXCHARLEN, DZERO, MNORMAL - use MemoryManagerModule, only: mem_allocate + use MemoryManagerModule, only: mem_reallocate use OpenSpecModule, only: access, form use InputOutputModule, only: getunit, urdaux, openfile ! -- dummy variables @@ -612,23 +620,24 @@ subroutine read_options(this) integer(I4B) :: isetgamma ! -- formats character(len=*), parameter :: fmtts = & - "(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" + &"(4x,'TIME-SERIES DATA WILL BE READ FROM FILE: ',a)" character(len=*), parameter :: fmtflow = & - "(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + &"(4x,'FLOWS WILL BE SAVED TO FILE: ',a,/4x,'OPENED ON UNIT: ',I7)" character(len=*), parameter :: fmtflow2 = & - "(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL')" + &"(4x,'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL')" character(len=*), parameter :: fmtssessv = & - "(4x, 'USING SSE AND SSV INSTEAD OF CR AND CC.')" + &"(4x,'USING SSE AND SSV INSTEAD OF CR AND CC.')" character(len=*), parameter :: fmtoffset = & - "(4x, 'INITIAL_STRESS TREATED AS AN OFFSET.')" + &"(4x,'INITIAL_STRESS TREATED AS AN OFFSET.')" character(len=*), parameter :: fmtopt = & - "(4x, A)" + &"(4x,A)" character(len=*), parameter :: fmtopti = & - "(4x, A, 1X, I0)" + &"(4x,A,1X,I0)" character(len=*), parameter :: fmtoptr = & - "(4x, A, 1X, G0)" + &"(4x,A,1X,G0)" character(len=*), parameter :: fmtfileout = & - "(4x, 'CSUB ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + "(4x,'CSUB ',1x,a,1x,' WILL BE SAVED TO FILE: ',a,/4x,& + &'OPENED ON UNIT: ',I7)" ! ! -- initialize variables ibrg = 0 @@ -654,8 +663,8 @@ subroutine read_options(this) lloc = 1 call urdaux(this%naux, this%parser%iuactive, this%iout, lloc, & istart, istop, caux, line, this%packName) - call mem_allocate(this%auxname, LENAUXNAME, this%naux, & - 'AUXNAME', this%memoryPath) + call mem_reallocate(this%auxname, LENAUXNAME, this%naux, & + 'AUXNAME', this%memoryPath) do n = 1, this%naux this%auxname(n) = caux(n) end do @@ -665,8 +674,8 @@ subroutine read_options(this) write (this%iout, fmtflow2) case ('PRINT_INPUT') this%iprpak = 1 - write (this%iout, '(4x,a)') 'LISTS OF '//trim(adjustl(this%packName))// & - ' CELLS WILL BE PRINTED.' + write (this%iout, '(4x,a)') & + 'LISTS OF '//trim(adjustl(this%packName))//' CELLS WILL BE PRINTED.' case ('PRINT_FLOWS') this%iprflow = 1 write (this%iout, '(4x,a)') trim(adjustl(this%packName))// & @@ -674,7 +683,7 @@ subroutine read_options(this) case ('BOUNDNAMES') this%inamedbound = 1 write (this%iout, '(4x,a)') trim(adjustl(this%packName))// & - ' BOUNDARIES HAVE NAMES IN LAST COLUMN.' ! user specified boundnames + ' BOUNDARIES HAVE NAMES IN LAST COLUMN.' ! user specified boundnames case ('TS6') call this%parser%GetStringCaps(keyword) if (trim(adjustl(keyword)) /= 'FILEIN') then @@ -883,7 +892,8 @@ subroutine read_options(this) this%ipakcsv = getunit() call openfile(this%ipakcsv, this%iout, fname, 'CSV', & filstat_opt='REPLACE', mode_opt=MNORMAL) - write (this%iout, fmtfileout) 'PACKAGE_CONVERGENCE', fname, this%ipakcsv + write (this%iout, fmtfileout) & + 'PACKAGE_CONVERGENCE', fname, this%ipakcsv else call store_error('Optional PACKAGE_CONVERGENCE keyword must be '// & 'followed by FILEOUT.') @@ -995,9 +1005,9 @@ subroutine read_options(this) if (ieslag /= 0) then ieslag = 0 write (this%iout, '(4x,a,2(/,6x,a))') & - 'EFFECTIVE_STRESS_LAG HAS BEEN SPECIFIED BUT HAS NO EFFECT WHEN USING', & - 'THE HEAD-BASED FORMULATION (HEAD_BASED HAS BEEN SPECIFIED IN THE', & - 'OPTIONS BLOCK)' + 'EFFECTIVE_STRESS_LAG HAS BEEN SPECIFIED BUT HAS NO EFFECT WHEN', & + 'USING THE HEAD-BASED FORMULATION (HEAD_BASED HAS BEEN SPECIFIED', & + 'IN THE OPTIONS BLOCK)' end if end if this%ieslag = ieslag @@ -1005,7 +1015,7 @@ subroutine read_options(this) ! -- recalculate BRG if necessary and output ! water compressibility values if (ibrg /= 0) then - this%brg = this%gammaw*this%beta + this%brg = this%gammaw * this%beta end if write (this%iout, fmtoptr) 'GAMMAW =', this%gammaw write (this%iout, fmtoptr) 'BETA =', this%beta @@ -1152,7 +1162,10 @@ subroutine csub_allocate_scalars(this) call mem_allocate(this%gwfiss0, 'GWFISS0', this%memoryPath) ! ! -- allocate TS object - allocate(this%TsManager) + allocate (this%TsManager) + ! + ! -- allocate text strings + call mem_allocate(this%auxname, LENAUXNAME, 0, 'AUXNAME', this%memoryPath) ! ! -- initialize values this%istounit = 0 @@ -1187,14 +1200,14 @@ subroutine csub_allocate_scalars(this) this%iupdatematprop = 0 this%epsilon = DZERO this%cc_crit = DEM7 - this%gammaw = DGRAVITY*1000._DP + this%gammaw = DGRAVITY * 1000._DP this%beta = 4.6512e-10_DP - this%brg = this%gammaw*this%beta + this%brg = this%gammaw * this%beta ! ! -- set omega value used for saturation calculations if (this%inewton /= 0) then this%satomega = DEM6 - this%epsilon = DHALF*DEM6 + this%epsilon = DHALF * DEM6 else this%satomega = DZERO end if @@ -1241,15 +1254,22 @@ subroutine csub_allocate_arrays(this) call mem_allocate(this%sgs, this%dis%nodes, 'SGS', trim(this%memoryPath)) call mem_allocate(this%cg_ske_cr, this%dis%nodes, 'CG_SKE_CR', & trim(this%memoryPath)) - call mem_allocate(this%cg_es, this%dis%nodes, 'CG_ES', trim(this%memoryPath)) - call mem_allocate(this%cg_es0, this%dis%nodes, 'CG_ES0', trim(this%memoryPath)) - call mem_allocate(this%cg_pcs, this%dis%nodes, 'CG_PCS', trim(this%memoryPath)) - call mem_allocate(this%cg_comp, this%dis%nodes, 'CG_COMP', trim(this%memoryPath)) + call mem_allocate(this%cg_es, this%dis%nodes, 'CG_ES', & + trim(this%memoryPath)) + call mem_allocate(this%cg_es0, this%dis%nodes, 'CG_ES0', & + trim(this%memoryPath)) + call mem_allocate(this%cg_pcs, this%dis%nodes, 'CG_PCS', & + trim(this%memoryPath)) + call mem_allocate(this%cg_comp, this%dis%nodes, 'CG_COMP', & + trim(this%memoryPath)) call mem_allocate(this%cg_tcomp, this%dis%nodes, 'CG_TCOMP', & trim(this%memoryPath)) - call mem_allocate(this%cg_stor, this%dis%nodes, 'CG_STOR', trim(this%memoryPath)) - call mem_allocate(this%cg_ske, this%dis%nodes, 'CG_SKE', trim(this%memoryPath)) - call mem_allocate(this%cg_sk, this%dis%nodes, 'CG_SK', trim(this%memoryPath)) + call mem_allocate(this%cg_stor, this%dis%nodes, 'CG_STOR', & + trim(this%memoryPath)) + call mem_allocate(this%cg_ske, this%dis%nodes, 'CG_SKE', & + trim(this%memoryPath)) + call mem_allocate(this%cg_sk, this%dis%nodes, 'CG_SK', & + trim(this%memoryPath)) call mem_allocate(this%cg_thickini, this%dis%nodes, 'CG_THICKINI', & trim(this%memoryPath)) call mem_allocate(this%cg_thetaini, this%dis%nodes, 'CG_THETAINI', & @@ -1332,6 +1352,10 @@ subroutine csub_allocate_arrays(this) if (this%inamedbound /= 0) then call mem_allocate(this%boundname, LENBOUNDNAME, this%ninterbeds, & 'BOUNDNAME', trim(this%memoryPath)) + else + call mem_allocate(this%boundname, LENBOUNDNAME, 1, & + 'BOUNDNAME', trim(this%memoryPath)) + end if ! ! -- allocate the nodelist and bound arrays @@ -1509,7 +1533,7 @@ subroutine csub_read_packagedata(this) 'for packagedata entry', itmp, '.' call store_error(errmsg) end if - rval = rval*baq + rval = rval * baq end if this%thickini(itmp) = rval if (this%iupdatematprop /= 0) then @@ -1780,7 +1804,7 @@ subroutine csub_read_packagedata(this) ! ! -- initialize delay interbed variables do n = 1, this%ndelaycells - rval = this%thickini(ib)/real(this%ndelaycells, DP) + rval = this%thickini(ib) / real(this%ndelaycells, DP) this%dbdzini(n, idelay) = rval this%dbh(n, idelay) = this%h0(ib) this%dbh0(n, idelay) = this%h0(ib) @@ -1881,8 +1905,8 @@ subroutine csub_fp(this) do ib = 1, this%ninterbeds idelay = this%idelay(ib) b0 = this%thickini(ib) - strain = this%tcomp(ib)/b0 - pctcomp = DHUNDRED*strain + strain = this%tcomp(ib) / b0 + pctcomp = DHUNDRED * strain pctcomp_arr(ib) = pctcomp if (pctcomp >= DONE) then iexceed = iexceed + 1 @@ -1942,10 +1966,10 @@ subroutine csub_fp(this) ctype = 'no-delay' else ctype = 'delay' - b0 = b0*this%rnb(ib) + b0 = b0 * this%rnb(ib) end if - strain = this%tcomp(ib)/b0 - pctcomp = DHUNDRED*strain + strain = this%tcomp(ib) / b0 + pctcomp = DHUNDRED * strain if (pctcomp >= 5.0_DP) then cflag = '**>=5%' else if (pctcomp >= DONE) then @@ -2033,10 +2057,10 @@ subroutine csub_fp(this) ctype = 'no-delay' else ctype = 'delay' - b0 = b0*this%rnb(ib) + b0 = b0 * this%rnb(ib) end if - strain = this%tcomp(ib)/b0 - pctcomp = DHUNDRED*strain + strain = this%tcomp(ib) / b0 + pctcomp = DHUNDRED * strain node = this%nodelist(ib) call this%dis%noder_to_array(node, locs) ! @@ -2070,9 +2094,9 @@ subroutine csub_fp(this) do node = 1, this%dis%nodes strain = DZERO if (this%cg_thickini(node) > DZERO) then - strain = this%cg_tcomp(node)/this%cg_thickini(node) + strain = this%cg_tcomp(node) / this%cg_thickini(node) end if - pctcomp = DHUNDRED*strain + pctcomp = DHUNDRED * strain pctcomp_arr(node) = pctcomp if (pctcomp >= DONE) then iexceed = iexceed + 1 @@ -2121,11 +2145,11 @@ subroutine csub_fp(this) do nn = 1, nlen node = imap_sel(nn) if (this%cg_thickini(node) > DZERO) then - strain = this%cg_tcomp(node)/this%cg_thickini(node) + strain = this%cg_tcomp(node) / this%cg_thickini(node) else strain = DZERO end if - pctcomp = DHUNDRED*strain + pctcomp = DHUNDRED * strain if (pctcomp >= 5.0_DP) then cflag = '**>=5%' else if (pctcomp >= DONE) then @@ -2201,11 +2225,11 @@ subroutine csub_fp(this) ! -- write data do node = 1, this%dis%nodes if (this%cg_thickini(node) > DZERO) then - strain = this%cg_tcomp(node)/this%cg_thickini(node) + strain = this%cg_tcomp(node) / this%cg_thickini(node) else strain = DZERO end if - pctcomp = DHUNDRED*strain + pctcomp = DHUNDRED * strain call this%dis%noder_to_array(node, locs) ! ! -- fill table line @@ -2229,8 +2253,9 @@ subroutine csub_fp(this) if (this%idb_nconv_count(2) > 0) then write (warnmsg, '(a,1x,a,1x,i0,1x,a,1x,a)') & 'Delay interbed cell heads were less than the top of the interbed', & - 'cell in', this%idb_nconv_count(2), 'interbed cells in non-convertible', & - 'GWF cells for at least one time step during the simulation.' + 'cell in', this%idb_nconv_count(2), 'interbed cells in ', & + 'non-convertible GWF cells for at least one time step during '// & + 'the simulation.' call store_warning(warnmsg) end if end if @@ -2452,14 +2477,13 @@ subroutine csub_da(this) ! ! -- deallocate and nullify observations deallocate (this%obs) - nullify(this%obs) + nullify (this%obs) end if ! ! -- deallocate TsManager deallocate (this%TsManager) nullify (this%TsManager) - ! ! -- deallocate parent call this%NumericalPackageType%da() @@ -2496,9 +2520,9 @@ subroutine csub_rp(this) real(DP), pointer :: bndElem => null() ! -- formats character(len=*), parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + &"('Looking for BEGIN PERIOD iper. Found ',a,' instead.')" character(len=*), parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + &"(1X,/1X,'REUSING ',a,'S FROM LAST STRESS PERIOD')" ! ! -- return if data is not read from file if (this%inunit == 0) return @@ -2508,7 +2532,8 @@ subroutine csub_rp(this) ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true., & + blockRequired=.false.) if (isfound) then ! ! -- read ionper and check for increasing period numbers @@ -2590,10 +2615,11 @@ subroutine csub_rp(this) ! ! -- get sig0 call this%parser%GetString(text) - jj = 1 ! For 'SIG0' + jj = 1 ! For 'SIG0' bndElem => this%sig0(nlist) - call read_value_or_time_series_adv(text, nlist, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, nlist, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & 'SIG0') ! ! -- write line to table @@ -2642,8 +2668,8 @@ subroutine csub_ad(this, nodes, hnew) use TdisModule, only: nper, kper ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: nodes !< number of active model nodes - real(DP), dimension(nodes), intent(in) :: hnew !< current head + integer(I4B), intent(in) :: nodes !< number of active model nodes + real(DP), dimension(nodes), intent(in) :: hnew !< current head ! -- local variables integer(I4B) :: ib integer(I4B) :: n @@ -2762,13 +2788,13 @@ subroutine csub_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: kiter !< outer iteration numbed - real(DP), intent(in), dimension(:) :: hold !< previous heads - real(DP), intent(in), dimension(:) :: hnew !< current heads - integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution - real(DP), dimension(njasln), intent(inout) :: amat !< A matrix - integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution - real(DP), intent(inout), dimension(:) :: rhs !< right-hand side + integer(I4B), intent(in) :: kiter !< outer iteration numbed + real(DP), intent(in), dimension(:) :: hold !< previous heads + real(DP), intent(in), dimension(:) :: hnew !< current heads + integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution + real(DP), dimension(njasln), intent(inout) :: amat !< A matrix + integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution + real(DP), intent(inout), dimension(:) :: rhs !< right-hand side ! -- local variables integer(I4B) :: ib integer(I4B) :: node @@ -2787,7 +2813,7 @@ subroutine csub_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) if (this%gwfiss == 0) then ! ! -- initialize tled - tled = DONE/delt + tled = DONE / delt ! ! -- coarse-grained storage do node = 1, this%dis%nodes @@ -2883,13 +2909,13 @@ subroutine csub_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: kiter !< outer iteration number - real(DP), intent(in), dimension(:) :: hold !< previous heads - real(DP), intent(in), dimension(:) :: hnew !< current heads - integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution - real(DP), dimension(njasln), intent(inout) :: amat !< A matrix - integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution - real(DP), intent(inout), dimension(:) :: rhs !< right-hand side + integer(I4B), intent(in) :: kiter !< outer iteration number + real(DP), intent(in), dimension(:) :: hold !< previous heads + real(DP), intent(in), dimension(:) :: hnew !< current heads + integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution + real(DP), dimension(njasln), intent(inout) :: amat !< A matrix + integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution + real(DP), intent(inout), dimension(:) :: rhs !< right-hand side ! -- local variables integer(I4B) :: idelay integer(I4B) :: node @@ -2902,7 +2928,7 @@ subroutine csub_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) ! ! -- formulate csub terms if (this%gwfiss == 0) then - tled = DONE/delt + tled = DONE / delt ! ! -- coarse-grained storage do node = 1, this%dis%nodes @@ -2993,16 +3019,16 @@ subroutine csub_cc(this, innertot, kiter, iend, icnvgmod, nodes, & use TdisModule, only: totim, kstp, kper, delt ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: innertot !< total number of inner iterations - integer(I4B), intent(in) :: kiter !< outer iteration number - integer(I4B), intent(in) :: iend !< flag indicating if it is the last iteration - integer(I4B), intent(in) :: icnvgmod !< flag indicating if the solution is considered converged - integer(I4B), intent(in) :: nodes !< number of active nodes - real(DP), dimension(nodes), intent(in) :: hnew !< current gwf head - real(DP), dimension(nodes), intent(in) :: hold !< gwf for previous time step - character(len=LENPAKLOC), intent(inout) :: cpak !< string location of the maximum change in csub package - integer(I4B), intent(inout) :: ipak !< node with the maximum change in csub package - real(DP), intent(inout) :: dpak !< maximum change in csub package + integer(I4B), intent(in) :: innertot !< total number of inner iterations + integer(I4B), intent(in) :: kiter !< outer iteration number + integer(I4B), intent(in) :: iend !< flag indicating if it is the last iteration + integer(I4B), intent(in) :: icnvgmod !< flag indicating if the solution is considered converged + integer(I4B), intent(in) :: nodes !< number of active nodes + real(DP), dimension(nodes), intent(in) :: hnew !< current gwf head + real(DP), dimension(nodes), intent(in) :: hold !< gwf for previous time step + character(len=LENPAKLOC), intent(inout) :: cpak !< string location of the maximum change in csub package + integer(I4B), intent(inout) :: ipak !< node with the maximum change in csub package + real(DP), intent(inout) :: dpak !< maximum change in csub package ! -- local variables character(len=LINELENGTH) :: tag character(len=LENPAKLOC) :: cloc @@ -3096,7 +3122,7 @@ subroutine csub_cc(this, innertot, kiter, iend, icnvgmod, nodes, & ! -- perform package convergence check if (icheck /= 0) then if (DELT > DZERO) then - tled = DONE/DELT + tled = DONE / DELT else tled = DZERO end if @@ -3125,22 +3151,22 @@ subroutine csub_cc(this, innertot, kiter, iend, icnvgmod, nodes, & ! ! -- calculate the change in storage call this%csub_delay_calc_dstor(ib, hcell, stoe, stoi) - v1 = (stoe + stoi)*area*this%rnb(ib)*tled + v1 = (stoe + stoi) * area * this%rnb(ib) * tled ! ! -- add water compressibility to storage term call this%csub_delay_calc_wcomp(ib, dwc) - v1 = v1 + dwc*area*this%rnb(ib) + v1 = v1 + dwc * area * this%rnb(ib) ! ! -- calculate the flow between the interbed and the cell call this%csub_delay_fc(ib, hcof, rhs) - v2 = (-hcof*hcell - rhs)*area*this%rnb(ib) + v2 = (-hcof * hcell - rhs) * area * this%rnb(ib) ! ! -- calculate the difference between the interbed change in ! storage and the flow between the interbed and the cell df = v2 - v1 ! ! -- normalize by cell area and convert to a depth - df = df*delt/area + df = df * delt / area ! ! -- evaluate magnitude of differences if (ifirst == 1) then @@ -3218,10 +3244,10 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) use ConstantsModule, only: LENBOUNDNAME, DZERO, DONE ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: nodes !< number of active model nodes - real(DP), intent(in), dimension(nodes) :: hnew !< current head - real(DP), intent(in), dimension(nodes) :: hold !< head for the previous time step - integer(I4B), intent(in) :: isuppress_output !< flag indicating if budget output should be suppressed + integer(I4B), intent(in) :: nodes !< number of active model nodes + real(DP), intent(in), dimension(nodes) :: hnew !< current head + real(DP), intent(in), dimension(nodes) :: hold !< head for the previous time step + integer(I4B), intent(in) :: isuppress_output !< flag indicating if budget output should be suppressed real(DP), dimension(:), contiguous, intent(inout) :: flowja ! -- local variables integer(I4B) :: ib @@ -3276,7 +3302,7 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) rratewc = DZERO if (this%gwfiss == 0) then if (DELT > DZERO) then - tled = DONE/DELT + tled = DONE / DELT else tled = DZERO end if @@ -3285,7 +3311,7 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) ! -- calculate coarse-grained storage terms call this%csub_cg_fc(node, tled, area, hnew(node), hold(node), & hcof, rhs) - rrate = hcof*hnew(node) - rhs + rrate = hcof * hnew(node) - rhs ! ! -- calculate compaction call this%csub_cg_calc_comp(node, hnew(node), hold(node), comp) @@ -3293,7 +3319,7 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) ! -- calculate coarse-grained water compressibility storage terms call this%csub_cg_wcomp_fc(node, tled, area, hnew(node), hold(node), & hcof, rhs) - rratewc = hcof*hnew(node) - rhs + rratewc = hcof * hnew(node) - rhs end if end if ! @@ -3347,7 +3373,7 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) b = this%thick(ib) ! -- delay interbeds else - b = this%thick(ib)*this%rnb(ib) + b = this%thick(ib) * this%rnb(ib) end if ! ! -- set variables required for no-delay and delay interbeds @@ -3361,7 +3387,7 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) ! -- update budget terms if transient stress period if (this%gwfiss == 0) then if (DELT > DZERO) then - tledm = DONE/DELT + tledm = DONE / DELT else tledm = DZERO end if @@ -3387,15 +3413,15 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) if (ielastic > 0 .or. iconvert == 0) then stoe = comp else - stoi = -pcs*rho2 + (rho2*es) - stoe = pcs*rho1 - (rho1*es0) + stoi = -pcs * rho2 + (rho2 * es) + stoe = pcs * rho1 - (rho1 * es0) end if compe = stoe compi = stoi - stoe = stoe*area - stoi = stoi*area - this%storagee(ib) = stoe*tledm - this%storagei(ib) = stoi*tledm + stoe = stoe * area + stoi = stoi * area + this%storagee(ib) = stoe * tledm + this%storagei(ib) = stoi * tledm ! ! -- update compaction this%comp(ib) = comp @@ -3424,14 +3450,14 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) ! ! -- calculate inelastic and elastic storage contributions call this%csub_delay_calc_dstor(ib, h, stoe, stoi) - this%storagee(ib) = stoe*area*this%rnb(ib)*tledm - this%storagei(ib) = stoi*area*this%rnb(ib)*tledm + this%storagee(ib) = stoe * area * this%rnb(ib) * tledm + this%storagei(ib) = stoi * area * this%rnb(ib) * tledm ! ! -- calculate flow across the top and bottom of the delay interbed - q = this%csub_calc_delay_flow(ib, 1, h)*area*this%rnb(ib) + q = this%csub_calc_delay_flow(ib, 1, h) * area * this%rnb(ib) this%dbflowtop(idelay) = q nn = this%ndelaycells - q = this%csub_calc_delay_flow(ib, nn, h)*area*this%rnb(ib) + q = this%csub_calc_delay_flow(ib, nn, h) * area * this%rnb(ib) this%dbflowbot(idelay) = q ! ! -- update states if required @@ -3453,7 +3479,8 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) ! ! -- update total compaction for each delay bed cell do n = 1, this%ndelaycells - this%dbtcomp(n, idelay) = this%dbtcomp(n, idelay) + this%dbcomp(n, idelay) + this%dbtcomp(n, idelay) = this%dbtcomp(n, idelay) + & + this%dbcomp(n, idelay) end do ! ! -- check delay bed heads relative to the top and bottom of each @@ -3468,12 +3495,12 @@ subroutine csub_cq(this, nodes, hnew, hold, isuppress_output, flowja) if (idelay == 0) then call this%csub_nodelay_wcomp_fc(ib, node, tledm, area, & hnew(node), hold(node), hcof, rhs) - rratewc = hcof*hnew(node) - rhs + rratewc = hcof * hnew(node) - rhs ! ! -- delay interbed else call this%csub_delay_calc_wcomp(ib, q) - rratewc = q*area*this%rnb(ib) + rratewc = q * area * this%rnb(ib) end if this%cell_wcstor(node) = this%cell_wcstor(node) + rratewc ! @@ -3522,7 +3549,7 @@ subroutine csub_bd(this, isuppress_output, model_budget) ! -- dummy variables class(GwfCsubType) :: this integer(I4B), intent(in) :: isuppress_output - type(BudgetType), intent(inout) :: model_budget !< model budget object + type(BudgetType), intent(inout) :: model_budget !< model budget object ! -- local real(DP) :: rin real(DP) :: rout @@ -3544,21 +3571,21 @@ subroutine csub_bd(this, isuppress_output, model_budget) isuppress_output, ' CSUB') end if call rate_accumulator(this%cell_wcstor, rin, rout) - call model_budget%addentry(rin, rout, delt, budtxt(4), & + call model_budget%addentry(rin, rout, delt, budtxt(4), & isuppress_output, ' CSUB') return end subroutine csub_bd - + !> @ brief Save model flows for package !! -!! Save cell-by-cell budget terms for the CSUB package. +!! Save cell-by-cell budget terms for the CSUB package. !! !< subroutine csub_save_model_flows(this, icbcfl, icbcun) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: icbcfl !< flag to output budget data - integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell file + integer(I4B), intent(in) :: icbcfl !< flag to output budget data + integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell file ! -- local variables character(len=1) :: cdatafmp = ' ' character(len=1) :: editdesc = ' ' @@ -3596,9 +3623,16 @@ subroutine csub_save_model_flows(this, icbcfl, icbcun) naux = 0 ! ! -- interbed elastic storage - call this%dis%record_srcdst_list_header(budtxt(2), this%name_model, & - this%name_model, this%name_model, this%packName, naux, & - this%auxname, ibinun, this%ninterbeds, this%iout) + call this%dis%record_srcdst_list_header(budtxt(2), & + this%name_model, & + this%name_model, & + this%name_model, & + this%packName, & + naux, & + this%auxname, & + ibinun, & + this%ninterbeds, & + this%iout) do ib = 1, this%ninterbeds q = this%storagee(ib) node = this%nodelist(ib) @@ -3607,9 +3641,16 @@ subroutine csub_save_model_flows(this, icbcfl, icbcun) end do ! ! -- interbed inelastic storage - call this%dis%record_srcdst_list_header(budtxt(3), this%name_model, & - this%name_model, this%name_model, this%packName, naux, & - this%auxname, ibinun, this%ninterbeds, this%iout) + call this%dis%record_srcdst_list_header(budtxt(3), & + this%name_model, & + this%name_model, & + this%name_model, & + this%packName, & + naux, & + this%auxname, & + ibinun, & + this%ninterbeds, & + this%iout) do ib = 1, this%ninterbeds q = this%storagei(ib) node = this%nodelist(ib) @@ -3630,15 +3671,15 @@ end subroutine csub_save_model_flows !> @ brief Save and print dependent values for package !! -!! Method saves cell-by-cell compaction and z-displacement terms. The method +!! Method saves cell-by-cell compaction and z-displacement terms. The method !! also calls the method to process observation output. !! !< subroutine csub_ot_dv(this, idvfl, idvprint) ! -- dummy variables - class(GwfCsubType) :: this - integer(I4B), intent(in) :: idvfl !< flag to save dependent variable data - integer(I4B), intent(in) :: idvprint !< flag to print dependent variable data + class(GwfCsubType) :: this + integer(I4B), intent(in) :: idvfl !< flag to save dependent variable data + integer(I4B), intent(in) :: idvprint !< flag to print dependent variable data ! -- local variables character(len=1) :: cdatafmp = ' ' character(len=1) :: editdesc = ' ' @@ -3657,7 +3698,7 @@ subroutine csub_ot_dv(this, idvfl, idvprint) real(DP) :: dinact ! -- formats character(len=*), parameter :: fmtnconv = & - "(/4x, 'DELAY INTERBED CELL HEADS IN ', i0, ' INTERBEDS IN', & + "(/4x, 'DELAY INTERBED CELL HEADS IN ', i0, ' INTERBEDS IN', & &' NON-CONVERTIBLE GWF CELLS WERE LESS THAN THE TOP OF THE INTERBED CELL')" ! ! -- Save compaction results @@ -3715,11 +3756,11 @@ subroutine csub_ot_dv(this, idvfl, idvprint) ! TO DO - ! -- disv or dis else - nlay = this%dis%nodesuser/ncpl + nlay = this%dis%nodesuser / ncpl do k = nlay - 1, 1, -1 do i = 1, ncpl - node = (k - 1)*ncpl + i - nodem = k*ncpl + i + node = (k - 1) * ncpl + i + nodem = k * ncpl + i this%buffusr(node) = this%buffusr(node) + this%buffusr(nodem) end do end do @@ -3882,8 +3923,8 @@ end subroutine csub_ot_dv subroutine csub_cg_calc_stress(this, nodes, hnew) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: nodes !< number of active model nodes - real(DP), dimension(nodes), intent(in) :: hnew !< current head + integer(I4B), intent(in) :: nodes !< number of active model nodes + real(DP), dimension(nodes), intent(in) :: hnew !< current head ! -- local variables integer(I4B) :: node integer(I4B) :: ii @@ -3928,9 +3969,9 @@ subroutine csub_cg_calc_stress(this, nodes, hnew) ! ! -- geostatic stress calculation if (hcell < top) then - gs = (top - hbar)*this%sgm(node) + (hbar - bot)*this%sgs(node) + gs = (top - hbar) * this%sgm(node) + (hbar - bot) * this%sgs(node) else - gs = thick*this%sgs(node) + gs = thick * this%sgs(node) end if ! ! -- cell contribution to geostatic stress @@ -3976,9 +4017,9 @@ subroutine csub_cg_calc_stress(this, nodes, hnew) else area_conn = this%dis%get_area(m) hwva = this%dis%con%hwva(iis) - va_scale = this%dis%con%hwva(iis)/this%dis%get_area(m) + va_scale = this%dis%con%hwva(iis) / this%dis%get_area(m) gs_conn = this%cg_gs(m) - gs = gs + (gs_conn*va_scale) + gs = gs + (gs_conn * va_scale) end if end if @@ -4144,13 +4185,13 @@ subroutine csub_nodelay_fc(this, ib, hcell, hcellold, rho1, rho2, rhs, & use TdisModule, only: delt ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in the cell - real(DP), intent(in) :: hcellold !< previous head in the cell - real(DP), intent(inout) :: rho1 !< current storage coefficient value using Sske - real(DP), intent(inout) :: rho2 !< current storage coefficient value based on Ssk - real(DP), intent(inout) :: rhs !< no-delay interbed contribution to the right-hand side - real(DP), intent(in), optional :: argtled !< optional reciprocal of the time step length + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in the cell + real(DP), intent(in) :: hcellold !< previous head in the cell + real(DP), intent(inout) :: rho1 !< current storage coefficient value using Sske + real(DP), intent(inout) :: rho2 !< current storage coefficient value based on Ssk + real(DP), intent(inout) :: rhs !< no-delay interbed contribution to the right-hand side + real(DP), intent(in), optional :: argtled !< optional reciprocal of the time step length ! -- local variables integer(I4B) :: node real(DP) :: tled @@ -4175,7 +4216,7 @@ subroutine csub_nodelay_fc(this, ib, hcell, hcellold, rho1, rho2, rhs, & if (present(argtled)) then tled = argtled else - tled = DONE/delt + tled = DONE / delt end if node = this%nodelist(ib) area = this%dis%get_area(node) @@ -4205,29 +4246,29 @@ subroutine csub_nodelay_fc(this, ib, hcell, hcellold, rho1, rho2, rhs, & ! current and previous head call this%csub_calc_sfacts(node, bot, znode, theta, es, es0, f) end if - sto_fac = tled*snnew*thick*f - sto_fac0 = tled*snold*thick*f + sto_fac = tled * snnew * thick * f + sto_fac0 = tled * snold * thick * f ! ! -- calculate rho1 and rho2 - rho1 = this%rci(ib)*sto_fac0 - rho2 = this%rci(ib)*sto_fac + rho1 = this%rci(ib) * sto_fac0 + rho2 = this%rci(ib) * sto_fac if (this%cg_es(node) > this%pcs(ib)) then this%iconvert(ib) = 1 - rho2 = this%ci(ib)*sto_fac + rho2 = this%ci(ib) * sto_fac end if ! ! -- calculate correction term - rcorr = rho2*(hcell - hbar) + rcorr = rho2 * (hcell - hbar) ! ! -- fill right-hand side if (this%ielastic(ib) /= 0) then - rhs = rho1*this%cg_es0(node) - & - rho2*(this%cg_gs(node) + bot) - & + rhs = rho1 * this%cg_es0(node) - & + rho2 * (this%cg_gs(node) + bot) - & rcorr else - rhs = -rho2*(this%cg_gs(node) + bot) + & - (this%pcs(ib)*(rho2 - rho1)) + & - (rho1*this%cg_es0(node)) - & + rhs = -rho2 * (this%cg_gs(node) + bot) + & + (this%pcs(ib) * (rho2 - rho1)) + & + (rho1 * this%cg_es0(node)) - & rcorr end if ! @@ -4253,12 +4294,12 @@ end subroutine csub_nodelay_fc subroutine csub_nodelay_calc_comp(this, ib, hcell, hcellold, comp, rho1, rho2) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head for the cell - real(DP), intent(in) :: hcellold !< previous head for the cell - real(DP), intent(inout) :: comp !< no-delay interbed compaction - real(DP), intent(inout) :: rho1 !< current storage coefficient based on Sske - real(DP), intent(inout) :: rho2 !< current storage coefficient based on Ssk + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head for the cell + real(DP), intent(in) :: hcellold !< previous head for the cell + real(DP), intent(inout) :: comp !< no-delay interbed compaction + real(DP), intent(inout) :: rho1 !< current storage coefficient based on Sske + real(DP), intent(inout) :: rho2 !< current storage coefficient based on Ssk ! -- local variables integer(I4B) :: node real(DP) :: es @@ -4279,9 +4320,9 @@ subroutine csub_nodelay_calc_comp(this, ib, hcell, hcellold, comp, rho1, rho2) ! ! -- calculate no-delay interbed compaction if (this%ielastic(ib) /= 0) then - comp = rho2*es - rho1*es0 + comp = rho2 * es - rho1 * es0 else - comp = -pcs*(rho2 - rho1) - (rho1*es0) + (rho2*es) + comp = -pcs * (rho2 - rho1) - (rho1 * es0) + (rho2 * es) end if ! ! -- return @@ -4299,8 +4340,8 @@ subroutine csub_set_initial_state(this, nodes, hnew) ! -- dummy variables class(GwfCsubType) :: this ! -- dummy variables - integer(I4B), intent(in) :: nodes !< number of active model nodes - real(DP), dimension(nodes), intent(in) :: hnew !< current heads + integer(I4B), intent(in) :: nodes !< number of active model nodes + real(DP), dimension(nodes), intent(in) :: hnew !< current heads ! -- local variables character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag @@ -4363,7 +4404,7 @@ subroutine csub_set_initial_state(this, nodes, hnew) ! ! -- delay bed initial states if (idelay /= 0) then - dzhalf = DHALF*this%dbdzini(1, idelay) + dzhalf = DHALF * this%dbdzini(1, idelay) ! ! -- fill delay bed head with aquifer head or offset from aquifer head ! heads need to be filled first since used to calculate @@ -4386,7 +4427,7 @@ subroutine csub_set_initial_state(this, nodes, hnew) zbot = this%dbz(n, idelay) - dzhalf ! -- adjust pcs to bottom of each delay bed cell ! not using csub_calc_adjes() since smoothing not required - dbpcs = pcs - (zbot - bot)*(this%sgs(node) - DONE) + dbpcs = pcs - (zbot - bot) * (this%sgs(node) - DONE) this%dbpcs(n, idelay) = dbpcs ! ! -- initialize effective stress for previous time step @@ -4420,14 +4461,14 @@ subroutine csub_set_initial_state(this, nodes, hnew) ! -- calculate znode and factor znode = this%csub_calc_znode(top, bot, hbar) fact = this%csub_calc_adjes(node, es, bot, znode) - fact = fact*(DONE + void) + fact = fact * (DONE + void) end if ! ! -- user-specified compression indices - multiply by dlog10es else fact = dlog10es end if - this%cg_ske_cr(node) = this%cg_ske_cr(node)*fact + this%cg_ske_cr(node) = this%cg_ske_cr(node) * fact ! ! -- write error message if negative compression indices if (fact <= DZERO) then @@ -4466,15 +4507,15 @@ subroutine csub_set_initial_state(this, nodes, hnew) ! -- calculate zone and factor znode = this%csub_calc_znode(top, bot, hbar) fact = this%csub_calc_adjes(node, es, bot, znode) - fact = fact*(DONE + void) + fact = fact * (DONE + void) end if ! ! -- user-specified compression indices - multiply by dlog10es else fact = dlog10es end if - this%ci(ib) = this%ci(ib)*fact - this%rci(ib) = this%rci(ib)*fact + this%ci(ib) = this%ci(ib) * fact + this%rci(ib) = this%rci(ib) * fact ! ! -- write error message if negative compression indices if (fact <= DZERO) then @@ -4644,15 +4685,15 @@ subroutine csub_set_initial_state(this, nodes, hnew) ! ! -- write the data do ib = 1, this%ninterbeds - fact = DONE/dlog10es + fact = DONE / dlog10es node = this%nodelist(ib) call this%dis%noder_to_string(node, cellid) ! ! -- write the columns call this%inputtab%add_term(ib) call this%inputtab%add_term(cellid) - call this%inputtab%add_term(this%ci(ib)*fact) - call this%inputtab%add_term(this%rci(ib)*fact) + call this%inputtab%add_term(this%ci(ib) * fact) + call this%inputtab%add_term(this%rci(ib) * fact) if (this%inamedbound /= 0) then call this%inputtab%add_term(this%boundname(ib)) end if @@ -4690,13 +4731,13 @@ end subroutine csub_set_initial_state subroutine csub_cg_fc(this, node, tled, area, hcell, hcellold, hcof, rhs) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: tled !< recripicol of the time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head - real(DP), intent(in) :: hcellold !< previous head - real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry - real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: tled !< recripicol of the time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head + real(DP), intent(in) :: hcellold !< previous head + real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry + real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -4727,19 +4768,19 @@ subroutine csub_cg_fc(this, node, tled, area, hcell, hcellold, hcof, rhs) ! ! -- storage coefficients call this%csub_cg_calc_sske(node, sske, hcell) - rho1 = sske*area*tthk*tled + rho1 = sske * area * tthk * tled ! ! -- update sk and ske - this%cg_ske(node) = sske*tthk*snold - this%cg_sk(node) = sske*tthk*snnew + this%cg_ske(node) = sske * tthk * snold + this%cg_sk(node) = sske * tthk * snnew ! ! -- calculate hcof and rhs term - hcof = -rho1*snnew - rhs = rho1*snold*this%cg_es0(node) - & - rho1*snnew*(this%cg_gs(node) + bot) + hcof = -rho1 * snnew + rhs = rho1 * snold * this%cg_es0(node) - & + rho1 * snnew * (this%cg_gs(node) + bot) ! ! -- calculate and apply the flow correction term - rhs = rhs - rho1*snnew*(hcell - hbar) + rhs = rhs - rho1 * snnew * (hcell - hbar) end if ! ! -- return @@ -4759,12 +4800,12 @@ end subroutine csub_cg_fc subroutine csub_cg_fn(this, node, tled, area, hcell, hcof, rhs) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: node !< node number - real(DP), intent(in) :: tled !< reciprocal of the time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry - real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry + integer(I4B), intent(in) :: node !< node number + real(DP), intent(in) :: tled !< reciprocal of the time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry + real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -4803,19 +4844,19 @@ subroutine csub_cg_fn(this, node, tled, area, hcell, hcof, rhs) ! ! -- storage coefficients call this%csub_cg_calc_sske(node, sske, hcell) - rho1 = sske*area*tthk*tled + rho1 = sske * area * tthk * tled ! ! -- calculate hcof term - hcof = rho1*snnew*(DONE - hbarderv) + & - rho1*(this%cg_gs(node) - hbar + bot)*satderv + hcof = rho1 * snnew * (DONE - hbarderv) + & + rho1 * (this%cg_gs(node) - hbar + bot) * satderv ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then - hcof = hcof - rho1*this%cg_es0(node)*satderv + hcof = hcof - rho1 * this%cg_es0(node) * satderv end if ! ! -- calculate rhs term - rhs = hcof*hcell + rhs = hcof * hcell end if ! ! -- return @@ -4834,13 +4875,13 @@ end subroutine csub_cg_fn subroutine csub_interbed_fc(this, ib, node, area, hcell, hcellold, hcof, rhs) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: hcof !< interbed A matrix entry - real(DP), intent(inout) :: rhs !< interbed right-hand side + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: hcof !< interbed A matrix entry + real(DP), intent(inout) :: rhs !< interbed right-hand side ! -- local variables real(DP) :: snnew real(DP) :: snold @@ -4901,10 +4942,10 @@ subroutine csub_interbed_fc(this, ib, node, area, hcell, hcellold, hcof, rhs) ! -- calculate delay interbed hcof and rhs call this%csub_delay_sln(ib, hcell) call this%csub_delay_fc(ib, hcof, rhs) - f = area*this%rnb(ib) + f = area * this%rnb(ib) end if - rhs = rhs*f - hcof = -hcof*f + rhs = rhs * f + hcof = -hcof * f end if ! ! -- return @@ -4925,12 +4966,12 @@ subroutine csub_interbed_fn(this, ib, node, hcell, hcellold, hcof, rhs) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: hcell !< current head in a cell - real(DP), intent(in) :: hcellold !< previous head in a cell - real(DP), intent(inout) :: hcof !< interbed A matrix entry - real(DP), intent(inout) :: rhs !< interbed right-hand side entry + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: hcell !< current head in a cell + real(DP), intent(in) :: hcellold !< previous head in a cell + real(DP), intent(inout) :: hcof !< interbed A matrix entry + real(DP), intent(inout) :: rhs !< interbed right-hand side entry ! -- local variables integer(I4B) :: idelay real(DP) :: hcofn @@ -4960,7 +5001,7 @@ subroutine csub_interbed_fn(this, ib, node, hcell, hcellold, hcof, rhs) ! ! -- skip inactive and constant head cells if (this%ibound(node) > 0) then - tled = DONE/delt + tled = DONE / delt tthk = this%thickini(ib) ! ! -- calculate cell saturation @@ -4985,18 +5026,18 @@ subroutine csub_interbed_fn(this, ib, node, hcell, hcellold, hcof, rhs) call this%csub_nodelay_fc(ib, hcell, hcellold, rho1, rho2, rhsn) ! ! -- calculate hcofn term - hcofn = rho2*(DONE - hbarderv)*snnew + & - rho2*(this%cg_gs(node) - hbar + bot)*satderv + hcofn = rho2 * (DONE - hbarderv) * snnew + & + rho2 * (this%cg_gs(node) - hbar + bot) * satderv if (this%ielastic(ib) == 0) then - hcofn = hcofn - rho2*this%pcs(ib)*satderv + hcofn = hcofn - rho2 * this%pcs(ib) * satderv end if ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then if (this%ielastic(ib) /= 0) then - hcofn = hcofn - rho1*this%cg_es0(node)*satderv + hcofn = hcofn - rho1 * this%cg_es0(node) * satderv else - hcofn = hcofn - rho1*(this%pcs(ib) - this%cg_es0(node))*satderv + hcofn = hcofn - rho1 * (this%pcs(ib) - this%cg_es0(node)) * satderv end if end if end if @@ -5016,9 +5057,9 @@ end subroutine csub_interbed_fn subroutine csub_cg_calc_sske(this, n, sske, hcell) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: n !< cell node number - real(DP), intent(inout) :: sske !< coarse grained Sske - real(DP), intent(in) :: hcell !< current head in cell + integer(I4B), intent(in) :: n !< cell node number + real(DP), intent(inout) :: sske !< coarse grained Sske + real(DP), intent(in) :: hcell !< current head in cell ! -- local variables real(DP) :: top real(DP) :: bot @@ -5059,7 +5100,7 @@ subroutine csub_cg_calc_sske(this, n, sske, hcell) ! current and previous head call this%csub_calc_sfacts(n, bot, znode, theta, es, es0, f) end if - sske = f*this%cg_ske_cr(n) + sske = f * this%cg_ske_cr(n) ! ! -- return return @@ -5075,10 +5116,10 @@ end subroutine csub_cg_calc_sske subroutine csub_cg_calc_comp(this, node, hcell, hcellold, comp) ! -- dummy variables class(GwfCsubType) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: comp !< coarse-grained compaction + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: comp !< coarse-grained compaction ! -- local variables real(DP) :: area real(DP) :: tled @@ -5093,7 +5134,7 @@ subroutine csub_cg_calc_comp(this, node, hcell, hcellold, comp) call this%csub_cg_fc(node, tled, area, hcell, hcellold, hcof, rhs) ! ! - calculate compaction - comp = hcof*hcell - rhs + comp = hcof * hcell - rhs ! ! -- return return @@ -5107,7 +5148,7 @@ end subroutine csub_cg_calc_comp subroutine csub_cg_update(this, node) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number + integer(I4B), intent(in) :: node !< cell node number ! -- local variables character(len=20) :: cellid real(DP) :: comp @@ -5155,13 +5196,13 @@ subroutine csub_cg_wcomp_fc(this, node, tled, area, hcell, hcellold, & hcof, rhs) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: tled !< reciprocal of the time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry - real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: tled !< reciprocal of the time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry + real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -5186,14 +5227,14 @@ subroutine csub_cg_wcomp_fc(this, node, tled, area, hcell, hcellold, & call this%csub_calc_sat(node, hcell, hcellold, snnew, snold) ! ! -- storage coefficients - wc0 = this%brg*area*tthk0*this%cg_theta0(node)*tled - wc = this%brg*area*tthk*this%cg_theta(node)*tled + wc0 = this%brg * area * tthk0 * this%cg_theta0(node) * tled + wc = this%brg * area * tthk * this%cg_theta(node) * tled ! ! -- calculate hcof term - hcof = -wc*snnew + hcof = -wc * snnew ! ! -- calculate rhs term - rhs = -wc0*snold*hcellold + rhs = -wc0 * snold * hcellold ! ! -- return return @@ -5212,13 +5253,13 @@ end subroutine csub_cg_wcomp_fc subroutine csub_cg_wcomp_fn(this, node, tled, area, hcell, hcellold, hcof, rhs) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: tled !< reciprocal of the time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry - real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: tled !< reciprocal of the time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: hcof !< coarse-grained A matrix entry + real(DP), intent(inout) :: rhs !< coarse-grained right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -5242,23 +5283,23 @@ subroutine csub_cg_wcomp_fn(this, node, tled, area, hcell, hcellold, hcof, rhs) satderv = this%csub_calc_sat_derivative(node, hcell) ! ! -- calculate water compressibility factor - f = this%brg*area*tled + f = this%brg * area * tled ! ! -- water compressibility coefficient - wc = f*tthk*this%cg_theta(node) + wc = f * tthk * this%cg_theta(node) ! ! -- calculate hcof term - hcof = -wc*hcell*satderv + hcof = -wc * hcell * satderv ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then tthk0 = this%cg_thick0(node) - wc0 = f*tthk0*this%cg_theta0(node) - hcof = hcof + wc*hcellold*satderv + wc0 = f * tthk0 * this%cg_theta0(node) + hcof = hcof + wc * hcellold * satderv end if ! ! -- calculate rhs term - rhs = hcof*hcell + rhs = hcof * hcell ! ! -- return return @@ -5278,14 +5319,14 @@ subroutine csub_nodelay_wcomp_fc(this, ib, node, tled, area, & hcell, hcellold, hcof, rhs) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: tled !< reciprocal of time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: hcof !< no-delay A matrix entry - real(DP), intent(inout) :: rhs !< no-delay right-hand side entry + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: tled !< reciprocal of time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: hcof !< no-delay A matrix entry + real(DP), intent(inout) :: rhs !< no-delay right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -5307,11 +5348,11 @@ subroutine csub_nodelay_wcomp_fc(this, ib, node, tled, area, & call this%csub_calc_sat(node, hcell, hcellold, snnew, snold) ! ! - f = this%brg*area*tled - wc0 = f*this%theta0(ib)*this%thick0(ib) - wc = f*this%theta(ib)*this%thick(ib) - hcof = -wc*snnew - rhs = -wc0*snold*hcellold + f = this%brg * area * tled + wc0 = f * this%theta0(ib) * this%thick0(ib) + wc = f * this%theta(ib) * this%thick(ib) + hcof = -wc * snnew + rhs = -wc0 * snold * hcellold ! ! -- return return @@ -5331,14 +5372,14 @@ subroutine csub_nodelay_wcomp_fn(this, ib, node, tled, area, & hcell, hcellold, hcof, rhs) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: tled !< reciprocal of time step length - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: hcof !< no-delay A matrix entry - real(DP), intent(inout) :: rhs !< no-delay right-hand side entry + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: tled !< reciprocal of time step length + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: hcof !< no-delay A matrix entry + real(DP), intent(inout) :: rhs !< no-delay right-hand side entry ! -- local variables real(DP) :: top real(DP) :: bot @@ -5356,25 +5397,25 @@ subroutine csub_nodelay_wcomp_fn(this, ib, node, tled, area, & bot = this%dis%bot(node) ! ! - f = this%brg*area*tled + f = this%brg * area * tled ! ! -- calculate saturation derivitive satderv = this%csub_calc_sat_derivative(node, hcell) ! ! -- calculate the current water compressibility factor - wc = f*this%theta(ib)*this%thick(ib) + wc = f * this%theta(ib) * this%thick(ib) ! ! -- calculate derivative term - hcof = -wc*hcell*satderv + hcof = -wc * hcell * satderv ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then - wc0 = f*this%theta0(ib)*this%thick0(ib) - hcof = hcof + wc0*hcellold*satderv + wc0 = f * this%theta0(ib) * this%thick0(ib) + hcof = hcof + wc0 * hcellold * satderv end if ! ! -- set rhs - rhs = hcof*hcell + rhs = hcof * hcell ! ! -- return return @@ -5389,11 +5430,11 @@ end subroutine csub_nodelay_wcomp_fn function csub_calc_void(this, theta) result(void) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - real(DP), intent(in) :: theta !< porosity + real(DP), intent(in) :: theta !< porosity ! -- local variables real(DP) :: void ! -- calculate void ratio - void = theta/(DONE - theta) + void = theta / (DONE - theta) ! ! -- return return @@ -5413,7 +5454,7 @@ function csub_calc_theta(this, void) result(theta) real(DP) :: theta ! ! -- calculate theta - theta = void/(DONE + void) + theta = void / (DONE + void) ! ! -- return return @@ -5428,7 +5469,7 @@ end function csub_calc_theta function csub_calc_interbed_thickness(this, ib) result(thick) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: ib !< interbed number ! -- local variables integer(I4B) :: idelay real(DP) :: thick @@ -5437,7 +5478,7 @@ function csub_calc_interbed_thickness(this, ib) result(thick) idelay = this%idelay(ib) thick = this%thick(ib) if (idelay /= 0) then - thick = thick*this%rnb(ib) + thick = thick * this%rnb(ib) end if ! ! -- return @@ -5457,9 +5498,9 @@ end function csub_calc_interbed_thickness function csub_calc_znode(this, top, bottom, zbar) result(znode) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - real(DP), intent(in) :: top !< top of cell - real(DP), intent(in) :: bottom !< bottom of cell - real(DP), intent(in) :: zbar !< corrected elevation + real(DP), intent(in) :: top !< top of cell + real(DP), intent(in) :: bottom !< bottom of cell + real(DP), intent(in) :: zbar !< corrected elevation ! -- local variables real(DP) :: znode real(DP) :: v @@ -5470,7 +5511,7 @@ function csub_calc_znode(this, top, bottom, zbar) result(znode) else v = zbar end if - znode = DHALF*(v + bottom) + znode = DHALF * (v + bottom) ! ! -- return return @@ -5487,15 +5528,15 @@ end function csub_calc_znode function csub_calc_adjes(this, node, es0, z0, z) result(es) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: es0 !< effective stress at elevation z0 - real(DP), intent(in) :: z0 !< elevation effective stress is calculate at - real(DP), intent(in) :: z !< elevation to calculate effective stress at + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: es0 !< effective stress at elevation z0 + real(DP), intent(in) :: z0 !< elevation effective stress is calculate at + real(DP), intent(in) :: z !< elevation to calculate effective stress at ! -- local variables real(DP) :: es ! ! -- adjust effective stress to vertical node position - es = es0 - (z - z0)*(this%sgs(node) - DONE) + es = es0 - (z - z0) * (this%sgs(node) - DONE) ! ! -- return return @@ -5511,7 +5552,7 @@ end function csub_calc_adjes subroutine csub_delay_head_check(this, ib) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: ib !< interbed number ! -- local variables integer(I4B) :: iviolate integer(I4B) :: idelay @@ -5531,7 +5572,7 @@ subroutine csub_delay_head_check(this, ib) idelaycells: do n = 1, this%ndelaycells z = this%dbz(n, idelay) h = this%dbh(n, idelay) - dzhalf = DHALF*this%dbdzini(1, idelay) + dzhalf = DHALF * this%dbdzini(1, idelay) ! ! -- non-convertible cell if (this%stoiconv(node) == 0) then @@ -5564,11 +5605,11 @@ end subroutine csub_delay_head_check subroutine csub_calc_sat(this, node, hcell, hcellold, snnew, snold) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: hcell !< current head - real(DP), intent(in) :: hcellold !< previous head - real(DP), intent(inout) :: snnew !< current saturation - real(DP), intent(inout) :: snold !< previous saturation + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: hcell !< current head + real(DP), intent(in) :: hcellold !< previous head + real(DP), intent(inout) :: snnew !< current saturation + real(DP), intent(inout) :: snold !< previous saturation ! -- local variables real(DP) :: top real(DP) :: bot @@ -5601,8 +5642,8 @@ end subroutine csub_calc_sat function csub_calc_sat_derivative(this, node, hcell) result(satderv) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: hcell !< current head + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: hcell !< current head ! -- local variables real(DP) :: satderv real(DP) :: top @@ -5632,13 +5673,13 @@ end function csub_calc_sat_derivative subroutine csub_calc_sfacts(this, node, bot, znode, theta, es, es0, fact) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - real(DP), intent(in) :: bot ! + integer(I4B), intent(in) :: node !< cell node number + real(DP), intent(in) :: bot ! real(DP), intent(in) :: znode - real(DP), intent(in) :: theta !< porosity - real(DP), intent(in) :: es !< current effective stress - real(DP), intent(in) :: es0 !< previous effective stress - real(DP), intent(inout) :: fact !< skeletal storage coefficient factor (1/((1+void)*bar(es))) + real(DP), intent(in) :: theta !< porosity + real(DP), intent(in) :: es !< current effective stress + real(DP), intent(in) :: es0 !< previous effective stress + real(DP), intent(inout) :: fact !< skeletal storage coefficient factor (1/((1+void)*bar(es))) ! -- local variables real(DP) :: esv real(DP) :: void @@ -5655,9 +5696,9 @@ subroutine csub_calc_sfacts(this, node, bot, znode, theta, es, es0, fact) ! -- calculate storage factors for the effective stress case void = this%csub_calc_void(theta) denom = this%csub_calc_adjes(node, esv, bot, znode) - denom = denom*(DONE + void) + denom = denom * (DONE + void) if (denom /= DZERO) then - fact = DONE/denom + fact = DONE / denom end if ! ! -- return @@ -5675,9 +5716,9 @@ end subroutine csub_calc_sfacts subroutine csub_adj_matprop(this, comp, thick, theta) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - real(DP), intent(in) :: comp !< compaction - real(DP), intent(inout) :: thick !< thickness - real(DP), intent(inout) :: theta !< porosity + real(DP), intent(in) :: comp !< compaction + real(DP), intent(inout) :: thick !< thickness + real(DP), intent(inout) :: theta !< porosity ! -- local variables real(DP) :: strain real(DP) :: void @@ -5687,10 +5728,10 @@ subroutine csub_adj_matprop(this, comp, thick, theta) void = this%csub_calc_void(theta) ! ! -- calculate strain - if (thick > DZERO) strain = -comp/thick + if (thick > DZERO) strain = -comp / thick ! ! -- update void ratio, theta, and thickness - void = void + strain*(DONE + void) + void = void + strain * (DONE + void) theta = this%csub_calc_theta(void) thick = thick - comp ! @@ -5708,9 +5749,9 @@ end subroutine csub_adj_matprop subroutine csub_delay_sln(this, ib, hcell, update) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in a cell - logical, intent(in), optional :: update !< optional logical variable indicating + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in a cell + logical, intent(in), optional :: update !< optional logical variable indicating !! if the maximum head change variable !! in a delay bed should be updated ! -- local variables @@ -5722,7 +5763,7 @@ subroutine csub_delay_sln(this, ib, hcell, update) real(DP) :: dh real(DP) :: dhmax real(DP) :: dhmax0 - real(DP), parameter :: dclose = DHUNDRED*DPREC + real(DP), parameter :: dclose = DHUNDRED * DPREC ! ! -- initialize variables if (present(update)) then @@ -5751,9 +5792,9 @@ subroutine csub_delay_sln(this, ib, hcell, update) call this%csub_delay_assemble(ib, hcell) ! ! -- solve for head change in delay interbed cells - call csub_delay_solve(this%ndelaycells, & - this%dbal, this%dbad, this%dbau, & - this%dbrhs, this%dbdh, this%dbaw) + call ims_misc_thomas(this%ndelaycells, & + this%dbal, this%dbad, this%dbau, & + this%dbrhs, this%dbdh, this%dbaw) ! ! -- calculate maximum head change and update delay bed heads dhmax = DZERO @@ -5804,7 +5845,7 @@ end subroutine csub_delay_sln subroutine csub_delay_init_zcell(this, ib) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: ib !< interbed number ! -- local variables integer(I4B) :: n integer(I4B) :: node @@ -5830,8 +5871,8 @@ subroutine csub_delay_init_zcell(this, ib) ! -- calculate znode based on assumption that the delay bed bottom ! is equal to the cell bottom znode = this%csub_calc_znode(top, bot, hbar) - dz = DHALF*this%dbdzini(1, idelay) - dzz = DHALF*b + dz = DHALF * this%dbdzini(1, idelay) + dzz = DHALF * b z = znode + dzz zr = dzz ! @@ -5865,8 +5906,8 @@ end subroutine csub_delay_init_zcell subroutine csub_delay_calc_stress(this, ib, hcell) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in a cell + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in a cell ! -- local variables integer(I4B) :: n integer(I4B) :: idelay @@ -5891,7 +5932,7 @@ subroutine csub_delay_calc_stress(this, ib, hcell) sigma = this%cg_gs(node) topaq = this%dis%top(node) botaq = this%dis%bot(node) - dzhalf = DHALF*this%dbdzini(1, idelay) + dzhalf = DHALF * this%dbdzini(1, idelay) top = this%dbz(1, idelay) + dzhalf ! ! -- calculate corrected head (hbar) @@ -5901,9 +5942,9 @@ subroutine csub_delay_calc_stress(this, ib, hcell) sgm = this%sgm(node) sgs = this%sgs(node) if (hcell < top) then - sadd = ((top - hbar)*sgm) + ((hbar - botaq)*sgs) + sadd = ((top - hbar) * sgm) + ((hbar - botaq) * sgs) else - sadd = (top - botaq)*sgs + sadd = (top - botaq) * sgs end if sigma = sigma - sadd ! @@ -5921,9 +5962,9 @@ subroutine csub_delay_calc_stress(this, ib, hcell) ! ! -- geostatic stress calculation if (h < top) then - sadd = ((top - hbar)*sgm) + ((hbar - bot)*sgs) + sadd = ((top - hbar) * sgm) + ((hbar - bot) * sgs) else - sadd = (top - bot)*sgs + sadd = (top - bot) * sgs end if sigma = sigma + sadd phead = hbar - bot @@ -5948,11 +5989,11 @@ end subroutine csub_delay_calc_stress subroutine csub_delay_calc_ssksske(this, ib, n, hcell, ssk, sske) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: n !< delay interbed cell number - real(DP), intent(in) :: hcell !< current head in a cell - real(DP), intent(inout) :: ssk !< delay interbed skeletal specific storage - real(DP), intent(inout) :: sske !< delay interbed elastic skeletal specific storage + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: n !< delay interbed cell number + real(DP), intent(in) :: hcell !< current head in a cell + real(DP), intent(inout) :: ssk !< delay interbed skeletal specific storage + real(DP), intent(inout) :: sske !< delay interbed elastic skeletal specific storage ! -- local variables integer(I4B) :: idelay integer(I4B) :: ielastic @@ -6004,7 +6045,7 @@ subroutine csub_delay_calc_ssksske(this, ib, n, hcell, ssk, sske) ! ! -- set variables for delay interbed zcell calulations zcenter = zcell + this%dbrelz(n, idelay) - dzhalf = DHALF*this%dbdzini(1, idelay) + dzhalf = DHALF * this%dbdzini(1, idelay) top = zcenter + dzhalf bot = zcenter - dzhalf h = this%dbh(n, idelay) @@ -6030,12 +6071,12 @@ subroutine csub_delay_calc_ssksske(this, ib, n, hcell, ssk, sske) call this%csub_calc_sfacts(node, zbot, znode, theta, es, es0, f) end if this%idbconvert(n, idelay) = 0 - sske = f*this%rci(ib) - ssk = f*this%rci(ib) + sske = f * this%rci(ib) + ssk = f * this%rci(ib) if (ielastic == 0) then if (this%dbes(n, idelay) > this%dbpcs(n, idelay)) then this%idbconvert(n, idelay) = 1 - ssk = f*this%ci(ib) + ssk = f * this%ci(ib) end if end if ! @@ -6053,8 +6094,8 @@ end subroutine csub_delay_calc_ssksske subroutine csub_delay_assemble(this, ib, hcell) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in a cell + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in a cell ! -- local variables integer(I4B) :: n real(DP) :: aii @@ -6095,13 +6136,13 @@ subroutine csub_delay_assemble_fc(this, ib, n, hcell, aii, au, al, r) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: n !< delay interbed cell number - real(DP), intent(in) :: hcell !< current head in a cell - real(DP), intent(inout) :: aii !< diagonal in the A matrix - real(DP), intent(inout) :: au !< upper term in the A matrix - real(DP), intent(inout) :: al !< lower term in the A matrix - real(DP), intent(inout) :: r !< right-hand side term + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: n !< delay interbed cell number + real(DP), intent(in) :: hcell !< current head in a cell + real(DP), intent(inout) :: aii !< diagonal in the A matrix + real(DP), intent(inout) :: au !< upper term in the A matrix + real(DP), intent(inout) :: al !< lower term in the A matrix + real(DP), intent(inout) :: r !< right-hand side term ! -- local variables integer(I4B) :: node integer(I4B) :: idelay @@ -6145,11 +6186,11 @@ subroutine csub_delay_assemble_fc(this, ib, n, hcell, aii, au, al, r) ielastic = this%ielastic(ib) node = this%nodelist(ib) dzini = this%dbdzini(1, idelay) - dzhalf = DHALF*dzini - tled = DONE/delt - c = this%kv(ib)/dzini - c2 = DTWO*c - c3 = DTHREE*c + dzhalf = DHALF * dzini + tled = DONE / delt + c = this%kv(ib) / dzini + c2 = DTWO * c + c3 = DTHREE * c ! ! -- add qdb terms aii = aii - c2 @@ -6157,7 +6198,7 @@ subroutine csub_delay_assemble_fc(this, ib, n, hcell, aii, au, al, r) ! -- top or bottom cell if (n == 1 .or. n == this%ndelaycells) then aii = aii - c - r = r - c2*hcell + r = r - c2 * hcell end if ! ! -- lower qdb term @@ -6191,28 +6232,28 @@ subroutine csub_delay_assemble_fc(this, ib, n, hcell, aii, au, al, r) call this%csub_delay_calc_ssksske(ib, n, hcell, ssk, sske) ! ! -- calculate and add storage terms - smult = dzini*tled + smult = dzini * tled gs = this%dbgeo(n, idelay) es0 = this%dbes0(n, idelay) pcs = this%dbpcs(n, idelay) - aii = aii - smult*dsn*ssk + aii = aii - smult * dsn * ssk if (ielastic /= 0) then - r = r - smult* & - (dsn*ssk*(gs + zbot) - dsn0*sske*es0) + r = r - smult * & + (dsn * ssk * (gs + zbot) - dsn0 * sske * es0) else - r = r - smult* & - (dsn*ssk*(gs + zbot - pcs) + dsn0*sske*(pcs - es0)) + r = r - smult * & + (dsn * ssk * (gs + zbot - pcs) + dsn0 * sske * (pcs - es0)) end if ! ! -- add storage correction term - r = r + smult*dsn*ssk*(h - hbar) + r = r + smult * dsn * ssk * (h - hbar) ! ! -- add water compressibility terms - wcf = this%brg*tled - wc = dz*wcf*theta - wc0 = dz0*wcf*theta0 - aii = aii - dsn*wc - r = r - dsn0*wc0*h0 + wcf = this%brg * tled + wc = dz * wcf * theta + wc0 = dz0 * wcf * theta0 + aii = aii - dsn * wc + r = r - dsn0 * wc0 * h0 ! ! -- return return @@ -6230,13 +6271,13 @@ subroutine csub_delay_assemble_fn(this, ib, n, hcell, aii, au, al, r) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: n !< delay interbed cell number - real(DP), intent(in) :: hcell !< current head in a cell - real(DP), intent(inout) :: aii !< diagonal in the A matrix - real(DP), intent(inout) :: au !< upper term in the A matrix - real(DP), intent(inout) :: al !< lower term in the A matrix - real(DP), intent(inout) :: r !< right-hand side term + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: n !< delay interbed cell number + real(DP), intent(in) :: hcell !< current head in a cell + real(DP), intent(inout) :: aii !< diagonal in the A matrix + real(DP), intent(inout) :: au !< upper term in the A matrix + real(DP), intent(inout) :: al !< lower term in the A matrix + real(DP), intent(inout) :: r !< right-hand side term ! -- local variables integer(I4B) :: node integer(I4B) :: idelay @@ -6286,11 +6327,11 @@ subroutine csub_delay_assemble_fn(this, ib, n, hcell, aii, au, al, r) ielastic = this%ielastic(ib) node = this%nodelist(ib) dzini = this%dbdzini(1, idelay) - dzhalf = DHALF*dzini - tled = DONE/delt - c = this%kv(ib)/dzini - c2 = DTWO*c - c3 = DTHREE*c + dzhalf = DHALF * dzini + tled = DONE / delt + c = this%kv(ib) / dzini + c2 = DTWO * c + c3 = DTHREE * c ! ! -- add qdb terms aii = aii - c2 @@ -6298,7 +6339,7 @@ subroutine csub_delay_assemble_fn(this, ib, n, hcell, aii, au, al, r) ! -- top or bottom cell if (n == 1 .or. n == this%ndelaycells) then aii = aii - c - r = r - c2*hcell + r = r - c2 * hcell end if ! ! -- lower qdb term @@ -6338,97 +6379,55 @@ subroutine csub_delay_assemble_fn(this, ib, n, hcell, aii, au, al, r) call this%csub_delay_calc_ssksske(ib, n, hcell, ssk, sske) ! ! -- calculate storage terms - smult = dzini*tled + smult = dzini * tled gs = this%dbgeo(n, idelay) es0 = this%dbes0(n, idelay) pcs = this%dbpcs(n, idelay) if (ielastic /= 0) then - qsto = smult*(dsn*ssk*(gs - hbar + zbot) - dsn0*sske*es0) - stoderv = -smult*dsn*ssk*hbarderv + & - smult*ssk*(gs - hbar + zbot)*dsnderv + qsto = smult * (dsn * ssk * (gs - hbar + zbot) - dsn0 * sske * es0) + stoderv = -smult * dsn * ssk * hbarderv + & + smult * ssk * (gs - hbar + zbot) * dsnderv else - qsto = smult*(dsn*ssk*(gs - hbar + zbot - pcs) + & - dsn0*sske*(pcs - es0)) - stoderv = -smult*dsn*ssk*hbarderv + & - smult*ssk*(gs - hbar + zbot - pcs)*dsnderv + qsto = smult * (dsn * ssk * (gs - hbar + zbot - pcs) + & + dsn0 * sske * (pcs - es0)) + stoderv = -smult * dsn * ssk * hbarderv + & + smult * ssk * (gs - hbar + zbot - pcs) * dsnderv end if ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then if (ielastic /= 0) then - stoderv = stoderv - smult*sske*es0*dsnderv + stoderv = stoderv - smult * sske * es0 * dsnderv else - stoderv = stoderv + smult*sske*(pcs - es0)*dsnderv + stoderv = stoderv + smult * sske * (pcs - es0) * dsnderv end if end if ! ! -- add newton-raphson storage terms aii = aii + stoderv - r = r - qsto + stoderv*h + r = r - qsto + stoderv * h ! ! -- add water compressibility terms - wcf = this%brg*tled - wc = dz*wcf*theta - wc0 = dz0*wcf*theta0 - qwc = dsn0*wc0*h0 - dsn*wc*h - wcderv = -dsn*wc - wc*h*dsnderv + wcf = this%brg * tled + wc = dz * wcf * theta + wc0 = dz0 * wcf * theta0 + qwc = dsn0 * wc0 * h0 - dsn * wc * h + wcderv = -dsn * wc - wc * h * dsnderv ! ! -- Add additional term if using lagged effective stress if (this%ieslag /= 0) then - wcderv = wcderv + wc0*h0*dsnderv + wcderv = wcderv + wc0 * h0 * dsnderv end if ! ! -- add newton-raphson water compressibility terms aii = aii + wcderv - r = r - qwc + wcderv*h + r = r - qwc + wcderv * h ! ! -- return return end subroutine csub_delay_assemble_fn - !> @brief Delay interbed linear solution - !! - !! Method to solve the tridiagonal linear equations for a delay interbed - !! using the Thomas algorithm. - !! - !< - subroutine csub_delay_solve(n, tl, td, tu, b, x, w) - ! -- dummy variables - integer(I4B), intent(in) :: n !< number of matrix rows - real(DP), dimension(n), intent(in) :: tl !< lower matrix terms - real(DP), dimension(n), intent(in) :: td !< diagonal matrix terms - real(DP), dimension(n), intent(in) :: tu !< upper matrix terms - real(DP), dimension(n), intent(in) :: b !< right-hand side vector - real(DP), dimension(n), intent(inout) :: x !< solution vectot - real(DP), dimension(n), intent(inout) :: w !< work vector - ! -- local variables - integer(I4B) :: j - real(DP) :: bet - real(DP) :: beti - ! - ! -- initialize variables - w(1) = DZERO - bet = td(1) - beti = DONE/bet - x(1) = b(1)*beti - ! - ! -- decomposition and forward substitution - do j = 2, n - w(j) = tu(j - 1)*beti - bet = td(j) - tl(j)*w(j) - beti = DONE/bet - x(j) = (b(j) - tl(j)*x(j - 1))*beti - end do - ! - ! -- backsubstitution - do j = n - 1, 1, -1 - x(j) = x(j) - w(j + 1)*x(j + 1) - end do - ! -- return - return - end subroutine csub_delay_solve - !> @brief Calculate delay interbed saturation !! !! Method to calculate the saturation in a delay interbed cell. @@ -6441,13 +6440,13 @@ subroutine csub_delay_calc_sat(this, node, idelay, n, hcell, hcellold, & snnew, snold) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - integer(I4B), intent(in) :: idelay !< delay interbed number - integer(I4B), intent(in) :: n !< delay interbed cell number - real(DP), intent(in) :: hcell !< current head in delay interbed cell n - real(DP), intent(in) :: hcellold !< previous head in delay interbed cell n - real(DP), intent(inout) :: snnew !< current saturation in delay interbed cell n - real(DP), intent(inout) :: snold !< previous saturation in delay interbed cell n + integer(I4B), intent(in) :: node !< cell node number + integer(I4B), intent(in) :: idelay !< delay interbed number + integer(I4B), intent(in) :: n !< delay interbed cell number + real(DP), intent(in) :: hcell !< current head in delay interbed cell n + real(DP), intent(in) :: hcellold !< previous head in delay interbed cell n + real(DP), intent(inout) :: snnew !< current saturation in delay interbed cell n + real(DP), intent(inout) :: snold !< previous saturation in delay interbed cell n ! -- local variables real(DP) :: dzhalf real(DP) :: top @@ -6455,7 +6454,7 @@ subroutine csub_delay_calc_sat(this, node, idelay, n, hcell, hcellold, & ! ! -- calculate delay interbed cell saturation if (this%stoiconv(node) /= 0) then - dzhalf = DHALF*this%dbdzini(n, idelay) + dzhalf = DHALF * this%dbdzini(n, idelay) top = this%dbz(n, idelay) + dzhalf bot = this%dbz(n, idelay) - dzhalf snnew = sQuadraticSaturation(top, bot, hcell, this%satomega) @@ -6483,10 +6482,10 @@ function csub_delay_calc_sat_derivative(this, node, idelay, n, hcell) & result(satderv) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: node !< cell node number - integer(I4B), intent(in) :: idelay !< delay interbed number - integer(I4B), intent(in) :: n !< delay interbed cell number - real(DP), intent(in) :: hcell !< current head in delay interbed cell n + integer(I4B), intent(in) :: node !< cell node number + integer(I4B), intent(in) :: idelay !< delay interbed number + integer(I4B), intent(in) :: n !< delay interbed cell number + real(DP), intent(in) :: hcell !< current head in delay interbed cell n ! -- local variables real(DP) :: satderv real(DP) :: dzhalf @@ -6494,7 +6493,7 @@ function csub_delay_calc_sat_derivative(this, node, idelay, n, hcell) & real(DP) :: bot ! ------------------------------------------------------------------------------ if (this%stoiconv(node) /= 0) then - dzhalf = DHALF*this%dbdzini(n, idelay) + dzhalf = DHALF * this%dbdzini(n, idelay) top = this%dbz(n, idelay) + dzhalf bot = this%dbz(n, idelay) - dzhalf satderv = sQuadraticSaturationDerivative(top, bot, hcell, this%satomega) @@ -6517,10 +6516,10 @@ end function csub_delay_calc_sat_derivative subroutine csub_delay_calc_dstor(this, ib, hcell, stoe, stoi) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(inout) :: stoe !< elastic storage change - real(DP), intent(inout) :: stoi !< inelastic storage change + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(inout) :: stoe !< elastic storage change + real(DP), intent(inout) :: stoi !< inelastic storage change ! -- local variables integer(I4B) :: idelay integer(I4B) :: ielastic @@ -6554,7 +6553,7 @@ subroutine csub_delay_calc_dstor(this, ib, hcell, stoe, stoi) ! if (this%thickini(ib) > DZERO) then fmult = this%dbdzini(1, idelay) - dzhalf = DHALF*this%dbdzini(1, idelay) + dzhalf = DHALF * this%dbdzini(1, idelay) do n = 1, this%ndelaycells call this%csub_delay_calc_ssksske(ib, n, hcell, ssk, sske) z = this%dbz(n, idelay) @@ -6564,26 +6563,26 @@ subroutine csub_delay_calc_dstor(this, ib, hcell, stoe, stoi) call this%csub_delay_calc_sat(node, idelay, n, h, h0, dsn, dsn0) hbar = sQuadratic0sp(h, zbot, this%satomega) if (ielastic /= 0) then - v1 = dsn*ssk*(this%dbgeo(n, idelay) - hbar + zbot) - & - dsn0*sske*this%dbes0(n, idelay) + v1 = dsn * ssk * (this%dbgeo(n, idelay) - hbar + zbot) - & + dsn0 * sske * this%dbes0(n, idelay) v2 = DZERO else - v1 = dsn*ssk*(this%dbgeo(n, idelay) - hbar + zbot - & - this%dbpcs(n, idelay)) - v2 = dsn0*sske*(this%dbpcs(n, idelay) - this%dbes0(n, idelay)) + v1 = dsn * ssk * (this%dbgeo(n, idelay) - hbar + zbot - & + this%dbpcs(n, idelay)) + v2 = dsn0 * sske * (this%dbpcs(n, idelay) - this%dbes0(n, idelay)) end if ! ! -- calculate inelastic and elastic storage components if (this%idbconvert(n, idelay) /= 0) then - stoi = stoi + v1*fmult - stoe = stoe + v2*fmult + stoi = stoi + v1 * fmult + stoe = stoe + v2 * fmult else - stoe = stoe + (v1 + v2)*fmult + stoe = stoe + (v1 + v2) * fmult end if ! ! calculate inelastic and elastic storativity - ske = ske + sske*fmult - sk = sk + ssk*fmult + ske = ske + sske * fmult + sk = sk + ssk * fmult end do end if ! @@ -6607,8 +6606,8 @@ subroutine csub_delay_calc_wcomp(this, ib, dwc) use TdisModule, only: delt ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(inout) :: dwc !< water compressibility change + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(inout) :: dwc !< water compressibility change ! -- local variables integer(I4B) :: idelay integer(I4B) :: node @@ -6631,17 +6630,17 @@ subroutine csub_delay_calc_wcomp(this, ib, dwc) if (this%thickini(ib) > DZERO) then idelay = this%idelay(ib) node = this%nodelist(ib) - tled = DONE/delt + tled = DONE / delt do n = 1, this%ndelaycells h = this%dbh(n, idelay) h0 = this%dbh0(n, idelay) dz = this%dbdz(n, idelay) dz0 = this%dbdz0(n, idelay) call this%csub_delay_calc_sat(node, idelay, n, h, h0, dsn, dsn0) - wc = dz*this%brg*this%dbtheta(n, idelay) - wc0 = dz0*this%brg*this%dbtheta0(n, idelay) - v = dsn0*wc0*h0 - dsn*wc*h - dwc = dwc + v*tled + wc = dz * this%brg * this%dbtheta(n, idelay) + wc0 = dz0 * this%brg * this%dbtheta0(n, idelay) + v = dsn0 * wc0 * h0 - dsn * wc * h + dwc = dwc + v * tled end do end if ! @@ -6661,12 +6660,12 @@ end subroutine csub_delay_calc_wcomp subroutine csub_delay_calc_comp(this, ib, hcell, hcellold, comp, compi, compe) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(in) :: hcell !< current head in cell - real(DP), intent(in) :: hcellold !< previous head in cell - real(DP), intent(inout) :: comp !< compaction in delay interbed - real(DP), intent(inout) :: compi !< inelastic compaction in delay interbed - real(DP), intent(inout) :: compe !< elastic compaction in delay interbed + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(in) :: hcell !< current head in cell + real(DP), intent(in) :: hcellold !< previous head in cell + real(DP), intent(inout) :: comp !< compaction in delay interbed + real(DP), intent(inout) :: compi !< inelastic compaction in delay interbed + real(DP), intent(inout) :: compe !< elastic compaction in delay interbed ! -- local variables integer(I4B) :: idelay integer(I4B) :: ielastic @@ -6705,32 +6704,32 @@ subroutine csub_delay_calc_comp(this, ib, hcell, hcellold, comp, compi, compe) call this%csub_delay_calc_sat(node, idelay, n, h, h0, dsn, dsn0) call this%csub_delay_calc_ssksske(ib, n, hcell, ssk, sske) if (ielastic /= 0) then - v1 = dsn*ssk*this%dbes(n, idelay) - sske*this%dbes0(n, idelay) + v1 = dsn * ssk * this%dbes(n, idelay) - sske * this%dbes0(n, idelay) v2 = DZERO else - v1 = dsn*ssk*(this%dbes(n, idelay) - this%dbpcs(n, idelay)) - v2 = dsn0*sske*(this%dbpcs(n, idelay) - this%dbes0(n, idelay)) + v1 = dsn * ssk * (this%dbes(n, idelay) - this%dbpcs(n, idelay)) + v2 = dsn0 * sske * (this%dbpcs(n, idelay) - this%dbes0(n, idelay)) end if - v = (v1 + v2)*fmult + v = (v1 + v2) * fmult comp = comp + v ! ! -- save compaction data - this%dbcomp(n, idelay) = v*snnew + this%dbcomp(n, idelay) = v * snnew ! ! -- calculate inelastic and elastic storage components if (this%idbconvert(n, idelay) /= 0) then - compi = compi + v1*fmult - compe = compe + v2*fmult + compi = compi + v1 * fmult + compe = compe + v2 * fmult else - compe = compe + (v1 + v2)*fmult + compe = compe + (v1 + v2) * fmult end if end do end if ! ! -- fill compaction - comp = comp*this%rnb(ib) - compi = compi*this%rnb(ib) - compe = compe*this%rnb(ib) + comp = comp * this%rnb(ib) + compi = compi * this%rnb(ib) + compe = compe * this%rnb(ib) ! ! -- return return @@ -6744,7 +6743,7 @@ end subroutine csub_delay_calc_comp subroutine csub_delay_update(this, ib) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: ib !< interbed number ! -- local variables integer(I4B) :: idelay integer(I4B) :: n @@ -6768,7 +6767,7 @@ subroutine csub_delay_update(this, ib) ! ! -- scale compaction by rnb to get the compaction for ! the interbed system (as opposed to the full system) - comp = comp/this%rnb(ib) + comp = comp / this%rnb(ib) ! ! -- update thickness and theta if (ABS(comp) > DZERO) then @@ -6790,19 +6789,19 @@ subroutine csub_delay_update(this, ib) this%dbdz(n, idelay) = thick this%dbtheta(n, idelay) = theta tthick = tthick + thick - wtheta = wtheta + thick*theta + wtheta = wtheta + thick * theta else thick = this%dbdz(n, idelay) theta = this%dbtheta(n, idelay) tthick = tthick + thick - wtheta = wtheta + thick*theta + wtheta = wtheta + thick * theta end if end do ! ! -- calculate thickness weighted theta and save thickness and weighted ! theta values for delay interbed if (tthick > DZERO) then - wtheta = wtheta/tthick + wtheta = wtheta / tthick else tthick = DZERO wtheta = DZERO @@ -6827,9 +6826,9 @@ end subroutine csub_delay_update subroutine csub_delay_fc(this, ib, hcof, rhs) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - real(DP), intent(inout) :: hcof !< head dependent coefficient - real(DP), intent(inout) :: rhs !< right-hand side + integer(I4B), intent(in) :: ib !< interbed number + real(DP), intent(inout) :: hcof !< head dependent coefficient + real(DP), intent(inout) :: rhs !< right-hand side ! -- local variables integer(I4B) :: idelay real(DP) :: c1 @@ -6841,11 +6840,11 @@ subroutine csub_delay_fc(this, ib, hcof, rhs) rhs = DZERO if (this%thickini(ib) > DZERO) then ! -- calculate terms for gwf matrix - c1 = DTWO*this%kv(ib)/this%dbdzini(1, idelay) - rhs = -c1*this%dbh(1, idelay) - c2 = DTWO* & - this%kv(ib)/this%dbdzini(this%ndelaycells, idelay) - rhs = rhs - c2*this%dbh(this%ndelaycells, idelay) + c1 = DTWO * this%kv(ib) / this%dbdzini(1, idelay) + rhs = -c1 * this%dbh(1, idelay) + c2 = DTWO * & + this%kv(ib) / this%dbdzini(this%ndelaycells, idelay) + rhs = rhs - c2 * this%dbh(this%ndelaycells, idelay) hcof = c1 + c2 end if ! @@ -6863,9 +6862,9 @@ end subroutine csub_delay_fc function csub_calc_delay_flow(this, ib, n, hcell) result(q) ! -- dummy variables class(GwfCsubType), intent(inout) :: this - integer(I4B), intent(in) :: ib !< interbed number - integer(I4B), intent(in) :: n !< delay interbed cell - real(DP), intent(in) :: hcell !< current head in cell + integer(I4B), intent(in) :: ib !< interbed number + integer(I4B), intent(in) :: n !< delay interbed cell + real(DP), intent(in) :: hcell !< current head in cell ! -- local variables integer(I4B) :: idelay real(DP) :: q @@ -6873,8 +6872,8 @@ function csub_calc_delay_flow(this, ib, n, hcell) result(q) ! ! -- calculate flow between delay interbed and GWF idelay = this%idelay(ib) - c = DTWO*this%kv(ib)/this%dbdzini(n, idelay) - q = c*(hcell - this%dbh(n, idelay)) + c = DTWO * this%kv(ib) / this%dbdzini(n, idelay) + q = c * (hcell - this%dbh(n, idelay)) ! ! -- return return @@ -7154,8 +7153,8 @@ subroutine csub_bd_obs(this) case ('DELAY-HEAD', 'DELAY-PRECONSTRESS', & 'DELAY-GSTRESS', 'DELAY-ESTRESS') if (n > this%ndelaycells) then - r = real(n - 1, DP)/real(this%ndelaycells, DP) - idelay = int(floor(r)) + 1 + r = real(n - 1, DP) / real(this%ndelaycells, DP) + idelay = int(floor(r)) + 1 ncol = n - int(floor(r)) * this%ndelaycells else idelay = 1 @@ -7212,12 +7211,12 @@ subroutine csub_bd_obs(this) ! ! -- add the coarse component if (j == 1) then - f = this%cg_thick(n)/this%cell_thick(n) - v = f*this%cg_theta(n) + f = this%cg_thick(n) / this%cell_thick(n) + v = f * this%cg_theta(n) else node = this%nodelist(n) - f = this%csub_calc_interbed_thickness(n)/this%cell_thick(node) - v = f*this%theta(n) + f = this%csub_calc_interbed_thickness(n) / this%cell_thick(node) + v = f * this%theta(n) end if case ('GSTRESS-CELL') v = this%cg_gs(n) @@ -7257,7 +7256,7 @@ subroutine csub_bd_obs(this) idelay = this%idelay(n) v = this%thick(n) if (idelay /= 0) then - v = v*this%rnb(n) + v = v * this%rnb(n) end if case ('COARSE-THICKNESS') v = this%cg_thick(n) @@ -7266,7 +7265,7 @@ subroutine csub_bd_obs(this) case ('DELAY-COMPACTION', 'DELAY-THICKNESS', & 'DELAY-THETA') if (n > this%ndelaycells) then - r = real(n, DP)/real(this%ndelaycells, DP) + r = real(n, DP) / real(this%ndelaycells, DP) idelay = int(floor(r)) + 1 ncol = mod(n, this%ndelaycells) else @@ -7380,7 +7379,7 @@ subroutine csub_rp_obs(this) n = obsrv%NodeNumber idelay = this%idelay(n) if (idelay /= 0) then - j = (idelay - 1)*this%ndelaycells + 1 + j = (idelay - 1) * this%ndelaycells + 1 n2 = obsrv%NodeNumber2 if (n2 < 1 .or. n2 > this%ndelaycells) then write (errmsg, '(a,2(1x,a),1x,i0,1x,a,i0,a)') & @@ -7389,7 +7388,7 @@ subroutine csub_rp_obs(this) '(specified value is ', n2, ').' call store_error(errmsg) else - j = (idelay - 1)*this%ndelaycells + n2 + j = (idelay - 1) * this%ndelaycells + n2 end if obsrv%BndFound = .true. call obsrv%AddObsIndex(j) @@ -7427,7 +7426,8 @@ subroutine csub_rp_obs(this) j = obsrv%NodeNumber if (j < 1 .or. j > this%ninterbeds) then write (errmsg, '(a,2(1x,a),1x,i0,1x,a,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), 'interbed cell must be greater ', & + trim(adjustl(obsrv%ObsTypeId)), & + 'interbed cell must be greater ', & 'than 0 and less than or equal to', this%ninterbeds, & '(specified value is ', j, ').' call store_error(errmsg) @@ -7488,10 +7488,10 @@ end subroutine csub_rp_obs !< subroutine csub_process_obsID(obsrv, dis, inunitobs, iout) ! -- dummy variables - type(ObserveType), intent(inout) :: obsrv !< observation type - class(DisBaseType), intent(in) :: dis !< pointer to the model discretization - integer(I4B), intent(in) :: inunitobs !< unit number of the observation file - integer(I4B), intent(in) :: iout !< unit number to the model listing file + type(ObserveType), intent(inout) :: obsrv !< observation type + class(DisBaseType), intent(in) :: dis !< pointer to the model discretization + integer(I4B), intent(in) :: inunitobs !< unit number of the observation file + integer(I4B), intent(in) :: iout !< unit number to the model listing file ! -- local variables integer(I4B) :: nn1 integer(I4B) :: nn2 diff --git a/src/Model/GroundWaterFlow/gwf3dis8.f90 b/src/Model/GroundWaterFlow/gwf3dis8.f90 index 499b951df30..d81cdffafe7 100644 --- a/src/Model/GroundWaterFlow/gwf3dis8.f90 +++ b/src/Model/GroundWaterFlow/gwf3dis8.f90 @@ -2,35 +2,35 @@ module GwfDisModule use ArrayReadersModule, only: ReadArray use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, DHALF, DZERO + use ConstantsModule, only: LINELENGTH, DHALF, DZERO, LENMEMPATH, LENVARNAME use BaseDisModule, only: DisBaseType use InputOutputModule, only: get_node, URWORD, ulasav, ulaprufw, ubdsv1, & ubdsv06 use SimModule, only: count_errors, store_error, store_error_unit use BlockParserModule, only: BlockParserType use MemoryManagerModule, only: mem_allocate - use TdisModule, only: kstp, kper, pertim, totim, delt + use MemoryHelperModule, only: create_mem_path + use TdisModule, only: kstp, kper, pertim, totim, delt implicit none private - public dis_cr, dis_init_mem, GwfDisType + public dis_cr, GwfDisType type, extends(DisBaseType) :: GwfDisType - integer(I4B), pointer :: nlay => null() ! number of layers - integer(I4B), pointer :: nrow => null() ! number of rows - integer(I4B), pointer :: ncol => null() ! number of columns - real(DP), dimension(:), pointer, contiguous :: delr => null() ! spacing along a row - real(DP), dimension(:), pointer, contiguous :: delc => null() ! spacing along a column - real(DP), dimension(:, :), pointer, contiguous :: top2d => null() ! top elevations for each cell at top of model (ncol, nrow) - real(DP), dimension(:, :, :), pointer, contiguous :: bot3d => null() ! bottom elevations for each cell (ncol, nrow, nlay) - integer(I4B), dimension(:, :, :), pointer, contiguous :: idomain => null() ! idomain (ncol, nrow, nlay) - real(DP), dimension(:, :, :), pointer :: botm => null() ! top and bottom elevations for each cell (ncol, nrow, nlay) - real(DP), dimension(:), pointer, contiguous :: cellx => null() ! cell center x coordinate for column j - real(DP), dimension(:), pointer, contiguous :: celly => null() ! cell center y coordinate for row i + integer(I4B), pointer :: nlay => null() ! number of layers + integer(I4B), pointer :: nrow => null() ! number of rows + integer(I4B), pointer :: ncol => null() ! number of columns + real(DP), dimension(:), pointer, contiguous :: delr => null() ! spacing along a row + real(DP), dimension(:), pointer, contiguous :: delc => null() ! spacing along a column + real(DP), dimension(:, :), pointer, contiguous :: top2d => null() ! top elevations for each cell at top of model (ncol, nrow) + real(DP), dimension(:, :, :), pointer, contiguous :: bot3d => null() ! bottom elevations for each cell (ncol, nrow, nlay) + integer(I4B), dimension(:, :, :), pointer, contiguous :: idomain => null() ! idomain (ncol, nrow, nlay) + real(DP), dimension(:, :, :), pointer :: botm => null() ! top and bottom elevations for each cell (ncol, nrow, nlay) + real(DP), dimension(:), pointer, contiguous :: cellx => null() ! cell center x coordinate for column j + real(DP), dimension(:), pointer, contiguous :: celly => null() ! cell center y coordinate for row i contains procedure :: dis_df => dis3d_df procedure :: dis_da => dis3d_da - procedure :: get_cellxy => get_cellxy_dis3d procedure :: get_dis_type => get_dis_type procedure, public :: record_array procedure, public :: read_layer_array @@ -48,9 +48,12 @@ module GwfDisModule procedure :: connection_vector procedure :: connection_normal ! -- private - procedure :: read_options - procedure :: read_dimensions - procedure :: read_mf6_griddata + procedure :: source_options + procedure :: source_dimensions + procedure :: source_griddata + procedure :: log_options + procedure :: log_dimensions + procedure :: log_griddata procedure :: grid_finalize procedure :: write_grb procedure :: allocate_scalars @@ -61,7 +64,7 @@ module GwfDisModule procedure :: read_dbl_array end type GwfDisType - contains +contains subroutine dis_cr(dis, name_model, inunit, iout) ! ****************************************************************************** @@ -70,107 +73,50 @@ subroutine dis_cr(dis, name_model, inunit, iout) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules + use IdmMf6FileLoaderModule, only: input_load + use ConstantsModule, only: LENPACKAGETYPE + ! -- dummy class(DisBaseType), pointer :: dis character(len=*), intent(in) :: name_model integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout + ! -- locals type(GwfDisType), pointer :: disnew + character(len=*), parameter :: fmtheader = & + "(1X, /1X, 'DIS -- STRUCTURED GRID DISCRETIZATION PACKAGE,', & + &' VERSION 2 : 3/27/2014 - INPUT READ FROM UNIT ', I0, /)" ! ------------------------------------------------------------------------------ - allocate(disnew) + allocate (disnew) dis => disnew call disnew%allocate_scalars(name_model) dis%inunit = inunit dis%iout = iout ! - ! -- Initialize block parser - call dis%parser%Initialize(dis%inunit, dis%iout) + ! -- if reading from file + if (inunit > 0) then + ! + ! -- Identify package + if (iout > 0) then + write (iout, fmtheader) inunit + end if + ! + ! -- Initialize block parser + call dis%parser%Initialize(inunit, iout) + ! + ! -- Use the input data model routines to load the input data + ! into memory + call input_load(dis%parser, 'DIS6', 'GWF', 'DIS', name_model, 'DIS', & + [character(len=LENPACKAGETYPE) ::], iout) + end if ! ! -- Return return end subroutine dis_cr - - subroutine dis_init_mem(dis, name_model, iout, nlay, nrow, ncol, & - delr, delc, top2d, bot3d, idomain) -! ****************************************************************************** -! dis_init_mem -- Create a new discretization 3d object from memory -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - class(DisBaseType), pointer :: dis - character(len=*), intent(in) :: name_model - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: nlay - integer(I4B), intent(in) :: nrow - integer(I4B), intent(in) :: ncol - real(DP), dimension(:), pointer, contiguous, intent(in) :: delr - real(DP), dimension(:), pointer, contiguous, intent(in) :: delc - real(DP), dimension(:, :), pointer, contiguous, intent(in) :: top2d - real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: bot3d - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in), & - optional :: idomain - ! -- local - type(GwfDisType), pointer :: disext - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: k - integer(I4B) :: ival - ! -- local -! ------------------------------------------------------------------------------ - allocate(disext) - dis => disext - call disext%allocate_scalars(name_model) - dis%inunit = 0 - dis%iout = iout - ! - ! -- set dimensions - disext%nrow = nrow - disext%ncol = ncol - disext%nlay = nlay - ! - ! -- calculate nodesuser - disext%nodesuser = disext%nlay * disext%nrow * disext%ncol - ! - ! -- Allocate delr, delc, and non-reduced vectors for dis - call mem_allocate(disext%delr, disext%ncol, 'DELR', disext%memoryPath) - call mem_allocate(disext%delc, disext%nrow, 'DELC', disext%memoryPath) - call mem_allocate(disext%idomain, disext%ncol, disext%nrow, disext%nlay, & - 'IDOMAIN',disext%memoryPath) - call mem_allocate(disext%top2d, disext%ncol, disext%nrow, 'TOP2D', & - disext%memoryPath) - call mem_allocate(disext%bot3d, disext%ncol, disext%nrow, disext%nlay, & - 'BOT3D', disext%memoryPath) - ! -- fill data - do i = 1, disext%nrow - disext%delc(i) = delc(i) - end do - do j = 1, disext%ncol - disext%delr(j) = delr(j) - end do - do k = 1, disext%nlay - do i = 1, disext%nrow - do j = 1, disext%ncol - if (k == 1) then - disext%top2d(j, i) = top2d(j, i) - end if - disext%bot3d(j, i, k) = bot3d(j, i, k) - if (present(idomain)) then - ival = idomain(j, i, k) - else - ival = 1 - end if - disext%idomain(j, i, k) = ival - end do - end do - end do - ! - ! -- Return - return - end subroutine dis_init_mem subroutine dis3d_df(this) ! ****************************************************************************** -! read_from_file -- Allocate and read discretization information +! dis3d_df -- Define ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -182,22 +128,17 @@ subroutine dis3d_df(this) ! -- locals ! ------------------------------------------------------------------------------ ! - ! -- read data from file + ! -- Transfer the data from the memory manager into this package object if (this%inunit /= 0) then ! - ! -- Identify package - write(this%iout,1) this%inunit -1 format(1X,/1X,'DIS -- STRUCTURED GRID DISCRETIZATION PACKAGE,', & - ' VERSION 2 : 3/27/2014 - INPUT READ FROM UNIT ',I0,//) - ! - ! -- Read options - call this%read_options() + ! -- source input options + call this%source_options() ! - ! -- Read dimensions block - call this%read_dimensions() + ! -- source input dimensions + call this%source_dimensions() ! - ! -- Read GRIDDATA block - call this%read_mf6_griddata() + ! -- source input griddata + call this%source_griddata() end if ! ! -- Final grid initialization @@ -216,11 +157,18 @@ subroutine dis3d_da(this) ! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_deallocate + use MemoryManagerExtModule, only: memorylist_remove + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisType) :: this ! -- locals ! ------------------------------------------------------------------------------ ! + ! -- Deallocate idm memory + call memorylist_remove(this%name_model, 'DIS', idm_context) + call memorylist_remove(component=this%name_model, & + context=idm_context) + ! ! -- DisBaseType deallocate call this%DisBaseType%dis_da() ! @@ -244,152 +192,122 @@ subroutine dis3d_da(this) return end subroutine dis3d_da - subroutine read_options(this) -! ****************************************************************************** -! read_options -- Read options -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ + !> @brief Copy options from IDM into package + !< + subroutine source_options(this) ! -- modules - use ConstantsModule, only: LINELENGTH + use KindModule, only: LGP + use MemoryTypeModule, only: MemoryType + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisInputModule, only: GwfDisParamFoundType ! -- dummy class(GwfDisType) :: this ! -- locals - character(len=LINELENGTH) :: errmsg, keyword - integer(I4B) :: ierr - logical :: isfound, endOfBlock -! ------------------------------------------------------------------------------ - ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - ! - ! -- set default options - this%lenuni = 0 - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING DISCRETIZATION OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('LENGTH_UNITS') - call this%parser%GetStringCaps(keyword) - if(keyword == 'FEET') then - this%lenuni = 1 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS FEET' - elseif(keyword == 'METERS') then - this%lenuni = 2 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS METERS' - elseif(keyword == 'CENTIMETERS') then - this%lenuni = 3 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS CENTIMETERS' - else - write(this%iout,'(4x,a)')'UNKNOWN UNIT: ',trim(keyword) - write(this%iout,'(4x,a)')'SETTING TO: ','UNDEFINED' - endif - case('NOGRB') - write(this%iout,'(4x,a)') 'BINARY GRB FILE WILL NOT BE WRITTEN' - this%writegrb = .false. - case('XORIGIN') - this%xorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'XORIGIN SPECIFIED AS ', & - this%xorigin - case('YORIGIN') - this%yorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'YORIGIN SPECIFIED AS ', & - this%yorigin - case('ANGROT') - this%angrot = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'ANGROT SPECIFIED AS ', & - this%angrot - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN DIS OPTION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END OF DISCRETIZATION OPTIONS' - else - write(this%iout,'(1x,a)')'NO OPTION BLOCK DETECTED.' + character(len=LENMEMPATH) :: idmMemoryPath + character(len=LENVARNAME), dimension(3) :: lenunits = & + &[character(len=LENVARNAME) :: 'FEET', 'METERS', 'CENTIMETERS'] + type(GwfDisParamFoundType) :: found + ! + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DIS', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%lenuni, 'LENGTH_UNITS', idmMemoryPath, lenunits, & + found%length_units) + call mem_set_value(this%nogrb, 'NOGRB', idmMemoryPath, found%nogrb) + call mem_set_value(this%xorigin, 'XORIGIN', idmMemoryPath, found%xorigin) + call mem_set_value(this%yorigin, 'YORIGIN', idmMemoryPath, found%yorigin) + call mem_set_value(this%angrot, 'ANGROT', idmMemoryPath, found%angrot) + ! + ! -- log values to list file + if (this%iout > 0) then + call this%log_options(found) end if - if(this%lenuni==0) write(this%iout,'(1x,a)') 'MODEL LENGTH UNIT IS UNDEFINED' ! ! -- Return return - end subroutine read_options + end subroutine source_options - subroutine read_dimensions(this) -! ****************************************************************************** -! read_dimensions -- Read dimensions -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH + !> @brief Write user options to list file + !< + subroutine log_options(this, found) + use GwfDisInputModule, only: GwfDisParamFoundType + class(GwfDisType) :: this + type(GwfDisParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Options' + + if (found%length_units) then + write (this%iout, '(4x,a,i0)') 'Model length unit [0=UND, 1=FEET, & + &2=METERS, 3=CENTIMETERS] set as ', this%lenuni + end if + + if (found%nogrb) then + write (this%iout, '(4x,a,i0)') 'Binary grid file [0=GRB, 1=NOGRB] & + &set as ', this%nogrb + end if + + if (found%xorigin) then + write (this%iout, '(4x,a,G0)') 'XORIGIN = ', this%xorigin + end if + + if (found%yorigin) then + write (this%iout, '(4x,a,G0)') 'YORIGIN = ', this%yorigin + end if + + if (found%angrot) then + write (this%iout, '(4x,a,G0)') 'ANGROT = ', this%angrot + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Options' + + end subroutine log_options + + !> @brief Copy dimensions from IDM into package + !< + subroutine source_dimensions(this) + use KindModule, only: LGP + use MemoryTypeModule, only: MemoryType + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisInputModule, only: GwfDisParamFoundType ! -- dummy class(GwfDisType) :: this ! -- locals - character(len=LINELENGTH) :: errmsg, keyword - integer(I4B) :: ierr + character(len=LENMEMPATH) :: idmMemoryPath integer(I4B) :: i, j, k - logical :: isfound, endOfBlock -! ------------------------------------------------------------------------------ + type(GwfDisParamFoundType) :: found ! - ! -- get dimensions block - call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse dimensions block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING DISCRETIZATION DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('NLAY') - this%nlay = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NLAY = ', this%nlay - case ('NROW') - this%nrow = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NROW = ', this%nrow - case ('NCOL') - this%ncol = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NCOL = ', this%ncol - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN DIS DIMENSION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END OF DISCRETIZATION DIMENSIONS' - else - call store_error('ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.') - call this%parser%StoreErrorUnit() + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DIS', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%nlay, 'NLAY', idmMemoryPath, found%nlay) + call mem_set_value(this%nrow, 'NROW', idmMemoryPath, found%nrow) + call mem_set_value(this%ncol, 'NCOL', idmMemoryPath, found%ncol) + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_dimensions(found) end if ! ! -- verify dimensions were set - if(this%nlay < 1) then + if (this%nlay < 1) then call store_error( & - 'ERROR. NLAY WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NLAY was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif - if(this%nrow < 1) then + end if + if (this%nrow < 1) then call store_error( & - 'ERROR. NROW WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NROW was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif - if(this%ncol < 1) then + end if + if (this%ncol < 1) then call store_error( & - 'ERROR. NCOL WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NCOL was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- calculate nodesuser this%nodesuser = this%nlay * this%nrow * this%ncol @@ -397,10 +315,10 @@ subroutine read_dimensions(this) ! -- Allocate delr, delc, and non-reduced vectors for dis call mem_allocate(this%delr, this%ncol, 'DELR', this%memoryPath) call mem_allocate(this%delc, this%nrow, 'DELC', this%memoryPath) - call mem_allocate(this%idomain, this%ncol, this%nrow, this%nlay, 'IDOMAIN', & + call mem_allocate(this%idomain, this%ncol, this%nrow, this%nlay, 'IDOMAIN', & this%memoryPath) call mem_allocate(this%top2d, this%ncol, this%nrow, 'TOP2D', this%memoryPath) - call mem_allocate(this%bot3d, this%ncol, this%nrow, this%nlay, 'BOT3D', & + call mem_allocate(this%bot3d, this%ncol, this%nrow, this%nlay, 'BOT3D', & this%memoryPath) call mem_allocate(this%cellx, this%ncol, 'CELLX', this%memoryPath) call mem_allocate(this%celly, this%nrow, 'CELLY', this%memoryPath) @@ -416,117 +334,104 @@ subroutine read_dimensions(this) ! ! -- Return return - end subroutine read_dimensions + end subroutine source_dimensions + + !> @brief Write dimensions to list file + !< + subroutine log_dimensions(this, found) + use GwfDisInputModule, only: GwfDisParamFoundType + class(GwfDisType) :: this + type(GwfDisParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Dimensions' + + if (found%nlay) then + write (this%iout, '(4x,a,i0)') 'NLAY = ', this%nlay + end if + + if (found%nrow) then + write (this%iout, '(4x,a,i0)') 'NROW = ', this%nrow + end if + + if (found%ncol) then + write (this%iout, '(4x,a,i0)') 'NCOL = ', this%ncol + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Dimensions' - subroutine read_mf6_griddata(this) + end subroutine log_dimensions + + subroutine source_griddata(this) ! ****************************************************************************** -! read_mf6_griddata -- Read griddata from a MODFLOW 6 ascii file +! source_griddata -- update simulation mempath griddata ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO - use MemoryManagerModule, only: mem_allocate + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisInputModule, only: GwfDisParamFoundType ! -- dummy class(GwfDisType) :: this ! -- locals - character(len=LINELENGTH) :: keyword - integer(I4B) :: n - integer(I4B) :: nvals - integer(I4B) :: ierr - logical :: isfound, endOfBlock - integer(I4B), parameter :: nname = 5 - logical, dimension(nname) :: lname - character(len=24),dimension(nname) :: aname - character(len=300) :: ermsg + character(len=LENMEMPATH) :: idmMemoryPath + type(GwfDisParamFoundType) :: found ! -- formats - ! -- data - data aname(1) /' DELR'/ - data aname(2) /' DELC'/ - data aname(3) /'TOP ELEVATION OF LAYER 1'/ - data aname(4) /' MODEL LAYER BOTTOM EL.'/ - data aname(5) /' IDOMAIN'/ ! ------------------------------------------------------------------------------ - do n = 1, size(aname) - lname(n) = .false. - end do ! - ! -- Read GRIDDATA block - call this%parser%GetBlock('GRIDDATA', isfound, ierr) - lname(:) = .false. - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('DELR') - call ReadArray(this%parser%iuactive, this%delr, aname(1), & - this%ndim, this%ncol, this%iout, 0) - lname(1) = .true. - case ('DELC') - call ReadArray(this%parser%iuactive, this%delc, aname(2), & - this%ndim, this%nrow, this%iout, 0) - lname(2) = .true. - case ('TOP') - call ReadArray(this%parser%iuactive, this%top2d(:,:), aname(3), & - this%ndim, this%ncol, this%nrow, this%iout, 0) - lname(3) = .true. - case ('BOTM') - call this%parser%GetStringCaps(keyword) - if (keyword .EQ. 'LAYERED') then - call ReadArray(this%parser%iuactive, this%bot3d(:,:,:), & - aname(4), this%ndim, this%ncol, this%nrow, & - this%nlay, this%iout, 1, this%nlay) - else - nvals = this%ncol * this%nrow * this%nlay - call ReadArray(this%parser%iuactive, this%bot3d(:,:,:), & - aname(4), this%ndim, nvals, this%iout) - end if - lname(4) = .true. - case ('IDOMAIN') - call this%parser%GetStringCaps(keyword) - if (keyword .EQ. 'LAYERED') then - call ReadArray(this%parser%iuactive, this%idomain, aname(5), & - this%ndim, this%ncol, this%nrow, this%nlay, & - this%iout, 1, this%nlay) - else - call ReadArray(this%parser%iuactive, this%idomain, aname(5), & - this%ndim, this%nodesuser, 1, 1, this%iout, 0, 0) - end if - lname(5) = .true. - case default - write(ermsg,'(4x,a,a)')'ERROR. UNKNOWN GRIDDATA TAG: ', & - trim(keyword) - call store_error(ermsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' - else - call store_error('ERROR. REQUIRED GRIDDATA BLOCK NOT FOUND.') - call this%parser%StoreErrorUnit() - end if + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DIS', idm_context) ! - ! -- Verify all required items were read (IDOMAIN not required) - do n = 1, nname - 1 - if(.not. lname(n)) then - write(ermsg,'(1x,a,a)') & - 'ERROR. REQUIRED INPUT WAS NOT SPECIFIED: ',aname(n) - call store_error(ermsg) - endif - enddo - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - endif + ! -- update defaults with idm sourced values + call mem_set_value(this%delr, 'DELR', idmMemoryPath, found%delr) + call mem_set_value(this%delc, 'DELC', idmMemoryPath, found%delc) + call mem_set_value(this%top2d, 'TOP', idmMemoryPath, found%top) + call mem_set_value(this%bot3d, 'BOTM', idmMemoryPath, found%botm) + call mem_set_value(this%idomain, 'IDOMAIN', idmMemoryPath, found%idomain) + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_griddata(found) + end if ! ! -- Return return - end subroutine read_mf6_griddata - + end subroutine source_griddata + + !> @brief Write dimensions to list file + !< + subroutine log_griddata(this, found) + use GwfDisInputModule, only: GwfDisParamFoundType + class(GwfDisType) :: this + type(GwfDisParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Griddata' + + if (found%delr) then + write (this%iout, '(4x,a)') 'DELR set from input file' + end if + + if (found%delc) then + write (this%iout, '(4x,a)') 'DELC set from input file' + end if + + if (found%top) then + write (this%iout, '(4x,a)') 'TOP set from input file' + end if + + if (found%botm) then + write (this%iout, '(4x,a)') 'BOTM set from input file' + end if + + if (found%idomain) then + write (this%iout, '(4x,a)') 'IDOMAIN set from input file' + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Griddata' + + end subroutine log_griddata + subroutine grid_finalize(this) ! ****************************************************************************** ! grid_finalize -- Finalize grid @@ -535,8 +440,7 @@ subroutine grid_finalize(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO + use ConstantsModule, only: LINELENGTH, DZERO use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwfDisType) :: this @@ -550,12 +454,12 @@ subroutine grid_finalize(this) real(DP) :: dz ! -- formats character(len=*), parameter :: fmtdz = & - "('ERROR. CELL (',i0,',',i0,',',i0,') THICKNESS <= 0. ', " // & - "'TOP, BOT: ',2(1pg24.15))" + "('CELL (',i0,',',i0,',',i0,') THICKNESS <= 0. ', & + &'TOP, BOT: ',2(1pg24.15))" character(len=*), parameter :: fmtnr = & - "(/1x, 'THE SPECIFIED IDOMAIN RESULTS IN A REDUCED NUMBER OF CELLS.'," // & - "/1x, 'NUMBER OF USER NODES: ',I0," // & - "/1X, 'NUMBER OF NODES IN SOLUTION: ', I0, //)" + "(/1x, 'The specified IDOMAIN results in a reduced number of cells.',& + &/1x, 'Number of user nodes: ',I0,& + &/1X, 'Number of nodes in solution: ', I0, //)" ! ------------------------------------------------------------------------------ ! ! -- count active cells @@ -563,16 +467,16 @@ subroutine grid_finalize(this) do k = 1, this%nlay do i = 1, this%nrow do j = 1, this%ncol - if(this%idomain(j, i, k) > 0) this%nodes = this%nodes + 1 - enddo - enddo - enddo + if (this%idomain(j, i, k) > 0) this%nodes = this%nodes + 1 + end do + end do + end do ! ! -- Check to make sure nodes is a valid number if (this%nodes == 0) then - call store_error('ERROR. MODEL DOES NOT HAVE ANY ACTIVE NODES.') - call store_error('MAKE SURE IDOMAIN ARRAY HAS SOME VALUES GREATER & - &THAN ZERO.') + call store_error('Model does not have any active nodes. & + &Ensure IDOMAIN array has some values greater & + &than zero.') call this%parser%StoreErrorUnit() end if ! @@ -590,20 +494,20 @@ subroutine grid_finalize(this) dz = top - this%bot3d(j, i, k) if (dz <= DZERO) then n = n + 1 - write(ermsg, fmt=fmtdz) k, i, j, top, this%bot3d(j, i, k) + write (ermsg, fmt=fmtdz) k, i, j, top, this%bot3d(j, i, k) call store_error(ermsg) - endif - enddo - enddo - enddo + end if + end do + end do + end do if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Write message if reduced grid - if(this%nodes < this%nodesuser) then - write(this%iout, fmtnr) this%nodesuser, this%nodes - endif + if (this%nodes < this%nodesuser) then + write (this%iout, fmtnr) this%nodesuser, this%nodes + end if ! ! -- Array size is now known, so allocate call this%allocate_arrays() @@ -612,52 +516,65 @@ subroutine grid_finalize(this) ! a negative number to indicate it is a pass-through cell, or ! a zero to indicate that the cell is excluded from the ! solution. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then node = 1 noder = 1 do k = 1, this%nlay do i = 1, this%nrow do j = 1, this%ncol - if(this%idomain(j, i, k) > 0) then + if (this%idomain(j, i, k) > 0) then this%nodereduced(node) = noder noder = noder + 1 - elseif(this%idomain(j, i, k) < 0) then + elseif (this%idomain(j, i, k) < 0) then this%nodereduced(node) = -1 else this%nodereduced(node) = 0 - endif + end if node = node + 1 - enddo - enddo - enddo - endif + end do + end do + end do + end if ! ! -- allocate and fill nodeuser if a reduced grid - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then node = 1 noder = 1 do k = 1, this%nlay do i = 1, this%nrow do j = 1, this%ncol - if(this%idomain(j, i, k) > 0) then + if (this%idomain(j, i, k) > 0) then this%nodeuser(noder) = node noder = noder + 1 - endif + end if node = node + 1 - enddo - enddo - enddo - endif + end do + end do + end do + end if + ! + ! -- fill x,y coordinate arrays + this%cellx(1) = DHALF * this%delr(1) + this%celly(this%nrow) = DHALF * this%delc(this%nrow) + do j = 2, this%ncol + this%cellx(j) = this%cellx(j - 1) + DHALF * this%delr(j - 1) + & + DHALF * this%delr(j) + end do + ! -- row number increases in negative y direction: + do i = this%nrow - 1, 1, -1 + this%celly(i) = this%celly(i + 1) + DHALF * this%delc(i + 1) + & + DHALF * this%delc(i) + end do ! ! -- Move top2d and botm3d into top and bot, and calculate area node = 0 - do k=1,this%nlay - do i=1,this%nrow - do j=1,this%ncol + do k = 1, this%nlay + do i = 1, this%nrow + do j = 1, this%ncol node = node + 1 noder = node - if(this%nodes < this%nodesuser) noder = this%nodereduced(node) - if(noder <= 0) cycle + if (this%nodes < this%nodesuser) noder = this%nodereduced(node) + if (noder <= 0) cycle if (k > 1) then top = this%bot3d(j, i, k - 1) else @@ -666,29 +583,20 @@ subroutine grid_finalize(this) this%top(noder) = top this%bot(noder) = this%bot3d(j, i, k) this%area(noder) = this%delr(j) * this%delc(i) - enddo - enddo - enddo - ! - ! -- fill x,y coordinate arrays - this%cellx(1) = DHALF*this%delr(1) - this%celly(this%nrow) = DHALF*this%delc(this%nrow) - do j = 2, this%ncol - this%cellx(j) = this%cellx(j-1) + DHALF*this%delr(j-1) + DHALF*this%delr(j) - enddo - ! -- row number increases in negative y direction: - do i = this%nrow-1, 1, -1 - this%celly(i) = this%celly(i+1) + DHALF*this%delc(i+1) + DHALF*this%delc(i) - enddo + this%xc(noder) = this%cellx(j) + this%yc(noder) = this%celly(i) + end do + end do + end do ! ! -- create and fill the connections object nrsize = 0 - if(this%nodes < this%nodesuser) nrsize = this%nodes - allocate(this%con) - call this%con%disconnections(this%name_model, this%nodes, & - this%ncol, this%nrow, this%nlay, & - nrsize, this%delr, this%delc, & - this%top, this%bot, this%nodereduced, & + if (this%nodes < this%nodesuser) nrsize = this%nodes + allocate (this%con) + call this%con%disconnections(this%name_model, this%nodes, & + this%ncol, this%nrow, this%nlay, & + nrsize, this%delr, this%delc, & + this%top, this%bot, this%nodereduced, & this%nodeuser) this%nja = this%con%nja this%njas = this%con%njas @@ -717,8 +625,8 @@ subroutine write_grb(this, icelltype) character(len=50) :: txthdr character(len=lentxt) :: txt character(len=LINELENGTH) :: fname - character(len=*),parameter :: fmtgrdsave = & - "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & + character(len=*), parameter :: fmtgrdsave = & + "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)" ! ------------------------------------------------------------------------------ ! @@ -727,97 +635,97 @@ subroutine write_grb(this, icelltype) ncpl = this%nrow * this%ncol ! ! -- Open the file - inquire(unit=this%inunit, name=fname) - fname = trim(fname) // '.grb' + inquire (unit=this%inunit, name=fname) + fname = trim(fname)//'.grb' iunit = getunit() - write(this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) - call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & + write (this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) + call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & form, access, 'REPLACE') ! ! -- write header information - write(txthdr, '(a)') 'GRID DIS' + write (txthdr, '(a)') 'GRID DIS' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a)') 'VERSION 1' + write (iunit) txthdr + write (txthdr, '(a)') 'VERSION 1' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'NTXT ', ntxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'NTXT ', ntxt txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'LENTXT ', lentxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'LENTXT ', lentxt txthdr(50:50) = new_line('a') - write(iunit) txthdr + write (iunit) txthdr ! ! -- write variable definitions - write(txt, '(3a, i0)') 'NCELLS ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser + write (txt, '(3a, i0)') 'NCELLS ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NLAY ', 'INTEGER ', 'NDIM 0 # ', this%nlay + write (iunit) txt + write (txt, '(3a, i0)') 'NLAY ', 'INTEGER ', 'NDIM 0 # ', this%nlay txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NROW ', 'INTEGER ', 'NDIM 0 # ', this%nrow + write (iunit) txt + write (txt, '(3a, i0)') 'NROW ', 'INTEGER ', 'NDIM 0 # ', this%nrow txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NCOL ', 'INTEGER ', 'NDIM 0 # ', this%ncol + write (iunit) txt + write (txt, '(3a, i0)') 'NCOL ', 'INTEGER ', 'NDIM 0 # ', this%ncol txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%nja + write (iunit) txt + write (txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%nja txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'DELR ', 'DOUBLE ', 'NDIM 1 ', this%ncol + write (iunit) txt + write (txt, '(3a, i0)') 'DELR ', 'DOUBLE ', 'NDIM 1 ', this%ncol txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'DELC ', 'DOUBLE ', 'NDIM 1 ', this%nrow + write (iunit) txt + write (txt, '(3a, i0)') 'DELC ', 'DOUBLE ', 'NDIM 1 ', this%nrow txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', ncpl + write (iunit) txt + write (txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', ncpl txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'BOTM ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'BOTM ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 + write (iunit) txt + write (txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', size(this%con%jausr) + write (iunit) txt + write (txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', size(this%con%jausr) txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IDOMAIN ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'IDOMAIN ', 'INTEGER ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt + write (iunit) txt ! ! -- write data - write(iunit) this%nodesuser ! ncells - write(iunit) this%nlay ! nlay - write(iunit) this%nrow ! nrow - write(iunit) this%ncol ! ncol - write(iunit) this%nja ! nja - write(iunit) this%xorigin ! xorigin - write(iunit) this%yorigin ! yorigin - write(iunit) this%angrot ! angrot - write(iunit) this%delr ! delr - write(iunit) this%delc ! delc - write(iunit) this%top2d ! top2d - write(iunit) this%bot3d ! bot3d - write(iunit) this%con%iausr ! iausr - write(iunit) this%con%jausr ! jausr - write(iunit) this%idomain ! idomain - write(iunit) icelltype ! icelltype + write (iunit) this%nodesuser ! ncells + write (iunit) this%nlay ! nlay + write (iunit) this%nrow ! nrow + write (iunit) this%ncol ! ncol + write (iunit) this%nja ! nja + write (iunit) this%xorigin ! xorigin + write (iunit) this%yorigin ! yorigin + write (iunit) this%angrot ! angrot + write (iunit) this%delr ! delr + write (iunit) this%delc ! delc + write (iunit) this%top2d ! top2d + write (iunit) this%bot3d ! bot3d + write (iunit) this%con%iausr ! iausr + write (iunit) this%con%jausr ! jausr + write (iunit) this%idomain ! idomain + write (iunit) icelltype ! icelltype ! ! -- Close the file - close(iunit) + close (iunit) ! ! -- return return @@ -842,12 +750,12 @@ subroutine nodeu_to_string(this, nodeu, str) ! ------------------------------------------------------------------------------ ! call get_ijk(nodeu, this%nrow, this%ncol, this%nlay, i, j, k) - write(kstr, '(i10)') k - write(istr, '(i10)') i - write(jstr, '(i10)') j - str = '(' // trim(adjustl(kstr)) // ',' // & - trim(adjustl(istr)) // ',' // & - trim(adjustl(jstr)) // ')' + write (kstr, '(i10)') k + write (istr, '(i10)') i + write (jstr, '(i10)') j + str = '('//trim(adjustl(kstr))//','// & + trim(adjustl(istr))//','// & + trim(adjustl(jstr))//')' ! ! -- return return @@ -875,8 +783,8 @@ subroutine nodeu_to_array(this, nodeu, arr) ! -- check the size of arr isize = size(arr) if (isize /= this%ndim) then - write(errmsg,'(a,i0,a,i0,a)') & - 'Program error: nodeu_to_array size of array (', isize, & + write (errmsg, '(a,i0,a,i0,a)') & + 'Program error: nodeu_to_array size of array (', isize, & ') is not equal to the discretization dimension (', this%ndim, ')' call store_error(errmsg, terminate=.TRUE.) end if @@ -914,28 +822,28 @@ function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) ! ------------------------------------------------------------------------------ ! ! -- check the node number if requested - if(icheck /= 0) then + if (icheck /= 0) then ! ! -- If within valid range, convert to reduced nodenumber - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, '(a,i10)') & + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, '(a,i10)') & 'Nodenumber less than 1 or greater than nodes:', nodeu call store_error(errmsg) nodenumber = 0 else nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) - endif + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + end if else nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) - endif + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + end if ! ! -- return return end function get_nodenumber_idx1 - function get_nodenumber_idx3(this, k, i, j, icheck) & + function get_nodenumber_idx3(this, k, i, j, icheck) & result(nodenumber) ! ****************************************************************************** ! get_nodenumber_idx3 -- Return a nodenumber from the user specified layer, row, @@ -958,34 +866,35 @@ function get_nodenumber_idx3(this, k, i, j, icheck) & integer(I4B) :: nodeu ! formats character(len=*), parameter :: fmterr = & - "('Error in structured-grid cell indices: layer = ',i0,', row = ',i0,', column = ',i0)" + "('Error in structured-grid cell indices: layer = ',i0,', & + &row = ',i0,', column = ',i0)" ! ------------------------------------------------------------------------------ ! nodeu = get_node(k, i, j, this%nlay, this%nrow, this%ncol) if (nodeu < 1) then - write(errmsg, fmterr) k, i, j + write (errmsg, fmterr) k, i, j call store_error(errmsg, terminate=.TRUE.) - endif + end if nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) ! ! -- check the node number if requested - if(icheck /= 0) then + if (icheck /= 0) then ! - if(k < 1 .or. k > this%nlay) & + if (k < 1 .or. k > this%nlay) & call store_error('Layer less than one or greater than nlay') - if(i < 1 .or. i > this%nrow) & + if (i < 1 .or. i > this%nrow) & call store_error('Row less than one or greater than nrow') - if(j < 1 .or. j > this%ncol) & + if (j < 1 .or. j > this%ncol) & call store_error('Column less than one or greater than ncol') ! ! -- Error if outside of range - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, '(a,i10)') & + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, '(a,i10)') & 'Nodenumber less than 1 or greater than nodes:', nodeu call store_error(errmsg) - endif - endif + end if + end if ! ! -- return return @@ -1039,14 +948,14 @@ subroutine allocate_arrays(this) call this%DisBaseType%allocate_arrays() ! ! -- Allocate arrays for GwfDisType - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call mem_allocate(this%nodeuser, this%nodes, 'NODEUSER', this%memoryPath) - call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', & + call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', & this%memoryPath) else call mem_allocate(this%nodeuser, 1, 'NODEUSER', this%memoryPath) call mem_allocate(this%nodereduced, 1, 'NODEREDUCED', this%memoryPath) - endif + end if ! ! -- Initialize this%mshape(1) = this%nlay @@ -1074,8 +983,8 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & integer(I4B), intent(inout) :: lloc integer(I4B), intent(inout) :: istart integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout character(len=*), intent(inout) :: line logical, optional, intent(in) :: flag_string logical, optional, intent(in) :: allow_zero @@ -1092,14 +1001,14 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & ! Check to see if first token in line can be read as an integer. lloclocal = lloc call urword(line, lloclocal, istart, istop, 1, ndum, r, iout, in) - read(line(istart:istop),*,iostat=istat)n + read (line(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in line is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! nlay = this%mshape(1) nrow = this%mshape(2) @@ -1114,28 +1023,28 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & if (allow_zero) then nodeu = 0 return - endif - endif - endif + end if + end if + end if ! - if(k < 1 .or. k > nlay) then - write(ermsg, *) ' Layer number in list is outside of the grid', k - call store_error(ermsg) + if (k < 1 .or. k > nlay) then + write (ermsg, *) ' Layer number in list is outside of the grid', k + call store_error(ermsg) end if - if(i < 1 .or. i > nrow) then - write(ermsg, *) ' Row number in list is outside of the grid', i - call store_error(ermsg) + if (i < 1 .or. i > nrow) then + write (ermsg, *) ' Row number in list is outside of the grid', i + call store_error(ermsg) end if - if(j < 1 .or. j > ncol) then - write(ermsg, *) ' Column number in list is outside of the grid', j - call store_error(ermsg) + if (j < 1 .or. j > ncol) then + write (ermsg, *) ' Column number in list is outside of the grid', j + call store_error(ermsg) end if nodeu = get_node(k, i, j, nlay, nrow, ncol) ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(ermsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (ermsg, *) ' Node number in list is outside of the grid', nodeu call store_error(ermsg) - inquire(unit=in, name=fname) + inquire (unit=in, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in line: ') @@ -1149,7 +1058,7 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & end function nodeu_from_string function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & - allow_zero) result(nodeu) + allow_zero) result(nodeu) ! ****************************************************************************** ! nodeu_from_cellid -- Receive cellid as a string and convert the string to a ! user nodenumber. @@ -1166,12 +1075,12 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! -- return integer(I4B) :: nodeu ! -- dummy - class(GwfDisType) :: this - character(len=*), intent(inout) :: cellid - integer(I4B), intent(in) :: inunit - integer(I4B), intent(in) :: iout - logical, optional, intent(in) :: flag_string - logical, optional, intent(in) :: allow_zero + class(GwfDisType) :: this + character(len=*), intent(inout) :: cellid + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout + logical, optional, intent(in) :: flag_string + logical, optional, intent(in) :: allow_zero ! -- local integer(I4B) :: lloclocal, istart, istop, ndum, n integer(I4B) :: k, i, j, nlay, nrow, ncol @@ -1185,14 +1094,14 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! Check to see if first token in cellid can be read as an integer. lloclocal = 1 call urword(cellid, lloclocal, istart, istop, 1, ndum, r, iout, inunit) - read(cellid(istart:istop), *, iostat=istat) n + read (cellid(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in cellid is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! nlay = this%mshape(1) nrow = this%mshape(2) @@ -1208,28 +1117,28 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & if (allow_zero) then nodeu = 0 return - endif - endif - endif + end if + end if + end if ! - if(k < 1 .or. k > nlay) then - write(ermsg, *) ' Layer number in list is outside of the grid', k - call store_error(ermsg) + if (k < 1 .or. k > nlay) then + write (ermsg, *) ' Layer number in list is outside of the grid', k + call store_error(ermsg) end if - if(i < 1 .or. i > nrow) then - write(ermsg, *) ' Row number in list is outside of the grid', i - call store_error(ermsg) + if (i < 1 .or. i > nrow) then + write (ermsg, *) ' Row number in list is outside of the grid', i + call store_error(ermsg) end if - if(j < 1 .or. j > ncol) then - write(ermsg, *) ' Column number in list is outside of the grid', j - call store_error(ermsg) + if (j < 1 .or. j > ncol) then + write (ermsg, *) ' Column number in list is outside of the grid', j + call store_error(ermsg) end if nodeu = get_node(k, i, j, nlay, nrow, ncol) ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(ermsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (ermsg, *) ' Node number in list is outside of the grid', nodeu call store_error(ermsg) - inquire(unit=inunit, name=fname) + inquire (unit=inunit, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in cellid: ') @@ -1241,7 +1150,6 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & return end function nodeu_from_cellid - logical function supports_layers(this) implicit none ! -- dummy @@ -1272,7 +1180,7 @@ function get_ncpl(this) return end function get_ncpl - subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & + subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ipos) ! ****************************************************************************** ! connection_normal -- calculate the normal vector components for reduced @@ -1301,10 +1209,10 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ------------------------------------------------------------------------------ ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then xcomp = DZERO ycomp = DZERO - if(nodem < noden) then + if (nodem < noden) then ! ! -- nodem must be above noden, so upward connection zcomp = DONE @@ -1312,7 +1220,7 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ! -- nodem must be below noden, so downward connection zcomp = -DONE - endif + end if else xcomp = DZERO ycomp = DZERO @@ -1329,15 +1237,15 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & xcomp = DONE else ! front ycomp = -DONE - endif + end if ! - endif + end if ! ! -- return return end subroutine connection_normal - subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & + subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & xcomp, ycomp, zcomp, conlen) ! ****************************************************************************** ! connection_vector -- calculate the unit vector components from reduced @@ -1373,28 +1281,28 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! ------------------------------------------------------------------------------ ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then ! ! -- vertical connection; set zcomp positive upward xcomp = DZERO ycomp = DZERO - if(nodem < noden) then + if (nodem < noden) then zcomp = DONE else zcomp = -DONE - endif + end if z1 = this%bot(noden) + DHALF * (this%top(noden) - this%bot(noden)) z2 = this%bot(nodem) + DHALF * (this%top(nodem) - this%bot(nodem)) conlen = abs(z2 - z1) else ! - if(nozee) then + if (nozee) then z1 = DZERO z2 = DZERO else z1 = this%bot(noden) + DHALF * satn * (this%top(noden) - this%bot(noden)) z2 = this%bot(nodem) + DHALF * satm * (this%top(nodem) - this%bot(nodem)) - endif + end if ipos = this%con%getjaindex(noden, nodem) ds = this%con%cl1(this%con%jas(ipos)) + this%con%cl2(this%con%jas(ipos)) nodeu1 = this%get_nodeuser(noden) @@ -1413,40 +1321,23 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & x2 = ds else ! front y2 = -ds - endif + end if call line_unit_vector(x1, y1, z1, x2, y2, z2, xcomp, ycomp, zcomp, conlen) - endif + end if ! ! -- return return end subroutine - - ! return x,y coordinate for a node - subroutine get_cellxy_dis3d(this, node, xcell, ycell) - use InputOutputModule, only: get_ijk - class(GwfDisType), intent(in) :: this - integer(I4B), intent(in) :: node ! the reduced node number - real(DP), intent(out) :: xcell, ycell ! the x,y for the cell - ! local - integer(I4B) :: nodeuser, i, j, k - - nodeuser = this%get_nodeuser(node) - call get_ijk(nodeuser, this%nrow, this%ncol, this%nlay, i, j, k) - - xcell = this%cellx(j) - ycell = this%celly(i) - - end subroutine get_cellxy_dis3d - + ! return discretization type subroutine get_dis_type(this, dis_type) - class(GwfDisType), intent(in) :: this - character(len=*), intent(out) :: dis_type - + class(GwfDisType), intent(in) :: this + character(len=*), intent(out) :: dis_type + dis_type = "DIS" - + end subroutine get_dis_type - + subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & iarray, aname) ! ****************************************************************************** @@ -1457,18 +1348,17 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & ! ------------------------------------------------------------------------------ ! -- modules use InputOutputModule, only: urword - use SimModule, only: store_error use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: iarray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: ival real(DP) :: rval @@ -1493,15 +1383,15 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & else nval = this%nodes itemp => iarray - endif + end if ! ! -- Read the array call urword(line, lloc, istart, istop, 1, ival, rval, iout, in) - if (line(istart:istop).EQ.'LAYERED') then + if (line(istart:istop) .EQ. 'LAYERED') then ! ! -- Read layered input call ReadArray(in, itemp, aname, this%ndim, ncol, nrow, nlay, nval, & - iout, 1, nlay) + iout, 1, nlay) else ! ! -- Read unstructured input @@ -1509,9 +1399,9 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & end if ! ! -- If reduced model, then need to copy from itemp(=>ibuff) to iarray - if (this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(itemp, iarray) - endif + end if ! ! -- return return @@ -1527,21 +1417,20 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & ! ------------------------------------------------------------------------------ ! -- modules use InputOutputModule, only: urword - use SimModule, only: store_error use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: ival - real(DP) :: rval + real(DP) :: rval integer(I4B) :: nlay integer(I4B) :: nrow integer(I4B) :: ncol @@ -1557,21 +1446,21 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & nrow = this%mshape(2) ncol = this%mshape(3) ! - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodesuser dtemp => this%dbuff else nval = this%nodes dtemp => darray - endif + end if ! ! -- Read the array call urword(line, lloc, istart, istop, 1, ival, rval, iout, in) - if (line(istart:istop).EQ.'LAYERED') then + if (line(istart:istop) .EQ. 'LAYERED') then ! ! -- Read structured input call ReadArray(in, dtemp, aname, this%ndim, ncol, nrow, nlay, nval, & - iout, 1, nlay) + iout, 1, nlay) else ! ! -- Read unstructured input @@ -1579,15 +1468,15 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & end if ! ! -- If reduced model, then need to copy from dtemp(=>dbuff) to darray - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(dtemp, darray) - endif + end if ! ! -- return return end subroutine read_dbl_array - subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & + subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & icolbnd, aname, inunit, iout) ! ****************************************************************************** ! read_layer_array -- Read a 2d double array into col icolbnd of darray. @@ -1620,8 +1509,8 @@ subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & ! ! -- Read the array nval = ncol * nrow - call ReadArray(inunit, this%dbuff, aname, this%ndim, ncol, nrow, nlay, & - nval, iout, 0, 0) + call ReadArray(inunit, this%dbuff, aname, this%ndim, ncol, nrow, nlay, & + nval, iout, 0, 0) ! ! -- Copy array into bound. Note that this routine was substantially ! changed on 9/21/2021 to support changes to READASARRAYS input @@ -1634,14 +1523,14 @@ subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & darray(icolbnd, ipos) = this%dbuff(nodeu) ipos = ipos + 1 ! - enddo - enddo + end do + end do ! ! -- return end subroutine read_layer_array - - subroutine record_array(this, darray, iout, iprint, idataun, aname, & - cdatafmp, nvaluesp, nwidthp, editdesc, dinact) + + subroutine record_array(this, darray, iout, iprint, idataun, aname, & + cdatafmp, nvaluesp, nwidthp, editdesc, dinact) ! ****************************************************************************** ! record_array -- Record a double precision array. The array will be ! printed to an external file and/or written to an unformatted external file @@ -1664,17 +1553,17 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(GwfDisType), intent(inout) :: this + class(GwfDisType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: iprint - integer(I4B), intent(in) :: idataun - character(len=*), intent(in) :: aname - character(len=*), intent(in) :: cdatafmp - integer(I4B), intent(in) :: nvaluesp - integer(I4B), intent(in) :: nwidthp - character(len=*), intent(in) :: editdesc - real(DP), intent(in) :: dinact + integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: iprint + integer(I4B), intent(in) :: idataun + character(len=*), intent(in) :: aname + character(len=*), intent(in) :: cdatafmp + integer(I4B), intent(in) :: nvaluesp + integer(I4B), intent(in) :: nwidthp + character(len=*), intent(in) :: editdesc + real(DP), intent(in) :: dinact ! -- local integer(I4B) :: k, ifirst integer(I4B) :: nlay @@ -1685,7 +1574,7 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & integer(I4B) :: istart, istop real(DP), dimension(:), pointer, contiguous :: dtemp ! -- formats - character(len=*),parameter :: fmthsv = & + character(len=*), parameter :: fmthsv = & "(1X,/1X,a,' WILL BE SAVED ON UNIT ',I4, & &' AT END OF TIME STEP',I5,', STRESS PERIOD ',I4)" ! ------------------------------------------------------------------------------ @@ -1697,61 +1586,61 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ! -- If this is a reduced model, then copy the values from darray into ! dtemp. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodes dtemp => this%dbuff do nodeu = 1, this%nodesuser noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) then + if (noder <= 0) then dtemp(nodeu) = dinact cycle - endif + end if dtemp(nodeu) = darray(noder) - enddo + end do else nval = this%nodes dtemp => darray - endif + end if ! ! -- Print to iout if iprint /= 0 - if(iprint /= 0) then + if (iprint /= 0) then istart = 1 do k = 1, nlay istop = istart + nrow * ncol - 1 - call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & + call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & aname, cdatafmp, nvaluesp, nwidthp, editdesc) istart = istop + 1 - enddo - endif + end do + end if ! ! -- Save array to an external file. - if(idataun > 0) then + if (idataun > 0) then ! -- write to binary file by layer ifirst = 1 istart = 1 - do k=1, nlay + do k = 1, nlay istop = istart + nrow * ncol - 1 - if(ifirst == 1) write(iout, fmthsv) & - trim(adjustl(aname)), idataun, & - kstp, kper + if (ifirst == 1) write (iout, fmthsv) & + trim(adjustl(aname)), idataun, & + kstp, kper ifirst = 0 - call ulasav(dtemp(istart:istop), aname, kstp, kper, & + call ulasav(dtemp(istart:istop), aname, kstp, kper, & pertim, totim, ncol, nrow, k, idataun) istart = istop + 1 - enddo - elseif(idataun < 0) then + end do + elseif (idataun < 0) then ! ! -- write entire array as one record - call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & + call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & iout, delt, pertim, totim) - endif + end if ! ! -- return return end subroutine record_array - subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & - dstmodel, dstpackage, naux, auxtxt, & + subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & + dstmodel, dstpackage, naux, auxtxt, & ibdchn, nlist, iout) ! ****************************************************************************** ! record_srcdst_list_header -- Record list header for imeth=6 @@ -1780,8 +1669,8 @@ subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & ncol = this%mshape(3) ! ! -- Use ubdsv06 to write list header - call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage,& - ibdchn, naux, auxtxt, ncol, nrow, nlay, & + call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage, & + ibdchn, naux, auxtxt, ncol, nrow, nlay, & nlist, iout, delt, pertim, totim) ! ! -- return @@ -1800,7 +1689,6 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & ! ------------------------------------------------------------------------------ ! -- modules use InputOutputModule, only: get_node - use SimModule, only: store_error use ConstantsModule, only: LINELENGTH ! -- dummy class(GwfDisType) :: this @@ -1820,10 +1708,11 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & nrow = this%mshape(2) ncol = this%mshape(3) ! - if(this%ndim > 1) then + if (this%ndim > 1) then ! nval = ncol * nrow - call ReadArray(inunit, this%ibuff, aname, this%ndim, ncol, nrow, nlay, nval, iout, 0, 0) + call ReadArray(inunit, this%ibuff, aname, this%ndim, ncol, nrow, nlay, & + nval, iout, 0, 0) ! ! -- Copy array into nodelist ipos = 1 @@ -1832,50 +1721,50 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & do ic = 1, ncol nodeu = get_node(1, ir, ic, nlay, nrow, ncol) il = this%ibuff(nodeu) - if(il < 1 .or. il > nlay) then - write(errmsg, *) 'INVALID LAYER NUMBER: ', il + if (il < 1 .or. il > nlay) then + write (errmsg, *) 'INVALID LAYER NUMBER: ', il call store_error(errmsg, terminate=.TRUE.) - endif + end if nodeu = get_node(il, ir, ic, nlay, nrow, ncol) noder = this%get_nodenumber(nodeu, 0) - if(ipos > maxbnd) then + if (ipos > maxbnd) then ierr = ipos else nodelist(ipos) = noder - endif + end if ipos = ipos + 1 - enddo - enddo + end do + end do ! ! -- Check for errors nbound = ipos - 1 - if(ierr > 0) then - write(errmsg, *) 'MAXBOUND DIMENSION IS TOO SMALL.' + if (ierr > 0) then + write (errmsg, *) 'MAXBOUND DIMENSION IS TOO SMALL.' call store_error(errmsg) - write(errmsg, *) 'INCREASE MAXBOUND TO: ', ierr + write (errmsg, *) 'INCREASE MAXBOUND TO: ', ierr call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- If nbound < maxbnd, then initialize nodelist to zero in this range - if(nbound < maxbnd) then - do ipos = nbound+1, maxbnd + if (nbound < maxbnd) then + do ipos = nbound + 1, maxbnd nodelist(ipos) = 0 - enddo - endif + end do + end if ! else ! ! -- For unstructured, read nodelist directly, then check node numbers call ReadArray(inunit, nodelist, aname, this%ndim, maxbnd, iout, 0) do noder = 1, maxbnd - if(noder < 1 .or. noder > this%nodes) then - write(errmsg, *) 'INVALID NODE NUMBER: ', noder + if (noder < 1 .or. noder > this%nodes) then + write (errmsg, *) 'INVALID NODE NUMBER: ', noder call store_error(errmsg, terminate=.TRUE.) - endif - enddo + end if + end do nbound = maxbnd ! - endif + end if ! ! -- return end subroutine nlarray_to_nodelist diff --git a/src/Model/GroundWaterFlow/gwf3dis8idm.f90 b/src/Model/GroundWaterFlow/gwf3dis8idm.f90 new file mode 100644 index 00000000000..c75fd75a284 --- /dev/null +++ b/src/Model/GroundWaterFlow/gwf3dis8idm.f90 @@ -0,0 +1,278 @@ +module GwfDisInputModule + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwf_dis_param_definitions + public gwf_dis_aggregate_definitions + public gwf_dis_block_definitions + public GwfDisParamFoundType + + type GwfDisParamFoundType + logical :: length_units = .false. + logical :: nogrb = .false. + logical :: xorigin = .false. + logical :: yorigin = .false. + logical :: angrot = .false. + logical :: nlay = .false. + logical :: nrow = .false. + logical :: ncol = .false. + logical :: delr = .false. + logical :: delc = .false. + logical :: top = .false. + logical :: botm = .false. + logical :: idomain = .false. + end type GwfDisParamFoundType + + type(InputParamDefinitionType), parameter :: & + gwfdis_length_units = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'OPTIONS', & ! block + 'LENGTH_UNITS', & ! tag name + 'LENGTH_UNITS', & ! fortran variable + 'STRING', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_nogrb = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'OPTIONS', & ! block + 'NOGRB', & ! tag name + 'NOGRB', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_xorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'OPTIONS', & ! block + 'XORIGIN', & ! tag name + 'XORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_yorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'OPTIONS', & ! block + 'YORIGIN', & ! tag name + 'YORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_angrot = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'OPTIONS', & ! block + 'ANGROT', & ! tag name + 'ANGROT', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_nlay = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'DIMENSIONS', & ! block + 'NLAY', & ! tag name + 'NLAY', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_nrow = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'DIMENSIONS', & ! block + 'NROW', & ! tag name + 'NROW', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_ncol = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'DIMENSIONS', & ! block + 'NCOL', & ! tag name + 'NCOL', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_delr = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'GRIDDATA', & ! block + 'DELR', & ! tag name + 'DELR', & ! fortran variable + 'DOUBLE1D', & ! type + 'NCOL', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_delc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'GRIDDATA', & ! block + 'DELC', & ! tag name + 'DELC', & ! fortran variable + 'DOUBLE1D', & ! type + 'NROW', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_top = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'GRIDDATA', & ! block + 'TOP', & ! tag name + 'TOP', & ! fortran variable + 'DOUBLE2D', & ! type + 'NCOL NROW', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_botm = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'GRIDDATA', & ! block + 'BOTM', & ! tag name + 'BOTM', & ! fortran variable + 'DOUBLE3D', & ! type + 'NCOL NROW NLAY', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdis_idomain = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DIS', & ! subcomponent + 'GRIDDATA', & ! block + 'IDOMAIN', & ! tag name + 'IDOMAIN', & ! fortran variable + 'INTEGER3D', & ! type + 'NCOL NROW NLAY', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_dis_param_definitions(*) = & + [ & + gwfdis_length_units, & + gwfdis_nogrb, & + gwfdis_xorigin, & + gwfdis_yorigin, & + gwfdis_angrot, & + gwfdis_nlay, & + gwfdis_nrow, & + gwfdis_ncol, & + gwfdis_delr, & + gwfdis_delc, & + gwfdis_top, & + gwfdis_botm, & + gwfdis_idomain & + ] + + type(InputParamDefinitionType), parameter :: & + gwf_dis_aggregate_definitions(*) = & + [ & + InputParamDefinitionType :: & + ] + + type(InputBlockDefinitionType), parameter :: & + gwf_dis_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .false., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'DIMENSIONS', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'GRIDDATA', & ! blockname + .true., & ! required + .false. & ! aggregate + ) & + ] + +end module GwfDisInputModule diff --git a/src/Model/GroundWaterFlow/gwf3disu8.f90 b/src/Model/GroundWaterFlow/gwf3disu8.f90 index 5394f0f68ab..02d1ff99b36 100644 --- a/src/Model/GroundWaterFlow/gwf3disu8.f90 +++ b/src/Model/GroundWaterFlow/gwf3disu8.f90 @@ -2,8 +2,9 @@ module GwfDisuModule use ArrayReadersModule, only: ReadArray use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: LENMODELNAME, LINELENGTH, DZERO, DONE - use ConnectionsModule, only: ConnectionsType, iac_to_ia + use ConstantsModule, only: LINELENGTH, LENMEMPATH, LENVARNAME, & + DZERO, DONE + use ConnectionsModule, only: iac_to_ia use InputOutputModule, only: URWORD, ulasav, ulaprufw, ubdsv1, ubdsv06 use SimModule, only: count_errors, store_error, store_error_unit use SimVariablesModule, only: errmsg @@ -17,33 +18,32 @@ module GwfDisuModule private public :: GwfDisuType public :: disu_cr - public :: disu_init_mem public :: CastAsDisuType type, extends(DisBaseType) :: GwfDisuType - integer(I4B), pointer :: njausr => null() ! user-specified nja size - integer(I4B), pointer :: nvert => null() ! number of x,y vertices - real(DP), pointer :: voffsettol => null() ! vertical offset tolerance - real(DP), dimension(:,:), pointer, contiguous :: vertices => null() ! cell vertices stored as 2d array of x and y - real(DP), dimension(:,:), pointer, contiguous :: cellxy => null() ! cell center stored as 2d array of x and y - real(DP), dimension(:), pointer, contiguous :: top1d => null() ! (size:nodesuser) cell top elevation - real(DP), dimension(:), pointer, contiguous :: bot1d => null() ! (size:nodesuser) cell bottom elevation - real(DP), dimension(:), pointer, contiguous :: area1d => null() ! (size:nodesuser) cell area, in plan view - integer(I4B), dimension(:), pointer, contiguous :: iainp => null() ! (size:nodesuser+1) user iac converted ia - integer(I4B), dimension(:), pointer, contiguous :: jainp => null() ! (size:njausr) user-input ja array - integer(I4B), dimension(:), pointer, contiguous :: ihcinp => null() ! (size:njausr) user-input ihc array - real(DP), dimension(:), pointer, contiguous :: cl12inp => null() ! (size:njausr) user-input cl12 array - real(DP), dimension(:), pointer, contiguous :: hwvainp => null() ! (size:njausr) user-input hwva array - real(DP), dimension(:), pointer, contiguous :: angldegxinp => null() ! (size:njausr) user-input angldegx array - integer(I4B), pointer :: iangledegx => null() ! =1 when angle information was present in input, 0 otherwise - integer(I4B), dimension(:), pointer, contiguous :: iavert => null() ! cell vertex pointer ia array - integer(I4B), dimension(:), pointer, contiguous:: javert => null() ! cell vertex pointer ja array - integer(I4B), dimension(:), pointer, contiguous :: idomain => null() ! idomain (nodes) - logical(LGP) :: readFromFile ! True, when DIS is read from file (almost always) + integer(I4B), pointer :: njausr => null() ! user-specified nja size + integer(I4B), pointer :: nvert => null() ! number of x,y vertices + real(DP), pointer :: voffsettol => null() ! vertical offset tolerance + real(DP), dimension(:, :), pointer, contiguous :: vertices => null() ! cell vertices stored as 2d array of x and y + real(DP), dimension(:, :), pointer, contiguous :: cellxy => null() ! cell center stored as 2d array of x and y + real(DP), dimension(:), pointer, contiguous :: top1d => null() ! (size:nodesuser) cell top elevation + real(DP), dimension(:), pointer, contiguous :: bot1d => null() ! (size:nodesuser) cell bottom elevation + real(DP), dimension(:), pointer, contiguous :: area1d => null() ! (size:nodesuser) cell area, in plan view + integer(I4B), dimension(:), pointer, contiguous :: iainp => null() ! (size:nodesuser+1) user iac converted ia + integer(I4B), dimension(:), pointer, contiguous :: jainp => null() ! (size:njausr) user-input ja array + integer(I4B), dimension(:), pointer, contiguous :: ihcinp => null() ! (size:njausr) user-input ihc array + real(DP), dimension(:), pointer, contiguous :: cl12inp => null() ! (size:njausr) user-input cl12 array + real(DP), dimension(:), pointer, contiguous :: hwvainp => null() ! (size:njausr) user-input hwva array + real(DP), dimension(:), pointer, contiguous :: angldegxinp => null() ! (size:njausr) user-input angldegx array + integer(I4B), pointer :: iangledegx => null() ! =1 when angle information was present in input, 0 otherwise + integer(I4B), dimension(:), pointer, contiguous :: iavert => null() ! cell vertex pointer ia array + integer(I4B), dimension(:), pointer, contiguous :: javert => null() ! cell vertex pointer ja array + integer(I4B), dimension(:), pointer, contiguous :: idomain => null() ! idomain (nodes) + logical(LGP) :: readFromFile ! True, when DIS is read from file (almost always) contains procedure :: dis_df => disu_df + procedure :: disu_load procedure :: dis_da => disu_da - procedure :: get_cellxy => get_cellxy_disu procedure :: get_dis_type => get_dis_type procedure :: disu_ck procedure :: grid_finalize @@ -62,12 +62,17 @@ module GwfDisuModule procedure :: allocate_scalars procedure :: allocate_arrays procedure :: allocate_arrays_mem - procedure :: read_options - procedure :: read_dimensions - procedure :: read_mf6_griddata - procedure :: read_connectivity - procedure :: read_vertices - procedure :: read_cell2d + procedure :: source_options + procedure :: source_dimensions + procedure :: source_griddata + procedure :: source_connectivity + procedure :: source_vertices + procedure :: source_cell2d + procedure :: log_options + procedure :: log_dimensions + procedure :: log_griddata + procedure :: log_connectivity + procedure :: define_cellverts procedure :: write_grb ! ! -- Read a node-sized model array (reduced or not) @@ -75,7 +80,7 @@ module GwfDisuModule procedure :: read_dbl_array end type GwfDisuType - contains +contains subroutine disu_cr(dis, name_model, inunit, iout) ! ****************************************************************************** @@ -84,6 +89,9 @@ subroutine disu_cr(dis, name_model, inunit, iout) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules + use IdmMf6FileLoaderModule, only: input_load + use ConstantsModule, only: LENPACKAGETYPE ! -- dummy class(DisBaseType), pointer :: dis character(len=*), intent(in) :: name_model @@ -91,10 +99,13 @@ subroutine disu_cr(dis, name_model, inunit, iout) integer(I4B), intent(in) :: iout ! -- local type(GwfDisuType), pointer :: disnew + character(len=*), parameter :: fmtheader = & + "(1X, /1X, 'DISU -- UNSTRUCTURED GRID DISCRETIZATION PACKAGE,', & + &' VERSION 2 : 3/27/2014 - INPUT READ FROM UNIT ', I0, //)" ! ------------------------------------------------------------------------------ ! ! -- Create a new discretization object - allocate(disnew) + allocate (disnew) dis => disnew ! ! -- Allocate scalars and assign data @@ -102,132 +113,64 @@ subroutine disu_cr(dis, name_model, inunit, iout) dis%inunit = inunit dis%iout = iout ! - ! -- Initialize block parser - call dis%parser%Initialize(dis%inunit, dis%iout) + ! -- if reading from file + if (inunit > 0) then + ! + ! -- Identify package + if (iout > 0) then + write (iout, fmtheader) inunit + end if + ! + ! -- initialize parser and load the disu input file + call dis%parser%Initialize(inunit, iout) + ! + ! -- Use the input data model routines to load the input data + ! into memory + call input_load(dis%parser, 'DISU6', 'GWF', 'DISU', name_model, 'DISU', & + [character(len=LENPACKAGETYPE) ::], iout) + ! + ! -- load disu + call disnew%disu_load() + end if ! ! -- Return return end subroutine disu_cr - - subroutine disu_init_mem(dis, name_model, iout, nodes, nja, & - top, bot, area, iac, ja, ihc, cl12, hwva, angldegx, & - nvert, vertices, cellxy, idomain) + + subroutine disu_load(this) ! ****************************************************************************** -! dis_init_mem -- Create a new unstructured discretization object from memory +! disu_load -- transfer data into this discretization object ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - class(DisBaseType), pointer :: dis - character(len=*), intent(in) :: name_model - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: nodes - integer(I4B), intent(in) :: nja - real(DP), dimension(:), pointer, contiguous, intent(in) :: top - real(DP), dimension(:), pointer, contiguous, intent(in) :: bot - real(DP), dimension(:), pointer, contiguous, intent(in) :: area - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: iac - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ja - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ihc - real(DP), dimension(:), pointer, contiguous, intent(in) :: cl12 - real(DP), dimension(:), pointer, contiguous, intent(in) :: hwva - real(DP), dimension(:), pointer, contiguous, intent(in), optional :: angldegx - integer(I4B), intent(in), optional :: nvert - integer(I4B), dimension(:, :), pointer, contiguous, intent(in), & - optional :: vertices - integer(I4B), dimension(:, :), pointer, contiguous, intent(in), & - optional :: cellxy - integer(I4B), dimension(:), pointer, contiguous, intent(in), & - optional :: idomain - ! -- local - type(GwfDisuType), pointer :: disext - integer(I4B) :: n - integer(I4B) :: j - integer(I4B) :: ival - real(DP), dimension(:), pointer, contiguous :: atemp + use MemoryHelperModule, only: create_mem_path + ! -- dummy + class(GwfDisuType) :: this ! ------------------------------------------------------------------------------ - allocate(disext) - dis => disext - call disext%allocate_scalars(name_model) - dis%inunit = 0 - dis%iout = iout - ! - ! -- set dimensions - disext%nodes = nodes - disext%nja = nja - if (present(nvert)) then - disext%nvert = nvert - end if ! - ! -- Calculate nodesuser - disext%nodesuser = disext%nodes + ! -- source input data + call this%source_options() + call this%source_dimensions() + call this%source_griddata() + call this%source_connectivity() ! - ! -- Allocate vectors for disu - call disext%allocate_arrays() - ! - ! -- fill data - do n = 1, disext%nodes - disext%top(n) = top(n) - disext%bot(n) = bot(n) - disext%area(n) = area(n) - disext%con%ia(n) = iac(n) - if (present(idomain)) then - ival = idomain(n) - else - ival = 1 - end if - disext%idomain(n) = ival - end do - call iac_to_ia(disext%con%ia) - do n = 1, nja - disext%con%ja(n) = ja(n) - end do - if (present(nvert)) then - if (present(vertices)) then - do n = 1, disext%nvert - do j = 1, 2 - disext%vertices(j, n) = vertices(j, n) - end do - end do - ! -- error - else - end if - if (present(cellxy)) then - do n = 1, disext%nodes - do j = 1, 2 - disext%cellxy(j, n) = cellxy(j, n) - end do - end do - ! -- error - else - end if + ! -- If NVERT specified and greater than 0, then source VERTICES and CELL2D + if (this%nvert > 0) then + call this%source_vertices() + call this%source_cell2d() else ! -- connection direction information cannot be calculated - disext%icondir = 0 + this%icondir = 0 end if ! - ! -- allocate space for atemp and fill - allocate(atemp(nja)) - if (present(angldegx)) then - disext%con%ianglex = 1 - do n = 1, nja - atemp(n) = angldegx(n) - end do - end if - ! - ! -- finalize connection data - call disext%con%con_finalize(ihc, cl12, hwva, atemp) - disext%njas = disext%con%njas - ! - ! -- deallocate temp arrays - deallocate(atemp) - ! - ! -- Make some final disu checks - call disext%disu_ck() + ! -- Make some final disu checks on the non-reduced user-provided + ! input + call this%disu_ck() ! ! -- Return return - end subroutine disu_init_mem + end subroutine disu_load subroutine disu_df(this) ! ****************************************************************************** @@ -240,34 +183,7 @@ subroutine disu_df(this) class(GwfDisuType) :: this ! ------------------------------------------------------------------------------ ! - ! -- read data from file - if (this%inunit /= 0) then - ! - ! -- Identify package - write(this%iout,1) this%inunit - 1 format(1X,/1X,'DISU -- UNSTRUCTURED GRID DISCRETIZATION PACKAGE,', & - ' VERSION 2 : 3/27/2014 - INPUT READ FROM UNIT ',I0,//) - ! - call this%read_options() - call this%read_dimensions() - call this%read_mf6_griddata() - call this%read_connectivity() - ! - ! -- If NVERT specified and greater than 0, then read VERTICES and CELL2D - if(this%nvert > 0) then - call this%read_vertices() - call this%read_cell2d() - else - ! -- connection direction information cannot be calculated - this%icondir = 0 - endif - end if - ! - ! -- Make some final disu checks on the non-reduced user-provided - ! input - call this%disu_ck() - ! - ! -- Finalize the grid by creating the connection object and reducing the + ! -- Finalize the grid by creating the connection object and reducing the ! grid using IDOMAIN, if necessary call this%grid_finalize() ! @@ -283,8 +199,7 @@ subroutine grid_finalize(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use MemoryManagerModule, only: mem_allocate + use MemoryManagerModule, only: mem_allocate, mem_reallocate ! -- dummy class(GwfDisuType) :: this ! -- locals @@ -294,32 +209,32 @@ subroutine grid_finalize(this) integer(I4B) :: nrsize ! -- formats character(len=*), parameter :: fmtdz = & - "('ERROR. CELL (',i0,',',i0,',',i0,') THICKNESS <= 0. ', " // & - "'TOP, BOT: ',2(1pg24.15))" + "('CELL (',i0,',',i0,',',i0,') THICKNESS <= 0. ', & + &'TOP, BOT: ',2(1pg24.15))" character(len=*), parameter :: fmtnr = & - "(/1x, 'THE SPECIFIED IDOMAIN RESULTS IN A REDUCED NUMBER OF CELLS.'," // & - "/1x, 'NUMBER OF USER NODES: ',I0," // & - "/1X, 'NUMBER OF NODES IN SOLUTION: ', I0, //)" + "(/1x, 'The specified IDOMAIN results in a reduced number of cells.',& + &/1x, 'Number of user nodes: ',I0,& + &/1X, 'Number of nodes in solution: ', I0, //)" ! ------------------------------------------------------------------------------ ! ! -- count active cells this%nodes = 0 do n = 1, this%nodesuser - if(this%idomain(n) > 0) this%nodes = this%nodes + 1 - enddo + if (this%idomain(n) > 0) this%nodes = this%nodes + 1 + end do ! ! -- Check to make sure nodes is a valid number if (this%nodes == 0) then - call store_error('ERROR. MODEL DOES NOT HAVE ANY ACTIVE NODES.') - call store_error('MAKE SURE IDOMAIN ARRAY HAS SOME VALUES GREATER & - &THAN ZERO.') + call store_error('Model does not have any active nodes. & + &Ensure IDOMAIN array has some values greater & + &than zero.') call this%parser%StoreErrorUnit() end if ! ! -- Write message if reduced grid - if(this%nodes < this%nodesuser) then - write(this%iout, fmtnr) this%nodesuser, this%nodes - endif + if (this%nodes < this%nodesuser) then + write (this%iout, fmtnr) this%nodesuser, this%nodes + end if ! ! -- Array size is now known, so allocate call this%allocate_arrays() @@ -328,51 +243,65 @@ subroutine grid_finalize(this) ! a negative number to indicate it is a pass-through cell, or ! a zero to indicate that the cell is excluded from the ! solution. (negative idomain not supported for disu) - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then noder = 1 do node = 1, this%nodesuser - if(this%idomain(node) > 0) then + if (this%idomain(node) > 0) then this%nodereduced(node) = noder noder = noder + 1 - elseif(this%idomain(node) < 0) then + elseif (this%idomain(node) < 0) then this%nodereduced(node) = -1 else this%nodereduced(node) = 0 - endif - enddo - endif + end if + end do + end if ! ! -- Fill nodeuser if a reduced grid - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then noder = 1 do node = 1, this%nodesuser - if(this%idomain(node) > 0) then + if (this%idomain(node) > 0) then this%nodeuser(noder) = node noder = noder + 1 - endif - enddo - endif + end if + end do + end if ! ! -- Move top1d, bot1d, and area1d into top, bot, and area do node = 1, this%nodesuser noder = node - if(this%nodes < this%nodesuser) noder = this%nodereduced(node) - if(noder <= 0) cycle + if (this%nodes < this%nodesuser) noder = this%nodereduced(node) + if (noder <= 0) cycle this%top(noder) = this%top1d(node) this%bot(noder) = this%bot1d(node) this%area(noder) = this%area1d(node) - enddo + end do + ! + ! -- fill cell center coordinates + if (this%nvert > 0) then + do node = 1, this%nodesuser + noder = node + if (this%nodes < this%nodesuser) noder = this%nodereduced(node) + if (noder <= 0) cycle + this%xc(noder) = this%cellxy(1, node) + this%yc(noder) = this%cellxy(2, node) + end do + else + call mem_reallocate(this%xc, 0, 'XC', this%memoryPath) + call mem_reallocate(this%yc, 0, 'YC', this%memoryPath) + end if ! ! -- create and fill the connections object nrsize = 0 - if(this%nodes < this%nodesuser) nrsize = this%nodes - allocate(this%con) - call this%con%disuconnections(this%name_model, this%nodes, & - this%nodesuser, nrsize, & - this%nodereduced, this%nodeuser, & - this%iainp, this%jainp, & - this%ihcinp, this%cl12inp, & - this%hwvainp, this%angldegxinp, & + if (this%nodes < this%nodesuser) nrsize = this%nodes + allocate (this%con) + call this%con%disuconnections(this%name_model, this%nodes, & + this%nodesuser, nrsize, & + this%nodereduced, this%nodeuser, & + this%iainp, this%jainp, & + this%ihcinp, this%cl12inp, & + this%hwvainp, this%angldegxinp, & this%iangledegx) this%nja = this%con%nja this%njas = this%con%njas @@ -398,19 +327,19 @@ subroutine disu_ck(this) real(DP) :: dz ! -- formats character(len=*), parameter :: fmtidm = & - "('Invalid idomain value ', i0, ' specified for node ', i0)" + &"('Invalid idomain value ', i0, ' specified for node ', i0)" character(len=*), parameter :: fmtdz = & - "('Cell ', i0, ' with thickness <= 0. Top, bot: ', 2(1pg24.15))" + &"('Cell ', i0, ' with thickness <= 0. Top, bot: ', 2(1pg24.15))" character(len=*), parameter :: fmtarea = & - "('Cell ', i0, ' with area <= 0. Area: ', 1(1pg24.15))" + &"('Cell ', i0, ' with area <= 0. Area: ', 1(1pg24.15))" character(len=*), parameter :: fmtjan = & - "('Cell ', i0, ' must have its first connection be itself. Found: ', i0)" + &"('Cell ', i0, ' must have its first connection be itself. Found: ', i0)" character(len=*), parameter :: fmtjam = & - "('Cell ', i0, ' has invalid connection in JA. Found: ', i0)" - character(len=*),parameter :: fmterrmsg = & + &"('Cell ', i0, ' has invalid connection in JA. Found: ', i0)" + character(len=*), parameter :: fmterrmsg = & "('Top elevation (', 1pg15.6, ') for cell ', i0, ' is above bottom & &elevation (', 1pg15.6, ') for cell ', i0, '. Based on node numbering & - &rules cell ', i0, ' must be below cell ', i0, '.')" + &rules cell ', i0, ' must be below cell ', i0, '.')" ! ------------------------------------------------------------------------------ ! ! -- Check connectivity @@ -425,7 +354,7 @@ subroutine disu_ck(this) this%jainp(ipos) = m end if if (n /= m) then - write(errmsg, fmtjan) n, m + write (errmsg, fmtjan) n, m call store_error(errmsg) end if ! @@ -434,26 +363,26 @@ subroutine disu_ck(this) m = this%jainp(ipos) if (m < 0 .or. m > this%nodesuser) then ! -- make sure first connection is to itself - write(errmsg, fmtjam) n, m - call store_error(errmsg) - end if + write (errmsg, fmtjam) n, m + call store_error(errmsg) + end if end do end do ! ! -- terminate if errors found - if(count_errors() > 0) then + if (count_errors() > 0) then if (this%inunit > 0) then call store_error_unit(this%inunit) end if - endif + end if ! ! -- Ensure idomain values are valid do n = 1, this%nodesuser - if(this%idomain(n) > 1 .or. this%idomain(n) < 0) then - write(errmsg, fmtidm) this%idomain(n), n + if (this%idomain(n) > 1 .or. this%idomain(n) < 0) then + write (errmsg, fmtidm) this%idomain(n), n call store_error(errmsg) end if - enddo + end do ! ! -- Check for zero and negative thickness and zero or negative areas ! for cells with idomain == 1 @@ -461,19 +390,19 @@ subroutine disu_ck(this) if (this%idomain(n) == 1) then dz = this%top1d(n) - this%bot1d(n) if (dz <= DZERO) then - write(errmsg, fmt=fmtdz) n, this%top1d(n), this%bot1d(n) + write (errmsg, fmt=fmtdz) n, this%top1d(n), this%bot1d(n) call store_error(errmsg) - endif + end if if (this%area1d(n) <= DZERO) then - write(errmsg, fmt=fmtarea) n, this%area1d(n) + write (errmsg, fmt=fmtarea) n, this%area1d(n) call store_error(errmsg) - endif + end if end if - enddo + end do ! ! -- check to make sure voffsettol is >= 0 if (this%voffsettol < DZERO) then - write(errmsg, '(a, 1pg15.6)') & + write (errmsg, '(a, 1pg15.6)') & 'Vertical offset tolerance must be greater than zero. Found ', & this%voffsettol call store_error(errmsg) @@ -489,9 +418,9 @@ subroutine disu_ck(this) m = this%jainp(ipos) ihc = this%ihcinp(ipos) if (ihc == 0 .and. m > n) then - dz = this%top1d(m) - this%bot1d(n) + dz = this%top1d(m) - this%bot1d(n) if (dz > this%voffsettol) then - write(errmsg, fmterrmsg) this%top1d(m), m, this%bot1d(n), n, m, n + write (errmsg, fmterrmsg) this%top1d(m), m, this%bot1d(n), n, m, n call store_error(errmsg) end if end if @@ -499,11 +428,11 @@ subroutine disu_ck(this) end do ! ! -- terminate if errors found - if(count_errors() > 0) then + if (count_errors() > 0) then if (this%inunit > 0) then call store_error_unit(this%inunit) end if - endif + end if ! ! -- Return return @@ -518,10 +447,17 @@ subroutine disu_da(this) ! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_deallocate + use MemoryManagerExtModule, only: memorylist_remove + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisuType) :: this ! ------------------------------------------------------------------------------ ! + ! -- Deallocate idm memory + call memorylist_remove(this%name_model, 'DISU', idm_context) + call memorylist_remove(component=this%name_model, & + context=idm_context) + ! ! -- scalars call mem_deallocate(this%njausr) call mem_deallocate(this%nvert) @@ -532,7 +468,7 @@ subroutine disu_da(this) if (this%readFromFile) then call mem_deallocate(this%top1d) call mem_deallocate(this%bot1d) - call mem_deallocate(this%area1d) + call mem_deallocate(this%area1d) if (associated(this%iavert)) then call mem_deallocate(this%iavert) call mem_deallocate(this%javert) @@ -543,13 +479,12 @@ subroutine disu_da(this) call mem_deallocate(this%ihcinp) call mem_deallocate(this%cl12inp) call mem_deallocate(this%hwvainp) - call mem_deallocate(this%angldegxinp) + call mem_deallocate(this%angldegxinp) end if call mem_deallocate(this%idomain) call mem_deallocate(this%cellxy) - call mem_deallocate(this%nodeuser) call mem_deallocate(this%nodereduced) ! @@ -576,8 +511,8 @@ subroutine nodeu_to_string(this, nodeu, str) character(len=10) :: nstr ! ------------------------------------------------------------------------------ ! - write(nstr, '(i0)') nodeu - str = '(' // trim(adjustl(nstr)) // ')' + write (nstr, '(i0)') nodeu + str = '('//trim(adjustl(nstr))//')' ! ! -- return return @@ -603,8 +538,8 @@ subroutine nodeu_to_array(this, nodeu, arr) ! -- check the size of arr isize = size(arr) if (isize /= this%ndim) then - write(errmsg,'(a,i0,a,i0,a)') & - 'Program error: nodeu_to_array size of array (', isize, & + write (errmsg, '(a,i0,a,i0,a)') & + 'Program error: nodeu_to_array size of array (', isize, & ') is not equal to the discretization dimension (', this%ndim, ')' call store_error(errmsg, terminate=.TRUE.) end if @@ -616,155 +551,161 @@ subroutine nodeu_to_array(this, nodeu, arr) return end subroutine nodeu_to_array - subroutine read_options(this) + !> @brief Write user options to list file + !< + subroutine log_options(this, found) + use GwfDisuInputModule, only: GwfDisuParamFoundType + class(GwfDisuType) :: this + type(GwfDisuParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Options' + + if (found%length_units) then + write (this%iout, '(4x,a,i0)') 'Model length unit [0=UND, 1=FEET, & + &2=METERS, 3=CENTIMETERS] set as ', this%lenuni + end if + + if (found%nogrb) then + write (this%iout, '(4x,a,i0)') 'Binary grid file [0=GRB, 1=NOGRB] & + &set as ', this%nogrb + end if + + if (found%xorigin) then + write (this%iout, '(4x,a,G0)') 'XORIGIN = ', this%xorigin + end if + + if (found%yorigin) then + write (this%iout, '(4x,a,G0)') 'YORIGIN = ', this%yorigin + end if + + if (found%angrot) then + write (this%iout, '(4x,a,G0)') 'ANGROT = ', this%angrot + end if + + if (found%voffsettol) then + write (this%iout, '(4x,a,G0)') 'VERTICAL_OFFSET_TOLERANCE = ', & + this%voffsettol + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Options' + + end subroutine log_options + + !> @brief Copy options from IDM into package + !< + subroutine source_options(this) ! ****************************************************************************** -! read_options -- Read discretization options +! source_options -- source options from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use MemoryManagerModule, only: mem_allocate - use ConstantsModule, only: LINELENGTH - use SimModule, only: count_errors, store_error - implicit none + ! -- modules + use KindModule, only: LGP + use MemoryHelperModule, only: create_mem_path + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisuInputModule, only: GwfDisuParamFoundType + ! -- dummy class(GwfDisuType) :: this - character(len=LINELENGTH) :: keyword - integer(I4B) :: ierr, nerr - logical :: isfound, endOfBlock + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + character(len=LENVARNAME), dimension(3) :: lenunits = & + &[character(len=LENVARNAME) :: 'FEET', 'METERS', 'CENTIMETERS'] + type(GwfDisuParamFoundType) :: found ! ------------------------------------------------------------------------------ ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - ! - ! -- set default options - this%lenuni = 0 - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING DISCRETIZATION OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('LENGTH_UNITS') - call this%parser%GetStringCaps(keyword) - if(keyword=='FEET') then - this%lenuni = 1 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS FEET' - elseif(keyword=='METERS') then - this%lenuni = 2 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS METERS' - elseif(keyword=='CENTIMETERS') then - this%lenuni = 3 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS CENTIMETERS' - else - write(this%iout,'(4x,a)')'UNKNOWN UNIT: ',trim(keyword) - write(this%iout,'(4x,a)')'SETTING TO: ','UNDEFINED' - endif - case('NOGRB') - write(this%iout,'(4x,a)') 'BINARY GRB FILE WILL NOT BE WRITTEN' - this%writegrb = .false. - case('XORIGIN') - this%xorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'XORIGIN SPECIFIED AS ', & - this%xorigin - case('YORIGIN') - this%yorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'YORIGIN SPECIFIED AS ', & - this%yorigin - case('ANGROT') - this%angrot = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'ANGROT SPECIFIED AS ', & - this%angrot - case('VERTICAL_OFFSET_TOLERANCE') - this%voffsettol = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') & - 'VERTICAL OFFSET TOLERANCE SPECIFIED AS ', this%voffsettol - case default - write(errmsg,'(a)')'Unknown DISU option: ' // trim(keyword) - call store_error(errmsg) - end select - end do - write(this%iout,'(1x,a)')'END OF DISCRETIZATION OPTIONS' - else - write(this%iout,'(1x,a)')'NO OPTION BLOCK DETECTED.' + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%lenuni, 'LENGTH_UNITS', idmMemoryPath, lenunits, & + found%length_units) + call mem_set_value(this%nogrb, 'NOGRB', idmMemoryPath, found%nogrb) + call mem_set_value(this%xorigin, 'XORIGIN', idmMemoryPath, found%xorigin) + call mem_set_value(this%yorigin, 'YORIGIN', idmMemoryPath, found%yorigin) + call mem_set_value(this%angrot, 'ANGROT', idmMemoryPath, found%angrot) + call mem_set_value(this%voffsettol, 'VOFFSETTOL', idmMemoryPath, & + found%voffsettol) + ! + ! -- log values to list file + if (this%iout > 0) then + call this%log_options(found) end if - if(this%lenuni==0) write(this%iout,'(1x,a)') 'MODEL LENGTH UNIT IS UNDEFINED' - ! - nerr = count_errors() - if(nerr > 0) then - call this%parser%StoreErrorUnit() - endif ! ! -- Return return - end subroutine read_options + end subroutine source_options + + !> @brief Write dimensions to list file + !< + subroutine log_dimensions(this, found) + use GwfDisuInputModule, only: GwfDisuParamFoundType + class(GwfDisuType) :: this + type(GwfDisuParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Dimensions' + + if (found%nodes) then + write (this%iout, '(4x,a,i0)') 'NODES = ', this%nodesuser + end if + + if (found%nja) then + write (this%iout, '(4x,a,i0)') 'NJA = ', this%njausr + end if + + if (found%nvert) then + write (this%iout, '(4x,a,i0)') 'NVERT = ', this%nvert + end if - subroutine read_dimensions(this) + write (this%iout, '(1x,a,/)') 'End Setting Discretization Dimensions' + + end subroutine log_dimensions + + !> @brief Copy dimensions from IDM into package + !< + subroutine source_dimensions(this) ! ****************************************************************************** -! read_dimensions -- Read discretization information from file +! source_dimensions -- source dimensions from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use MemoryManagerModule, only: mem_allocate - use ConstantsModule, only: LINELENGTH - use SimModule, only: count_errors, store_error - implicit none + use KindModule, only: LGP + use MemoryHelperModule, only: create_mem_path + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisuInputModule, only: GwfDisuParamFoundType + ! -- dummy class(GwfDisuType) :: this - character(len=LINELENGTH) :: keyword - integer(I4B) :: n, ierr - logical :: isfound, endOfBlock + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + integer(I4B) :: n + type(GwfDisuParamFoundType) :: found ! ------------------------------------------------------------------------------ ! - ! -- Initialize dimensions - this%nodesuser = -1 - this%njausr = -1 - ! - ! -- get options block - call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING DISCRETIZATION DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('NODES') - this%nodesuser = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NODES = ', this%nodesuser - case ('NJA') - this%njausr = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NJA = ', this%njausr - case ('NVERT') - this%nvert = this%parser%GetInteger() - write(this%iout,'(3x,a,i0)') 'NVERT = ', this%nvert - write(this%iout,'(3x,a)') 'VERTICES AND CELL2D BLOCKS WILL ' // & - 'BE READ BELOW. ' - case default - write(errmsg,'(a)') 'Unknown DISU dimension: ' // trim(keyword) - call store_error(errmsg) - end select - end do - write(this%iout,'(1x,a)') 'END OF DISCRETIZATION OPTIONS' - else - call store_error('Required dimensions block not found.') + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%nodesuser, 'NODES', idmMemoryPath, found%nodes) + call mem_set_value(this%njausr, 'NJA', idmMemoryPath, found%nja) + call mem_set_value(this%nvert, 'NVERT', idmMemoryPath, found%nvert) + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_dimensions(found) end if ! ! -- verify dimensions were set - if(this%nodesuser < 1) then + if (this%nodesuser < 1) then call store_error( & - 'NODES was not specified or was specified incorrectly.') - endif - if(this%njausr < 1) then + 'NODES was not specified or was specified incorrectly.') + end if + if (this%njausr < 1) then call store_error( & - 'NJA was not specified or was specified incorrectly.') - endif + 'NJA was not specified or was specified incorrectly.') + end if ! ! -- terminate if errors were detected if (count_errors() > 0) then @@ -783,12 +724,13 @@ subroutine read_dimensions(this) call mem_allocate(this%ihcinp, this%njausr, 'IHCINP', this%memoryPath) call mem_allocate(this%cl12inp, this%njausr, 'CL12INP', this%memoryPath) call mem_allocate(this%hwvainp, this%njausr, 'HWVAINP', this%memoryPath) - call mem_allocate(this%angldegxinp, this%njausr, 'ANGLDEGXINP', this%memoryPath) - if(this%nvert > 0) then + call mem_allocate(this%angldegxinp, this%njausr, 'ANGLDEGXINP', & + this%memoryPath) + if (this%nvert > 0) then call mem_allocate(this%cellxy, 2, this%nodesuser, 'CELLXY', this%memoryPath) else call mem_allocate(this%cellxy, 2, 0, 'CELLXY', this%memoryPath) - endif + end if ! ! -- initialize all cells to be active (idomain = 1) do n = 1, this%nodesuser @@ -797,410 +739,317 @@ subroutine read_dimensions(this) ! ! -- Return return - end subroutine read_dimensions + end subroutine source_dimensions + + !> @brief Write griddata found to list file + !< + subroutine log_griddata(this, found) + use GwfDisuInputModule, only: GwfDisuParamFoundType + class(GwfDisuType) :: this + type(GwfDisuParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Griddata' + + if (found%top) then + write (this%iout, '(4x,a)') 'TOP set from input file' + end if + + if (found%bot) then + write (this%iout, '(4x,a)') 'BOT set from input file' + end if + + if (found%area) then + write (this%iout, '(4x,a)') 'AREA set from input file' + end if + + if (found%idomain) then + write (this%iout, '(4x,a)') 'IDOMAIN set from input file' + end if - subroutine read_mf6_griddata(this) + write (this%iout, '(1x,a,/)') 'End Setting Discretization Griddata' + + end subroutine log_griddata + + subroutine source_griddata(this) ! ****************************************************************************** -! read_mf6_griddata -- Read discretization data +! source_griddata -- source griddata from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use MemoryManagerModule, only: mem_allocate + use MemoryHelperModule, only: create_mem_path + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisuInputModule, only: GwfDisuParamFoundType ! -- dummy class(GwfDisuType) :: this - ! -- local - character(len=LINELENGTH) :: keyword - integer(I4B) :: n - integer(I4B) :: ierr - logical :: isfound, endOfBlock - integer(I4B), parameter :: nname = 4 - logical,dimension(nname) :: lname - character(len=24),dimension(nname) :: aname(nname) + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + type(GwfDisuParamFoundType) :: found ! -- formats - ! -- data - data aname(1) /' TOP'/ - data aname(2) /' BOT'/ - data aname(3) /' AREA'/ - data aname(4) /' IDOMAIN'/ ! ------------------------------------------------------------------------------ ! - ! -- get disdata block - call this%parser%GetBlock('GRIDDATA', isfound, ierr) - lname(:) = .false. - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('TOP') - call ReadArray(this%parser%iuactive, this%top1d, aname(1), & - this%ndim, this%nodesuser, this%iout, 0) - lname(1) = .true. - case ('BOT') - call ReadArray(this%parser%iuactive, this%bot1d, aname(2), & - this%ndim, this%nodesuser, this%iout, 0) - lname(2) = .true. - case ('AREA') - call ReadArray(this%parser%iuactive, this%area1d, aname(3), & - this%ndim, this%nodesuser, this%iout, 0) - lname(3) = .true. - case ('IDOMAIN') - call ReadArray(this%parser%iuactive, this%idomain, aname(4), & - this%ndim, this%nodesuser, this%iout, 0) - lname(4) = .true. - case default - write(errmsg,'(a)') 'Unknown GRIDDATA tag: ' // trim(keyword) - call store_error(errmsg) - end select - end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' - else - call store_error('Required GRIDDATA block not found.') - end if + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) ! - ! -- verify all items were read - do n = 1, nname - if (n == 4) cycle - if(.not. lname(n)) then - write(errmsg,'(a)') 'Required input was not specified: ', trim(aname(n)) - call store_error(errmsg) - endif - enddo + ! -- update defaults with idm sourced values + call mem_set_value(this%top1d, 'TOP', idmMemoryPath, found%top) + call mem_set_value(this%bot1d, 'BOT', idmMemoryPath, found%bot) + call mem_set_value(this%area1d, 'AREA', idmMemoryPath, found%area) + call mem_set_value(this%idomain, 'IDOMAIN', idmMemoryPath, found%idomain) ! - ! -- terminate if errors were detected - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + ! -- log simulation values + if (this%iout > 0) then + call this%log_griddata(found) end if ! ! -- Return return - end subroutine read_mf6_griddata + end subroutine source_griddata + + !> @brief Write griddata found to list file + !< + subroutine log_connectivity(this, found, iac) + use GwfDisuInputModule, only: GwfDisuParamFoundType + class(GwfDisuType) :: this + type(GwfDisuParamFoundType), intent(in) :: found + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: iac + + write (this%iout, '(1x,a)') 'Setting Discretization Connectivity' + + if (associated(iac)) then + write (this%iout, '(4x,a)') 'IAC set from input file' + end if + + if (found%ja) then + write (this%iout, '(4x,a)') 'JA set from input file' + end if + + if (found%ihc) then + write (this%iout, '(4x,a)') 'IHC set from input file' + end if - subroutine read_connectivity(this) + if (found%cl12) then + write (this%iout, '(4x,a)') 'CL12 set from input file' + end if + + if (found%hwva) then + write (this%iout, '(4x,a)') 'HWVA set from input file' + end if + + if (found%angldegx) then + write (this%iout, '(4x,a)') 'ANGLDEGX set from input file' + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Connectivity' + + end subroutine log_connectivity + + subroutine source_connectivity(this) ! ****************************************************************************** -! read_connectivity -- Read user-specified connectivity information +! source_connectivity -- source connection data from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH, DONE, DHALF, DPIO180, DNODATA - use SimModule, only: store_error, count_errors, store_error_unit + use MemoryHelperModule, only: create_mem_path + use MemoryManagerModule, only: mem_setptr + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisuInputModule, only: GwfDisuParamFoundType ! -- dummy class(GwfDisuType) :: this - ! -- local - character(len=LINELENGTH) :: keyword - integer(I4B) :: n - integer(I4B) :: ierr - logical :: isfound, endOfBlock - integer(I4B), parameter :: nname = 6 - logical,dimension(nname) :: lname - character(len=24),dimension(nname) :: aname(nname) + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + type(GwfDisuParamFoundType) :: found + integer(I4B), dimension(:), contiguous, pointer :: iac => null() ! -- formats - ! -- data - data aname(1) /' IAC'/ - data aname(2) /' JA'/ - data aname(3) /' IHC'/ - data aname(4) /' CL12'/ - data aname(5) /' HWVA'/ - data aname(6) /' ANGLDEGX'/ ! ------------------------------------------------------------------------------ ! - ! -- get connectiondata block - call this%parser%GetBlock('CONNECTIONDATA', isfound, ierr) - lname(:) = .false. - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING CONNECTIONDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('IAC') - call ReadArray(this%parser%iuactive, this%iainp, aname(1), 1, & - this%nodesuser, this%iout, 0) - lname(1) = .true. - ! - ! -- Convert iac to ia - call iac_to_ia(this%iainp) - case ('JA') - call ReadArray(this%parser%iuactive, this%jainp, aname(2), 1, & - this%njausr, this%iout, 0) - lname(2) = .true. - case ('IHC') - call ReadArray(this%parser%iuactive, this%ihcinp, aname(3), 1, & - this%njausr, this%iout, 0) - lname(3) = .true. - case ('CL12') - call ReadArray(this%parser%iuactive, this%cl12inp, aname(4), 1, & - this%njausr, this%iout, 0) - lname(4) = .true. - case ('HWVA') - call ReadArray(this%parser%iuactive, this%hwvainp, aname(5), 1, & - this%njausr, this%iout, 0) - lname(5) = .true. - case ('ANGLDEGX') - call ReadArray(this%parser%iuactive, this%angldegxinp, aname(6), 1, & - this%njausr, this%iout, 0) - lname(6) = .true. - case default - write(errmsg,'(4x,a,a)')'Unknown CONNECTIONDATA tag: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END PROCESSING CONNECTIONDATA' - else - call store_error('Required CONNECTIONDATA block not found.') - call this%parser%StoreErrorUnit() - end if + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) ! - ! -- store whether angledegx was read - if (lname(6)) this%iangledegx = 1 + ! -- update defaults with idm sourced values + call mem_set_value(this%jainp, 'JA', idmMemoryPath, found%ja) + call mem_set_value(this%ihcinp, 'IHC', idmMemoryPath, found%ihc) + call mem_set_value(this%cl12inp, 'CL12', idmMemoryPath, found%cl12) + call mem_set_value(this%hwvainp, 'HWVA', idmMemoryPath, found%hwva) + call mem_set_value(this%angldegxinp, 'ANGLDEGX', idmMemoryPath, & + found%angldegx) ! - ! -- verify all items were read - do n = 1, nname - ! - ! -- skip angledegx because it is not required - if(aname(n) == aname(6)) cycle - ! - ! -- error if not read - if(.not. lname(n)) then - write(errmsg,'(1x,a,a)') & - 'REQUIRED CONNECTIONDATA INPUT WAS NOT SPECIFIED: ', & - adjustl(trim(aname(n))) - call store_error(errmsg) - endif - enddo - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - endif - if (.not. lname(6)) then - write(this%iout, '(1x,a)') 'ANGLDEGX NOT FOUND IN CONNECTIONDATA ' // & - 'BLOCK. SOME CAPABILITIES MAY BE LIMITED.' - end if + ! -- set pointer to iac input array + call mem_setptr(iac, 'IAC', idmMemoryPath) + ! + ! -- Convert iac to ia + if (associated(iac)) call iac_to_ia(iac, this%iainp) + ! + ! -- Set angldegx flag if found + if (found%angldegx) this%iangledegx = 1 + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_connectivity(found, iac) + end if ! ! -- Return return - end subroutine read_connectivity + end subroutine source_connectivity - subroutine read_vertices(this) + subroutine source_vertices(this) ! ****************************************************************************** -! read_vertices -- Read data +! source_vertices -- source vertex data from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error + use MemoryManagerModule, only: mem_setptr + use MemoryHelperModule, only: create_mem_path + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisuType) :: this + ! -- local integer(I4B) :: i - integer(I4B) :: ierr, ival - logical :: isfound, endOfBlock - real(DP) :: xmin, xmax, ymin, ymax + character(len=LENMEMPATH) :: idmMemoryPath + real(DP), dimension(:), contiguous, pointer :: vert_x => null() + real(DP), dimension(:), contiguous, pointer :: vert_y => null() ! -- formats - character(len=*), parameter :: fmtvnum = & - "('ERROR. VERTEX NUMBER NOT CONSECUTIVE. LOOKING FOR ',i0," // & - "' BUT FOUND ', i0)" - character(len=*), parameter :: fmtnvert = & - "(3x, 'SUCCESSFULLY READ ',i0,' (X,Y) COORDINATES')" - character(len=*), parameter :: fmtcoord = & - "(3x, a,' COORDINATE = ', 1(1pg24.15))" ! ------------------------------------------------------------------------------ ! - ! --Read DISDATA block - call this%parser%GetBlock('VERTICES', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then - write(this%iout,'(/,1x,a)') 'PROCESSING VERTICES' + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) + ! + ! -- set pointers to memory manager input arrays + call mem_setptr(vert_x, 'XV', idmMemoryPath) + call mem_setptr(vert_y, 'YV', idmMemoryPath) + ! + ! -- set vertices 2d array + if (associated(vert_x) .and. associated(vert_y)) then do i = 1, this%nvert - call this%parser%GetNextLine(endOfBlock) - ! - ! -- vertex number - ival = this%parser%GetInteger() - if(ival /= i) then - write(errmsg, fmtvnum) i, ival - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - ! - ! -- x - this%vertices(1, i) = this%parser%GetDouble() - ! - ! -- y - this%vertices(2, i) = this%parser%GetDouble() - ! - ! -- set min/max coords - if(i == 1) then - xmin = this%vertices(1, i) - xmax = xmin - ymin = this%vertices(2, i) - ymax = ymin - else - xmin = min(xmin, this%vertices(1, i)) - xmax = max(xmax, this%vertices(1, i)) - ymin = min(ymin, this%vertices(2, i)) - ymax = max(ymax, this%vertices(2, i)) - endif - enddo - ! - ! -- Terminate the block - call this%parser%terminateblock() + this%vertices(1, i) = vert_x(i) + this%vertices(2, i) = vert_y(i) + end do else - call store_error('Required vertices block not found.') - call this%parser%StoreErrorUnit() + call store_error('Required Vertex arrays not found.') + end if + ! + ! -- log + if (this%iout > 0) then + write (this%iout, '(1x,a)') 'Discretization Vertex data loaded' end if ! - ! -- Write information - write(this%iout, fmtnvert) this%nvert - write(this%iout, fmtcoord) 'MINIMUM X', xmin - write(this%iout, fmtcoord) 'MAXIMUM X', xmax - write(this%iout, fmtcoord) 'MINIMUM Y', ymin - write(this%iout, fmtcoord) 'MAXIMUM Y', ymax - write(this%iout,'(1x,a)')'END PROCESSING VERTICES' + ! -- Return + return + end subroutine source_vertices + + subroutine define_cellverts(this, icell2d, ncvert, icvert) + ! -- modules + use SparseModule, only: sparsematrix + ! -- dummy + class(GwfDisuType) :: this + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icell2d + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: ncvert + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icvert + ! -- locals + type(sparsematrix) :: vert_spm + integer(I4B) :: i, j, ierr + integer(I4B) :: icv_idx, startvert, maxnnz = 5 +! ------------------------------------------------------------------------------ + ! + ! -- initialize sparse matrix + call vert_spm%init(this%nodesuser, this%nvert, maxnnz) + ! + ! -- add sparse matrix connections from input memory paths + icv_idx = 1 + do i = 1, this%nodesuser + if (icell2d(i) /= i) call store_error('ICELL2D input sequence violation.') + do j = 1, ncvert(i) + call vert_spm%addconnection(i, icvert(icv_idx), 0) + if (j == 1) then + startvert = icvert(icv_idx) + elseif (j == ncvert(i) .and. (icvert(icv_idx) /= startvert)) then + call vert_spm%addconnection(i, startvert, 0) + end if + icv_idx = icv_idx + 1 + end do + end do + ! + ! -- allocate and fill iavert and javert + call mem_allocate(this%iavert, this%nodesuser + 1, 'IAVERT', this%memoryPath) + call mem_allocate(this%javert, vert_spm%nnz, 'JAVERT', this%memoryPath) + call vert_spm%filliaja(this%iavert, this%javert, ierr) + call vert_spm%destroy() ! ! -- Return return - end subroutine read_vertices + end subroutine define_cellverts - subroutine read_cell2d(this) + subroutine source_cell2d(this) ! ****************************************************************************** -! read_cell2d -- Read information describing the two dimensional (x, y) -! configuration of each cell. +! source_cell2d -- source cell2d data from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use InputOutputModule, only: urword - use SparseModule, only: sparsematrix + use MemoryHelperModule, only: create_mem_path + use MemoryManagerModule, only: mem_setptr + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisuType) :: this - integer(I4B) :: i, j, ivert, ivert1, ncvert - integer(I4B) :: ierr, ival - logical :: isfound, endOfBlock - integer(I4B) :: maxvert, maxvertcell, iuext - real(DP) :: xmin, xmax, ymin, ymax - integer(I4B), dimension(:), allocatable :: maxnnz - type(sparsematrix) :: vertspm + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + integer(I4B), dimension(:), contiguous, pointer :: icell2d => null() + integer(I4B), dimension(:), contiguous, pointer :: ncvert => null() + integer(I4B), dimension(:), contiguous, pointer :: icvert => null() + real(DP), dimension(:), contiguous, pointer :: cell_x => null() + real(DP), dimension(:), contiguous, pointer :: cell_y => null() + integer(I4B) :: i ! -- formats - character(len=*), parameter :: fmtcnum = & - "('ERROR. CELL NUMBER NOT CONSECUTIVE. LOOKING FOR ',i0," // & - "' BUT FOUND ', i0)" - character(len=*), parameter :: fmtncpl = & - "(3x, 'SUCCESSFULLY READ ',i0,' CELL2D INFORMATION ENTRIES')" - character(len=*), parameter :: fmtcoord = & - "(3x, a,' CELL CENTER = ', 1(1pg24.15))" - character(len=*), parameter :: fmtmaxvert = & - "(3x, 'MAXIMUM NUMBER OF CELL2D VERTICES IS ',i0,' FOR CELL ', i0)" ! ------------------------------------------------------------------------------ ! - ! -- initialize - maxvert = 0 - maxvertcell = 0 + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISU', idm_context) ! - ! -- Initialize estimate of the max number of vertices for each cell - ! (using 5 as default) and initialize the sparse matrix, which will - ! temporarily store the vertex numbers for each cell. This will - ! be converted to iavert and javert after all cell vertices have - ! been read. - allocate(maxnnz(this%nodesuser)) - do i = 1, this%nodesuser - maxnnz(i) = 5 - enddo - call vertspm%init(this%nodesuser, this%nvert, maxnnz) - ! - ! --Read CELL2D block - call this%parser%GetBlock('CELL2D', isfound, ierr, supportOpenClose=.true.) - if(isfound) then - write(this%iout,'(/,1x,a)') 'PROCESSING CELL2D' + ! -- set pointers to input path ncvert and icvert + call mem_setptr(icell2d, 'ICELL2D', idmMemoryPath) + call mem_setptr(ncvert, 'NCVERT', idmMemoryPath) + call mem_setptr(icvert, 'ICVERT', idmMemoryPath) + ! + ! -- + if (associated(icell2d) .and. associated(ncvert) & + .and. associated(icvert)) then + call this%define_cellverts(icell2d, ncvert, icvert) + else + call store_error('Required cell vertex arrays not found.') + end if + ! + ! -- set pointers to cell center arrays + call mem_setptr(cell_x, 'XC', idmMemoryPath) + call mem_setptr(cell_y, 'YC', idmMemoryPath) + ! + ! -- set cell centers + if (associated(cell_x) .and. associated(cell_y)) then do i = 1, this%nodesuser - call this%parser%GetNextLine(endOfBlock) - ! - ! -- cell number - ival = this%parser%GetInteger() - if(ival /= i) then - write(errmsg, fmtcnum) i, ival - call store_error(errmsg) - call store_error_unit(iuext) - endif - ! - ! -- Cell x center - this%cellxy(1, i) = this%parser%GetDouble() - ! - ! -- Cell y center - this%cellxy(2, i) = this%parser%GetDouble() - ! - ! -- Number of vertices for this cell - ncvert = this%parser%GetInteger() - if(ncvert > maxvert) then - maxvert = ncvert - maxvertcell = i - endif - ! - ! -- Read each vertex number, and then close the polygon if - ! the last vertex does not equal the first vertex - do j = 1, ncvert - ivert = this%parser%GetInteger() - call vertspm%addconnection(i, ivert, 0) - ! - ! -- If necessary, repeat the last vertex in order to close the cell - if(j == 1) then - ivert1 = ivert - elseif(j == ncvert) then - if(ivert1 /= ivert) then - call vertspm%addconnection(i, ivert1, 0) - endif - endif - enddo - ! - ! -- set min/max coords - if(i == 1) then - xmin = this%cellxy(1, i) - xmax = xmin - ymin = this%cellxy(2, i) - ymax = ymin - else - xmin = min(xmin, this%cellxy(1, i)) - xmax = max(xmax, this%cellxy(1, i)) - ymin = min(ymin, this%cellxy(2, i)) - ymax = max(ymax, this%cellxy(2, i)) - endif - enddo - ! - ! -- Terminate the block - call this%parser%terminateblock() + this%cellxy(1, i) = cell_x(i) + this%cellxy(2, i) = cell_y(i) + end do else - call store_error('Required CELL2D block not found.') - call this%parser%StoreErrorUnit() + call store_error('Required cell center arrays not found.') end if ! - ! -- Convert vertspm into ia/ja form - call mem_allocate(this%iavert, this%nodesuser + 1, 'IAVERT', this%memoryPath) - call mem_allocate(this%javert, vertspm%nnz, 'JAVERT', this%memoryPath) - - call vertspm%filliaja(this%iavert, this%javert, ierr) - call vertspm%destroy() - ! - ! -- Write information - write(this%iout, fmtncpl) this%nodesuser - write(this%iout, fmtcoord) 'MINIMUM X', xmin - write(this%iout, fmtcoord) 'MAXIMUM X', xmax - write(this%iout, fmtcoord) 'MINIMUM Y', ymin - write(this%iout, fmtcoord) 'MAXIMUM Y', ymax - write(this%iout, fmtmaxvert) maxvert, maxvertcell - write(this%iout,'(1x,a)')'END PROCESSING VERTICES' + ! -- log + if (this%iout > 0) then + write (this%iout, '(1x,a)') 'Discretization Cell2d data loaded' + end if ! ! -- Return return - end subroutine read_cell2d + end subroutine source_cell2d subroutine write_grb(this, icelltype) ! ****************************************************************************** @@ -1221,8 +1070,8 @@ subroutine write_grb(this, icelltype) character(len=50) :: txthdr character(len=lentxt) :: txt character(len=LINELENGTH) :: fname - character(len=*),parameter :: fmtgrdsave = & - "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & + character(len=*), parameter :: fmtgrdsave = & + "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)" ! ------------------------------------------------------------------------------ ! @@ -1231,101 +1080,101 @@ subroutine write_grb(this, icelltype) if (this%nvert > 0) ntxt = ntxt + 5 ! ! -- Open the file - inquire(unit=this%inunit, name=fname) - fname = trim(fname) // '.grb' + inquire (unit=this%inunit, name=fname) + fname = trim(fname)//'.grb' iunit = getunit() - write(this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) - call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & + write (this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) + call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & form, access, 'REPLACE') ! ! -- write header information - write(txthdr, '(a)') 'GRID DISU' + write (txthdr, '(a)') 'GRID DISU' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a)') 'VERSION 1' + write (iunit) txthdr + write (txthdr, '(a)') 'VERSION 1' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'NTXT ', ntxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'NTXT ', ntxt txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'LENTXT ', lentxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'LENTXT ', lentxt txthdr(50:50) = new_line('a') - write(iunit) txthdr + write (iunit) txthdr ! ! -- write variable definitions - write(txt, '(3a, i0)') 'NODES ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser + write (txt, '(3a, i0)') 'NODES ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%con%nja + write (iunit) txt + write (txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%con%nja txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg24.15)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot + write (iunit) txt + write (txt, '(3a, 1pg24.15)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'BOT ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'BOT ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 + write (iunit) txt + write (txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', this%con%nja + write (iunit) txt + write (txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', this%con%nja txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt + write (iunit) txt ! ! -- if vertices have been read then write additional header information if (this%nvert > 0) then - write(txt, '(3a, i0)') 'VERTICES ', 'DOUBLE ', 'NDIM 2 2 ', this%nvert + write (txt, '(3a, i0)') 'VERTICES ', 'DOUBLE ', 'NDIM 2 2 ', this%nvert txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'CELLX ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'CELLX ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'CELLY ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'CELLY ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IAVERT ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 + write (iunit) txt + write (txt, '(3a, i0)') 'IAVERT ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'JAVERT ', 'INTEGER ', 'NDIM 1 ', size(this%javert) + write (iunit) txt + write (txt, '(3a, i0)') 'JAVERT ', 'INTEGER ', 'NDIM 1 ', size(this%javert) txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - endif + write (iunit) txt + end if ! ! -- write data - write(iunit) this%nodesuser ! nodes - write(iunit) this%nja ! nja - write(iunit) this%xorigin ! xorigin - write(iunit) this%yorigin ! yorigin - write(iunit) this%angrot ! angrot - write(iunit) this%top1d ! top - write(iunit) this%bot1d ! bot - write(iunit) this%con%iausr ! ia - write(iunit) this%con%jausr ! ja - write(iunit) icelltype ! icelltype + write (iunit) this%nodesuser ! nodes + write (iunit) this%nja ! nja + write (iunit) this%xorigin ! xorigin + write (iunit) this%yorigin ! yorigin + write (iunit) this%angrot ! angrot + write (iunit) this%top1d ! top + write (iunit) this%bot1d ! bot + write (iunit) this%con%iausr ! ia + write (iunit) this%con%jausr ! ja + write (iunit) icelltype ! icelltype ! ! -- if vertices have been read then write additional data if (this%nvert > 0) then - write(iunit) this%vertices ! vertices - write(iunit) (this%cellxy(1, i), i = 1, this%nodesuser) ! cellx - write(iunit) (this%cellxy(2, i), i = 1, this%nodesuser) ! celly - write(iunit) this%iavert ! iavert - write(iunit) this%javert ! javert - endif + write (iunit) this%vertices ! vertices + write (iunit) (this%cellxy(1, i), i=1, this%nodesuser) ! cellx + write (iunit) (this%cellxy(2, i), i=1, this%nodesuser) ! celly + write (iunit) this%iavert ! iavert + write (iunit) this%javert ! javert + end if ! ! -- Close the file - close(iunit) + close (iunit) ! ! -- return return @@ -1341,22 +1190,19 @@ function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error - implicit none class(GwfDisuType), intent(in) :: this integer(I4B), intent(in) :: nodeu integer(I4B), intent(in) :: icheck integer(I4B) :: nodenumber ! ------------------------------------------------------------------------------ ! - if(icheck /= 0) then - if(nodeu < 1 .or. nodeu > this%nodes) then - write(errmsg, '(a,i10)') & + if (icheck /= 0) then + if (nodeu < 1 .or. nodeu > this%nodes) then + write (errmsg, '(a,i10)') & 'Nodenumber less than 1 or greater than nodes:', nodeu call store_error(errmsg) - endif - endif + end if + end if ! ! -- set node number to passed in nodenumber since there is a one to one ! mapping for an unstructured grid @@ -1370,7 +1216,7 @@ function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) return end function get_nodenumber_idx1 - subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & + subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ipos) ! ****************************************************************************** ! connection_normal -- calculate the normal vector components for reduced @@ -1381,7 +1227,6 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: store_error ! -- dummy class(GwfDisuType) :: this integer(I4B), intent(in) :: noden @@ -1396,12 +1241,12 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ------------------------------------------------------------------------------ ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then ! ! -- connection is vertical xcomp = DZERO ycomp = DZERO - if(nodem < noden) then + if (nodem < noden) then ! ! -- nodem must be above noden, so upward connection zcomp = DONE @@ -1409,7 +1254,7 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ! -- nodem must be below noden, so downward connection zcomp = -DONE - endif + end if else ! -- find from anglex, since anglex is symmetric, need to flip vector ! for lower triangle (nodem < noden) @@ -1419,13 +1264,13 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & xcomp = cos(angle) * dmult ycomp = sin(angle) * dmult zcomp = DZERO - endif + end if ! ! -- return return end subroutine connection_normal - subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & + subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & xcomp, ycomp, zcomp, conlen) ! ****************************************************************************** ! connection_vector -- calculate the unit vector components from reduced @@ -1439,7 +1284,6 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! ------------------------------------------------------------------------------ ! -- modules use ConstantsModule, only: DHALF - use SimModule, only: store_error use DisvGeom, only: line_unit_vector ! -- dummy class(GwfDisuType) :: this @@ -1459,19 +1303,21 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! ! -- Terminate with error if requesting unit vector components for problems ! without cell data - if (size(this%cellxy,2) < 1) then - write(errmsg, '(a)') & - 'Cannot calculate unit vector components for DISU grid if VERTEX ' // & + if (size(this%cellxy, 2) < 1) then + write (errmsg, '(a)') & + 'Cannot calculate unit vector components for DISU grid if VERTEX '// & 'data are not specified' call store_error(errmsg, terminate=.TRUE.) end if ! - ! -- Find xy coords - call this%get_cellxy(noden, xn, yn) - call this%get_cellxy(nodem, xm, ym) + ! -- get xy center coords + xn = this%xc(noden) + yn = this%yc(noden) + xm = this%xc(nodem) + ym = this%yc(nodem) ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then ! ! -- vertical connection, calculate z as cell center elevation zn = this%bot(noden) + DHALF * (this%top(noden) - this%bot(noden)) @@ -1486,48 +1332,24 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & else zn = this%bot(noden) + DHALF * satn * (this%top(noden) - this%bot(noden)) zm = this%bot(nodem) + DHALF * satm * (this%top(nodem) - this%bot(nodem)) - endif - endif + end if + end if ! ! -- Use coords to find vector components and connection length - call line_unit_vector(xn, yn, zn, xm, ym, zm, xcomp, ycomp, zcomp, & + call line_unit_vector(xn, yn, zn, xm, ym, zm, xcomp, ycomp, zcomp, & conlen) ! ! -- return return end subroutine connection_vector - subroutine get_cellxy_disu(this, node, xcell, ycell) -! ****************************************************************************** -! get_cellxy_disu -- assign xcell and ycell -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - class(GwfDisuType), intent(in) :: this - integer(I4B), intent(in) :: node ! the reduced node number - real(DP), intent(out) :: xcell, ycell ! the x,y for the cell - ! -- local - integer(I4B) :: nu -! ------------------------------------------------------------------------------ - ! - ! -- Convert to user node number (because that's how cell centers are - ! stored) and then set xcell and ycell - nu = this%get_nodeuser(node) - xcell = this%cellxy(1, nu) - ycell = this%cellxy(2, nu) - ! - ! -- return - return - end subroutine get_cellxy_disu - ! return discretization type subroutine get_dis_type(this, dis_type) - class(GwfDisuType), intent(in) :: this - character(len=*), intent(out) :: dis_type - + class(GwfDisuType), intent(in) :: this + character(len=*), intent(out) :: dis_type + dis_type = "DISU" - + end subroutine get_dis_type subroutine allocate_scalars(this, name_model) @@ -1584,13 +1406,14 @@ subroutine allocate_arrays(this) call this%DisBaseType%allocate_arrays() ! ! -- Allocate arrays in DISU - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call mem_allocate(this%nodeuser, this%nodes, 'NODEUSER', this%memoryPath) - call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', this%memoryPath) + call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', & + this%memoryPath) else call mem_allocate(this%nodeuser, 1, 'NODEUSER', this%memoryPath) call mem_allocate(this%nodereduced, 1, 'NODEREDUCED', this%memoryPath) - endif + end if ! ! -- Initialize this%mshape(1) = this%nodesuser @@ -1602,11 +1425,11 @@ end subroutine allocate_arrays subroutine allocate_arrays_mem(this) use MemoryManagerModule, only: mem_allocate class(GwfDisuType) :: this - + call mem_allocate(this%idomain, this%nodes, 'IDOMAIN', this%memoryPath) call mem_allocate(this%vertices, 2, this%nvert, 'VERTICES', this%memoryPath) call mem_allocate(this%cellxy, 2, this%nodes, 'CELLXY', this%memoryPath) - + end subroutine allocate_arrays_mem function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & @@ -1628,7 +1451,7 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & integer(I4B), intent(inout) :: istop integer(I4B), intent(in) :: in integer(I4B), intent(in) :: iout - character(len=*), intent(inout) :: line + character(len=*), intent(inout) :: line logical, optional, intent(in) :: flag_string logical, optional, intent(in) :: allow_zero integer(I4B) :: nodeu @@ -1643,14 +1466,14 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & ! Check to see if first token in line can be read as an integer. lloclocal = lloc call urword(line, lloclocal, istart, istop, 1, ndum, r, iout, in) - read(line(istart:istop),*,iostat=istat)n + read (line(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in line is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! call urword(line, lloc, istart, istop, 2, nodeu, r, iout, in) ! @@ -1658,14 +1481,14 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & if (present(allow_zero)) then if (allow_zero) then return - endif - endif - endif + end if + end if + end if ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, *) ' Node number in list is outside of the grid', nodeu call store_error(errmsg) - inquire(unit=in, name=fname) + inquire (unit=in, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in line: ') @@ -1679,7 +1502,7 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & end function nodeu_from_string function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & - allow_zero) result(nodeu) + allow_zero) result(nodeu) ! ****************************************************************************** ! nodeu_from_cellid -- Receive cellid as a string and convert the string to a ! user nodenumber. @@ -1714,14 +1537,14 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! Check to see if first token in cellid can be read as an integer. lloclocal = 1 call urword(cellid, lloclocal, istart, istop, 1, ndum, r, iout, inunit) - read(cellid(istart:istop), *, iostat=istat) n + read (cellid(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in cellid is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! lloclocal = 1 call urword(cellid, lloclocal, istart, istop, 2, nodeu, r, iout, inunit) @@ -1730,14 +1553,14 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & if (present(allow_zero)) then if (allow_zero) then return - endif - endif - endif + end if + end if + end if ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, *) ' Node number in list is outside of the grid', nodeu call store_error(errmsg) - inquire(unit=inunit, name=fname) + inquire (unit=inunit, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in cellid: ') @@ -1788,19 +1611,16 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use InputOutputModule, only: urword - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisuType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisuType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: iarray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: nval integer(I4B), dimension(:), pointer, contiguous :: itemp @@ -1810,22 +1630,22 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & ! subroutine. The temporary array will point to ibuff if it is a ! reduced structured system, or to iarray if it is an unstructured ! model. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodesuser itemp => this%ibuff else nval = this%nodes itemp => iarray - endif + end if ! ! -- Read the array ! -- Read unstructured input call ReadArray(in, itemp, aname, this%ndim, nval, iout, 0) ! ! -- If reduced model, then need to copy from itemp(=>ibuff) to iarray - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(itemp, iarray) - endif + end if ! ! -- return return @@ -1840,19 +1660,16 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use InputOutputModule, only: urword - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisuType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisuType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: nval real(DP), dimension(:), pointer, contiguous :: dtemp @@ -1862,28 +1679,28 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & ! subroutine. The temporary array will point to dbuff if it is a ! reduced structured system, or to darray if it is an unstructured ! model. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodesuser dtemp => this%dbuff else nval = this%nodes dtemp => darray - endif + end if ! ! -- Read the array call ReadArray(in, dtemp, aname, this%ndim, nval, iout, 0) ! ! -- If reduced model, then need to copy from dtemp(=>dbuff) to darray - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(dtemp, darray) - endif + end if ! ! -- return return end subroutine read_dbl_array - subroutine record_array(this, darray, iout, iprint, idataun, aname, & - cdatafmp, nvaluesp, nwidthp, editdesc, dinact) + subroutine record_array(this, darray, iout, iprint, idataun, aname, & + cdatafmp, nvaluesp, nwidthp, editdesc, dinact) ! ****************************************************************************** ! record_array -- Record a double precision array. The array will be ! printed to an external file and/or written to an unformatted external file @@ -1906,17 +1723,17 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(GwfDisuType), intent(inout) :: this + class(GwfDisuType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: iprint - integer(I4B), intent(in) :: idataun - character(len=*), intent(in) :: aname - character(len=*), intent(in) :: cdatafmp - integer(I4B), intent(in) :: nvaluesp - integer(I4B), intent(in) :: nwidthp - character(len=*), intent(in) :: editdesc - real(DP), intent(in) :: dinact + integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: iprint + integer(I4B), intent(in) :: idataun + character(len=*), intent(in) :: aname + character(len=*), intent(in) :: cdatafmp + integer(I4B), intent(in) :: nvaluesp + integer(I4B), intent(in) :: nwidthp + character(len=*), intent(in) :: editdesc + real(DP), intent(in) :: dinact ! -- local integer(I4B) :: k, ifirst integer(I4B) :: nlay @@ -1927,7 +1744,7 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & integer(I4B) :: istart, istop real(DP), dimension(:), pointer, contiguous :: dtemp ! -- formats - character(len=*),parameter :: fmthsv = & + character(len=*), parameter :: fmthsv = & "(1X,/1X,a,' WILL BE SAVED ON UNIT ',I4, & &' AT END OF TIME STEP',I5,', STRESS PERIOD ',I4)" ! ------------------------------------------------------------------------------ @@ -1939,61 +1756,61 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ! -- If this is a reduced model, then copy the values from darray into ! dtemp. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodes dtemp => this%dbuff do nodeu = 1, this%nodesuser noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) then + if (noder <= 0) then dtemp(nodeu) = dinact cycle - endif + end if dtemp(nodeu) = darray(noder) - enddo + end do else nval = this%nodes dtemp => darray - endif + end if ! ! -- Print to iout if iprint /= 0 - if(iprint /= 0) then + if (iprint /= 0) then istart = 1 do k = 1, nlay istop = istart + nrow * ncol - 1 - call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & + call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & aname, cdatafmp, nvaluesp, nwidthp, editdesc) istart = istop + 1 - enddo - endif + end do + end if ! ! -- Save array to an external file. - if(idataun > 0) then + if (idataun > 0) then ! -- write to binary file by layer ifirst = 1 istart = 1 - do k=1, nlay + do k = 1, nlay istop = istart + nrow * ncol - 1 - if(ifirst == 1) write(iout, fmthsv) & - trim(adjustl(aname)), idataun, & - kstp, kper + if (ifirst == 1) write (iout, fmthsv) & + trim(adjustl(aname)), idataun, & + kstp, kper ifirst = 0 - call ulasav(dtemp(istart:istop), aname, kstp, kper, & + call ulasav(dtemp(istart:istop), aname, kstp, kper, & pertim, totim, ncol, nrow, k, idataun) istart = istop + 1 - enddo - elseif(idataun < 0) then + end do + elseif (idataun < 0) then ! ! -- write entire array as one record - call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & + call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & iout, delt, pertim, totim) - endif + end if ! ! -- return return end subroutine record_array - subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & - dstmodel, dstpackage, naux, auxtxt, & + subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & + dstmodel, dstpackage, naux, auxtxt, & ibdchn, nlist, iout) ! ****************************************************************************** ! record_srcdst_list_header -- Record list header for imeth=6 @@ -2022,8 +1839,8 @@ subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & ncol = this%mshape(1) ! ! -- Use ubdsv06 to write list header - call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage,& - ibdchn, naux, auxtxt, ncol, nrow, nlay, & + call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage, & + ibdchn, naux, auxtxt, ncol, nrow, nlay, & nlist, iout, delt, pertim, totim) ! ! -- return @@ -2033,11 +1850,11 @@ end subroutine record_srcdst_list_header !> @brief Cast base to DISU !< function CastAsDisuType(dis) result(disu) - class(*), pointer :: dis !< base pointer to DISU object + class(*), pointer :: dis !< base pointer to DISU object class(GwfDisuType), pointer :: disu !< the resulting DISU pointer disu => null() - select type(dis) + select type (dis) class is (GwfDisuType) disu => dis end select diff --git a/src/Model/GroundWaterFlow/gwf3disu8idm.f90 b/src/Model/GroundWaterFlow/gwf3disu8idm.f90 new file mode 100644 index 00000000000..42245c2ae42 --- /dev/null +++ b/src/Model/GroundWaterFlow/gwf3disu8idm.f90 @@ -0,0 +1,578 @@ +module GwfDisuInputModule + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwf_disu_param_definitions + public gwf_disu_aggregate_definitions + public gwf_disu_block_definitions + public GwfDisuParamFoundType + + type GwfDisuParamFoundType + logical :: length_units = .false. + logical :: nogrb = .false. + logical :: xorigin = .false. + logical :: yorigin = .false. + logical :: angrot = .false. + logical :: voffsettol = .false. + logical :: nodes = .false. + logical :: nja = .false. + logical :: nvert = .false. + logical :: top = .false. + logical :: bot = .false. + logical :: area = .false. + logical :: idomain = .false. + logical :: iac = .false. + logical :: ja = .false. + logical :: ihc = .false. + logical :: cl12 = .false. + logical :: hwva = .false. + logical :: angldegx = .false. + logical :: iv = .false. + logical :: xv = .false. + logical :: yv = .false. + logical :: icell2d = .false. + logical :: xc = .false. + logical :: yc = .false. + logical :: ncvert = .false. + logical :: icvert = .false. + end type GwfDisuParamFoundType + + type(InputParamDefinitionType), parameter :: & + gwfdisu_length_units = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'LENGTH_UNITS', & ! tag name + 'LENGTH_UNITS', & ! fortran variable + 'STRING', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_nogrb = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'NOGRB', & ! tag name + 'NOGRB', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_xorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'XORIGIN', & ! tag name + 'XORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_yorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'YORIGIN', & ! tag name + 'YORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_angrot = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'ANGROT', & ! tag name + 'ANGROT', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_voffsettol = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'OPTIONS', & ! block + 'VERTICAL_OFFSET_TOLERANCE', & ! tag name + 'VOFFSETTOL', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_nodes = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'DIMENSIONS', & ! block + 'NODES', & ! tag name + 'NODES', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_nja = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'DIMENSIONS', & ! block + 'NJA', & ! tag name + 'NJA', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_nvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'DIMENSIONS', & ! block + 'NVERT', & ! tag name + 'NVERT', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_top = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'GRIDDATA', & ! block + 'TOP', & ! tag name + 'TOP', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_bot = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'GRIDDATA', & ! block + 'BOT', & ! tag name + 'BOT', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_area = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'GRIDDATA', & ! block + 'AREA', & ! tag name + 'AREA', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_idomain = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'GRIDDATA', & ! block + 'IDOMAIN', & ! tag name + 'IDOMAIN', & ! fortran variable + 'INTEGER1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_iac = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'IAC', & ! tag name + 'IAC', & ! fortran variable + 'INTEGER1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_ja = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'JA', & ! tag name + 'JA', & ! fortran variable + 'INTEGER1D', & ! type + 'NJA', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_ihc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'IHC', & ! tag name + 'IHC', & ! fortran variable + 'INTEGER1D', & ! type + 'NJA', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_cl12 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'CL12', & ! tag name + 'CL12', & ! fortran variable + 'DOUBLE1D', & ! type + 'NJA', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_hwva = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'HWVA', & ! tag name + 'HWVA', & ! fortran variable + 'DOUBLE1D', & ! type + 'NJA', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_angldegx = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CONNECTIONDATA', & ! block + 'ANGLDEGX', & ! tag name + 'ANGLDEGX', & ! fortran variable + 'DOUBLE1D', & ! type + 'NJA', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_iv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'VERTICES', & ! block + 'IV', & ! tag name + 'IV', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_xv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'VERTICES', & ! block + 'XV', & ! tag name + 'XV', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_yv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'VERTICES', & ! block + 'YV', & ! tag name + 'YV', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_icell2d = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'ICELL2D', & ! tag name + 'ICELL2D', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_xc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'XC', & ! tag name + 'XC', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_yc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'YC', & ! tag name + 'YC', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_ncvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'NCVERT', & ! tag name + 'NCVERT', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_icvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'ICVERT', & ! tag name + 'ICVERT', & ! fortran variable + 'INTEGER1D', & ! type + 'NCVERT', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_disu_param_definitions(*) = & + [ & + gwfdisu_length_units, & + gwfdisu_nogrb, & + gwfdisu_xorigin, & + gwfdisu_yorigin, & + gwfdisu_angrot, & + gwfdisu_voffsettol, & + gwfdisu_nodes, & + gwfdisu_nja, & + gwfdisu_nvert, & + gwfdisu_top, & + gwfdisu_bot, & + gwfdisu_area, & + gwfdisu_idomain, & + gwfdisu_iac, & + gwfdisu_ja, & + gwfdisu_ihc, & + gwfdisu_cl12, & + gwfdisu_hwva, & + gwfdisu_angldegx, & + gwfdisu_iv, & + gwfdisu_xv, & + gwfdisu_yv, & + gwfdisu_icell2d, & + gwfdisu_xc, & + gwfdisu_yc, & + gwfdisu_ncvert, & + gwfdisu_icvert & + ] + + type(InputParamDefinitionType), parameter :: & + gwfdisu_vertices = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'VERTICES', & ! block + 'VERTICES', & ! tag name + 'VERTICES', & ! fortran variable + 'RECARRAY IV XV YV', & ! type + 'NVERT', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisu_cell2d = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISU', & ! subcomponent + 'CELL2D', & ! block + 'CELL2D', & ! tag name + 'CELL2D', & ! fortran variable + 'RECARRAY ICELL2D XC YC NCVERT ICVERT', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_disu_aggregate_definitions(*) = & + [ & + gwfdisu_vertices, & + gwfdisu_cell2d & + ] + + type(InputBlockDefinitionType), parameter :: & + gwf_disu_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .false., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'DIMENSIONS', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'GRIDDATA', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'CONNECTIONDATA', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'VERTICES', & ! blockname + .true., & ! required + .true. & ! aggregate + ), & + InputBlockDefinitionType( & + 'CELL2D', & ! blockname + .true., & ! required + .true. & ! aggregate + ) & + ] + +end module GwfDisuInputModule diff --git a/src/Model/GroundWaterFlow/gwf3disv8.f90 b/src/Model/GroundWaterFlow/gwf3disv8.f90 index 95476e6b8d4..4b5bfc9c7da 100644 --- a/src/Model/GroundWaterFlow/gwf3disv8.f90 +++ b/src/Model/GroundWaterFlow/gwf3disv8.f90 @@ -2,7 +2,8 @@ module GwfDisvModule use ArrayReadersModule, only: ReadArray use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH + use ConstantsModule, only: LINELENGTH, LENMEMPATH, LENVARNAME, DZERO, DONE, & + DHALF use BaseDisModule, only: DisBaseType use InputOutputModule, only: get_node, URWORD, ulasav, ulaprufw, ubdsv1, & ubdsv06 @@ -10,29 +11,28 @@ module GwfDisvModule use DisvGeom, only: DisvGeomType use BlockParserModule, only: BlockParserType use MemoryManagerModule, only: mem_allocate - use TdisModule, only: kstp, kper, pertim, totim, delt + use MemoryHelperModule, only: create_mem_path + use TdisModule, only: kstp, kper, pertim, totim, delt implicit none private - public disv_cr, disv_init_mem, GwfDisvType + public disv_cr, GwfDisvType type, extends(DisBaseType) :: GwfDisvType - integer(I4B), pointer :: nlay => null() ! number of layers - integer(I4B), pointer :: ncpl => null() ! number of cells per layer - integer(I4B), pointer :: nvert => null() ! number of x,y vertices - real(DP), dimension(:,:), pointer, contiguous :: vertices => null() ! cell vertices stored as 2d array of x and y - real(DP), dimension(:,:), pointer, contiguous :: cellxy => null() ! cell center stored as 2d array of x and y - integer(I4B), dimension(:), pointer, contiguous :: iavert => null() ! cell vertex pointer ia array - integer(I4B), dimension(:), pointer, contiguous :: javert => null() ! cell vertex pointer ja array - real(DP), dimension(:, :), pointer, contiguous :: top2d => null() ! top elevations for each cell at top of model (ncpl, 1) - real(DP), dimension(:, :, :), pointer, contiguous :: bot3d => null() ! bottom elevations for each cell (ncpl, 1, nlay) - integer(I4B), dimension(:, :, :), pointer, contiguous :: idomain => null() ! idomain (ncpl, 1, nlay) - type(DisvGeomType) :: cell1 ! cell object used to calculate geometric properties - type(DisvGeomType) :: cell2 ! cell object used to calculate geometric properties + integer(I4B), pointer :: nlay => null() ! number of layers + integer(I4B), pointer :: ncpl => null() ! number of cells per layer + integer(I4B), pointer :: nvert => null() ! number of x,y vertices + real(DP), dimension(:, :), pointer, contiguous :: vertices => null() ! cell vertices stored as 2d array of x and y + real(DP), dimension(:, :), pointer, contiguous :: cellxy => null() ! cell center stored as 2d array of x and y + integer(I4B), dimension(:), pointer, contiguous :: iavert => null() ! cell vertex pointer ia array + integer(I4B), dimension(:), pointer, contiguous :: javert => null() ! cell vertex pointer ja array + real(DP), dimension(:), pointer, contiguous :: top1d => null() ! top elevations for each cell at top of model (ncpl) + real(DP), dimension(:, :), pointer, contiguous :: bot2d => null() ! bottom elevations for each cell (ncpl, nlay) + integer(I4B), dimension(:, :), pointer, contiguous :: idomain => null() ! idomain (ncpl, nlay) contains procedure :: dis_df => disv_df procedure :: dis_da => disv_da - procedure :: get_cellxy => get_cellxy_disv + procedure :: disv_load procedure :: get_dis_type => get_dis_type procedure, public :: record_array procedure, public :: read_layer_array @@ -50,11 +50,15 @@ module GwfDisvModule procedure :: supports_layers procedure :: get_ncpl ! -- private - procedure :: read_options - procedure :: read_dimensions - procedure :: read_vertices - procedure :: read_cell2d - procedure :: read_mf6_griddata + procedure :: source_options + procedure :: source_dimensions + procedure :: source_griddata + procedure :: source_vertices + procedure :: source_cell2d + procedure :: log_options + procedure :: log_dimensions + procedure :: log_griddata + procedure :: define_cellverts procedure :: grid_finalize procedure :: connect procedure :: write_grb @@ -67,7 +71,7 @@ module GwfDisvModule ! end type GwfDisvType - contains +contains subroutine disv_cr(dis, name_model, inunit, iout) ! ****************************************************************************** @@ -76,141 +80,82 @@ subroutine disv_cr(dis, name_model, inunit, iout) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + use IdmMf6FileLoaderModule, only: input_load + use ConstantsModule, only: LENPACKAGETYPE class(DisBaseType), pointer :: dis character(len=*), intent(in) :: name_model integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout type(GwfDisvType), pointer :: disnew + character(len=*), parameter :: fmtheader = & + "(1X, /1X, 'DISV -- VERTEX GRID DISCRETIZATION PACKAGE,', & + &' VERSION 1 : 12/23/2015 - INPUT READ FROM UNIT ', I0, //)" ! ------------------------------------------------------------------------------ - allocate(disnew) + allocate (disnew) dis => disnew call disnew%allocate_scalars(name_model) dis%inunit = inunit dis%iout = iout ! - ! -- Initialize block parser - call dis%parser%Initialize(dis%inunit, dis%iout) + ! -- if reading from file + if (inunit > 0) then + ! + ! -- Identify package + if (iout > 0) then + write (iout, fmtheader) inunit + end if + ! + ! -- initialize parser and load the disv input file + call dis%parser%Initialize(dis%inunit, dis%iout) + ! + ! -- Use the input data model routines to load the input data + ! into memory + call input_load(dis%parser, 'DISV6', 'GWF', 'DISV', name_model, 'DISV', & + [character(len=LENPACKAGETYPE) ::], iout) + ! + ! -- load disv + call disnew%disv_load() + end if ! ! -- Return return end subroutine disv_cr - - subroutine disv_init_mem(dis, name_model, iout, nlay, ncpl, & - top2d, bot3d, vertices, cellxy, idomain) + + subroutine disv_load(this) ! ****************************************************************************** -! dis_init_mem -- Create a new discretization by vertices object from memory +! disv_load -- transfer data into this discretization object ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - class(DisBaseType), pointer :: dis - character(len=*), intent(in) :: name_model - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: nlay - integer(I4B), intent(in) :: ncpl - real(DP), dimension(:, :), pointer, contiguous, intent(in) :: top2d - real(DP), dimension(:, :, :), pointer, contiguous, intent(in) :: bot3d - integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: vertices - integer(I4B), dimension(:, :), pointer, contiguous, intent(in) :: cellxy - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(in), & - optional :: idomain - ! -- local - type(GwfDisvType), pointer :: disext - integer(I4B) :: n - integer(I4B) :: j - integer(I4B) :: k - integer(I4B) :: ival - ! -- local + ! -- dummy + class(GwfDisvType) :: this + ! -- locals ! ------------------------------------------------------------------------------ - allocate(disext) - dis => disext - call disext%allocate_scalars(name_model) - dis%inunit = 0 - dis%iout = iout - ! - ! -- set dimensions - disext%ncpl = ncpl - disext%nlay = nlay - ! - ! -- Calculate nodesuser - disext%nodesuser = disext%nlay * disext%ncpl ! - ! -- Allocate non-reduced vectors for disv - call mem_allocate(disext%idomain, disext%ncpl, 1, disext%nlay, 'IDOMAIN', & - disext%memoryPath) - call mem_allocate(disext%top2d, disext%ncpl, 1, 'TOP2D', disext%memoryPath) - call mem_allocate(disext%bot3d, disext%ncpl, 1, disext%nlay, 'BOT3D', & - disext%memoryPath) - ! - ! -- Allocate vertices array - call mem_allocate(disext%vertices, 2, disext%nvert, 'VERTICES', disext%memoryPath) - call mem_allocate(disext%cellxy, 2, disext%ncpl, 'CELLXY', disext%memoryPath) - ! - ! -- fill data - do k = 1, disext%nlay - do j = 1, disext%ncpl - if (k == 1) then - disext%top2d(j, 1) = top2d(j, 1) - end if - disext%bot3d(j, 1, k) = bot3d(j, 1, k) - if (present(idomain)) then - ival = idomain(j, 1, k) - else - ival = 1 - end if - disext%idomain(j, 1, k) = ival - end do - end do - do n = 1, disext%nvert - do j = 1, 2 - disext%vertices(j, n) = vertices(j, n) - end do - end do - do n = 1, disext%ncpl - do j = 1, 2 - disext%cellxy(j, n) = cellxy(j, n) - end do - end do + ! -- source input data + call this%source_options() + call this%source_dimensions() + call this%source_griddata() + call this%source_vertices() + call this%source_cell2d() ! ! -- Return return - end subroutine disv_init_mem + end subroutine disv_load subroutine disv_df(this) ! ****************************************************************************** -! read_from_file -- Allocate and read discretization information +! disv_df -- Define ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules ! -- dummy class(GwfDisvType) :: this ! -- locals ! ------------------------------------------------------------------------------ - ! - ! -- read data from file - if (this%inunit /= 0) then - ! - ! -- Identify package - write(this%iout,1) this%inunit - 1 format(1X,/1X,'DISV -- VERTEX GRID DISCRETIZATION PACKAGE,', & - ' VERSION 1 : 12/23/2015 - INPUT READ FROM UNIT ',I0,//) - ! - ! -- Read options - call this%read_options() - ! - ! -- Read dimensions block - call this%read_dimensions() - ! - ! -- Read GRIDDATA block - call this%read_mf6_griddata() - ! - ! -- Read VERTICES block - call this%read_vertices() - ! - ! -- Read CELL2D block - call this%read_cell2d() - end if ! ! -- Final grid initialization call this%grid_finalize() @@ -228,11 +173,18 @@ subroutine disv_da(this) ! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_deallocate + use MemoryManagerExtModule, only: memorylist_remove + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisvType) :: this ! -- locals ! ------------------------------------------------------------------------------ ! + ! -- Deallocate idm memory + call memorylist_remove(this%name_model, 'DISV', idm_context) + call memorylist_remove(component=this%name_model, & + context=idm_context) + ! ! -- DisBaseType deallocate call this%DisBaseType%dis_da() ! @@ -248,171 +200,152 @@ subroutine disv_da(this) call mem_deallocate(this%cellxy) call mem_deallocate(this%iavert) call mem_deallocate(this%javert) - call mem_deallocate(this%top2d) - call mem_deallocate(this%bot3d) + call mem_deallocate(this%top1d) + call mem_deallocate(this%bot2d) call mem_deallocate(this%idomain) ! ! -- Return return end subroutine disv_da - subroutine read_options(this) + !> @brief Copy options from IDM into package + !< + subroutine source_options(this) ! ****************************************************************************** -! read_options -- Read options +! source_options -- source options from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH + ! -- modules + use KindModule, only: LGP + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisvInputModule, only: GwfDisvParamFoundType ! -- dummy class(GwfDisvType) :: this ! -- locals - character(len=LINELENGTH) :: errmsg, keyword - integer(I4B) :: ierr - logical :: isfound, endOfBlock + character(len=LENMEMPATH) :: idmMemoryPath + character(len=LENVARNAME), dimension(3) :: lenunits = & + &[character(len=LENVARNAME) :: 'FEET', 'METERS', 'CENTIMETERS'] + type(GwfDisvParamFoundType) :: found ! ------------------------------------------------------------------------------ ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - ! - ! -- set default options - this%lenuni = 0 - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(/,1x,a)')'PROCESSING DISCRETIZATION OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('LENGTH_UNITS') - call this%parser%GetStringCaps(keyword) - if(keyword=='FEET') then - this%lenuni = 1 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS FEET' - elseif(keyword=='METERS') then - this%lenuni = 2 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS METERS' - elseif(keyword=='CENTIMETERS') then - this%lenuni = 3 - write(this%iout,'(4x,a)') 'MODEL LENGTH UNIT IS CENTIMETERS' - else - write(this%iout,'(4x,a)')'UNKNOWN UNIT: ',trim(keyword) - write(this%iout,'(4x,a)')'SETTING TO: ','UNDEFINED' - endif - case('NOGRB') - write(this%iout,'(4x,a)') 'BINARY GRB FILE WILL NOT BE WRITTEN' - this%writegrb = .false. - case('XORIGIN') - this%xorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'XORIGIN SPECIFIED AS ', & - this%xorigin - case('YORIGIN') - this%yorigin = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'YORIGIN SPECIFIED AS ', & - this%yorigin - case('ANGROT') - this%angrot = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg24.15)') 'ANGROT SPECIFIED AS ', & - this%angrot - case default - write(errmsg,'(4x,a,a)')'Unknown DIS option: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - else - write(this%iout,'(1x,a)')'NO DISV OPTION BLOCK DETECTED.' + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISV', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%lenuni, 'LENGTH_UNITS', idmMemoryPath, lenunits, & + found%length_units) + call mem_set_value(this%nogrb, 'NOGRB', idmMemoryPath, found%nogrb) + call mem_set_value(this%xorigin, 'XORIGIN', idmMemoryPath, found%xorigin) + call mem_set_value(this%yorigin, 'YORIGIN', idmMemoryPath, found%yorigin) + call mem_set_value(this%angrot, 'ANGROT', idmMemoryPath, found%angrot) + ! + ! -- log values to list file + if (this%iout > 0) then + call this%log_options(found) end if - if(this%lenuni==0) write(this%iout,'(3x,a)') 'MODEL LENGTH UNIT IS UNDEFINED' - if(isfound) then - write(this%iout,'(1x,a)')'END OF DISCRETIZATION OPTIONS' - endif ! ! -- Return return - end subroutine read_options + end subroutine source_options + + !> @brief Write user options to list file + !< + subroutine log_options(this, found) + use GwfDisvInputModule, only: GwfDisvParamFoundType + class(GwfDisvType) :: this + type(GwfDisvParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Options' + + if (found%length_units) then + write (this%iout, '(4x,a,i0)') 'Model length unit [0=UND, 1=FEET, & + &2=METERS, 3=CENTIMETERS] set as ', this%lenuni + end if + + if (found%nogrb) then + write (this%iout, '(4x,a,i0)') 'Binary grid file [0=GRB, 1=NOGRB] & + &set as ', this%nogrb + end if + + if (found%xorigin) then + write (this%iout, '(4x,a,G0)') 'XORIGIN = ', this%xorigin + end if + + if (found%yorigin) then + write (this%iout, '(4x,a,G0)') 'YORIGIN = ', this%yorigin + end if + + if (found%angrot) then + write (this%iout, '(4x,a,G0)') 'ANGROT = ', this%angrot + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Options' - subroutine read_dimensions(this) + end subroutine log_options + + !> @brief Copy dimensions from IDM into package + !< + subroutine source_dimensions(this) ! ****************************************************************************** -! read_dimensions -- Read dimensions +! source_dimensions -- source dimensions from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH + use KindModule, only: LGP + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisvInputModule, only: GwfDisvParamFoundType ! -- dummy class(GwfDisvType) :: this ! -- locals - character(len=LINELENGTH) :: errmsg, keyword - integer(I4B) :: ierr - logical :: isfound, endOfBlock - integer(I4B) :: j - integer(I4B) :: k + character(len=LENMEMPATH) :: idmMemoryPath + integer(I4B) :: j, k + type(GwfDisvParamFoundType) :: found ! ------------------------------------------------------------------------------ ! - ! -- get dimensions block - call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse dimensions block if detected - if (isfound) then - write(this%iout,'(/,1x,a)')'PROCESSING DISCRETIZATION DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('NLAY') - this%nlay = this%parser%GetInteger() - write(this%iout,'(3x,a,i0)')'NLAY = ', this%nlay - case ('NCPL') - this%ncpl = this%parser%GetInteger() - write(this%iout,'(3x,a,i0)')'NCPL = ', this%ncpl - case ('NVERT') - this%nvert = this%parser%GetInteger() - write(this%iout,'(3x,a,i0)')'NVERT = ', this%nvert - case default - write(errmsg,'(4x,a,a)')'Unknown DISV dimension: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - else - call store_error('ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.') - call this%parser%StoreErrorUnit() + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISV', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%nlay, 'NLAY', idmMemoryPath, found%nlay) + call mem_set_value(this%ncpl, 'NCPL', idmMemoryPath, found%ncpl) + call mem_set_value(this%nvert, 'NVERT', idmMemoryPath, found%nvert) + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_dimensions(found) end if ! ! -- verify dimensions were set - if(this%nlay < 1) then + if (this%nlay < 1) then call store_error( & - 'NLAY WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NLAY was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif - if(this%ncpl < 1) then + end if + if (this%ncpl < 1) then call store_error( & - 'NCPL WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NCPL was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif - if(this%nvert < 1) then + end if + if (this%nvert < 1) then call store_error( & - 'NVERT WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.') + 'NVERT was not specified or was specified incorrectly.') call this%parser%StoreErrorUnit() - endif - write(this%iout,'(1x,a)')'END OF DISCRETIZATION DIMENSIONS' + end if ! ! -- Calculate nodesuser this%nodesuser = this%nlay * this%ncpl ! ! -- Allocate non-reduced vectors for disv - call mem_allocate(this%idomain, this%ncpl, 1, this%nlay, 'IDOMAIN', & + call mem_allocate(this%idomain, this%ncpl, this%nlay, 'IDOMAIN', & + this%memoryPath) + call mem_allocate(this%top1d, this%ncpl, 'TOP1D', this%memoryPath) + call mem_allocate(this%bot2d, this%ncpl, this%nlay, 'BOT2D', & this%memoryPath) - call mem_allocate(this%top2d, this%ncpl, 1, 'TOP2D', this%memoryPath) - call mem_allocate(this%bot3d, this%ncpl, 1, this%nlay, 'BOT3D', this%memoryPath) ! ! -- Allocate vertices array call mem_allocate(this%vertices, 2, this%nvert, 'VERTICES', this%memoryPath) @@ -421,116 +354,100 @@ subroutine read_dimensions(this) ! -- initialize all cells to be active (idomain = 1) do k = 1, this%nlay do j = 1, this%ncpl - this%idomain(j, 1, k) = 1 + this%idomain(j, k) = 1 end do end do ! ! -- Return return - end subroutine read_dimensions + end subroutine source_dimensions + + !> @brief Write dimensions to list file + !< + subroutine log_dimensions(this, found) + use GwfDisvInputModule, only: GwfDisvParamFoundType + class(GwfDisvType) :: this + type(GwfDisvParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Dimensions' + + if (found%nlay) then + write (this%iout, '(4x,a,i0)') 'NLAY = ', this%nlay + end if - subroutine read_mf6_griddata(this) + if (found%ncpl) then + write (this%iout, '(4x,a,i0)') 'NCPL = ', this%ncpl + end if + + if (found%nvert) then + write (this%iout, '(4x,a,i0)') 'NVERT = ', this%nvert + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Dimensions' + + end subroutine log_dimensions + + subroutine source_griddata(this) ! ****************************************************************************** -! read_mf6_griddata -- Read grid data from a MODFLOW 6 ascii file +! source_griddata -- source griddata from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfDisvInputModule, only: GwfDisvParamFoundType ! -- dummy class(GwfDisvType) :: this ! -- locals - character(len=LINELENGTH) :: keyword - integer(I4B) :: n - integer(I4B) :: ierr - logical :: isfound, endOfBlock - integer(I4B), parameter :: nname = 3 - logical, dimension(nname) :: lname - character(len=24),dimension(nname) :: aname - character(len=300) :: ermsg + character(len=LENMEMPATH) :: idmMemoryPath + type(GwfDisvParamFoundType) :: found ! -- formats - character(len=*), parameter :: fmtdz = & - "('ERROR. CELL (',i0,',',i0,') THICKNESS <= 0. ', " // & - "'TOP, BOT: ',2(1pg24.15))" - character(len=*), parameter :: fmtnr = & - "(/1x, 'THE SPECIFIED IDOMAIN RESULTS IN A REDUCED NUMBER OF CELLS.'," // & - "/1x, 'NUMBER OF USER NODES: ',I0," // & - "/1X, 'NUMBER OF NODES IN SOLUTION: ', I0, //)" - ! -- data - data aname(1) /'TOP ELEVATION OF LAYER 1'/ - data aname(2) /' MODEL LAYER BOTTOM EL.'/ - data aname(3) /' IDOMAIN'/ ! ------------------------------------------------------------------------------ ! - ! --Read GRIDDATA block - call this%parser%GetBlock('GRIDDATA', isfound, ierr) - lname(:) = .false. - if(isfound) then - write(this%iout,'(/,1x,a)')'PROCESSING GRIDDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('TOP') - call ReadArray(this%parser%iuactive, this%top2d(:, :), & - aname(1), this%ndim, this%ncpl, 1, this%iout, 0) - lname(1) = .true. - case ('BOTM') - call this%parser%GetStringCaps(keyword) - if (keyword.EQ.'LAYERED') then - call ReadArray(this%parser%iuactive, & - this%bot3d(:,:,:), aname(2), this%ndim, & - this%ncpl, 1, this%nlay, this%iout, 1, this%nlay) - else - call ReadArray(this%parser%iuactive, & - this%bot3d(:, :, :), aname(2), & - this%ndim, this%nodesuser, 1, 1, this%iout, 0, 0) - end if - lname(2) = .true. - case ('IDOMAIN') - call this%parser%GetStringCaps(keyword) - if (keyword.EQ.'LAYERED') then - call ReadArray(this%parser%iuactive, this%idomain, aname(3), & - this%ndim, this%ncpl, 1, this%nlay, this%iout, & - 1, this%nlay) - else - call ReadArray(this%parser%iuactive, this%idomain, aname(3), & - this%ndim, this%nodesuser, 1, 1, this%iout, & - 0, 0) - end if - lname(3) = .true. - case default - write(ermsg,'(4x,a,a)')'Unknown GRIDDATA tag: ', & - trim(keyword) - call store_error(ermsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' - else - call store_error('ERROR. REQUIRED GRIDDATA BLOCK NOT FOUND.') - call this%parser%StoreErrorUnit() - end if + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISV', idm_context) ! - ! -- Verify all required items were read (IDOMAIN not required) - do n = 1, nname - 1 - if(.not. lname(n)) then - write(ermsg,'(1x,a,a)') & - 'ERROR. REQUIRED INPUT WAS NOT SPECIFIED: ',aname(n) - call store_error(ermsg) - endif - enddo - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - endif + ! -- update defaults with idm sourced values + call mem_set_value(this%top1d, 'TOP', idmMemoryPath, found%top) + call mem_set_value(this%bot2d, 'BOTM', idmMemoryPath, found%botm) + call mem_set_value(this%idomain, 'IDOMAIN', idmMemoryPath, found%idomain) + ! + ! -- log simulation values + if (this%iout > 0) then + call this%log_griddata(found) + end if ! ! -- Return return - end subroutine read_mf6_griddata - + end subroutine source_griddata + + !> @brief Write griddata found to list file + !< + subroutine log_griddata(this, found) + use GwfDisvInputModule, only: GwfDisvParamFoundType + class(GwfDisvType) :: this + type(GwfDisvParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting Discretization Griddata' + + if (found%top) then + write (this%iout, '(4x,a)') 'TOP set from input file' + end if + + if (found%botm) then + write (this%iout, '(4x,a)') 'BOTM set from input file' + end if + + if (found%idomain) then + write (this%iout, '(4x,a)') 'IDOMAIN set from input file' + end if + + write (this%iout, '(1x,a,/)') 'End Setting Discretization Griddata' + + end subroutine log_griddata + subroutine grid_finalize(this) ! ****************************************************************************** ! grid_finalize -- Finalize grid @@ -539,8 +456,6 @@ subroutine grid_finalize(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO ! -- dummy class(GwfDisvType) :: this ! -- locals @@ -550,12 +465,12 @@ subroutine grid_finalize(this) character(len=300) :: ermsg ! -- formats character(len=*), parameter :: fmtdz = & - "('ERROR. CELL (',i0,',',i0,') THICKNESS <= 0. ', " // & - "'TOP, BOT: ',2(1pg24.15))" + "('CELL (',i0,',',i0,') THICKNESS <= 0. ', & + &'TOP, BOT: ',2(1pg24.15))" character(len=*), parameter :: fmtnr = & - "(/1x, 'THE SPECIFIED IDOMAIN RESULTS IN A REDUCED NUMBER OF CELLS.'," // & - "/1x, 'NUMBER OF USER NODES: ',I7," // & - "/1X, 'NUMBER OF NODES IN SOLUTION: ', I7, //)" + "(/1x, 'The specified IDOMAIN results in a reduced number of cells.',& + &/1x, 'Number of user nodes: ',I0,& + &/1X, 'Number of nodes in solution: ', I0, //)" ! -- data ! ------------------------------------------------------------------------------ ! @@ -563,44 +478,44 @@ subroutine grid_finalize(this) this%nodes = 0 do k = 1, this%nlay do j = 1, this%ncpl - if(this%idomain(j, 1, k) > 0) this%nodes = this%nodes + 1 - enddo - enddo + if (this%idomain(j, k) > 0) this%nodes = this%nodes + 1 + end do + end do ! ! -- Check to make sure nodes is a valid number if (this%nodes == 0) then - call store_error('MODEL DOES NOT HAVE ANY ACTIVE NODES.') - call store_error('MAKE SURE IDOMAIN ARRAY HAS SOME VALUES GREATER & - &THAN ZERO.') + call store_error('Model does not have any active nodes. & + &Ensure IDOMAIN array has some values greater & + &than zero.') call this%parser%StoreErrorUnit() end if ! ! -- Check cell thicknesses do k = 1, this%nlay do j = 1, this%ncpl - if (this%idomain(j, 1, k) == 0) cycle - if (this%idomain(j, 1, k) > 0) then + if (this%idomain(j, k) == 0) cycle + if (this%idomain(j, k) > 0) then if (k > 1) then - top = this%bot3d(j, 1, k - 1) + top = this%bot2d(j, k - 1) else - top = this%top2d(j, 1) + top = this%top1d(j) end if - dz = top - this%bot3d(j, 1, k) + dz = top - this%bot2d(j, k) if (dz <= DZERO) then - write(ermsg, fmt=fmtdz) k, j, top, this%bot3d(j, 1, k) + write (ermsg, fmt=fmtdz) k, j, top, this%bot2d(j, k) call store_error(ermsg) - endif - endif - enddo - enddo + end if + end if + end do + end do if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Write message if reduced grid - if(this%nodes < this%nodesuser) then - write(this%iout, fmtnr) this%nodesuser, this%nodes - endif + if (this%nodes < this%nodesuser) then + write (this%iout, fmtnr) this%nodesuser, this%nodes + end if ! ! -- Array size is now known, so allocate call this%allocate_arrays() @@ -609,291 +524,219 @@ subroutine grid_finalize(this) ! a negative number to indicate it is a pass-through cell, or ! a zero to indicate that the cell is excluded from the ! solution. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then node = 1 noder = 1 do k = 1, this%nlay do j = 1, this%ncpl - if(this%idomain(j, 1, k) > 0) then + if (this%idomain(j, k) > 0) then this%nodereduced(node) = noder noder = noder + 1 - elseif(this%idomain(j, 1, k) < 0) then + elseif (this%idomain(j, k) < 0) then this%nodereduced(node) = -1 else this%nodereduced(node) = 0 - endif + end if node = node + 1 - enddo - enddo - endif + end do + end do + end if ! ! -- allocate and fill nodeuser if a reduced grid - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then node = 1 noder = 1 do k = 1, this%nlay do j = 1, this%ncpl - if(this%idomain(j, 1, k) > 0) then + if (this%idomain(j, k) > 0) then this%nodeuser(noder) = node noder = noder + 1 - endif + end if node = node + 1 - enddo - enddo - endif + end do + end do + end if ! - ! -- Move top2d and bot3d into top and bot, and calculate area + ! -- Move top1d and bot2d into top and bot + ! and set x and y center coordinates node = 0 do k = 1, this%nlay do j = 1, this%ncpl node = node + 1 noder = node - if(this%nodes < this%nodesuser) noder = this%nodereduced(node) - if(noder <= 0) cycle + if (this%nodes < this%nodesuser) noder = this%nodereduced(node) + if (noder <= 0) cycle if (k > 1) then - top = this%bot3d(j, 1, k - 1) + top = this%bot2d(j, k - 1) else - top = this%top2d(j, 1) + top = this%top1d(j) end if this%top(noder) = top - this%bot(noder) = this%bot3d(j, 1, k) - enddo - enddo + this%bot(noder) = this%bot2d(j, k) + this%xc(noder) = this%cellxy(1, j) + this%yc(noder) = this%cellxy(2, j) + end do + end do ! ! -- Build connections call this%connect() ! - ! -- Create two cell objects that can be used for geometric processing - call this%cell1%init(this%nlay, this%ncpl, this%nodes, this%top, this%bot, & - this%iavert, this%javert, this%vertices, this%cellxy, & - this%nodereduced, this%nodeuser) - call this%cell2%init(this%nlay, this%ncpl, this%nodes, this%top, this%bot, & - this%iavert, this%javert, this%vertices, this%cellxy, & - this%nodereduced, this%nodeuser) - ! ! -- Return return end subroutine grid_finalize - subroutine read_vertices(this) + subroutine source_vertices(this) ! ****************************************************************************** -! read_vertices -- Read data +! source_vertices -- source vertex data from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO + use MemoryManagerModule, only: mem_setptr + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisvType) :: this + ! -- local integer(I4B) :: i - integer(I4B) :: ierr, ival - logical :: isfound, endOfBlock - real(DP) :: xmin, xmax, ymin, ymax - character(len=300) :: ermsg + character(len=LENMEMPATH) :: idmMemoryPath + real(DP), dimension(:), contiguous, pointer :: vert_x => null() + real(DP), dimension(:), contiguous, pointer :: vert_y => null() ! -- formats - character(len=*), parameter :: fmtvnum = & - "('ERROR. VERTEX NUMBER NOT CONSECUTIVE. LOOKING FOR ',i0," // & - "' BUT FOUND ', i0)" - character(len=*), parameter :: fmtnvert = & - "(3x, 'SUCCESSFULLY READ ',i0,' (X,Y) COORDINATES')" - character(len=*), parameter :: fmtcoord = & - "(3x, a,' COORDINATE = ', 1(1pg24.15))" ! ------------------------------------------------------------------------------ ! - ! -- Calculates nodesuser - this%nodesuser = this%nlay * this%ncpl + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISV', idm_context) ! - ! --Read DISDATA block - call this%parser%GetBlock('VERTICES', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then - write(this%iout,'(/,1x,a)') 'PROCESSING VERTICES' + ! -- set pointers to memory manager input arrays + call mem_setptr(vert_x, 'XV', idmMemoryPath) + call mem_setptr(vert_y, 'YV', idmMemoryPath) + ! + ! -- set vertices 2d array + if (associated(vert_x) .and. associated(vert_y)) then do i = 1, this%nvert - call this%parser%GetNextLine(endOfBlock) - ! - ! -- vertex number - ival = this%parser%GetInteger() - if(ival /= i) then - write(ermsg, fmtvnum) i, ival - call store_error(ermsg) - call this%parser%StoreErrorUnit() - endif - ! - ! -- x - this%vertices(1, i) = this%parser%GetDouble() - ! - ! -- y - this%vertices(2, i) = this%parser%GetDouble() - ! - ! -- set min/max coords - if(i == 1) then - xmin = this%vertices(1, i) - xmax = xmin - ymin = this%vertices(2, i) - ymax = ymin - else - xmin = min(xmin, this%vertices(1, i)) - xmax = max(xmax, this%vertices(1, i)) - ymin = min(ymin, this%vertices(2, i)) - ymax = max(ymax, this%vertices(2, i)) - endif - enddo - ! - ! -- Terminate the block - call this%parser%terminateblock() + this%vertices(1, i) = vert_x(i) + this%vertices(2, i) = vert_y(i) + end do else - call store_error('Required VERTICES block not found.') - call this%parser%StoreErrorUnit() + call store_error('Required Vertex arrays not found.') + end if + ! + ! -- log + if (this%iout > 0) then + write (this%iout, '(1x,a)') 'Discretization Vertex data loaded' end if ! - ! -- Write information - write(this%iout, fmtnvert) this%nvert - write(this%iout, fmtcoord) 'MINIMUM X', xmin - write(this%iout, fmtcoord) 'MAXIMUM X', xmax - write(this%iout, fmtcoord) 'MINIMUM Y', ymin - write(this%iout, fmtcoord) 'MAXIMUM Y', ymax - write(this%iout,'(1x,a)')'END PROCESSING VERTICES' + ! -- Return + return + end subroutine source_vertices + + subroutine define_cellverts(this, icell2d, ncvert, icvert) + ! -- modules + use SparseModule, only: sparsematrix + ! -- dummy + class(GwfDisvType) :: this + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icell2d + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: ncvert + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: icvert + ! -- locals + type(sparsematrix) :: vert_spm + integer(I4B) :: i, j, ierr + integer(I4B) :: icv_idx, startvert, maxnnz = 5 +! ------------------------------------------------------------------------------ + ! + ! -- initialize sparse matrix + call vert_spm%init(this%ncpl, this%nvert, maxnnz) + ! + ! -- add sparse matrix connections from input memory paths + icv_idx = 1 + do i = 1, this%ncpl + if (icell2d(i) /= i) call store_error('ICELL2D input sequence violation.') + do j = 1, ncvert(i) + call vert_spm%addconnection(i, icvert(icv_idx), 0) + if (j == 1) then + startvert = icvert(icv_idx) + elseif (j == ncvert(i) .and. (icvert(icv_idx) /= startvert)) then + call vert_spm%addconnection(i, startvert, 0) + end if + icv_idx = icv_idx + 1 + end do + end do + ! + ! -- allocate and fill iavert and javert + call mem_allocate(this%iavert, this%ncpl + 1, 'IAVERT', this%memoryPath) + call mem_allocate(this%javert, vert_spm%nnz, 'JAVERT', this%memoryPath) + call vert_spm%filliaja(this%iavert, this%javert, ierr) + call vert_spm%destroy() ! ! -- Return return - end subroutine read_vertices + end subroutine define_cellverts - subroutine read_cell2d(this) + subroutine source_cell2d(this) ! ****************************************************************************** -! read_cell2d -- Read information describing the two dimensional (x, y) -! configuration of each cell. +! source_cell2d -- source cell2d data from memory manager input path ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use SimModule, only: count_errors, store_error - use ConstantsModule, only: LINELENGTH, DZERO - use InputOutputModule, only: urword - use SparseModule, only: sparsematrix - use MemoryManagerModule, only: mem_allocate + use MemoryManagerModule, only: mem_setptr + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context ! -- dummy class(GwfDisvType) :: this - integer(I4B) :: i, j, ivert, ivert1, ncvert - integer(I4B) :: ierr, ival - logical :: isfound, endOfBlock - integer(I4B) :: maxvert, maxvertcell, iuext - real(DP) :: xmin, xmax, ymin, ymax - character(len=300) :: ermsg - integer(I4B), dimension(:), allocatable :: maxnnz - type(sparsematrix) :: vertspm + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + integer(I4B), dimension(:), contiguous, pointer :: icell2d => null() + integer(I4B), dimension(:), contiguous, pointer :: ncvert => null() + integer(I4B), dimension(:), contiguous, pointer :: icvert => null() + real(DP), dimension(:), contiguous, pointer :: cell_x => null() + real(DP), dimension(:), contiguous, pointer :: cell_y => null() + integer(I4B) :: i ! -- formats - character(len=*), parameter :: fmtcnum = & - "('ERROR. CELL NUMBER NOT CONSECUTIVE. LOOKING FOR ',i0," // & - "' BUT FOUND ', i0)" - character(len=*), parameter :: fmtncpl = & - "(3x, 'SUCCESSFULLY READ ',i0,' CELL2D INFORMATION ENTRIES')" - character(len=*), parameter :: fmtcoord = & - "(3x, a,' CELL CENTER = ', 1(1pg24.15))" - character(len=*), parameter :: fmtmaxvert = & - "(3x, 'MAXIMUM NUMBER OF CELL2D VERTICES IS ',i0,' FOR CELL ', i0)" ! ------------------------------------------------------------------------------ ! - ! -- initialize - maxvert = 0 - maxvertcell = 0 + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DISV', idm_context) ! - ! -- Initialize estimate of the max number of vertices for each cell - ! (using 5 as default) and initialize the sparse matrix, which will - ! temporarily store the vertex numbers for each cell. This will - ! be converted to iavert and javert after all cell vertices have - ! been read. - allocate(maxnnz(this%ncpl)) - do i = 1, this%ncpl - maxnnz(i) = 5 - enddo - call vertspm%init(this%ncpl, this%nvert, maxnnz) - ! - ! --Read CELL2D block - call this%parser%GetBlock('CELL2D', isfound, ierr, supportOpenClose=.true.) - if(isfound) then - write(this%iout,'(/,1x,a)') 'PROCESSING CELL2D' + ! -- set pointers to input path ncvert and icvert + call mem_setptr(icell2d, 'ICELL2D', idmMemoryPath) + call mem_setptr(ncvert, 'NCVERT', idmMemoryPath) + call mem_setptr(icvert, 'ICVERT', idmMemoryPath) + ! + ! -- + if (associated(icell2d) .and. associated(ncvert) & + .and. associated(icvert)) then + call this%define_cellverts(icell2d, ncvert, icvert) + else + call store_error('Required cell vertex array(s) [ICELL2D, NCVERT, ICVERT] & + ¬ found.') + end if + ! + ! -- copy cell center idm sourced values to local arrays + call mem_setptr(cell_x, 'XC', idmMemoryPath) + call mem_setptr(cell_y, 'YC', idmMemoryPath) + ! + ! -- set cell centers + if (associated(cell_x) .and. associated(cell_y)) then do i = 1, this%ncpl - call this%parser%GetNextLine(endOfBlock) - ! - ! -- cell number - ival = this%parser%GetInteger() - if(ival /= i) then - write(ermsg, fmtcnum) i, ival - call store_error(ermsg) - call store_error_unit(iuext) - endif - ! - ! -- Cell x center - this%cellxy(1, i) = this%parser%GetDouble() - ! - ! -- Cell y center - this%cellxy(2, i) = this%parser%GetDouble() - ! - ! -- Number of vertices for this cell - ncvert = this%parser%GetInteger() - if(ncvert > maxvert) then - maxvert = ncvert - maxvertcell = i - endif - ! - ! -- Read each vertex number, and then close the polygon if - ! the last vertex does not equal the first vertex - do j = 1, ncvert - ivert = this%parser%GetInteger() - call vertspm%addconnection(i, ivert, 0) - ! - ! -- If necessary, repeat the last vertex in order to close the cell - if(j == 1) then - ivert1 = ivert - elseif(j == ncvert) then - if(ivert1 /= ivert) then - call vertspm%addconnection(i, ivert1, 0) - endif - endif - enddo - ! - ! -- set min/max coords - if(i == 1) then - xmin = this%cellxy(1, i) - xmax = xmin - ymin = this%cellxy(2, i) - ymax = ymin - else - xmin = min(xmin, this%cellxy(1, i)) - xmax = max(xmax, this%cellxy(1, i)) - ymin = min(ymin, this%cellxy(2, i)) - ymax = max(ymax, this%cellxy(2, i)) - endif - enddo - ! - ! -- Terminate the block - call this%parser%terminateblock() + this%cellxy(1, i) = cell_x(i) + this%cellxy(2, i) = cell_y(i) + end do else - call store_error('Required CELL2D block not found.') - call this%parser%StoreErrorUnit() + call store_error('Required cell center arrays not found.') end if ! - ! -- Convert vertspm into ia/ja form - call mem_allocate(this%iavert, this%ncpl+1, 'IAVERT', this%memoryPath) - call mem_allocate(this%javert, vertspm%nnz, 'JAVERT', this%memoryPath) - call vertspm%filliaja(this%iavert, this%javert, ierr) - call vertspm%destroy() - ! - ! -- Write information - write(this%iout, fmtncpl) this%ncpl - write(this%iout, fmtcoord) 'MINIMUM X', xmin - write(this%iout, fmtcoord) 'MAXIMUM X', xmax - write(this%iout, fmtcoord) 'MINIMUM Y', ymin - write(this%iout, fmtcoord) 'MAXIMUM Y', ymax - write(this%iout, fmtmaxvert) maxvert, maxvertcell - write(this%iout,'(1x,a)')'END PROCESSING VERTICES' + ! -- log + if (this%iout > 0) then + write (this%iout, '(1x,a)') 'Discretization Cell2d data loaded' + end if ! ! -- Return return - end subroutine read_cell2d + end subroutine source_cell2d subroutine connect(this) ! ****************************************************************************** @@ -908,39 +751,66 @@ subroutine connect(this) ! -- local integer(I4B) :: j, k integer(I4B) :: noder, nrsize + integer(I4B) :: narea_eq_zero + integer(I4B) :: narea_lt_zero real(DP) :: area character(len=LINELENGTH) :: errmsg ! ------------------------------------------------------------------------------ + ! + ! -- Initialize + narea_eq_zero = 0 + narea_lt_zero = 0 ! ! -- Assign the cell area do j = 1, this%ncpl area = this%get_cell2d_area(j) do k = 1, this%nlay noder = this%get_nodenumber(k, j, 0) - if(noder > 0) this%area(noder) = area - enddo - if (area < 0) then - write(errmsg, '(a,i0)') 'ERROR. CELL2D AREA LESS THAN ZERO FOR CELL ', j + if (noder > 0) this%area(noder) = area + end do + if (area < DZERO) then + narea_lt_zero = narea_lt_zero + 1 + write (errmsg, '(a,i0)') & + &'Calculated CELL2D area less than zero for cell ', j call store_error(errmsg) - endif - enddo + end if + if (area == DZERO) then + narea_eq_zero = narea_eq_zero + 1 + write (errmsg, '(a,i0)') & + 'Calculated CELL2D area is zero for cell ', j + call store_error(errmsg) + end if + end do ! ! -- check for errors - if(count_errors() > 0) then - write(errmsg, '(a)') 'CELL VERTICES MUST BE LISTED IN CLOCKWISE ORDER. ' - call store_error(errmsg) + if (count_errors() > 0) then + if (narea_lt_zero > 0) then + write (errmsg, '(i0, a)') narea_lt_zero, & + ' cell(s) have an area less than zero. Calculated cell & + &areas must be greater than zero. Negative areas often & + &mean vertices are not listed in clockwise order.' + call store_error(errmsg) + end if + if (narea_eq_zero > 0) then + write (errmsg, '(i0, a)') narea_eq_zero, & + ' cell(s) have an area equal to zero. Calculated cell & + &areas must be greater than zero. Calculated cell & + &areas equal to zero indicate that the cell is not defined & + &by a valid polygon.' + call store_error(errmsg) + end if call store_error_unit(this%inunit) - endif + end if ! ! -- create and fill the connections object nrsize = 0 - if(this%nodes < this%nodesuser) nrsize = this%nodes - allocate(this%con) - call this%con%disvconnections(this%name_model, this%nodes, & - this%ncpl, this%nlay, nrsize, & - this%nvert, this%vertices, this%iavert, & - this%javert, this%cellxy, & - this%top, this%bot, & + if (this%nodes < this%nodesuser) nrsize = this%nodes + allocate (this%con) + call this%con%disvconnections(this%name_model, this%nodes, & + this%ncpl, this%nlay, nrsize, & + this%nvert, this%vertices, this%iavert, & + this%javert, this%cellxy, & + this%top, this%bot, & this%nodereduced, this%nodeuser) this%nja = this%con%nja this%njas = this%con%njas @@ -960,7 +830,6 @@ subroutine write_grb(this, icelltype) ! -- modules use InputOutputModule, only: getunit, openfile use OpenSpecModule, only: access, form - use ConstantsModule, only: DZERO ! -- dummy class(GwfDisvType) :: this integer(I4B), dimension(:), intent(in) :: icelltype @@ -970,8 +839,8 @@ subroutine write_grb(this, icelltype) character(len=50) :: txthdr character(len=lentxt) :: txt character(len=LINELENGTH) :: fname - character(len=*),parameter :: fmtgrdsave = & - "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & + character(len=*), parameter :: fmtgrdsave = & + "(4X,'BINARY GRID INFORMATION WILL BE WRITTEN TO:', & &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)" ! ------------------------------------------------------------------------------ ! @@ -979,113 +848,115 @@ subroutine write_grb(this, icelltype) ntxt = 20 ! ! -- Open the file - inquire(unit=this%inunit, name=fname) - fname = trim(fname) // '.grb' + inquire (unit=this%inunit, name=fname) + fname = trim(fname)//'.grb' iunit = getunit() - write(this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) - call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & + write (this%iout, fmtgrdsave) iunit, trim(adjustl(fname)) + call openfile(iunit, this%iout, trim(adjustl(fname)), 'DATA(BINARY)', & form, access, 'REPLACE') ! ! -- write header information - write(txthdr, '(a)') 'GRID DISV' + write (txthdr, '(a)') 'GRID DISV' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a)') 'VERSION 1' + write (iunit) txthdr + write (txthdr, '(a)') 'VERSION 1' txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'NTXT ', ntxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'NTXT ', ntxt txthdr(50:50) = new_line('a') - write(iunit) txthdr - write(txthdr, '(a, i0)') 'LENTXT ', lentxt + write (iunit) txthdr + write (txthdr, '(a, i0)') 'LENTXT ', lentxt txthdr(50:50) = new_line('a') - write(iunit) txthdr + write (iunit) txthdr ! ! -- write variable definitions - write(txt, '(3a, i0)') 'NCELLS ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser + write (txt, '(3a, i0)') 'NCELLS ', 'INTEGER ', 'NDIM 0 # ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NLAY ', 'INTEGER ', 'NDIM 0 # ', this%nlay + write (iunit) txt + write (txt, '(3a, i0)') 'NLAY ', 'INTEGER ', 'NDIM 0 # ', this%nlay txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NCPL ', 'INTEGER ', 'NDIM 0 # ', this%ncpl + write (iunit) txt + write (txt, '(3a, i0)') 'NCPL ', 'INTEGER ', 'NDIM 0 # ', this%ncpl txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NVERT ', 'INTEGER ', 'NDIM 0 # ', this%nvert + write (iunit) txt + write (txt, '(3a, i0)') 'NVERT ', 'INTEGER ', 'NDIM 0 # ', this%nvert txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NJAVERT ', 'INTEGER ', 'NDIM 0 # ', size(this%javert) + write (iunit) txt + write (txt, '(3a, i0)') 'NJAVERT ', 'INTEGER ', 'NDIM 0 # ', size(this%javert) txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%con%nja + write (iunit) txt + write (txt, '(3a, i0)') 'NJA ', 'INTEGER ', 'NDIM 0 # ', this%con%nja txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg25.15e3)') 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin + write (iunit) txt + write (txt, '(3a, 1pg25.15e3)') & + 'XORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%xorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg25.15e3)') 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin + write (iunit) txt + write (txt, '(3a, 1pg25.15e3)') & + 'YORIGIN ', 'DOUBLE ', 'NDIM 0 # ', this%yorigin txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, 1pg25.15e3)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot + write (iunit) txt + write (txt, '(3a, 1pg25.15e3)') 'ANGROT ', 'DOUBLE ', 'NDIM 0 # ', this%angrot txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', this%ncpl + write (iunit) txt + write (txt, '(3a, i0)') 'TOP ', 'DOUBLE ', 'NDIM 1 ', this%ncpl txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'BOTM ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'BOTM ', 'DOUBLE ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'VERTICES ', 'DOUBLE ', 'NDIM 2 2 ', this%nvert + write (iunit) txt + write (txt, '(3a, i0)') 'VERTICES ', 'DOUBLE ', 'NDIM 2 2 ', this%nvert txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'CELLX ', 'DOUBLE ', 'NDIM 1 ', this%ncpl + write (iunit) txt + write (txt, '(3a, i0)') 'CELLX ', 'DOUBLE ', 'NDIM 1 ', this%ncpl txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'CELLY ', 'DOUBLE ', 'NDIM 1 ', this%ncpl + write (iunit) txt + write (txt, '(3a, i0)') 'CELLY ', 'DOUBLE ', 'NDIM 1 ', this%ncpl txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IAVERT ', 'INTEGER ', 'NDIM 1 ', this%ncpl + 1 + write (iunit) txt + write (txt, '(3a, i0)') 'IAVERT ', 'INTEGER ', 'NDIM 1 ', this%ncpl + 1 txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'JAVERT ', 'INTEGER ', 'NDIM 1 ', size(this%javert) + write (iunit) txt + write (txt, '(3a, i0)') 'JAVERT ', 'INTEGER ', 'NDIM 1 ', size(this%javert) txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 + write (iunit) txt + write (txt, '(3a, i0)') 'IA ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + 1 txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', size(this%con%jausr) + write (iunit) txt + write (txt, '(3a, i0)') 'JA ', 'INTEGER ', 'NDIM 1 ', size(this%con%jausr) txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'IDOMAIN ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'IDOMAIN ', 'INTEGER ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt - write(txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser + write (iunit) txt + write (txt, '(3a, i0)') 'ICELLTYPE ', 'INTEGER ', 'NDIM 1 ', this%nodesuser txt(lentxt:lentxt) = new_line('a') - write(iunit) txt + write (iunit) txt ! ! -- write data - write(iunit) this%nodesuser ! ncells - write(iunit) this%nlay ! nlay - write(iunit) this%ncpl ! ncpl - write(iunit) this%nvert ! nvert - write(iunit) size(this%javert) ! njavert - write(iunit) this%nja ! nja - write(iunit) this%xorigin ! xorigin - write(iunit) this%yorigin ! yorigin - write(iunit) this%angrot ! angrot - write(iunit) this%top2d ! top - write(iunit) this%bot3d ! botm - write(iunit) this%vertices ! vertices - write(iunit) (this%cellxy(1, i), i = 1, this%ncpl) ! cellx - write(iunit) (this%cellxy(2, i), i = 1, this%ncpl) ! celly - write(iunit) this%iavert ! iavert - write(iunit) this%javert ! javert - write(iunit) this%con%iausr ! iausr - write(iunit) this%con%jausr ! jausr - write(iunit) this%idomain ! idomain - write(iunit) icelltype ! icelltype + write (iunit) this%nodesuser ! ncells + write (iunit) this%nlay ! nlay + write (iunit) this%ncpl ! ncpl + write (iunit) this%nvert ! nvert + write (iunit) size(this%javert) ! njavert + write (iunit) this%nja ! nja + write (iunit) this%xorigin ! xorigin + write (iunit) this%yorigin ! yorigin + write (iunit) this%angrot ! angrot + write (iunit) this%top1d ! top + write (iunit) this%bot2d ! botm + write (iunit) this%vertices ! vertices + write (iunit) (this%cellxy(1, i), i=1, this%ncpl) ! cellx + write (iunit) (this%cellxy(2, i), i=1, this%ncpl) ! celly + write (iunit) this%iavert ! iavert + write (iunit) this%javert ! javert + write (iunit) this%con%iausr ! iausr + write (iunit) this%con%jausr ! jausr + write (iunit) this%idomain ! idomain + write (iunit) icelltype ! icelltype ! ! -- Close the file - close(iunit) + close (iunit) ! ! -- return return @@ -1111,10 +982,10 @@ subroutine nodeu_to_string(this, nodeu, str) ! ------------------------------------------------------------------------------ ! call get_ijk(nodeu, 1, this%ncpl, this%nlay, i, j, k) - write(kstr, '(i10)') k - write(jstr, '(i10)') j - str = '(' // trim(adjustl(kstr)) // ',' // & - trim(adjustl(jstr)) // ')' + write (kstr, '(i10)') k + write (jstr, '(i10)') j + str = '('//trim(adjustl(kstr))//','// & + trim(adjustl(jstr))//')' ! ! -- return return @@ -1142,8 +1013,8 @@ subroutine nodeu_to_array(this, nodeu, arr) ! -- check the size of arr isize = size(arr) if (isize /= this%ndim) then - write(errmsg,'(a,i0,a,i0,a)') & - 'Program error: nodeu_to_array size of array (', isize, & + write (errmsg, '(a,i0,a,i0,a)') & + 'Program error: nodeu_to_array size of array (', isize, & ') is not equal to the discretization dimension (', this%ndim, ')' call store_error(errmsg, terminate=.TRUE.) end if @@ -1158,7 +1029,7 @@ subroutine nodeu_to_array(this, nodeu, arr) ! -- return return end subroutine nodeu_to_array - + function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) ! ****************************************************************************** ! get_nodenumber -- Return a nodenumber from the user specified node number @@ -1168,7 +1039,6 @@ function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH ! -- return integer(I4B) :: nodenumber ! -- dummy @@ -1180,28 +1050,28 @@ function get_nodenumber_idx1(this, nodeu, icheck) result(nodenumber) ! ------------------------------------------------------------------------------ ! ! -- check the node number if requested - if(icheck /= 0) then + if (icheck /= 0) then ! ! -- If within valid range, convert to reduced nodenumber - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, '(a,i10)') & + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, '(a,i10)') & 'Nodenumber less than 1 or greater than nodes:', nodeu call store_error(errmsg) nodenumber = 0 else nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) - endif + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + end if else nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) - endif + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + end if ! ! -- return return end function get_nodenumber_idx1 - function get_nodenumber_idx2(this, k, j, icheck) & + function get_nodenumber_idx2(this, k, j, icheck) & result(nodenumber) ! ****************************************************************************** ! get_nodenumber_idx2 -- Return a nodenumber from the user specified layer and @@ -1210,7 +1080,6 @@ function get_nodenumber_idx2(this, k, j, icheck) & ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH use InputOutputModule, only: get_node implicit none ! -- return @@ -1224,38 +1093,38 @@ function get_nodenumber_idx2(this, k, j, icheck) & integer(I4B) :: nodeu ! formats character(len=*), parameter :: fmterr = & - "('Error in disv grid cell indices: layer = ',i0,', node = ',i0)" + &"('Error in disv grid cell indices: layer = ',i0,', node = ',i0)" ! ------------------------------------------------------------------------------ ! nodeu = get_node(k, 1, j, this%nlay, 1, this%ncpl) if (nodeu < 1) then - write(errmsg, fmterr) k, j + write (errmsg, fmterr) k, j call store_error(errmsg, terminate=.TRUE.) - endif + end if nodenumber = nodeu - if(this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) + if (this%nodes < this%nodesuser) nodenumber = this%nodereduced(nodeu) ! ! -- check the node number if requested - if(icheck /= 0) then + if (icheck /= 0) then ! - if(k < 1 .or. k > this%nlay) & + if (k < 1 .or. k > this%nlay) & call store_error('Layer less than one or greater than nlay') - if(j < 1 .or. j > this%ncpl) & + if (j < 1 .or. j > this%ncpl) & call store_error('Node number less than one or greater than ncpl') ! ! -- Error if outside of range - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(errmsg, '(a,i10)') & + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (errmsg, '(a,i10)') & 'Nodenumber less than 1 or greater than nodes:', nodeu call store_error(errmsg) - endif - endif + end if + end if ! ! -- return return end function get_nodenumber_idx2 - subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & + subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ipos) ! ****************************************************************************** ! connection_normal -- calculate the normal vector components for reduced @@ -1266,8 +1135,6 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: DONE, DZERO - use SimModule, only: store_error ! -- dummy class(GwfDisvType) :: this integer(I4B), intent(in) :: noden @@ -1284,10 +1151,10 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ------------------------------------------------------------------------------ ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then xcomp = DZERO ycomp = DZERO - if(nodem < noden) then + if (nodem < noden) then ! ! -- nodem must be above noden, so upward connection zcomp = DONE @@ -1295,7 +1162,7 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! ! -- nodem must be below noden, so downward connection zcomp = -DONE - endif + end if else ! -- find from anglex, since anglex is symmetric, need to flip vector ! for lower triangle (nodem < noden) @@ -1306,13 +1173,13 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & xcomp = cos(angle) * dmult ycomp = sin(angle) * dmult zcomp = DZERO - endif + end if ! ! -- return return end subroutine connection_normal - subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & + subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & xcomp, ycomp, zcomp, conlen) ! ****************************************************************************** ! connection_vector -- calculate the unit vector components from reduced @@ -1325,8 +1192,6 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: DZERO, DONE, DHALF - use SimModule, only: store_error use InputOutputModule, only: get_jk use DisvGeom, only: line_unit_vector ! -- dummy @@ -1347,16 +1212,16 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! ------------------------------------------------------------------------------ ! ! -- Set vector components based on ihc - if(ihc == 0) then + if (ihc == 0) then ! ! -- vertical connection; set zcomp positive upward xcomp = DZERO ycomp = DZERO - if(nodem < noden) then + if (nodem < noden) then zcomp = DONE else zcomp = -DONE - endif + end if zn = this%bot(noden) + DHALF * (this%top(noden) - this%bot(noden)) zm = this%bot(nodem) + DHALF * (this%top(nodem) - this%bot(nodem)) conlen = abs(zm - zn) @@ -1370,7 +1235,7 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & else zn = this%bot(noden) + DHALF * satn * (this%top(noden) - this%bot(noden)) zm = this%bot(nodem) + DHALF * satm * (this%top(nodem) - this%bot(nodem)) - endif + end if nodeu = this%get_nodeuser(noden) call get_jk(nodeu, this%ncpl, this%nlay, ncell2d, k) nodeu = this%get_nodeuser(nodem) @@ -1379,40 +1244,23 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & yn = this%cellxy(2, ncell2d) xm = this%cellxy(1, mcell2d) ym = this%cellxy(2, mcell2d) - call line_unit_vector(xn, yn, zn, xm, ym, zm, xcomp, ycomp, zcomp, & + call line_unit_vector(xn, yn, zn, xm, ym, zm, xcomp, ycomp, zcomp, & conlen) - endif + end if ! ! -- return return end subroutine connection_vector - ! return x,y coordinate for a node - subroutine get_cellxy_disv(this, node, xcell, ycell) - use InputOutputModule, only: get_jk - class(GwfDisvType), intent(in) :: this - integer(I4B), intent(in) :: node ! the reduced node number - real(DP), intent(out) :: xcell, ycell ! the x,y for the cell - ! local - integer(I4B) :: nodeuser, ncell2d, k - - nodeuser = this%get_nodeuser(node) - call get_jk(nodeuser, this%ncpl, this%nlay, ncell2d, k) - - xcell = this%cellxy(1, ncell2d) - ycell = this%cellxy(2, ncell2d) - - end subroutine get_cellxy_disv - - ! return discretization type + ! return discretization type subroutine get_dis_type(this, dis_type) - class(GwfDisvType), intent(in) :: this - character(len=*), intent(out) :: dis_type - + class(GwfDisvType), intent(in) :: this + character(len=*), intent(out) :: dis_type + dis_type = "DISV" - + end subroutine get_dis_type - + subroutine allocate_scalars(this, name_model) ! ****************************************************************************** ! allocate_scalars -- Allocate and initialize scalars @@ -1462,13 +1310,14 @@ subroutine allocate_arrays(this) call this%DisBaseType%allocate_arrays() ! ! -- Allocate arrays for GwfDisvType - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call mem_allocate(this%nodeuser, this%nodes, 'NODEUSER', this%memoryPath) - call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', this%memoryPath) + call mem_allocate(this%nodereduced, this%nodesuser, 'NODEREDUCED', & + this%memoryPath) else call mem_allocate(this%nodeuser, 1, 'NODEUSER', this%memoryPath) call mem_allocate(this%nodereduced, 1, 'NODEREDUCED', this%memoryPath) - endif + end if ! -- Initialize this%mshape(1) = this%nlay this%mshape(2) = this%ncpl @@ -1488,7 +1337,6 @@ function get_cell2d_area(this, icell2d) result(area) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- module - use ConstantsModule, only: DZERO, DHALF, DONE ! -- dummy class(GwfDisvType) :: this integer(I4B), intent(in) :: icell2d @@ -1507,26 +1355,26 @@ function get_cell2d_area(this, icell2d) result(area) icount = 1 do ivert = this%iavert(icell2d), this%iavert(icell2d + 1) - 1 x = this%vertices(1, this%javert(ivert)) - if(icount < nvert) then + if (icount < nvert) then y = this%vertices(2, this%javert(ivert + 1)) else y = this%vertices(2, this%javert(this%iavert(icell2d))) - endif + end if area = area + x * y icount = icount + 1 - enddo + end do ! icount = 1 do ivert = this%iavert(icell2d), this%iavert(icell2d + 1) - 1 y = this%vertices(2, this%javert(ivert)) - if(icount < nvert) then + if (icount < nvert) then x = this%vertices(1, this%javert(ivert + 1)) else x = this%vertices(1, this%javert(this%iavert(icell2d))) - endif + end if area = area - x * y icount = icount + 1 - enddo + end do ! area = -DONE * area * DHALF ! @@ -1569,14 +1417,14 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & ! Check to see if first token in line can be read as an integer. lloclocal = lloc call urword(line, lloclocal, istart, istop, 1, ndum, r, iout, in) - read(line(istart:istop),*,iostat=istat)n + read (line(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in line is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! nlay = this%mshape(1) nrow = 1 @@ -1590,24 +1438,24 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & if (allow_zero) then nodeu = 0 return - endif - endif - endif + end if + end if + end if ! - if(k < 1 .or. k > nlay) then - write(ermsg, *) ' Layer number in list is outside of the grid', k - call store_error(ermsg) + if (k < 1 .or. k > nlay) then + write (ermsg, *) ' Layer number in list is outside of the grid', k + call store_error(ermsg) end if - if(j < 1 .or. j > ncpl) then - write(ermsg, *) ' Cell2d number in list is outside of the grid', j - call store_error(ermsg) + if (j < 1 .or. j > ncpl) then + write (ermsg, *) ' Cell2d number in list is outside of the grid', j + call store_error(ermsg) end if nodeu = get_node(k, 1, j, nlay, nrow, ncpl) ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(ermsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (ermsg, *) ' Node number in list is outside of the grid', nodeu call store_error(ermsg) - inquire(unit=in, name=fname) + inquire (unit=in, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in line: ') @@ -1620,7 +1468,7 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & end function nodeu_from_string function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & - allow_zero) result(nodeu) + allow_zero) result(nodeu) ! ****************************************************************************** ! nodeu_from_cellid -- Receive cellid as a string and convert the string to a ! user nodenumber. @@ -1638,7 +1486,7 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & integer(I4B) :: nodeu ! -- dummy class(GwfDisvType) :: this - character(len=*), intent(inout) :: cellid + character(len=*), intent(inout) :: cellid integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout logical, optional, intent(in) :: flag_string @@ -1656,14 +1504,14 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! Check to see if first token in cellid can be read as an integer. lloclocal = 1 call urword(cellid, lloclocal, istart, istop, 1, ndum, r, iout, inunit) - read(cellid(istart:istop), *, iostat=istat) n + read (cellid(istart:istop), *, iostat=istat) n if (istat /= 0) then ! First token in cellid is not an integer; return flag to this effect. nodeu = -2 return - endif - endif - endif + end if + end if + end if ! nlay = this%mshape(1) nrow = 1 @@ -1678,24 +1526,24 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & if (allow_zero) then nodeu = 0 return - endif - endif - endif + end if + end if + end if ! - if(k < 1 .or. k > nlay) then - write(ermsg, *) ' Layer number in list is outside of the grid', k - call store_error(ermsg) + if (k < 1 .or. k > nlay) then + write (ermsg, *) ' Layer number in list is outside of the grid', k + call store_error(ermsg) end if - if(j < 1 .or. j > ncpl) then - write(ermsg, *) ' Cell2d number in list is outside of the grid', j - call store_error(ermsg) + if (j < 1 .or. j > ncpl) then + write (ermsg, *) ' Cell2d number in list is outside of the grid', j + call store_error(ermsg) end if nodeu = get_node(k, 1, j, nlay, nrow, ncpl) ! - if(nodeu < 1 .or. nodeu > this%nodesuser) then - write(ermsg, *) ' Node number in list is outside of the grid', nodeu + if (nodeu < 1 .or. nodeu > this%nodesuser) then + write (ermsg, *) ' Node number in list is outside of the grid', nodeu call store_error(ermsg) - inquire(unit=inunit, name=fname) + inquire (unit=inunit, name=fname) call store_error('Error converting in file: ') call store_error(trim(adjustl(fname))) call store_error('Cell number cannot be determined in cellid: ') @@ -1746,19 +1594,16 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use InputOutputModule, only: urword - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisvType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisvType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: iarray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: ival real(DP) :: rval @@ -1777,21 +1622,21 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & nrow = 1 ncol = this%mshape(2) ! - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodesuser itemp => this%ibuff else nval = this%nodes itemp => iarray - endif + end if ! ! -- Read the array call urword(line, lloc, istart, istop, 1, ival, rval, iout, in) - if (line(istart:istop).EQ.'LAYERED') then + if (line(istart:istop) .EQ. 'LAYERED') then ! ! -- Read layered input call ReadArray(in, itemp, aname, this%ndim, ncol, nrow, nlay, nval, & - iout, 1, nlay) + iout, 1, nlay) else ! ! -- Read unstructured input @@ -1799,9 +1644,9 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & end if ! ! -- If reduced model, then need to copy from itemp(=>ibuff) to iarray - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(itemp, iarray) - endif + end if ! ! -- return return @@ -1816,19 +1661,16 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use InputOutputModule, only: urword - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwfDisvType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(GwfDisvType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! -- local integer(I4B) :: ival real(DP) :: rval @@ -1847,21 +1689,21 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & nrow = 1 ncol = this%mshape(2) ! - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodesuser dtemp => this%dbuff else nval = this%nodes dtemp => darray - endif + end if ! ! -- Read the array call urword(line, lloc, istart, istop, 1, ival, rval, iout, in) - if (line(istart:istop).EQ.'LAYERED') then + if (line(istart:istop) .EQ. 'LAYERED') then ! ! -- Read structured input call ReadArray(in, dtemp, aname, this%ndim, ncol, nrow, nlay, nval, & - iout, 1, nlay) + iout, 1, nlay) else ! ! -- Read unstructured input @@ -1869,15 +1711,15 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & end if ! ! -- If reduced model, then need to copy from dtemp(=>dbuff) to darray - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then call this%fill_grid_array(dtemp, darray) - endif + end if ! ! -- return return end subroutine read_dbl_array - subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & + subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & icolbnd, aname, inunit, iout) ! ****************************************************************************** ! read_layer_array -- Read a 2d double array into col icolbnd of darray. @@ -1922,14 +1764,14 @@ subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & nodeu = get_node(1, ir, ic, nlay, nrow, ncol) darray(icolbnd, ipos) = this%dbuff(nodeu) ipos = ipos + 1 - enddo - enddo + end do + end do ! ! -- return end subroutine read_layer_array - subroutine record_array(this, darray, iout, iprint, idataun, aname, & - cdatafmp, nvaluesp, nwidthp, editdesc, dinact) + subroutine record_array(this, darray, iout, iprint, idataun, aname, & + cdatafmp, nvaluesp, nwidthp, editdesc, dinact) ! ****************************************************************************** ! record_array -- Record a double precision array. The array will be ! printed to an external file and/or written to an unformatted external file @@ -1952,17 +1794,17 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(GwfDisvType), intent(inout) :: this + class(GwfDisvType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: iprint - integer(I4B), intent(in) :: idataun - character(len=*), intent(in) :: aname - character(len=*), intent(in) :: cdatafmp - integer(I4B), intent(in) :: nvaluesp - integer(I4B), intent(in) :: nwidthp - character(len=*), intent(in) :: editdesc - real(DP), intent(in) :: dinact + integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: iprint + integer(I4B), intent(in) :: idataun + character(len=*), intent(in) :: aname + character(len=*), intent(in) :: cdatafmp + integer(I4B), intent(in) :: nvaluesp + integer(I4B), intent(in) :: nwidthp + character(len=*), intent(in) :: editdesc + real(DP), intent(in) :: dinact ! -- local integer(I4B) :: k, ifirst integer(I4B) :: nlay @@ -1973,7 +1815,7 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & integer(I4B) :: istart, istop real(DP), dimension(:), pointer, contiguous :: dtemp ! -- formats - character(len=*),parameter :: fmthsv = & + character(len=*), parameter :: fmthsv = & "(1X,/1X,a,' WILL BE SAVED ON UNIT ',I4, & &' AT END OF TIME STEP',I5,', STRESS PERIOD ',I4)" ! ------------------------------------------------------------------------------ @@ -1985,61 +1827,61 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! ! -- If this is a reduced model, then copy the values from darray into ! dtemp. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nval = this%nodes dtemp => this%dbuff do nodeu = 1, this%nodesuser noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) then + if (noder <= 0) then dtemp(nodeu) = dinact cycle - endif + end if dtemp(nodeu) = darray(noder) - enddo + end do else nval = this%nodes dtemp => darray - endif + end if ! ! -- Print to iout if iprint /= 0 - if(iprint /= 0) then + if (iprint /= 0) then istart = 1 do k = 1, nlay istop = istart + nrow * ncol - 1 - call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & + call ulaprufw(ncol, nrow, kstp, kper, k, iout, dtemp(istart:istop), & aname, cdatafmp, nvaluesp, nwidthp, editdesc) istart = istop + 1 - enddo - endif + end do + end if ! ! -- Save array to an external file. - if(idataun > 0) then + if (idataun > 0) then ! -- write to binary file by layer ifirst = 1 istart = 1 - do k=1, nlay + do k = 1, nlay istop = istart + nrow * ncol - 1 - if(ifirst == 1) write(iout, fmthsv) & - trim(adjustl(aname)), idataun, & - kstp, kper + if (ifirst == 1) write (iout, fmthsv) & + trim(adjustl(aname)), idataun, & + kstp, kper ifirst = 0 - call ulasav(dtemp(istart:istop), aname, kstp, kper, & + call ulasav(dtemp(istart:istop), aname, kstp, kper, & pertim, totim, ncol, nrow, k, idataun) istart = istop + 1 - enddo - elseif(idataun < 0) then + end do + elseif (idataun < 0) then ! ! -- write entire array as one record - call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & + call ubdsv1(kstp, kper, aname, -idataun, dtemp, ncol, nrow, nlay, & iout, delt, pertim, totim) - endif + end if ! ! -- return return end subroutine record_array - subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & - dstmodel, dstpackage, naux, auxtxt, & + subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & + dstmodel, dstpackage, naux, auxtxt, & ibdchn, nlist, iout) ! ****************************************************************************** ! record_srcdst_list_header -- Record list header for imeth=6 @@ -2068,8 +1910,8 @@ subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & ncol = this%mshape(2) ! ! -- Use ubdsv06 to write list header - call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage,& - ibdchn, naux, auxtxt, ncol, nrow, nlay, & + call ubdsv06(kstp, kper, text, textmodel, textpackage, dstmodel, dstpackage, & + ibdchn, naux, auxtxt, ncol, nrow, nlay, & nlist, iout, delt, pertim, totim) ! ! -- return @@ -2088,8 +1930,6 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & ! ------------------------------------------------------------------------------ ! -- modules use InputOutputModule, only: get_node - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH ! -- dummy class(GwfDisvType) :: this integer(I4B), intent(in) :: maxbnd @@ -2118,36 +1958,36 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & do ic = 1, ncol nodeu = get_node(1, ir, ic, nlay, nrow, ncol) il = this%ibuff(nodeu) - if(il < 1 .or. il > nlay) then - write(errmsg, *) 'ERROR. INVALID LAYER NUMBER: ', il + if (il < 1 .or. il > nlay) then + write (errmsg, *) 'ERROR. INVALID LAYER NUMBER: ', il call store_error(errmsg, terminate=.TRUE.) - endif + end if nodeu = get_node(il, ir, ic, nlay, nrow, ncol) noder = this%get_nodenumber(nodeu, 0) - if(ipos > maxbnd) then + if (ipos > maxbnd) then ierr = ipos else nodelist(ipos) = noder - endif + end if ipos = ipos + 1 - enddo - enddo + end do + end do ! ! -- Check for errors nbound = ipos - 1 - if(ierr > 0) then - write(errmsg, *) 'ERROR. MAXBOUND DIMENSION IS TOO SMALL.' + if (ierr > 0) then + write (errmsg, *) 'ERROR. MAXBOUND DIMENSION IS TOO SMALL.' call store_error(errmsg) - write(errmsg, *) 'INCREASE MAXBOUND TO: ', ierr + write (errmsg, *) 'INCREASE MAXBOUND TO: ', ierr call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- If nbound < maxbnd, then initialize nodelist to zero in this range - if(nbound < maxbnd) then - do ipos = nbound+1, maxbnd + if (nbound < maxbnd) then + do ipos = nbound + 1, maxbnd nodelist(ipos) = 0 - enddo - endif + end do + end if ! ! -- return end subroutine nlarray_to_nodelist diff --git a/src/Model/GroundWaterFlow/gwf3disv8idm.f90 b/src/Model/GroundWaterFlow/gwf3disv8idm.f90 new file mode 100644 index 00000000000..86e553c1dfc --- /dev/null +++ b/src/Model/GroundWaterFlow/gwf3disv8idm.f90 @@ -0,0 +1,429 @@ +module GwfDisvInputModule + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwf_disv_param_definitions + public gwf_disv_aggregate_definitions + public gwf_disv_block_definitions + public GwfDisvParamFoundType + + type GwfDisvParamFoundType + logical :: length_units = .false. + logical :: nogrb = .false. + logical :: xorigin = .false. + logical :: yorigin = .false. + logical :: angrot = .false. + logical :: nlay = .false. + logical :: ncpl = .false. + logical :: nvert = .false. + logical :: top = .false. + logical :: botm = .false. + logical :: idomain = .false. + logical :: iv = .false. + logical :: xv = .false. + logical :: yv = .false. + logical :: icell2d = .false. + logical :: xc = .false. + logical :: yc = .false. + logical :: ncvert = .false. + logical :: icvert = .false. + end type GwfDisvParamFoundType + + type(InputParamDefinitionType), parameter :: & + gwfdisv_length_units = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'OPTIONS', & ! block + 'LENGTH_UNITS', & ! tag name + 'LENGTH_UNITS', & ! fortran variable + 'STRING', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_nogrb = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'OPTIONS', & ! block + 'NOGRB', & ! tag name + 'NOGRB', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_xorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'OPTIONS', & ! block + 'XORIGIN', & ! tag name + 'XORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_yorigin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'OPTIONS', & ! block + 'YORIGIN', & ! tag name + 'YORIGIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_angrot = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'OPTIONS', & ! block + 'ANGROT', & ! tag name + 'ANGROT', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_nlay = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'DIMENSIONS', & ! block + 'NLAY', & ! tag name + 'NLAY', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_ncpl = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'DIMENSIONS', & ! block + 'NCPL', & ! tag name + 'NCPL', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_nvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'DIMENSIONS', & ! block + 'NVERT', & ! tag name + 'NVERT', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_top = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'GRIDDATA', & ! block + 'TOP', & ! tag name + 'TOP', & ! fortran variable + 'DOUBLE1D', & ! type + 'NCPL', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_botm = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'GRIDDATA', & ! block + 'BOTM', & ! tag name + 'BOTM', & ! fortran variable + 'DOUBLE2D', & ! type + 'NCPL NLAY', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_idomain = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'GRIDDATA', & ! block + 'IDOMAIN', & ! tag name + 'IDOMAIN', & ! fortran variable + 'INTEGER2D', & ! type + 'NCPL NLAY', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_iv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'VERTICES', & ! block + 'IV', & ! tag name + 'IV', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_xv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'VERTICES', & ! block + 'XV', & ! tag name + 'XV', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_yv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'VERTICES', & ! block + 'YV', & ! tag name + 'YV', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_icell2d = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'ICELL2D', & ! tag name + 'ICELL2D', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_xc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'XC', & ! tag name + 'XC', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_yc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'YC', & ! tag name + 'YC', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_ncvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'NCVERT', & ! tag name + 'NCVERT', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_icvert = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'ICVERT', & ! tag name + 'ICVERT', & ! fortran variable + 'INTEGER1D', & ! type + 'NCVERT', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_disv_param_definitions(*) = & + [ & + gwfdisv_length_units, & + gwfdisv_nogrb, & + gwfdisv_xorigin, & + gwfdisv_yorigin, & + gwfdisv_angrot, & + gwfdisv_nlay, & + gwfdisv_ncpl, & + gwfdisv_nvert, & + gwfdisv_top, & + gwfdisv_botm, & + gwfdisv_idomain, & + gwfdisv_iv, & + gwfdisv_xv, & + gwfdisv_yv, & + gwfdisv_icell2d, & + gwfdisv_xc, & + gwfdisv_yc, & + gwfdisv_ncvert, & + gwfdisv_icvert & + ] + + type(InputParamDefinitionType), parameter :: & + gwfdisv_vertices = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'VERTICES', & ! block + 'VERTICES', & ! tag name + 'VERTICES', & ! fortran variable + 'RECARRAY IV XV YV', & ! type + 'NVERT', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfdisv_cell2d = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'DISV', & ! subcomponent + 'CELL2D', & ! block + 'CELL2D', & ! tag name + 'CELL2D', & ! fortran variable + 'RECARRAY ICELL2D XC YC NCVERT ICVERT', & ! type + 'NCPL', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_disv_aggregate_definitions(*) = & + [ & + gwfdisv_vertices, & + gwfdisv_cell2d & + ] + + type(InputBlockDefinitionType), parameter :: & + gwf_disv_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .false., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'DIMENSIONS', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'GRIDDATA', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'VERTICES', & ! blockname + .true., & ! required + .true. & ! aggregate + ), & + InputBlockDefinitionType( & + 'CELL2D', & ! blockname + .true., & ! required + .true. & ! aggregate + ) & + ] + +end module GwfDisvInputModule diff --git a/src/Model/GroundWaterFlow/gwf3drn8.f90 b/src/Model/GroundWaterFlow/gwf3drn8.f90 index 22e2ea82e9c..45a329f9faa 100644 --- a/src/Model/GroundWaterFlow/gwf3drn8.f90 +++ b/src/Model/GroundWaterFlow/gwf3drn8.f90 @@ -1,10 +1,10 @@ module DrnModule use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DONE, DTWO, & + use ConstantsModule, only: DZERO, DONE, DTWO, & LENFTYPE, LENPACKAGENAME, LENAUXNAME, LINELENGTH use MemoryHelperModule, only: create_mem_path - use SmoothingModule, only: sQSaturation, sQSaturationDerivative, & - sQuadraticSaturation + use SmoothingModule, only: sQSaturation, sQSaturationDerivative, & + sQuadraticSaturation use BndModule, only: BndType use ObsModule, only: DefaultObsIdProcessor use TimeSeriesLinkModule, only: TimeSeriesLinkType, & @@ -16,30 +16,30 @@ module DrnModule public :: drn_create public :: DrnType ! - character(len=LENFTYPE) :: ftype = 'DRN' - character(len=LENPACKAGENAME) :: text = ' DRN' + character(len=LENFTYPE) :: ftype = 'DRN' + character(len=LENPACKAGENAME) :: text = ' DRN' ! type, extends(BndType) :: DrnType - + integer(I4B), pointer :: iauxddrncol => null() integer(I4B), pointer :: icubic_scaling => null() - - contains - procedure :: allocate_scalars => drn_allocate_scalars - procedure :: bnd_options => drn_options - procedure :: bnd_ck => drn_ck - procedure :: bnd_cf => drn_cf - procedure :: bnd_fc => drn_fc - procedure :: bnd_fn => drn_fn - procedure :: bnd_da => drn_da - procedure :: define_listlabel - procedure :: get_drain_elevations - procedure :: get_drain_factor - ! -- methods for observations - procedure, public :: bnd_obs_supported => drn_obs_supported - procedure, public :: bnd_df_obs => drn_df_obs - ! -- method for time series - procedure, public :: bnd_rp_ts => drn_rp_ts + + contains + procedure :: allocate_scalars => drn_allocate_scalars + procedure :: bnd_options => drn_options + procedure :: bnd_ck => drn_ck + procedure :: bnd_cf => drn_cf + procedure :: bnd_fc => drn_fc + procedure :: bnd_fn => drn_fn + procedure :: bnd_da => drn_da + procedure :: define_listlabel + procedure :: get_drain_elevations + procedure :: get_drain_factor + ! -- methods for observations + procedure, public :: bnd_obs_supported => drn_obs_supported + procedure, public :: bnd_df_obs => drn_df_obs + ! -- method for time series + procedure, public :: bnd_rp_ts => drn_rp_ts end type DrnType contains @@ -55,10 +55,10 @@ subroutine drn_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -66,7 +66,7 @@ subroutine drn_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(drnobj) + allocate (drnobj) packobj => drnobj ! ! -- create name and memory path @@ -80,12 +80,12 @@ subroutine drn_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) call packobj%pack_initialize() ! ! -- initialize - packobj%inunit=inunit - packobj%iout=iout - packobj%id=id + packobj%inunit = inunit + packobj%iout = iout + packobj%id = id packobj%ibcnum = ibcnum - packobj%ncolbnd=2 ! drnelev, conductance - packobj%iscloc=2 !sfac applies to conductance + packobj%ncolbnd = 2 ! drnelev, conductance + packobj%iscloc = 2 !sfac applies to conductance packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return @@ -159,9 +159,9 @@ subroutine drn_options(this, option, found) use InputOutputModule, only: urword use SimModule, only: store_error ! -- dummy - class(DrnType), intent(inout) :: this + class(DrnType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=LINELENGTH) :: errmsg character(len=LENAUXNAME) :: ddrnauxname @@ -169,41 +169,41 @@ subroutine drn_options(this, option, found) ! ------------------------------------------------------------------------------ ! select case (option) - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case('AUXDEPTHNAME') - call this%parser%GetStringCaps(ddrnauxname) - this%iauxddrncol = -1 - write(this%iout, '(4x,a,a)') & - 'AUXILIARY DRAIN DEPTH NAME: ', trim(ddrnauxname) - found = .true. + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + found = .true. + case ('AUXDEPTHNAME') + call this%parser%GetStringCaps(ddrnauxname) + this%iauxddrncol = -1 + write (this%iout, '(4x,a,a)') & + 'AUXILIARY DRAIN DEPTH NAME: ', trim(ddrnauxname) + found = .true. ! ! -- right now these are options that are only available in the ! development version and are not included in the documentation. ! These options are only available when IDEVELOPMODE in ! constants module is set to 1 - case ('DEV_CUBIC_SCALING') - call this%parser%DevOpt() - this%icubic_scaling = 1 - write(this%iout, '(4x,a,1x,a)') & - 'CUBIC SCALING will be used for drains with non-zero DDRN values', & - 'even if the NEWTON-RAPHSON method is not being used.' - found = .true. - case default - ! - ! -- No options found - found = .false. + case ('DEV_CUBIC_SCALING') + call this%parser%DevOpt() + this%icubic_scaling = 1 + write (this%iout, '(4x,a,1x,a)') & + 'CUBIC SCALING will be used for drains with non-zero DDRN values', & + 'even if the NEWTON-RAPHSON method is not being used.' + found = .true. + case default + ! + ! -- No options found + found = .false. end select ! ! -- DDRN was specified, so find column of auxvar that will be used if (this%iauxddrncol < 0) then ! ! -- Error if no aux variable specified - if(this%naux == 0) then - write(errmsg,'(a,2(1x,a))') & - 'AUXDDRNNAME WAS SPECIFIED AS', trim(adjustl(ddrnauxname)), & + if (this%naux == 0) then + write (errmsg, '(a,2(1x,a))') & + 'AUXDDRNNAME WAS SPECIFIED AS', trim(adjustl(ddrnauxname)), & 'BUT NO AUX VARIABLES SPECIFIED.' call store_error(errmsg) end if @@ -211,16 +211,16 @@ subroutine drn_options(this, option, found) ! -- Assign ddrn column this%iauxddrncol = 0 do n = 1, this%naux - if(ddrnauxname == this%auxname(n)) then + if (ddrnauxname == this%auxname(n)) then this%iauxddrncol = n exit end if end do ! ! -- Error if aux variable cannot be found - if(this%iauxddrncol == 0) then - write(errmsg,'(a,2(1x,a))') & - 'AUXDDRNNAME WAS SPECIFIED AS', trim(adjustl(ddrnauxname)), & + if (this%iauxddrncol == 0) then + write (errmsg, '(a,2(1x,a))') & + 'AUXDDRNNAME WAS SPECIFIED AS', trim(adjustl(ddrnauxname)), & 'BUT NO AUX VARIABLE FOUND WITH THIS NAME.' call store_error(errmsg) end if @@ -241,7 +241,7 @@ subroutine drn_ck(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(DrnType),intent(inout) :: this + class(DrnType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg integer(I4B) :: i @@ -251,32 +251,32 @@ subroutine drn_ck(this) real(DP) :: drntop real(DP) :: drnbot ! -- formats - character(len=*), parameter :: fmtddrnerr = & - "('SCALED-CONDUCTANCE DRN BOUNDARY (',i0,') BOTTOM ELEVATION " // & - "(',f10.3,') IS LESS THAN CELL BOTTOM (',f10.3,')')" - character(len=*), parameter :: fmtdrnerr = & - "('DRN BOUNDARY (',i0,') ELEVATION (',f10.3,') IS LESS THAN CELL " // & - "BOTTOM (',f10.3,')')" + character(len=*), parameter :: fmtddrnerr = & + "('SCALED-CONDUCTANCE DRN BOUNDARY (',i0,') BOTTOM ELEVATION & + &(',f10.3,') IS LESS THAN CELL BOTTOM (',f10.3,')')" + character(len=*), parameter :: fmtdrnerr = & + "('DRN BOUNDARY (',i0,') ELEVATION (',f10.3,') IS LESS THAN CELL & + &BOTTOM (',f10.3,')')" ! ------------------------------------------------------------------------------ ! ! -- check stress period data do i = 1, this%nbound - node = this%nodelist(i) - bt = this%dis%bot(node) - ! - ! -- calculate the drainage depth and the top and bottom of - ! the conductance scaling elevations - call this%get_drain_elevations(i, drndepth, drntop, drnbot) - ! - ! -- accumulate errors - if (drnbot < bt .and. this%icelltype(node) /= 0) then - if (drndepth /= DZERO) then - write(errmsg, fmt=fmtddrnerr) i, drnbot, bt - else - write(errmsg, fmt=fmtdrnerr) i, drnbot, bt - end if - call store_error(errmsg) + node = this%nodelist(i) + bt = this%dis%bot(node) + ! + ! -- calculate the drainage depth and the top and bottom of + ! the conductance scaling elevations + call this%get_drain_elevations(i, drndepth, drntop, drnbot) + ! + ! -- accumulate errors + if (drnbot < bt .and. this%icelltype(node) /= 0) then + if (drndepth /= DZERO) then + write (errmsg, fmt=fmtddrnerr) i, drnbot, bt + else + write (errmsg, fmt=fmtdrnerr) i, drnbot, bt end if + call store_error(errmsg) + end if end do ! ! -- write summary of drain package error messages @@ -310,7 +310,7 @@ subroutine drn_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no drains - if(this%nbound == 0) return + if (this%nbound == 0) return ! ! -- pakmvrobj cf lrm = .true. @@ -322,14 +322,14 @@ subroutine drn_cf(this, reset_mover) ! -- Calculate hcof and rhs for each drn entry do i = 1, this%nbound node = this%nodelist(i) - if(this%ibound(node) <= 0) then + if (this%ibound(node) <= 0) then this%hcof(i) = DZERO this%rhs(i) = DZERO cycle end if ! ! -- set local variables for this drain - cdrn = this%bound(2,i) + cdrn = this%bound(2, i) ! ! -- calculate the drainage scaling factor call this%get_drain_factor(i, fact, drnbot) @@ -367,9 +367,9 @@ subroutine drn_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- packmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() - endif + end if ! ! -- Copy package rhs and hcof into solution rhs and amat do i = 1, this%nbound @@ -383,17 +383,17 @@ subroutine drn_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active and this drain is discharging, ! store available water (as positive value). - if(this%imover == 1 .and. fact > DZERO) then - drncond = this%bound(2,i) + if (this%imover == 1 .and. fact > DZERO) then + drncond = this%bound(2, i) qdrn = fact * drncond * (this%xnew(n) - drnbot) call this%pakmvrobj%accumulate_qformvr(i, qdrn) - endif - enddo + end if + end do ! ! -- return return end subroutine drn_fc - + subroutine drn_fn(this, rhs, ia, idxglo, amatsln) ! ************************************************************************** ! drn_fn -- Fill newton terms @@ -427,12 +427,12 @@ subroutine drn_fn(this, rhs, ia, idxglo, amatsln) node = this%nodelist(i) ! ! -- test if node is constant or inactive - if(this%ibound(node) <= 0) then + if (this%ibound(node) <= 0) then cycle end if ! ! -- set local variables for this drain - cdrn = this%bound(2,i) + cdrn = this%bound(2, i) xnew = this%xnew(node) ! ! -- calculate the drainage depth and the top and bottom of @@ -441,7 +441,7 @@ subroutine drn_fn(this, rhs, ia, idxglo, amatsln) ! ! -- calculate scaling factor if (drndepth /= DZERO) then - drterm = sQSaturationDerivative(drntop, drnbot, xnew, & + drterm = sQSaturationDerivative(drntop, drnbot, xnew, & c1=-DONE, c2=DTWO) drterm = drterm * cdrn * (drnbot - xnew) ! @@ -456,7 +456,7 @@ subroutine drn_fn(this, rhs, ia, idxglo, amatsln) ! -- return return end subroutine drn_fn - + subroutine define_listlabel(this) ! ****************************************************************************** ! define_listlabel -- Define the list heading that is written to iout when @@ -469,28 +469,27 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'DRAIN EL.' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'DRAIN EL.' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return end subroutine define_listlabel - subroutine get_drain_elevations(this, i, drndepth, drntop, drnbot) ! ****************************************************************************** ! get_drain_elevations -- Define drain depth and the top and bottom elevations @@ -512,7 +511,7 @@ subroutine get_drain_elevations(this, i, drndepth, drntop, drnbot) ! ! -- initialize dummy and local variables drndepth = DZERO - drnelev = this%bound(1,i) + drnelev = this%bound(1, i) ! ! -- set the drain depth if (this%iauxddrncol > 0) then @@ -533,7 +532,6 @@ subroutine get_drain_elevations(this, i, drndepth, drntop, drnbot) return end subroutine get_drain_elevations - subroutine get_drain_factor(this, i, factor, opt_drnbot) ! ****************************************************************************** ! get_drain_factor -- Get the drain conductance scale factor. @@ -553,39 +551,39 @@ subroutine get_drain_factor(this, i, factor, opt_drnbot) real(DP) :: drntop real(DP) :: drnbot ! ------------------------------------------------------------------------------ - ! - ! -- set local variables for this drain - node = this%nodelist(i) - xnew = this%xnew(node) - ! - ! -- calculate the drainage depth and the top and bottom of - ! the conductance scaling elevations - call this%get_drain_elevations(i, drndepth, drntop, drnbot) - ! - ! -- set opt_drnbot to drnbot if passed as dummy variable - if (present(opt_drnbot)) then - opt_drnbot = drnbot + ! + ! -- set local variables for this drain + node = this%nodelist(i) + xnew = this%xnew(node) + ! + ! -- calculate the drainage depth and the top and bottom of + ! the conductance scaling elevations + call this%get_drain_elevations(i, drndepth, drntop, drnbot) + ! + ! -- set opt_drnbot to drnbot if passed as dummy variable + if (present(opt_drnbot)) then + opt_drnbot = drnbot + end if + ! + ! -- calculate scaling factor + if (drndepth /= DZERO) then + if (this%icubic_scaling /= 0) then + factor = sQSaturation(drntop, drnbot, xnew, c1=-DONE, c2=DTWO) + else + factor = sQuadraticSaturation(drntop, drnbot, xnew, eps=DZERO) end if - ! - ! -- calculate scaling factor - if (drndepth /= DZERO) then - if (this%icubic_scaling /= 0) then - factor = sQSaturation(drntop, drnbot, xnew, c1=-DONE, c2=DTWO) - else - factor = sQuadraticSaturation(drntop, drnbot, xnew, eps=DZERO) - end if + else + if (xnew <= drnbot) then + factor = DZERO else - if (xnew <= drnbot) then - factor = DZERO - else - factor = DONE - end if + factor = DONE end if + end if ! ! -- return return end subroutine get_drain_factor - + ! -- Procedures related to observations logical function drn_obs_supported(this) @@ -647,7 +645,7 @@ subroutine drn_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) @@ -656,8 +654,8 @@ subroutine drn_rp_ts(this) case (2) tslink%Text = 'COND' end select - endif - enddo + end if + end do ! return end subroutine drn_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3evt8.f90 b/src/Model/GroundWaterFlow/gwf3evt8.f90 index 08c243fb644..f7d7382225b 100644 --- a/src/Model/GroundWaterFlow/gwf3evt8.f90 +++ b/src/Model/GroundWaterFlow/gwf3evt8.f90 @@ -4,7 +4,8 @@ module EvtModule use ConstantsModule, only: DZERO, DONE, LENFTYPE, LENPACKAGENAME, MAXCHARLEN use MemoryHelperModule, only: create_mem_path use BndModule, only: BndType - use SimModule, only: store_error, store_error_unit + use SimModule, only: store_error, store_error_unit, count_errors + use SimVariablesModule, only: errmsg use ObsModule, only: DefaultObsIdProcessor use TimeArraySeriesLinkModule, only: TimeArraySeriesLinkType use TimeSeriesLinkModule, only: TimeSeriesLinkType, & @@ -16,16 +17,16 @@ module EvtModule private public :: evt_create ! - character(len=LENFTYPE) :: ftype = 'EVT' - character(len=LENPACKAGENAME) :: text = ' EVT' - character(len=LENPACKAGENAME) :: texta = ' EVTA' + character(len=LENFTYPE) :: ftype = 'EVT' + character(len=LENPACKAGENAME) :: text = ' EVT' + character(len=LENPACKAGENAME) :: texta = ' EVTA' ! type, extends(BndType) :: EvtType ! -- logicals logical, private :: segsdefined = .true. logical, private :: fixed_cell = .false. logical, private :: read_as_arrays = .false. - logical, private:: surfratespecified = .false. + logical, private :: surfratespecified = .false. ! -- integers integer(I4B), pointer :: inievt => null() integer(I4B), pointer, private :: nseg => null() @@ -33,20 +34,21 @@ module EvtModule integer(I4B), dimension(:), pointer, contiguous :: nodesontop => null() contains procedure :: evt_allocate_scalars - procedure :: bnd_options => evt_options - procedure :: read_dimensions => evt_read_dimensions - procedure :: read_initial_attr => evt_read_initial_attr - procedure :: bnd_rp => evt_rp + procedure :: bnd_options => evt_options + procedure :: read_dimensions => evt_read_dimensions + procedure :: read_initial_attr => evt_read_initial_attr + procedure :: bnd_rp => evt_rp procedure :: set_nodesontop - procedure :: bnd_cf => evt_cf - procedure :: bnd_fc => evt_fc - procedure :: bnd_da => evt_da - procedure :: define_listlabel => evt_define_listlabel + procedure :: bnd_cf => evt_cf + procedure :: bnd_fc => evt_fc + procedure :: bnd_da => evt_da + procedure :: define_listlabel => evt_define_listlabel procedure, private :: evt_rp_array procedure, private :: evt_rp_list procedure, private :: default_nodelist + procedure, private :: check_pxdp ! -- for observations - procedure, public :: bnd_obs_supported => evt_obs_supported + procedure, public :: bnd_obs_supported => evt_obs_supported procedure, public :: bnd_df_obs => evt_df_obs ! -- for time series procedure, public :: bnd_rp_ts => evt_rp_ts @@ -64,7 +66,7 @@ module EvtModule ! 4->3+nseg Proportion of Extinction Depth PXDP PXDP ! 4+nseg->3+2(nseg) Proportion of Max ET Rate PETM PETM - contains +contains subroutine evt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ****************************************************************************** @@ -77,10 +79,10 @@ subroutine evt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -88,7 +90,7 @@ subroutine evt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate evt object and scalar variables - allocate(evtobj) + allocate (evtobj) packobj => evtobj ! ! -- create name and memory path @@ -105,9 +107,9 @@ subroutine evt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%iout = iout packobj%id = id packobj%ibcnum = ibcnum - packobj%ncolbnd = 3 ! Assumes NSEG = 1 - packobj%iscloc = 2 ! sfac applies to max. ET rate - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ncolbnd = 3 ! Assumes NSEG = 1 and SURF_RATE_SPECIFIED=False + packobj%iscloc = 2 ! sfac applies to max. ET rate + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! indxconvertflux is Column index of bound that will be multiplied by ! cell area to convert flux rates to flow rates packobj%indxconvertflux = 2 @@ -127,7 +129,7 @@ subroutine evt_allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(EvtType), intent(inout) :: this + class(EvtType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars @@ -155,61 +157,61 @@ subroutine evt_options(this, option, found) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(EvtType), intent(inout) :: this + class(EvtType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: ermsg ! -- formats - character(len=*),parameter :: fmtihact = & - "(4x, 'EVAPOTRANSPIRATION WILL BE APPLIED TO HIGHEST ACTIVE CELL.')" - character(len=*),parameter :: fmtfixedcell = & - "(4x, 'EVAPOTRANSPIRATION WILL BE APPLIED TO SPECIFIED CELL.')" + character(len=*), parameter :: fmtihact = & + &"(4x, 'EVAPOTRANSPIRATION WILL BE APPLIED TO HIGHEST ACTIVE CELL.')" + character(len=*), parameter :: fmtfixedcell = & + &"(4x, 'EVAPOTRANSPIRATION WILL BE APPLIED TO SPECIFIED CELL.')" character(len=*), parameter :: fmtreadasarrays = & - "(4x, 'EVAPOTRANSPIRATION INPUT WILL BE READ AS ARRAYS.')" + &"(4x, 'EVAPOTRANSPIRATION INPUT WILL BE READ AS ARRAYS.')" character(len=*), parameter :: fmtsrz = & - "(4x, 'ET RATE AT SURFACE WILL BE ZERO.')" + &"(4x, 'ET RATE AT SURFACE WILL BE ZERO.')" character(len=*), parameter :: fmtsrs = & - "(4x, 'ET RATE AT SURFACE WILL BE AS SPECIFIED BY PETM0.')" + &"(4x, 'ET RATE AT SURFACE WILL BE AS SPECIFIED BY PETM0.')" ! ------------------------------------------------------------------------------ ! ! -- Check for FIXED_CELL AND LAYERED select case (option) case ('FIXED_CELL') this%fixed_cell = .true. - write(this%iout, fmtfixedcell) + write (this%iout, fmtfixedcell) found = .true. case ('SURF_RATE_SPECIFIED') this%surfratespecified = .true. - write(this%iout, fmtsrs) + write (this%iout, fmtsrs) found = .true. ! if (this%read_as_arrays) then - ermsg = 'READASARRAYS option is not compatible with the' // & + ermsg = 'READASARRAYS option is not compatible with the'// & ' SURF_RATE_SPECIFIED option.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if case ('READASARRAYS') if (this%dis%supports_layers()) then this%read_as_arrays = .true. this%text = texta else - ermsg = 'READASARRAYS option is not compatible with selected' // & + ermsg = 'READASARRAYS option is not compatible with selected'// & ' discretization type.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! if (this%surfratespecified) then - ermsg = 'READASARRAYS option is not compatible with the' // & + ermsg = 'READASARRAYS option is not compatible with the'// & ' SURF_RATE_SPECIFIED option.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Write option - write(this%iout, fmtreadasarrays) + write (this%iout, fmtreadasarrays) ! found = .true. case default @@ -232,14 +234,14 @@ subroutine evt_read_dimensions(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_unit ! -- dummy - class(EvtType),intent(inout) :: this + class(EvtType), intent(inout) :: this ! -- local - character(len=LINELENGTH) :: errmsg, keyword + character(len=LINELENGTH) :: keyword integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- format character(len=*), parameter :: fmtnsegerr = & - "('Error: In EVT, NSEG must be > 0 but is specified as ',i0)" + &"('Error: In EVT, NSEG must be > 0 but is specified as ',i0)" ! ------------------------------------------------------------------------------ ! ! Dimensions block is not required if: @@ -254,7 +256,7 @@ subroutine evt_read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) @@ -263,58 +265,64 @@ subroutine evt_read_dimensions(this) select case (keyword) case ('MAXBOUND') if (this%read_as_arrays) then - errmsg = 'When READASARRAYS option is used for the selected' // & + errmsg = 'When READASARRAYS option is used for the selected'// & ' discretization package, MAXBOUND may not be specified.' call store_error(errmsg) call this%parser%StoreErrorUnit() else this%maxbound = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)') 'MAXBOUND = ', this%maxbound - endif + write (this%iout, '(4x,a,i7)') 'MAXBOUND = ', this%maxbound + end if case ('NSEG') this%nseg = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NSEG = ', this%nseg + write (this%iout, '(4x,a,i0)') 'NSEG = ', this%nseg if (this%nseg < 1) then - write(errmsg,fmtnsegerr)this%nseg + write (errmsg, fmtnsegerr) this%nseg call store_error(errmsg) call this%parser%StoreErrorUnit() elseif (this%nseg > 1) then ! NSEG>1 is supported only if readasarrays is false if (this%read_as_arrays) then - errmsg = 'In the EVT package, NSEG cannot be greater than 1' // & + errmsg = 'In the EVT package, NSEG cannot be greater than 1'// & ' when READASARRAYS is used.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! -- Recalculate number of columns required in bound array. if (this%surfratespecified) then - this%ncolbnd = 4 + 2*(this%nseg-1) + this%ncolbnd = 4 + 2 * (this%nseg - 1) else - this%ncolbnd = 3 + 2*(this%nseg-1) - endif - endif + this%ncolbnd = 3 + 2 * (this%nseg - 1) + end if + elseif (this%nseg == 1) then + ! if surf_rate_specified is true, will still read petm0 + if (this%surfratespecified) then + this%ncolbnd = this%ncolbnd + 1 + end if + end if case default - write(errmsg,'(4x,a,a)') & + write (errmsg, '(4x,a,a)') & 'Unknown '//trim(this%text)//' DIMENSION: ', trim(keyword) call store_error(errmsg) call this%parser%StoreErrorUnit() end select end do ! - write(this%iout,'(1x,a)')'END OF '//trim(adjustl(this%text))//' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' else call store_error('Required DIMENSIONS block not found.') call this%parser%StoreErrorUnit() - endif - endif + end if + end if ! ! -- verify dimensions were set - if(this%maxbound <= 0) then - write(errmsg, '(1x,a)') & + if (this%maxbound <= 0) then + write (errmsg, '(1x,a)') & 'MAXBOUND must be an integer greater than zero.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Call define_listlabel to construct the list label that is written ! when PRINT_INPUT option is used. @@ -333,11 +341,11 @@ subroutine evt_read_initial_attr(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(EvtType),intent(inout) :: this + class(EvtType), intent(inout) :: this ! if (this%read_as_arrays) then call this%default_nodelist() - endif + end if ! return end subroutine evt_read_initial_attr @@ -356,27 +364,27 @@ subroutine evt_rp(this) use SimModule, only: store_error use ArrayHandlersModule, only: ifind ! -- dummy - class(EvtType),intent(inout) :: this + class(EvtType), intent(inout) :: this ! -- local integer(I4B) :: ierr integer(I4B) :: node, n integer(I4B) :: inievt, inrate, insurf, indepth integer(I4B) :: kpxdp, kpetm logical :: isfound, supportopenclose - character(len=LINELENGTH) :: line, msg, errmsg + character(len=LINELENGTH) :: line, msg ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" character(len=*), parameter :: fmtnbd = & - "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6," // & - "') IS GREATER THAN MAXIMUM(',I6,')')" + "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6,& + &') IS GREATER THAN MAXIMUM(',I6,')')" ! ------------------------------------------------------------------------------ ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then @@ -386,8 +394,9 @@ subroutine evt_rp(this) ! When reading a list, OPEN/CLOSE is handled by list reader, ! so supportOpenClose needs to be false in call the GetBlock. ! When reading as arrays, set supportOpenClose as desired. - call this%parser%GetBlock('PERIOD', isfound, ierr) - if(isfound) then + call this%parser%GetBlock('PERIOD', isfound, ierr, & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -400,11 +409,11 @@ subroutine evt_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- Read data if ionper == kper @@ -430,27 +439,27 @@ subroutine evt_rp(this) ! -- Read Evt input as arrays call this%evt_rp_array(line, inrate, insurf, indepth, & kpxdp, kpetm) - endif + end if ! ! -- Ensure that all required PXDP and PETM arrays ! have been defined or redefined. if (this%surfratespecified) then - if (kpxdp == this%nseg .and. kpxdp == this%nseg) then + if (kpxdp == this%nseg .and. kpetm == this%nseg) then this%segsdefined = .true. - endif + end if else - if (kpxdp == this%nseg-1 .and. kpxdp == this%nseg-1) then + if (kpxdp == this%nseg - 1 .and. kpxdp == this%nseg - 1) then this%segsdefined = .true. - endif - endif + end if + end if if (.not. this%segsdefined) then msg = 'Error in EVT input: Definition of PXDP or PETM is incomplete.' call store_error(msg) call this%parser%StoreErrorUnit() - endif + end if else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + write (this%iout, fmtlsp) trim(this%filtyp) + end if ! ! -- If rate was read, then multiply by cell area. If inrate = 2, then ! rate is begin managed as a time series, and the time series object @@ -461,13 +470,85 @@ subroutine evt_rp(this) if (node > 0) then this%bound(2, n) = this%bound(2, n) * this%dis%get_area(node) end if - enddo - endif + end do + ! + ! -- ensure pxdp is monotonically increasing + if (this%nseg > 1) then + call this%check_pxdp() + end if + end if ! ! -- return return end subroutine evt_rp + !> @brief Subroutine to check pxdp + !! + !! If the number of EVT segments (nseg) is greater than one, then + !! pxdp must be monotically increasing from zero to one. Check + !! to make sure this is the case. + !! + !< + subroutine check_pxdp(this) + ! -- dummy + class(EvtType), intent(inout) :: this !< EvtType + ! -- local + integer(I4B) :: n + integer(I4B) :: node + integer(I4B) :: i + integer(I4B) :: ierrmono + real(DP) :: pxdp1 + real(DP) :: pxdp2 + character(len=15) :: nodestr + ! -- formats + character(len=*), parameter :: fmtpxdp0 = & + &"('PXDP must be between 0 and 1. Found ', G0, ' for cell ', A)" + character(len=*), parameter :: fmtpxdp = & + &"('PXDP is not monotonically increasing for cell ', A)" + ! + ! -- check and make sure that pxdp is monotonically increasing and + ! that pxdp values are between 0 and 1 + do n = 1, this%nbound + node = this%nodelist(n) + pxdp1 = DZERO + ierrmono = 0 + segloop: do i = 1, this%nseg + ! + ! -- set and check pxdp2 + if (i < this%nseg) then + pxdp2 = this%bound(i + 3, n) + if (pxdp2 <= DZERO .or. pxdp2 >= DONE) then + call this%dis%noder_to_string(node, nodestr) + write (errmsg, fmtpxdp0) pxdp2, trim(nodestr) + call store_error(errmsg) + end if + else + pxdp2 = DONE + end if + ! + ! -- check for monotonically increasing condition + if (pxdp2 - pxdp1 < DZERO) then + if (ierrmono == 0) then + ! -- only store mono error once for each node + call this%dis%noder_to_string(node, nodestr) + write (errmsg, fmtpxdp) trim(nodestr) + call store_error(errmsg) + end if + ierrmono = 1 + end if + pxdp1 = pxdp2 + end do segloop + end do + ! + ! -- terminate if errors encountered + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine check_pxdp + subroutine set_nodesontop(this) ! ****************************************************************************** ! set_nodesontop -- store nodelist in nodesontop @@ -476,21 +557,21 @@ subroutine set_nodesontop(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(EvtType),intent(inout) :: this + class(EvtType), intent(inout) :: this ! -- local integer(I4B) :: n ! -- formats ! ------------------------------------------------------------------------------ ! ! -- allocate if necessary - if(.not. associated(this%nodesontop)) then - allocate(this%nodesontop(this%maxbound)) - endif + if (.not. associated(this%nodesontop)) then + allocate (this%nodesontop(this%maxbound)) + end if ! ! -- copy nodelist into nodesontop do n = 1, this%nbound this%nodesontop(n) = this%nodelist(n) - enddo + end do ! ! -- return return @@ -518,7 +599,7 @@ subroutine evt_cf(this, reset_mover) if (this%nbound == 0) return ! ! -- Calculate hcof and rhs for each ET node - do i=1,this%nbound + do i = 1, this%nbound ! ! -- Find the node number if (this%fixed_cell) then @@ -539,7 +620,7 @@ subroutine evt_cf(this, reset_mover) if (this%ibound(node) == 0) & call this%dis%highest_active(node, this%ibound) this%nodelist(i) = node - endif + end if ! ! -- set rhs and hcof to zero this%rhs(i) = DZERO @@ -548,12 +629,12 @@ subroutine evt_cf(this, reset_mover) ! -- if ibound is positive and not overlain by a lake, then add terms if (this%ibound(node) > 0 .and. this%ibound(node) /= 10000) then ! - c = this%bound(2,i) ! RATE -- max. ET rate - s = this%bound(1,i) ! SURFACE -- ET surface elevation + c = this%bound(2, i) ! RATE -- max. ET rate + s = this%bound(1, i) ! SURFACE -- ET surface elevation h = this%xnew(node) if (this%surfratespecified) then - petm0 = this%bound(4+2*(this%nseg-1),i) ! PETM0 - endif + petm0 = this%bound(4 + 2 * (this%nseg - 1), i) ! PETM0 + end if ! ! -- If head in cell is greater than or equal to SURFACE, ET is constant if (h >= s) then @@ -563,11 +644,11 @@ subroutine evt_cf(this, reset_mover) else ! -- Subtract -RATE from RHS this%rhs(i) = this%rhs(i) + c - endif + end if else ! -- If depth to water >= extinction depth, then ET is 0 d = S - h - x = this%bound(3,i) ! DEPTH -- extinction depth + x = this%bound(3, i) ! DEPTH -- extinction depth if (d < x) then ! -- Variable range. add ET terms to both RHS and HCOF. if (this%nseg > 1) then @@ -587,7 +668,7 @@ subroutine evt_cf(this, reset_mover) petm1 = petm0 else petm1 = DONE - endif + end if ! -- Initialize indices to point to elements preceding ! pxdp1 and petm1 (values for lower end of segment 1). idxdepth = 3 @@ -602,38 +683,38 @@ subroutine evt_cf(this, reset_mover) idxdepth = idxdepth + 1 idxrate = idxrate + 1 ! -- Get proportions for lower end of segment - pxdp2 = this%bound(idxdepth,i) - petm2 = this%bound(idxrate,i) + pxdp2 = this%bound(idxdepth, i) + petm2 = this%bound(idxrate, i) else pxdp2 = DONE petm2 = DZERO - endif - if (d <= pxdp2*x) then + end if + if (d <= pxdp2 * x) then ! -- head is in domain of this segment exit segloop - endif + end if ! -- Proportions at lower end of segment will be for ! upper end of segment next time through loop pxdp1 = pxdp2 petm1 = petm2 - enddo segloop + end do segloop ! -- Calculate terms to add to RHS and HCOF based on ! segment that applies at head elevation - thcof = - (petm1 - petm2) * c / ((pxdp2 - pxdp1) * x) + thcof = -(petm1 - petm2) * c / ((pxdp2 - pxdp1) * x) trhs = thcof * (s - pxdp1 * x) + petm1 * c else ! -- Calculate terms to add to RHS and HCOF based on simple ! linear relation of ET vs. head for single segment trhs = c - c * s / x thcof = -c / x - endif + end if this%rhs(i) = this%rhs(i) + trhs this%hcof(i) = this%hcof(i) + thcof - endif - endif - endif + end if + end if + end if ! - enddo + end do ! ! -- return return @@ -669,7 +750,7 @@ subroutine evt_fc(this, rhs, ia, idxglo, amatsln) rhs(n) = rhs(n) + this%rhs(i) ipos = ia(n) amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) - enddo + end do ! ! -- return return @@ -689,7 +770,7 @@ subroutine evt_da(this) ! ------------------------------------------------------------------------------ ! ! -- arrays - if(associated(this%nodesontop)) deallocate(this%nodesontop) + if (associated(this%nodesontop)) deallocate (this%nodesontop) ! ! -- scalars call mem_deallocate(this%inievt) @@ -715,13 +796,13 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & use SimModule, only: store_error use ArrayHandlersModule, only: ifind ! -- dummy - class(EvtType), intent(inout) :: this + class(EvtType), intent(inout) :: this character(len=LINELENGTH), intent(inout) :: line - integer(I4B), intent(inout) :: inrate - integer(I4B), intent(inout) :: insurf - integer(I4B), intent(inout) :: indepth - integer(I4B), intent(inout) :: kpxdp - integer(I4B), intent(inout) :: kpetm + integer(I4B), intent(inout) :: inrate + integer(I4B), intent(inout) :: insurf + integer(I4B), intent(inout) :: indepth + integer(I4B), intent(inout) :: kpxdp + integer(I4B), intent(inout) :: kpetm ! -- local integer(I4B) :: n integer(I4B) :: indx, ipos @@ -737,18 +818,18 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & real(DP), dimension(:), pointer :: bndArrayPtr => null() real(DP), dimension(:), pointer :: auxArrayPtr => null() real(DP), dimension(:), pointer :: auxMultArray => null() - type(TimeArraySeriesLinkType), pointer :: tasLink => null() + type(TimeArraySeriesLinkType), pointer :: tasLink => null() ! -- formats - character(len=*),parameter :: fmtevtauxmult = & + character(len=*), parameter :: fmtevtauxmult = & "(4x, 'THE ET RATE ARRAY IS BEING MULTIPLED BY THE AUXILIARY ARRAY WITH & &THE NAME: ', A)" ! -- data - data aname(1) /' LAYER OR NODE INDEX'/ - data aname(2) /' ET SURFACE'/ - data aname(3) /' EVAPOTRANSPIRATION RATE'/ - data aname(4) /' EXTINCTION DEPTH'/ - data aname(5) /'EXTINCT. DEP. PROPORTION'/ - data aname(6) /' ET RATE PROPORTION'/ + data aname(1)/' LAYER OR NODE INDEX'/ + data aname(2)/' ET SURFACE'/ + data aname(3)/' EVAPOTRANSPIRATION RATE'/ + data aname(4)/' EXTINCTION DEPTH'/ + data aname(5)/'EXTINCT. DEP. PROPORTION'/ + data aname(6)/' ET RATE PROPORTION'/ ! ------------------------------------------------------------------------------ ! ! -- Initialize @@ -774,11 +855,12 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & call store_error('****ERROR. IEVT IS NOT FIRST VARIABLE IN & &PERIOD BLOCK OR IT IS SPECIFIED MORE THAN ONCE.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Read the IEVT array call this%dis%nlarray_to_nodelist(this%nodelist, this%maxbound, & - this%nbound, aname(1), this%parser%iuactive, this%iout) + this%nbound, aname(1), & + this%parser%iuactive, this%iout) ! ! -- set flag to indicate that IEVT has been read this%inievt = 1 @@ -793,13 +875,13 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & call store_error('Error. IEVT must be read at least once ') call store_error('prior to reading the SURFACE array.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Read the surface array, then indicate ! that surface array was read by setting insurf - call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, 1, aname(2), this%parser%iuactive, & - this%iout) + call this%dis%read_layer_array(this%nodelist, this%bound, this%ncolbnd, & + this%maxbound, 1, aname(2), & + this%parser%iuactive, this%iout) insurf = 1 ! case ('RATE') @@ -812,15 +894,15 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & call this%parser%GetStringCaps(tasName) ! -- Ensure that time-array series has been defined and that name ! of time-array series is valid. - jcol = 2 ! for max ET rate - bndArrayPtr => this%bound(jcol,:) + jcol = 2 ! for max ET rate + bndArrayPtr => this%bound(jcol, :) ! Make a time-array-series link and add it to the list of links ! contained in the TimeArraySeriesManagerType object. convertflux = .true. - call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & - this%iprpak, tasName, 'RATE', & - convertFlux, this%nodelist, & - this%parser%iuactive) + call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & + this%iprpak, tasName, 'RATE', & + convertFlux, this%nodelist, & + this%parser%iuactive) lpos = this%TasManager%CountLinks() tasLink => this%TasManager%GetLink(lpos) inrate = 2 @@ -829,10 +911,11 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & ! -- Read the Max. ET Rate array, then indicate ! that rate array was read by setting inrate call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, 2, aname(3), this%parser%iuactive, & - this%iout) + this%ncolbnd, this%maxbound, 2, & + aname(3), this%parser%iuactive, & + this%iout) inrate = 1 - endif + end if ! case ('DEPTH') ! @@ -840,13 +923,13 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & call store_error('IEVT must be read at least once ') call store_error('prior to reading the DEPTH array.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Read the extinction-depth array, then indicate ! that depth array was read by setting indepth - call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, 3, aname(4), this%parser%iuactive, & - this%iout) + call this%dis%read_layer_array(this%nodelist, this%bound, this%ncolbnd, & + this%maxbound, 3, aname(4), & + this%parser%iuactive, this%iout) indepth = 1 ! case ('PXDP') @@ -854,56 +937,56 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & ermsg = 'EVT input: PXDP cannot be specified when NSEG < 2' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! if (this%inievt == 0) then call store_error('IEVT must be read at least once ') call store_error('prior to reading any PXDP array.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Assign column for this PXDP vector in bound array kpxdp = kpxdp + 1 - if (kpxdp < this%nseg-1) this%segsdefined = .false. - if (kpxdp > this%nseg-1) then + if (kpxdp < this%nseg - 1) this%segsdefined = .false. + if (kpxdp > this%nseg - 1) then ermsg = 'EVT: Number of PXDP arrays exceeds NSEG-1.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if indx = 3 + kpxdp ! ! -- Read the PXDP array - call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, indx, aname(5), & - this%parser%iuactive, this%iout) + call this%dis%read_layer_array(this%nodelist, this%bound, this%ncolbnd, & + this%maxbound, indx, aname(5), & + this%parser%iuactive, this%iout) ! case ('PETM') if (this%nseg < 2) then ermsg = 'EVT input: PETM cannot be specified when NSEG < 2' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! if (this%inievt == 0) then call store_error('IEVT must be read at least once ') call store_error('prior to reading any PETM array.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Assign column for this PETM vector in bound array kpetm = kpetm + 1 - if (kpetm < this%nseg-1) this%segsdefined = .false. - if (kpetm > this%nseg-1) then + if (kpetm < this%nseg - 1) this%segsdefined = .false. + if (kpetm > this%nseg - 1) then ermsg = 'EVT: Number of PETM arrays exceeds NSEG-1.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if indx = 3 + this%nseg - 1 + kpetm ! ! -- Read the PETM array - call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, indx, aname(6), & - this%parser%iuactive, this%iout) + call this%dis%read_layer_array(this%nodelist, this%bound, this%ncolbnd, & + this%maxbound, indx, aname(6), & + this%parser%iuactive, this%iout) ! case default ! @@ -921,22 +1004,23 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & ! -- Get time-array series name call this%parser%GetStringCaps(tasName) jauxcol = jauxcol + 1 - auxArrayPtr => this%auxvar(jauxcol,:) + auxArrayPtr => this%auxvar(jauxcol, :) ! Make a time-array-series link and add it to the list of links ! contained in the TimeArraySeriesManagerType object. convertflux = .false. - call this%TasManager%MakeTasLink(this%packName, auxArrayPtr, & - this%iprpak, tasName, & - this%auxname(ipos), convertFlux, & - this%nodelist, this%parser%iuactive) + call this%TasManager%MakeTasLink(this%packName, auxArrayPtr, & + this%iprpak, tasName, & + this%auxname(ipos), convertFlux, & + this%nodelist, this%parser%iuactive) else ! ! -- Read the aux variable array call this%dis%read_layer_array(this%nodelist, this%auxvar, & - this%naux, this%maxbound, ipos, atemp, this%parser%iuactive, & - this%iout) - endif - endif + this%naux, this%maxbound, ipos, & + atemp, this%parser%iuactive, & + this%iout) + end if + end if ! ! -- Nothing found if (.not. found) then @@ -944,13 +1028,13 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & call store_error('LOOKING FOR VALID VARIABLE NAME. FOUND: ') call store_error(trim(line)) call this%parser%StoreErrorUnit() - endif + end if ! ! If this aux variable has been designated as a multiplier array ! by presence of AUXMULTNAME, set local pointer appropriately. if (this%iauxmultcol > 0 .and. this%iauxmultcol == ipos) then - auxMultArray => this%auxvar(this%iauxmultcol,:) - endif + auxMultArray => this%auxvar(this%iauxmultcol, :) + end if end select ! ! -- Increment the number of variables read @@ -960,14 +1044,14 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & ! ! -- Ensure that all required PXDP and PETM arrays ! have been defined or redefined. - if (kpxdp == this%nseg-1 .and. kpxdp == this%nseg-1) then + if (kpxdp == this%nseg - 1 .and. kpxdp == this%nseg - 1) then this%segsdefined = .true. - endif + end if if (.not. this%segsdefined) then ermsg = 'EVT input: Definition of PXDP or PETM is incomplete.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! ! If the multiplier-array pointer has been assigned and ! stress is controlled by a time-array series, assign @@ -975,18 +1059,18 @@ subroutine evt_rp_array(this, line, inrate, insurf, indepth, & if (associated(auxMultArray)) then if (associated(tasLink)) then tasLink%RMultArray => auxMultArray - endif - endif + end if + end if ! ! -- If et rate was read and auxmultcol was specified, then multiply ! the et rate by the multplier column - if(inrate == 1 .and. this%iauxmultcol > 0) then - write(this%iout, fmtevtauxmult) this%auxname(this%iauxmultcol) + if (inrate == 1 .and. this%iauxmultcol > 0) then + write (this%iout, fmtevtauxmult) this%auxname(this%iauxmultcol) do n = 1, this%nbound - this%bound(this%iscloc, n) = this%bound(this%iscloc, n) * & - this%auxvar(this%iauxmultcol, n) - enddo - endif + this%bound(this%iscloc, n) = this%bound(this%iscloc, n) * & + this%auxvar(this%iauxmultcol, n) + end do + end if ! return end subroutine evt_rp_array @@ -1000,27 +1084,27 @@ subroutine evt_rp_list(this, inrate) ! ------------------------------------------------------------------------------ ! -- dummy class(EvtType), intent(inout) :: this - integer(I4B), intent(inout) :: inrate + integer(I4B), intent(inout) :: inrate ! -- local integer(I4B) :: maxboundorig, nlist ! ------------------------------------------------------------------------------ ! nlist = -1 maxboundorig = this%maxbound - call this%dis%read_list(this%parser%iuactive, this%iout, this%iprpak, & - nlist, this%inamedbound, this%iauxmultcol, & - this%nodelist, this%bound, this%auxvar, & - this%auxname, this%boundname, this%listlabel, & - this%packName, this%tsManager, this%iscloc, & - this%indxconvertflux) + call this%dis%read_list(this%parser%iuactive, this%iout, this%iprpak, & + nlist, this%inamedbound, this%iauxmultcol, & + this%nodelist, this%bound, this%auxvar, & + this%auxname, this%boundname, this%listlabel, & + this%packName, this%tsManager, this%iscloc, & + this%indxconvertflux) this%nbound = nlist if (this%maxbound > maxboundorig) then ! -- The arrays that belong to BndType have been extended. ! Now, EVT array nodesontop needs to be recreated. if (associated(this%nodesontop)) then - deallocate(this%nodesontop) - endif - endif + deallocate (this%nodesontop) + end if + end if if (.not. this%fixed_cell) call this%set_nodesontop() inrate = 1 ! @@ -1043,45 +1127,45 @@ subroutine evt_define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'SURFACE' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'MAX. RATE' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'EXT. DEPTH' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'SURFACE' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'MAX. RATE' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'EXT. DEPTH' ! ! -- add headings for as many PXDP and PETM columns as needed nsegm1 = this%nseg - 1 if (nsegm1 > 0) then - do i = 1,nsegm1 - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'PXDP' - enddo - do i = 1,nsegm1 - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'PETM' - enddo - endif + do i = 1, nsegm1 + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'PXDP' + end do + do i = 1, nsegm1 + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'PETM' + end do + end if ! ! -- PETM0, if SURF_RATE_SPECIFIED is used if (this%surfratespecified) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'PETM0' - endif + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'PETM0' + end if ! ! ! -- multiplier ! if(this%multindex > 0) & ! write(this%listlabel, '(a, a16)') trim(this%listlabel), 'MULTIPLIER' ! ! -- boundary name - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -1106,15 +1190,15 @@ subroutine default_nodelist(this) ! ------------------------------------------------------------------------------ ! ! -- set variables - if(this%dis%ndim == 3) then + if (this%dis%ndim == 3) then nlay = this%dis%mshape(1) nrow = this%dis%mshape(2) ncol = this%dis%mshape(3) - elseif(this%dis%ndim == 2) then + elseif (this%dis%ndim == 2) then nlay = this%dis%mshape(1) nrow = 1 ncol = this%dis%mshape(2) - endif + end if ! ! -- Populate nodelist ipos = 1 @@ -1125,8 +1209,8 @@ subroutine default_nodelist(this) noder = this%dis%get_nodenumber(nodeu, 0) this%nodelist(ipos) = noder ipos = ipos + 1 - enddo - enddo + end do + end do ! ! Set flag that indicates IEVT has been assigned, and assign nbound. this%inievt = 1 @@ -1134,7 +1218,7 @@ subroutine default_nodelist(this) ! ! -- if fixed_cell option not set, then need to store nodelist ! in the nodesontop array - if(.not. this%fixed_cell) call this%set_nodesontop() + if (.not. this%fixed_cell) call this%set_nodesontop() ! ! -- return end subroutine default_nodelist @@ -1212,8 +1296,8 @@ subroutine evt_rp_ts(this) case (3) tslink%Text = 'DEPTH' end select - endif - enddo + end if + end do ! return end subroutine evt_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3ghb8.f90 b/src/Model/GroundWaterFlow/gwf3ghb8.f90 index 274b775af6d..9757b1a16c4 100644 --- a/src/Model/GroundWaterFlow/gwf3ghb8.f90 +++ b/src/Model/GroundWaterFlow/gwf3ghb8.f90 @@ -1,11 +1,11 @@ module ghbmodule use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, LENFTYPE, LENPACKAGENAME - use MemoryHelperModule, only: create_mem_path - use BndModule, only: BndType - use ObsModule, only: DefaultObsIdProcessor - use TimeSeriesLinkModule, only: TimeSeriesLinkType, & - GetTimeSeriesLinkFromList + use ConstantsModule, only: DZERO, LENFTYPE, LENPACKAGENAME + use MemoryHelperModule, only: create_mem_path + use BndModule, only: BndType + use ObsModule, only: DefaultObsIdProcessor + use TimeSeriesLinkModule, only: TimeSeriesLinkType, & + GetTimeSeriesLinkFromList ! implicit none ! @@ -13,8 +13,8 @@ module ghbmodule public :: ghb_create public :: GhbType ! - character(len=LENFTYPE) :: ftype = 'GHB' - character(len=LENPACKAGENAME) :: text = ' GHB' + character(len=LENFTYPE) :: ftype = 'GHB' + character(len=LENPACKAGENAME) :: text = ' GHB' ! type, extends(BndType) :: GhbType contains @@ -43,10 +43,10 @@ subroutine ghb_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -54,7 +54,7 @@ subroutine ghb_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(ghbobj) + allocate (ghbobj) packobj => ghbobj ! ! -- create name and memory path @@ -67,13 +67,13 @@ subroutine ghb_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! -- initialize package call packobj%pack_initialize() ! - packobj%inunit=inunit - packobj%iout=iout - packobj%id=id + packobj%inunit = inunit + packobj%iout = iout + packobj%id = id packobj%ibcnum = ibcnum - packobj%ncolbnd=2 - packobj%iscloc=2 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ncolbnd = 2 + packobj%iscloc = 2 + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return @@ -89,20 +89,20 @@ subroutine ghb_options(this, option, found) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GhbType), intent(inout) :: this + class(GhbType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! ------------------------------------------------------------------------------ ! select case (option) - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case default - ! - ! -- No options found - found = .false. + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + found = .true. + case default + ! + ! -- No options found + found = .false. end select ! ! -- return @@ -120,7 +120,7 @@ subroutine ghb_ck(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(GhbType),intent(inout) :: this + class(GhbType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg integer(I4B) :: i @@ -128,19 +128,19 @@ subroutine ghb_ck(this) real(DP) :: bt ! -- formats character(len=*), parameter :: fmtghberr = & - "('GHB BOUNDARY (',i0,') HEAD (',f10.3,') IS LESS THAN CELL " // & - "BOTTOM (',f10.3,')')" + "('GHB BOUNDARY (',i0,') HEAD (',f10.3,') IS LESS THAN CELL & + &BOTTOM (',f10.3,')')" ! ------------------------------------------------------------------------------ ! ! -- check stress period data do i = 1, this%nbound - node = this%nodelist(i) - bt = this%dis%bot(node) - ! -- accumulate errors - if (this%bound(1,i) < bt .and. this%icelltype(node) /= 0) then - write(errmsg, fmt=fmtghberr) i, this%bound(1,i), bt - call store_error(errmsg) - end if + node = this%nodelist(i) + bt = this%dis%bot(node) + ! -- accumulate errors + if (this%bound(1, i) < bt .and. this%icelltype(node) /= 0) then + write (errmsg, fmt=fmtghberr) i, this%bound(1, i), bt + call store_error(errmsg) + end if end do ! !write summary of ghb package error messages @@ -170,25 +170,25 @@ subroutine ghb_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no ghbs - if(this%nbound.eq.0) return + if (this%nbound .eq. 0) return ! ! -- packmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() - endif + end if ! ! -- Calculate hcof and rhs for each ghb entry - do i=1,this%nbound - node=this%nodelist(i) - if(this%ibound(node).le.0) then - this%hcof(i)=DZERO - this%rhs(i)=DZERO - cycle - endif - this%hcof(i) = -this%bound(2,i) - this%rhs(i) = -this%bound(2,i) * this%bound(1,i) + do i = 1, this%nbound + node = this%nodelist(i) + if (this%ibound(node) .le. 0) then + this%hcof(i) = DZERO + this%rhs(i) = DZERO + cycle + end if + this%hcof(i) = -this%bound(2, i) + this%rhs(i) = -this%bound(2, i) * this%bound(1, i) end do ! ! -- return @@ -214,9 +214,9 @@ subroutine ghb_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() - endif + end if ! ! -- Copy package rhs and hcof into solution rhs and amat do i = 1, this%nbound @@ -227,13 +227,13 @@ subroutine ghb_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active and this boundary is discharging, ! store available water (as positive value). - bhead = this%bound(1,i) - if(this%imover == 1 .and. this%xnew(n) > bhead) then - cond = this%bound(2,i) + bhead = this%bound(1, i) + if (this%imover == 1 .and. this%xnew(n) > bhead) then + cond = this%bound(2, i) qghb = cond * (this%xnew(n) - bhead) call this%pakmvrobj%accumulate_qformvr(i, qghb) - endif - enddo + end if + end do ! ! -- return return @@ -251,22 +251,22 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STAGE' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STAGE' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -275,36 +275,36 @@ end subroutine define_listlabel ! -- Procedures related to observations logical function ghb_obs_supported(this) - ! ****************************************************************************** - ! ghb_obs_supported - ! -- Return true because GHB package supports observations. - ! -- Overrides BndType%bnd_obs_supported() - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! ghb_obs_supported + ! -- Return true because GHB package supports observations. + ! -- Overrides BndType%bnd_obs_supported() + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ implicit none class(GhbType) :: this - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ ghb_obs_supported = .true. return end function ghb_obs_supported subroutine ghb_df_obs(this) - ! ****************************************************************************** - ! ghb_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by GHB package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! ghb_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by GHB package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ implicit none ! -- dummy class(GhbType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ call this%obs%StoreObsType('ghb', .true., indx) this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor ! @@ -331,7 +331,7 @@ subroutine ghb_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) @@ -340,8 +340,8 @@ subroutine ghb_rp_ts(this) case (2) tslink%Text = 'COND' end select - endif - enddo + end if + end do ! return end subroutine ghb_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3hfb8.f90 b/src/Model/GroundWaterFlow/gwf3hfb8.f90 index 8e1e3fdfb05..ffec99e84bd 100644 --- a/src/Model/GroundWaterFlow/gwf3hfb8.f90 +++ b/src/Model/GroundWaterFlow/gwf3hfb8.f90 @@ -2,10 +2,11 @@ module GwfHfbModule use KindModule, only: DP, I4B - use Xt3dModule, only: Xt3dType + use Xt3dModule, only: Xt3dType + use GwfVscModule, only: GwfVscType use NumericalPackageModule, only: NumericalPackageType - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType implicit none @@ -14,34 +15,41 @@ module GwfHfbModule public :: hfb_cr type, extends(NumericalPackageType) :: GwfHfbType - integer(I4B), pointer :: maxhfb => null() !max number of hfb's - integer(I4B), pointer :: nhfb => null() !number of hfb's - integer(I4B), dimension(:), pointer, contiguous :: noden => null() !first cell - integer(I4B), dimension(:), pointer, contiguous :: nodem => null() !second cell - integer(I4B), dimension(:), pointer, contiguous :: idxloc => null() !position in model ja - real(DP), dimension(:), pointer, contiguous :: hydchr => null() !hydraulic characteristic of the barrier - real(DP), dimension(:), pointer, contiguous :: csatsav => null() !value of condsat prior to hfb modification - real(DP), dimension(:), pointer, contiguous :: condsav => null() !saved conductance of combined npf and hfb - type(Xt3dType), pointer :: xt3d => null() !pointer to xt3d object - ! - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !pointer to model ibound - integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !pointer to model icelltype - integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !pointer to model ihc - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !pointer to model ia - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !pointer to model ja - integer(I4B), dimension(:), pointer, contiguous :: jas => null() !pointer to model jas - integer(I4B), dimension(:), pointer, contiguous :: isym => null() !pointer to model isym - real(DP), dimension(:), pointer, contiguous :: condsat => null() !pointer to model condsat - real(DP), dimension(:), pointer, contiguous :: top => null() !pointer to model top - real(DP), dimension(:), pointer, contiguous :: bot => null() !pointer to model bot - real(DP), dimension(:), pointer, contiguous :: hwva => null() !pointer to model hwva + + type(GwfVscType), pointer :: vsc => null() !< viscosity object + integer(I4B), pointer :: maxhfb => null() !< max number of hfb's + integer(I4B), pointer :: nhfb => null() !< number of hfb's + integer(I4B), dimension(:), pointer, contiguous :: noden => null() !< first cell + integer(I4B), dimension(:), pointer, contiguous :: nodem => null() !< second cell + integer(I4B), dimension(:), pointer, contiguous :: idxloc => null() !< position in model ja + real(DP), dimension(:), pointer, contiguous :: hydchr => null() !< hydraulic characteristic of the barrier + real(DP), dimension(:), pointer, contiguous :: csatsav => null() !< value of condsat prior to hfb modification + real(DP), dimension(:), pointer, contiguous :: condsav => null() !< saved conductance of combined npf and hfb + type(Xt3dType), pointer :: xt3d => null() !< pointer to xt3d object + ! + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< pointer to model icelltype + integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !< pointer to model ihc + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< pointer to model ia + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< pointer to model ja + integer(I4B), dimension(:), pointer, contiguous :: jas => null() !< pointer to model jas + integer(I4B), dimension(:), pointer, contiguous :: isym => null() !< pointer to model isym + real(DP), dimension(:), pointer, contiguous :: condsat => null() !< pointer to model condsat + real(DP), dimension(:), pointer, contiguous :: top => null() !< pointer to model top + real(DP), dimension(:), pointer, contiguous :: bot => null() !< pointer to model bot + real(DP), dimension(:), pointer, contiguous :: hwva => null() !< pointer to model hwva + real(DP), dimension(:), pointer, contiguous :: hnew => null() !< pointer to model xnew + ! + ! -- viscosity flag + integer(I4B), pointer :: ivsc => null() !< flag indicating if viscosity is active in the model + contains procedure :: hfb_ar procedure :: hfb_rp procedure :: hfb_fc procedure :: hfb_cq procedure :: hfb_da - procedure :: allocate_scalars + procedure :: allocate_scalars procedure, private :: allocate_arrays procedure, private :: read_options procedure, private :: read_dimensions @@ -49,9 +57,10 @@ module GwfHfbModule procedure, private :: check_data procedure, private :: condsat_reset procedure, private :: condsat_modify + end type GwfHfbType - contains +contains subroutine hfb_cr(hfbobj, name_model, inunit, iout) ! ****************************************************************************** @@ -68,7 +77,7 @@ subroutine hfb_cr(hfbobj, name_model, inunit, iout) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(hfbobj) + allocate (hfbobj) ! ! -- create name and memory path call hfbobj%set_names(1, name_model, 'HFB', 'HFB') @@ -87,7 +96,7 @@ subroutine hfb_cr(hfbobj, name_model, inunit, iout) return end subroutine hfb_cr - subroutine hfb_ar(this, ibound, xt3d, dis) + subroutine hfb_ar(this, ibound, xt3d, dis, invsc, vsc) ! ****************************************************************************** ! hfb_ar -- Allocate and read ! ****************************************************************************** @@ -101,28 +110,33 @@ subroutine hfb_ar(this, ibound, xt3d, dis) class(GwfHfbType) :: this integer(I4B), dimension(:), pointer, contiguous :: ibound type(Xt3dType), pointer :: xt3d - class(DisBaseType), pointer, intent(inout) :: dis + class(DisBaseType), pointer, intent(inout) :: dis !< discretization package + integer(I4B), pointer :: invsc !< indicates if viscosity package is active + type(GwfVscType), pointer, intent(in) :: vsc !< viscosity package + ! -- local ! -- formats - character(len=*), parameter :: fmtheader = & - &"(1x, /1x, 'HFB -- HORIZONTAL FLOW BARRIER PACKAGE, VERSION 8, ', & - &'4/24/2015 INPUT READ FROM UNIT ', i4, //)" + character(len=*), parameter :: fmtheader = & + "(1x, /1x, 'HFB -- HORIZONTAL FLOW BARRIER PACKAGE, VERSION 8, ', & + &'4/24/2015 INPUT READ FROM UNIT ', i4, //)" ! ------------------------------------------------------------------------------ ! ! -- Print a message identifying the node property flow package. - write(this%iout, fmtheader) this%inunit + write (this%iout, fmtheader) this%inunit ! ! -- Set pointers this%dis => dis this%ibound => ibound this%xt3d => xt3d - call mem_setptr(this%icelltype, 'ICELLTYPE', create_mem_path(this%name_model, 'NPF')) + call mem_setptr(this%icelltype, 'ICELLTYPE', & + create_mem_path(this%name_model, 'NPF')) call mem_setptr(this%ihc, 'IHC', create_mem_path(this%name_model, 'CON')) call mem_setptr(this%ia, 'IA', create_mem_path(this%name_model, 'CON')) call mem_setptr(this%ja, 'JA', create_mem_path(this%name_model, 'CON')) call mem_setptr(this%jas, 'JAS', create_mem_path(this%name_model, 'CON')) call mem_setptr(this%isym, 'ISYM', create_mem_path(this%name_model, 'CON')) - call mem_setptr(this%condsat, 'CONDSAT', create_mem_path(this%name_model, 'NPF')) + call mem_setptr(this%condsat, 'CONDSAT', create_mem_path(this%name_model, & + 'NPF')) call mem_setptr(this%top, 'TOP', create_mem_path(this%name_model, 'DIS')) call mem_setptr(this%bot, 'BOT', create_mem_path(this%name_model, 'DIS')) call mem_setptr(this%hwva, 'HWVA', create_mem_path(this%name_model, 'CON')) @@ -131,6 +145,16 @@ subroutine hfb_ar(this, ibound, xt3d, dis) call this%read_dimensions() call this%allocate_arrays() ! + ! -- If vsc package active, set ivsc + if (invsc /= 0) then + this%ivsc = 1 + this%vsc => vsc + ! + ! -- Notify user via listing file viscosity accounted for by HFB package + write (this%iout, '(/1x,a,a)') 'Viscosity active in ', & + trim(this%filtyp)//' Package calculations: '//trim(adjustl(this%packName)) + end if + ! ! -- return return end subroutine hfb_ar @@ -153,10 +177,10 @@ subroutine hfb_rp(this) integer(I4B) :: ierr logical :: isfound ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" ! ------------------------------------------------------------------------------ ! ! -- Set ionper to the stress period number for which a new block of data @@ -165,8 +189,9 @@ subroutine hfb_rp(this) ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -179,20 +204,20 @@ subroutine hfb_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! - if(this%ionper == kper) then + if (this%ionper == kper) then call this%condsat_reset() call this%read_data() call this%condsat_modify() else - write(this%iout,fmtlsp) 'HFB' - endif + write (this%iout, fmtlsp) 'HFB' + end if ! ! -- return return @@ -210,17 +235,17 @@ subroutine hfb_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: DHALF, DZERO + use ConstantsModule, only: DHALF, DZERO, DONE ! -- dummy class(GwfHfbType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(:) :: idxglo - real(DP),intent(inout),dimension(:) :: rhs - real(DP),intent(inout),dimension(:) :: hnew + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(:) :: idxglo + real(DP), intent(inout), dimension(:) :: rhs + real(DP), intent(inout), dimension(:) :: hnew ! -- local - integer(I4B) :: nodes, nja + integer(I4B) :: nodes, nja integer(I4B) :: ihfb, n, m integer(I4B) :: ipos integer(I4B) :: idiag, isymcon @@ -228,8 +253,11 @@ subroutine hfb_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) real(DP) :: cond, condhfb, aterm real(DP) :: fawidth, faheight real(DP) :: topn, topm, botn, botm + real(DP) :: viscratio ! ------------------------------------------------------------------------------ ! + ! -- initialize variables + viscratio = DONE nodes = this%dis%nodes nja = this%dis%con%nja if (associated(this%xt3d%ixt3d)) then @@ -238,81 +266,92 @@ subroutine hfb_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ixt3d = 0 end if ! - if(ixt3d > 0) then + if (ixt3d > 0) then ! do ihfb = 1, this%nhfb n = min(this%noden(ihfb), this%nodem(ihfb)) m = max(this%noden(ihfb), this%nodem(ihfb)) ! -- Skip if either cell is inactive. - if(this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle - !!! if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle + !!! if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ivsc /= 0) then + call this%vsc%get_visc_ratio(n, m, hnew(n), hnew(m), viscratio) + end if ! -- Compute scale factor for hfb correction - if(this%hydchr(ihfb) > DZERO) then - if(this%inewton == 0) then + if (this%hydchr(ihfb) > DZERO) then + if (this%inewton == 0) then ipos = this%idxloc(ihfb) topn = this%top(n) topm = this%top(m) botn = this%bot(n) botm = this%bot(m) - if(this%icelltype(n) == 1) then - if(hnew(n) < topn) topn = hnew(n) - endif - if(this%icelltype(m) == 1) then - if(hnew(m) < topm) topm = hnew(m) - endif - if(this%ihc(this%jas(ipos)) == 2) then + if (this%icelltype(n) == 1) then + if (hnew(n) < topn) topn = hnew(n) + end if + if (this%icelltype(m) == 1) then + if (hnew(m) < topm) topm = hnew(m) + end if + if (this%ihc(this%jas(ipos)) == 2) then faheight = min(topn, topm) - max(botn, botm) else - faheight = DHALF * ( (topn - botn) + (topm - botm) ) - endif + faheight = DHALF * ((topn - botn) + (topm - botm)) + end if fawidth = this%hwva(this%jas(ipos)) - condhfb = this%hydchr(ihfb) * fawidth * faheight + condhfb = this%hydchr(ihfb) * viscratio * & + fawidth * faheight else - condhfb = this%hydchr(ihfb) + condhfb = this%hydchr(ihfb) * viscratio end if else condhfb = this%hydchr(ihfb) - endif + end if ! -- Make hfb corrections for xt3d - call this%xt3d%xt3d_fhfb(kiter, nodes, nja, njasln, amat, idxglo, & - rhs, hnew, n, m, condhfb) + call this%xt3d%xt3d_fhfb(kiter, nodes, nja, njasln, amat, idxglo, & + rhs, hnew, n, m, condhfb) end do ! else ! ! -- For Newton, the effect of the barrier is included in condsat. - if(this%inewton == 0) then + if (this%inewton == 0) then do ihfb = 1, this%nhfb ipos = this%idxloc(ihfb) aterm = amat(idxglo(ipos)) n = this%noden(ihfb) m = this%nodem(ihfb) - if(this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle - if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle + ! + if (this%ivsc /= 0) then + call this%vsc%get_visc_ratio(n, m, hnew(n), hnew(m), viscratio) + end if + ! + if (this%icelltype(n) == 1 .or. this%icelltype(m) == 1 .or. & + this%ivsc /= 0) then ! ! -- Calculate hfb conductance topn = this%top(n) topm = this%top(m) botn = this%bot(n) botm = this%bot(m) - if(this%icelltype(n) == 1) then - if(hnew(n) < topn) topn = hnew(n) - endif - if(this%icelltype(m) == 1) then - if(hnew(m) < topm) topm = hnew(m) - endif - if(this%ihc(this%jas(ipos)) == 2) then + if (this%icelltype(n) == 1) then + if (hnew(n) < topn) topn = hnew(n) + end if + if (this%icelltype(m) == 1) then + if (hnew(m) < topm) topm = hnew(m) + end if + if (this%ihc(this%jas(ipos)) == 2) then faheight = min(topn, topm) - max(botn, botm) else - faheight = DHALF * ( (topn - botn) + (topm - botm) ) - endif - if(this%hydchr(ihfb) > DZERO) then + faheight = DHALF * ((topn - botn) + (topm - botm)) + end if + if (this%hydchr(ihfb) > DZERO) then fawidth = this%hwva(this%jas(ipos)) - condhfb = this%hydchr(ihfb) * fawidth * faheight + condhfb = this%hydchr(ihfb) * viscratio * & + fawidth * faheight cond = aterm * condhfb / (aterm + condhfb) else - cond = - aterm * this%hydchr(ihfb) - endif + cond = -aterm * this%hydchr(ihfb) + end if ! ! -- Save cond for budget calculation this%condsav(ihfb) = cond @@ -328,11 +367,11 @@ subroutine hfb_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) amat(idxglo(idiag)) = amat(idxglo(idiag)) + aterm - cond amat(idxglo(isymcon)) = cond ! - endif - enddo - endif + end if + end do + end if ! - endif + end if ! ! -- return return @@ -348,11 +387,11 @@ subroutine hfb_cq(this, hnew, flowja) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: DHALF, DZERO + use ConstantsModule, only: DHALF, DZERO, DONE ! -- dummy class(GwfHfbType) :: this - real(DP),intent(inout),dimension(:) :: hnew - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(inout), dimension(:) :: hnew + real(DP), intent(inout), dimension(:) :: flowja ! -- local integer(I4B) :: ihfb, n, m integer(I4B) :: ipos @@ -362,49 +401,58 @@ subroutine hfb_cq(this, hnew, flowja) real(DP) :: condhfb real(DP) :: fawidth, faheight real(DP) :: topn, topm, botn, botm + real(DP) :: viscratio ! ------------------------------------------------------------------------------ ! + ! -- initialize viscratio + viscratio = DONE + ! if (associated(this%xt3d%ixt3d)) then ixt3d = this%xt3d%ixt3d else ixt3d = 0 end if ! - if(ixt3d > 0) then + if (ixt3d > 0) then ! do ihfb = 1, this%nhfb n = min(this%noden(ihfb), this%nodem(ihfb)) m = max(this%noden(ihfb), this%nodem(ihfb)) ! -- Skip if either cell is inactive. - if(this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle - !!! if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle + !!! if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ivsc /= 0) then + call this%vsc%get_visc_ratio(n, m, hnew(n), hnew(m), viscratio) + end if + ! ! -- Compute scale factor for hfb correction - if(this%hydchr(ihfb) > DZERO) then - if(this%inewton == 0) then + if (this%hydchr(ihfb) > DZERO) then + if (this%inewton == 0) then ipos = this%idxloc(ihfb) topn = this%top(n) topm = this%top(m) botn = this%bot(n) botm = this%bot(m) - if(this%icelltype(n) == 1) then - if(hnew(n) < topn) topn = hnew(n) - endif - if(this%icelltype(m) == 1) then - if(hnew(m) < topm) topm = hnew(m) - endif - if(this%ihc(this%jas(ipos)) == 2) then + if (this%icelltype(n) == 1) then + if (hnew(n) < topn) topn = hnew(n) + end if + if (this%icelltype(m) == 1) then + if (hnew(m) < topm) topm = hnew(m) + end if + if (this%ihc(this%jas(ipos)) == 2) then faheight = min(topn, topm) - max(botn, botm) else - faheight = DHALF * ( (topn - botn) + (topm - botm) ) - endif + faheight = DHALF * ((topn - botn) + (topm - botm)) + end if fawidth = this%hwva(this%jas(ipos)) - condhfb = this%hydchr(ihfb) * fawidth * faheight + condhfb = this%hydchr(ihfb) * viscratio * & + fawidth * faheight else condhfb = this%hydchr(ihfb) end if else condhfb = this%hydchr(ihfb) - endif + end if ! -- Make hfb corrections for xt3d call this%xt3d%xt3d_flowjahfb(n, m, hnew, flowja, condhfb) end do @@ -412,22 +460,25 @@ subroutine hfb_cq(this, hnew, flowja) else ! ! -- Recalculate flowja for non-newton unconfined. - if(this%inewton == 0) then + if (this%inewton == 0) then do ihfb = 1, this%nhfb n = this%noden(ihfb) m = this%nodem(ihfb) - if(this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle - if(this%icelltype(n) == 1 .or. this%icelltype(m) == 1) then + if (this%ibound(n) == 0 .or. this%ibound(m) == 0) cycle + if (this%icelltype(n) == 1 .or. this%icelltype(m) == 1 .or. & + this%ivsc /= 0) then ipos = this%dis%con%getjaindex(n, m) + ! + ! -- condsav already accnts for visc adjustment cond = this%condsav(ihfb) qnm = cond * (hnew(m) - hnew(n)) flowja(ipos) = qnm ipos = this%dis%con%getjaindex(m, n) flowja(ipos) = -qnm ! - endif - enddo - endif + end if + end do + end if ! end if ! @@ -453,6 +504,7 @@ subroutine hfb_da(this) ! -- Scalars call mem_deallocate(this%maxhfb) call mem_deallocate(this%nhfb) + call mem_deallocate(this%ivsc) ! ! -- Arrays if (this%inunit > 0) then @@ -462,25 +514,26 @@ subroutine hfb_da(this) call mem_deallocate(this%idxloc) call mem_deallocate(this%csatsav) call mem_deallocate(this%condsav) - endif + end if ! ! -- deallocate parent call this%NumericalPackageType%da() ! ! -- nullify pointers - this%xt3d => null() - this%inewton => null() - this%ibound => null() - this%icelltype => null() - this%ihc => null() - this%ia => null() - this%ja => null() - this%jas => null() - this%isym => null() - this%condsat => null() - this%top => null() - this%bot => null() - this%hwva => null() + this%xt3d => null() + this%inewton => null() + this%ibound => null() + this%icelltype => null() + this%ihc => null() + this%ia => null() + this%ja => null() + this%jas => null() + this%isym => null() + this%condsat => null() + this%top => null() + this%bot => null() + this%hwva => null() + this%vsc => null() ! ! -- return return @@ -506,9 +559,13 @@ subroutine allocate_scalars(this) call mem_allocate(this%maxhfb, 'MAXHFB', this%memoryPath) call mem_allocate(this%nhfb, 'NHFB', this%memoryPath) ! + ! -- allocate flag for determining if vsc active + call mem_allocate(this%ivsc, 'IVSC', this%memoryPath) + ! ! -- initialize this%maxhfb = 0 this%nhfb = 0 + this%ivsc = 0 ! ! -- return return @@ -539,7 +596,7 @@ subroutine allocate_arrays(this) ! -- initialize idxloc to 0 do ihfb = 1, this%maxhfb this%idxloc(ihfb) = 0 - enddo + end do ! ! -- return return @@ -565,28 +622,28 @@ subroutine read_options(this) ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING HFB OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING HFB OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') & - 'THE LIST OF HFBS WILL BE PRINTED.' - case default - write(errmsg,'(4x,a,a)') 'Unknown HFB option: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') & + 'THE LIST OF HFBS WILL BE PRINTED.' + case default + write (errmsg, '(4x,a,a)') 'Unknown HFB option: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF HFB OPTIONS' + write (this%iout, '(1x,a)') 'END OF HFB OPTIONS' end if ! ! -- return @@ -603,7 +660,7 @@ subroutine read_dimensions(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_unit ! -- dummy - class(GwfHfbType),intent(inout) :: this + class(GwfHfbType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg, keyword integer(I4B) :: ierr @@ -613,40 +670,40 @@ subroutine read_dimensions(this) ! ! -- get dimensions block call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING HFB DIMENSIONS' + write (this%iout, '(/1x,a)') 'PROCESSING HFB DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('MAXHFB') - this%maxhfb = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)') 'MAXHFB = ', this%maxhfb - case default - write(errmsg,'(4x,a,a)') & - 'Unknown HFB dimension: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('MAXHFB') + this%maxhfb = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'MAXHFB = ', this%maxhfb + case default + write (errmsg, '(4x,a,a)') & + 'Unknown HFB dimension: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do ! - write(this%iout,'(1x,a)')'END OF HFB DIMENSIONS' + write (this%iout, '(1x,a)') 'END OF HFB DIMENSIONS' else call store_error('Required DIMENSIONS block not found.') call this%parser%StoreErrorUnit() end if ! ! -- verify dimensions were set - if(this%maxhfb <= 0) then - write(errmsg, '(1x,a)') & + if (this%maxhfb <= 0) then + write (errmsg, '(1x,a)') & 'MAXHFB must be specified with value greater than zero.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -676,11 +733,11 @@ subroutine read_data(this) character(len=*), parameter :: fmthfb = "(i10, 2a10, 1(1pg15.6))" ! ------------------------------------------------------------------------------ ! - write(this%iout,'(//,1x,a)')'READING HFB DATA' - if(this%iprpak > 0) then - write(this%iout, '(3a10, 1a15)') 'HFB NUM', 'CELL1', 'CELL2', & - 'HYDCHR' - endif + write (this%iout, '(//,1x,a)') 'READING HFB DATA' + if (this%iprpak > 0) then + write (this%iout, '(3a10, 1a15)') 'HFB NUM', 'CELL1', 'CELL2', & + 'HYDCHR' + end if ! ihfb = 0 this%nhfb = 0 @@ -692,40 +749,42 @@ subroutine read_data(this) ! ! -- Reset lloc and read noden, nodem, and hydchr ihfb = ihfb + 1 - if(ihfb > this%maxhfb) then + if (ihfb > this%maxhfb) then call store_error('MAXHFB not large enough.') call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetCellid(this%dis%ndim, cellidn) this%noden(ihfb) = this%dis%noder_from_cellid(cellidn, & - this%parser%iuactive, this%iout) + this%parser%iuactive, & + this%iout) call this%parser%GetCellid(this%dis%ndim, cellidm) this%nodem(ihfb) = this%dis%noder_from_cellid(cellidm, & - this%parser%iuactive, this%iout) + this%parser%iuactive, & + this%iout) this%hydchr(ihfb) = this%parser%GetDouble() ! ! -- Print input if requested - if(this%iprpak /= 0) then + if (this%iprpak /= 0) then call this%dis%noder_to_string(this%noden(ihfb), nodenstr) call this%dis%noder_to_string(this%nodem(ihfb), nodemstr) - write(this%iout, fmthfb) ihfb, trim(adjustl(nodenstr)), & - trim(adjustl(nodemstr)), this%hydchr(ihfb) - endif + write (this%iout, fmthfb) ihfb, trim(adjustl(nodenstr)), & + trim(adjustl(nodemstr)), this%hydchr(ihfb) + end if ! this%nhfb = ihfb - enddo readloop + end do readloop ! ! -- Stop if errors nerr = count_errors() - if(nerr > 0) then + if (nerr > 0) then call store_error('Errors encountered in HFB input file.') call this%parser%StoreErrorUnit() - endif + end if ! - write(this%iout, '(3x,i0,a,i0)') this%nhfb, & - ' HFBs READ FOR STRESS PERIOD ', kper + write (this%iout, '(3x,i0,a,i0)') this%nhfb, & + ' HFBs READ FOR STRESS PERIOD ', kper call this%check_data() - write(this%iout, '(1x,a)')'END READING HFB DATA' + write (this%iout, '(1x,a)') 'END READING HFB DATA' ! ! -- return return @@ -751,9 +810,9 @@ subroutine check_data(this) character(len=LINELENGTH) :: errmsg logical :: found ! -- formats - character(len=*), parameter :: fmterr = "(1x, 'HFB no. ',i0, & + character(len=*), parameter :: fmterr = "(1x, 'HFB no. ',i0, & &' is between two unconnected cells: ', a, ' and ', a)" - character(len=*), parameter :: fmtverr = "(1x, 'HFB no. ',i0, & + character(len=*), parameter :: fmtverr = "(1x, 'HFB no. ',i0, & &' is between two cells not horizontally connected: ', a, ' and ', a)" ! ------------------------------------------------------------------------------ ! @@ -761,20 +820,20 @@ subroutine check_data(this) n = this%noden(ihfb) m = this%nodem(ihfb) found = .false. - do ipos = this%ia(n)+1, this%ia(n+1)-1 + do ipos = this%ia(n) + 1, this%ia(n + 1) - 1 if (m == this%ja(ipos)) then found = .true. this%idxloc(ihfb) = ipos exit - endif - enddo + end if + end do ! ! -- check to make sure cells are connected if (.not. found) then call this%dis%noder_to_string(n, nodenstr) call this%dis%noder_to_string(m, nodemstr) - write(errmsg, fmterr) ihfb, trim(adjustl(nodenstr)), & - trim(adjustl(nodemstr)) + write (errmsg, fmterr) ihfb, trim(adjustl(nodenstr)), & + trim(adjustl(nodemstr)) call store_error(errmsg) else ! @@ -783,17 +842,17 @@ subroutine check_data(this) if (this%ihc(this%jas(ipos)) == 0) then call this%dis%noder_to_string(n, nodenstr) call this%dis%noder_to_string(m, nodemstr) - write(errmsg, fmtverr) ihfb, trim(adjustl(nodenstr)), & - trim(adjustl(nodemstr)) + write (errmsg, fmtverr) ihfb, trim(adjustl(nodenstr)), & + trim(adjustl(nodemstr)) call store_error(errmsg) end if end if - enddo + end do ! ! -- Stop if errors detected - if(count_errors() > 0) then + if (count_errors() > 0) then call store_error_unit(this%inunit) - endif + end if ! ! -- return return @@ -817,7 +876,7 @@ subroutine condsat_reset(this) do ihfb = 1, this%nhfb ipos = this%idxloc(ihfb) this%condsat(this%jas(ipos)) = this%csatsav(ihfb) - enddo + end do ! ! -- return return @@ -850,29 +909,31 @@ subroutine condsat_modify(this) this%csatsav(ihfb) = cond n = this%noden(ihfb) m = this%nodem(ihfb) - if(this%inewton == 1 .or. & - (this%icelltype(n) == 0 .and. this%icelltype(m) == 0) ) then + ! + if (this%inewton == 1 .or. & + (this%icelltype(n) == 0 .and. this%icelltype(m) == 0)) then ! ! -- Calculate hfb conductance topn = this%top(n) topm = this%top(m) botn = this%bot(n) botm = this%bot(m) - if(this%ihc(this%jas(ipos)) == 2) then + if (this%ihc(this%jas(ipos)) == 2) then faheight = min(topn, topm) - max(botn, botm) else - faheight = DHALF * ( (topn - botn) + (topm - botm) ) - endif - if(this%hydchr(ihfb) > DZERO) then + faheight = DHALF * ((topn - botn) + (topm - botm)) + end if + if (this%hydchr(ihfb) > DZERO) then fawidth = this%hwva(this%jas(ipos)) - condhfb = this%hydchr(ihfb) * fawidth * faheight + condhfb = this%hydchr(ihfb) * & + fawidth * faheight cond = cond * condhfb / (cond + condhfb) else - cond = - cond * this%hydchr(ihfb) - endif + cond = -cond * this%hydchr(ihfb) + end if this%condsat(this%jas(ipos)) = cond - endif - enddo + end if + end do ! ! -- return return diff --git a/src/Model/GroundWaterFlow/gwf3ic8.f90 b/src/Model/GroundWaterFlow/gwf3ic8.f90 index de4a6f8f4b9..91991d170b2 100644 --- a/src/Model/GroundWaterFlow/gwf3ic8.f90 +++ b/src/Model/GroundWaterFlow/gwf3ic8.f90 @@ -2,8 +2,8 @@ module GwfIcModule use KindModule, only: DP, I4B use NumericalPackageModule, only: NumericalPackageType - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType implicit none private @@ -11,16 +11,16 @@ module GwfIcModule public :: ic_cr type, extends(NumericalPackageType) :: GwfIcType - real(DP), dimension(:), pointer, contiguous :: strt => null() ! starting head + real(DP), dimension(:), pointer, contiguous :: strt => null() ! starting head contains - procedure :: ic_ar - procedure :: ic_da + procedure :: ic_ar + procedure :: ic_da procedure, private :: allocate_arrays procedure, private :: read_options - procedure :: read_data + procedure :: read_data end type GwfIcType - contains +contains subroutine ic_cr(ic, name_model, inunit, iout, dis) ! ****************************************************************************** @@ -38,7 +38,7 @@ subroutine ic_cr(ic, name_model, inunit, iout, dis) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(ic) + allocate (ic) ! ! -- create name and memory path call ic%set_names(1, name_model, 'IC', 'IC') @@ -77,9 +77,9 @@ subroutine ic_ar(this, x) ! ------------------------------------------------------------------------------ ! ! -- Print a message identifying the initial conditions package. - write(this%iout,1) this%inunit - 1 format(1x,/1x,'IC -- INITIAL CONDITIONS PACKAGE, VERSION 8, 3/28/2015', & - ' INPUT READ FROM UNIT ',i0) + write (this%iout, 1) this%inunit +1 format(1x, /1x, 'IC -- INITIAL CONDITIONS PACKAGE, VERSION 8, 3/28/2015', & + ' INPUT READ FROM UNIT ', i0) ! ! -- Allocate arrays call this%allocate_arrays(this%dis%nodes) @@ -93,7 +93,7 @@ subroutine ic_ar(this, x) ! -- Assign x equal to strt do n = 1, this%dis%nodes x(n) = this%strt(n) - enddo + end do ! ! -- Return return @@ -154,8 +154,8 @@ subroutine read_options(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error ! -- dummy class(GwfIcType) :: this ! -- local @@ -171,24 +171,24 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING IC OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING IC OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case default - write(errmsg,'(4x,a,a)') 'Unknown IC option: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case default + write (errmsg, '(4x,a,a)') 'Unknown IC option: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF IC OPTIONS' + write (this%iout, '(1x,a)') 'END OF IC OPTIONS' end if ! ! -- Return return - end subroutine read_options + end subroutine read_options subroutine read_data(this) ! ****************************************************************************** @@ -198,8 +198,8 @@ subroutine read_data(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error ! -- dummy class(GwfIcType) :: this ! -- local @@ -216,8 +216,8 @@ subroutine read_data(this) ! ! -- get griddata block call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING GRIDDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -225,17 +225,17 @@ subroutine read_data(this) call this%parser%GetRemainingLine(line) lloc = 1 select case (keyword) - case ('STRT') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%strt, & - aname(1)) - case default - write(errmsg,'(4x,a,a)') 'Unknown GRIDDATA tag: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('STRT') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%strt, & + aname(1)) + case default + write (errmsg, '(4x,a,a)') 'Unknown GRIDDATA tag: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' + write (this%iout, '(1x,a)') 'END PROCESSING GRIDDATA' else call store_error('Required GRIDDATA block not found.') call this%parser%StoreErrorUnit() diff --git a/src/Model/GroundWaterFlow/gwf3lak8.f90 b/src/Model/GroundWaterFlow/gwf3lak8.f90 index 00c55efdab0..cfb921248fa 100644 --- a/src/Model/GroundWaterFlow/gwf3lak8.f90 +++ b/src/Model/GroundWaterFlow/gwf3lak8.f90 @@ -1,22 +1,22 @@ module LakModule ! use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & - DZERO, DPREC, DEM30, DEM9, DEM6, DEM5, & - DEM4, DEM2, DEM1, DHALF, DP7, DONE, & + use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & + DZERO, DPREC, DEM30, DEM9, DEM6, DEM5, & + DEM4, DEM2, DEM1, DHALF, DP7, DONE, & DTWO, DPI, DTHREE, DEIGHT, DTEN, DHUNDRED, DEP20, & - DONETHIRD, DTWOTHIRDS, DFIVETHIRDS, & - DGRAVITY, DCD, & - NAMEDBOUNDFLAG, LENFTYPE, LENPACKAGENAME, & - LENPAKLOC, DNODATA, & - TABLEFT, TABCENTER, TABRIGHT, & + DONETHIRD, DTWOTHIRDS, DFIVETHIRDS, & + DGRAVITY, DCD, & + NAMEDBOUNDFLAG, LENFTYPE, LENPACKAGENAME, & + LENPAKLOC, DNODATA, & + TABLEFT, TABCENTER, TABRIGHT, & TABSTRING, TABUCSTRING, TABINTEGER, TABREAL - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & + use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & mem_deallocate use MemoryHelperModule, only: create_mem_path - use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & - sQuadraticSaturationDerivative, & - sQSaturationDerivative + use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & + sQuadraticSaturationDerivative, & + sQSaturationDerivative use BndModule, only: BndType use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr use TableModule, only: TableType, table_cr @@ -24,10 +24,10 @@ module LakModule use ObsModule, only: ObsType use InputOutputModule, only: get_node, URWORD, extract_idnum_or_bndname use BaseDisModule, only: DisBaseType - use SimModule, only: count_errors, store_error, store_error_unit + use SimModule, only: count_errors, store_error, store_error_unit use GenericUtilitiesModule, only: sim_message - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType use SimVariablesModule, only: errmsg ! implicit none @@ -36,14 +36,14 @@ module LakModule public :: LakType public :: lak_create ! - character(len=LENFTYPE) :: ftype = 'LAK' - character(len=LENPACKAGENAME) :: text = ' LAK' + character(len=LENFTYPE) :: ftype = 'LAK' + character(len=LENPACKAGENAME) :: text = ' LAK' ! type LakTabType - real(DP), dimension(:), pointer, contiguous :: tabstage => null() - real(DP), dimension(:), pointer, contiguous :: tabvolume => null() - real(DP), dimension(:), pointer, contiguous :: tabsarea => null() - real(DP), dimension(:), pointer, contiguous :: tabwarea => null() + real(DP), dimension(:), pointer, contiguous :: tabstage => null() + real(DP), dimension(:), pointer, contiguous :: tabvolume => null() + real(DP), dimension(:), pointer, contiguous :: tabsarea => null() + real(DP), dimension(:), pointer, contiguous :: tabwarea => null() end type LakTabType ! type, extends(BndType) :: LakType @@ -78,50 +78,50 @@ module LakModule integer(I4B), dimension(:), pointer, contiguous :: nlakeconn => null() integer(I4B), dimension(:), pointer, contiguous :: idxlakeconn => null() integer(I4B), dimension(:), pointer, contiguous :: ntabrow => null() - real(DP), dimension(:), pointer, contiguous :: strt => null() - real(DP), dimension(:), pointer, contiguous :: laketop => null() - real(DP), dimension(:), pointer, contiguous :: lakebot => null() - real(DP), dimension(:), pointer, contiguous :: sareamax => null() - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: lakename => null() - character (len=8), dimension(:), pointer, contiguous :: status => null() - real(DP), dimension(:), pointer, contiguous :: avail => null() - real(DP), dimension(:), pointer, contiguous :: lkgwsink => null() + real(DP), dimension(:), pointer, contiguous :: strt => null() + real(DP), dimension(:), pointer, contiguous :: laketop => null() + real(DP), dimension(:), pointer, contiguous :: lakebot => null() + real(DP), dimension(:), pointer, contiguous :: sareamax => null() + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: lakename => null() + character(len=8), dimension(:), pointer, contiguous :: status => null() + real(DP), dimension(:), pointer, contiguous :: avail => null() + real(DP), dimension(:), pointer, contiguous :: lkgwsink => null() real(DP), dimension(:), pointer, contiguous :: stage => null() real(DP), dimension(:), pointer, contiguous :: rainfall => null() real(DP), dimension(:), pointer, contiguous :: evaporation => null() real(DP), dimension(:), pointer, contiguous :: runoff => null() real(DP), dimension(:), pointer, contiguous :: inflow => null() real(DP), dimension(:), pointer, contiguous :: withdrawal => null() - real(DP), dimension(:,:), pointer, contiguous :: lauxvar => null() + real(DP), dimension(:, :), pointer, contiguous :: lauxvar => null() ! ! -- table data integer(I4B), dimension(:), pointer, contiguous :: ialaktab => null() - real(DP), dimension(:), pointer, contiguous :: tabstage => null() - real(DP), dimension(:), pointer, contiguous :: tabvolume => null() - real(DP), dimension(:), pointer, contiguous :: tabsarea => null() - real(DP), dimension(:), pointer, contiguous :: tabwarea => null() + real(DP), dimension(:), pointer, contiguous :: tabstage => null() + real(DP), dimension(:), pointer, contiguous :: tabvolume => null() + real(DP), dimension(:), pointer, contiguous :: tabsarea => null() + real(DP), dimension(:), pointer, contiguous :: tabwarea => null() ! ! -- lake solution data integer(I4B), dimension(:), pointer, contiguous :: ncncvr => null() - real(DP), dimension(:), pointer, contiguous :: surfin => null() - real(DP), dimension(:), pointer, contiguous :: surfout => null() - real(DP), dimension(:), pointer, contiguous :: surfout1 => null() - real(DP), dimension(:), pointer, contiguous :: precip => null() - real(DP), dimension(:), pointer, contiguous :: precip1 => null() - real(DP), dimension(:), pointer, contiguous :: evap => null() - real(DP), dimension(:), pointer, contiguous :: evap1 => null() - real(DP), dimension(:), pointer, contiguous :: evapo => null() - real(DP), dimension(:), pointer, contiguous :: withr => null() - real(DP), dimension(:), pointer, contiguous :: withr1 => null() - real(DP), dimension(:), pointer, contiguous :: flwin => null() - real(DP), dimension(:), pointer, contiguous :: flwiter => null() - real(DP), dimension(:), pointer, contiguous :: flwiter1 => null() - real(DP), dimension(:), pointer, contiguous :: seep => null() - real(DP), dimension(:), pointer, contiguous :: seep1 => null() - real(DP), dimension(:), pointer, contiguous :: seep0 => null() - real(DP), dimension(:), pointer, contiguous :: stageiter => null() - real(DP), dimension(:), pointer, contiguous :: chterm => null() + real(DP), dimension(:), pointer, contiguous :: surfin => null() + real(DP), dimension(:), pointer, contiguous :: surfout => null() + real(DP), dimension(:), pointer, contiguous :: surfout1 => null() + real(DP), dimension(:), pointer, contiguous :: precip => null() + real(DP), dimension(:), pointer, contiguous :: precip1 => null() + real(DP), dimension(:), pointer, contiguous :: evap => null() + real(DP), dimension(:), pointer, contiguous :: evap1 => null() + real(DP), dimension(:), pointer, contiguous :: evapo => null() + real(DP), dimension(:), pointer, contiguous :: withr => null() + real(DP), dimension(:), pointer, contiguous :: withr1 => null() + real(DP), dimension(:), pointer, contiguous :: flwin => null() + real(DP), dimension(:), pointer, contiguous :: flwiter => null() + real(DP), dimension(:), pointer, contiguous :: flwiter1 => null() + real(DP), dimension(:), pointer, contiguous :: seep => null() + real(DP), dimension(:), pointer, contiguous :: seep1 => null() + real(DP), dimension(:), pointer, contiguous :: seep0 => null() + real(DP), dimension(:), pointer, contiguous :: stageiter => null() + real(DP), dimension(:), pointer, contiguous :: chterm => null() ! ! -- lake convergence integer(I4B), dimension(:), pointer, contiguous :: iseepc => null() @@ -139,16 +139,16 @@ module LakModule integer(I4B), dimension(:), pointer, contiguous :: cellid => null() integer(I4B), dimension(:), pointer, contiguous :: nodesontop => null() integer(I4B), dimension(:), pointer, contiguous :: ictype => null() - real(DP), dimension(:), pointer, contiguous :: bedleak => null() - real(DP), dimension(:), pointer, contiguous :: belev => null() - real(DP), dimension(:), pointer, contiguous :: telev => null() - real(DP), dimension(:), pointer, contiguous :: connlength => null() - real(DP), dimension(:), pointer, contiguous :: connwidth => null() - real(DP), dimension(:), pointer, contiguous :: sarea => null() - real(DP), dimension(:), pointer, contiguous :: warea => null() - real(DP), dimension(:), pointer, contiguous :: satcond => null() - real(DP), dimension(:), pointer, contiguous :: simcond => null() - real(DP), dimension(:), pointer, contiguous :: simlakgw => null() + real(DP), dimension(:), pointer, contiguous :: bedleak => null() + real(DP), dimension(:), pointer, contiguous :: belev => null() + real(DP), dimension(:), pointer, contiguous :: telev => null() + real(DP), dimension(:), pointer, contiguous :: connlength => null() + real(DP), dimension(:), pointer, contiguous :: connwidth => null() + real(DP), dimension(:), pointer, contiguous :: sarea => null() + real(DP), dimension(:), pointer, contiguous :: warea => null() + real(DP), dimension(:), pointer, contiguous :: satcond => null() + real(DP), dimension(:), pointer, contiguous :: simcond => null() + real(DP), dimension(:), pointer, contiguous :: simlakgw => null() ! ! -- lake outlet data integer(I4B), dimension(:), pointer, contiguous :: lakein => null() @@ -159,7 +159,7 @@ module LakModule real(DP), dimension(:), pointer, contiguous :: outwidth => null() real(DP), dimension(:), pointer, contiguous :: outrough => null() real(DP), dimension(:), pointer, contiguous :: outslope => null() - real(DP), dimension(:), pointer, contiguous :: simoutrate => null() + real(DP), dimension(:), pointer, contiguous :: simoutrate => null() ! ! -- lake output data real(DP), dimension(:), pointer, contiguous :: qauxcbc => null() @@ -175,9 +175,9 @@ module LakModule integer(I4B), pointer :: gwfik33 => NULL() ! ! -- package x, xold, and ibound - integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !package ibound - real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !package x vector - real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !package xold vector + integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !package ibound + real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !package x vector + real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !package xold vector ! ! -- lake budget object type(BudgetObjectType), pointer :: budobj => null() @@ -188,10 +188,13 @@ module LakModule ! ! -- density variables integer(I4B), pointer :: idense - real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() + real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() + ! + ! -- viscosity variables + real(DP), dimension(:, :), pointer, contiguous :: viscratios => null() !< viscosity ratios (1: lak vsc ratio; 2: gwf vsc ratio) ! ! -- type bound procedures - contains + contains procedure :: lak_allocate_scalars procedure :: lak_allocate_arrays procedure :: bnd_options => lak_options @@ -231,7 +234,7 @@ module LakModule procedure, private :: lak_calculate_sarea procedure, private :: lak_calculate_warea procedure, private :: lak_calculate_conn_warea - procedure, public :: lak_calculate_vol + procedure, public :: lak_calculate_vol procedure, private :: lak_calculate_conductance procedure, private :: lak_calculate_cond_head procedure, private :: lak_calculate_conn_conductance @@ -265,8 +268,10 @@ module LakModule ! -- table procedure, private :: lak_setup_tableobj ! -- density - procedure :: lak_activate_density + procedure :: lak_activate_density procedure, private :: lak_calculate_density_exchange + ! -- viscosity + procedure :: lak_activate_viscosity end type LakType contains @@ -281,17 +286,17 @@ subroutine lak_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(LakType), pointer :: lakobj ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(lakobj) + allocate (lakobj) packobj => lakobj ! ! -- create name and memory path @@ -309,9 +314,9 @@ subroutine lak_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%id = id packobj%ibcnum = ibcnum packobj%ncolbnd = 3 - packobj%iscloc = 0 ! not supported + packobj%iscloc = 0 ! not supported packobj%isadvpak = 1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return @@ -325,7 +330,7 @@ subroutine lak_allocate_scalars(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType), intent(inout) :: this + class(LakType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars @@ -375,6 +380,7 @@ subroutine lak_allocate_scalars(this) this%bditems = 11 this%cbcauxitems = 1 this%idense = 0 + this%ivsc = 0 ! ! -- return return @@ -389,7 +395,7 @@ subroutine lak_allocate_arrays(this) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(LakType), intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local integer(I4B) :: i ! ------------------------------------------------------------------------------ @@ -398,18 +404,18 @@ subroutine lak_allocate_arrays(this) call this%BndType%allocate_arrays() ! ! -- allocate character array for budget text - allocate(this%clakbudget(this%bditems)) + allocate (this%clakbudget(this%bditems)) ! !-- fill clakbudget - this%clakbudget(1) = ' GWF' - this%clakbudget(2) = ' RAINFALL' - this%clakbudget(3) = ' EVAPORATION' - this%clakbudget(4) = ' RUNOFF' - this%clakbudget(5) = ' EXT-INFLOW' - this%clakbudget(6) = ' WITHDRAWAL' - this%clakbudget(7) = ' EXT-OUTFLOW' - this%clakbudget(8) = ' STORAGE' - this%clakbudget(9) = ' CONSTANT' + this%clakbudget(1) = ' GWF' + this%clakbudget(2) = ' RAINFALL' + this%clakbudget(3) = ' EVAPORATION' + this%clakbudget(4) = ' RUNOFF' + this%clakbudget(5) = ' EXT-INFLOW' + this%clakbudget(6) = ' WITHDRAWAL' + this%clakbudget(7) = ' EXT-OUTFLOW' + this%clakbudget(8) = ' STORAGE' + this%clakbudget(9) = ' CONSTANT' this%clakbudget(10) = ' FROM-MVR' this%clakbudget(11) = ' TO-MVR' ! @@ -424,7 +430,7 @@ subroutine lak_allocate_arrays(this) end if ! ! -- allocate character array for budget text - allocate(this%cauxcbc(this%cbcauxitems)) + allocate (this%cauxcbc(this%cbcauxitems)) ! ! -- allocate and initialize qauxcbc call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', this%memoryPath) @@ -445,10 +451,13 @@ subroutine lak_allocate_arrays(this) ! -- allocate denseterms to size 0 call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath) ! + ! -- allocate viscratios to size 0 + call mem_allocate(this%viscratios, 2, 0, 'VISCRATIOS', this%memoryPath) + ! ! -- return return end subroutine lak_allocate_arrays - + subroutine lak_read_lakes(this) ! ****************************************************************************** ! pak1read_dimensions -- Read the dimensions for this package @@ -461,7 +470,7 @@ subroutine lak_read_lakes(this) use SimModule, only: store_error, count_errors, store_error_unit use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: text character(len=LENBOUNDNAME) :: bndName, bndNameTemp @@ -486,7 +495,8 @@ subroutine lak_read_lakes(this) ! ! -- allocate lake data call mem_allocate(this%nlakeconn, this%nlakes, 'NLAKECONN', this%memoryPath) - call mem_allocate(this%idxlakeconn, this%nlakes+1, 'IDXLAKECONN', this%memoryPath) + call mem_allocate(this%idxlakeconn, this%nlakes + 1, 'IDXLAKECONN', & + this%memoryPath) call mem_allocate(this%ntabrow, this%nlakes, 'NTABROW', this%memoryPath) call mem_allocate(this%strt, this%nlakes, 'STRT', this%memoryPath) call mem_allocate(this%laketop, this%nlakes, 'LAKETOP', this%memoryPath) @@ -494,11 +504,13 @@ subroutine lak_read_lakes(this) call mem_allocate(this%sareamax, this%nlakes, 'SAREAMAX', this%memoryPath) call mem_allocate(this%stage, this%nlakes, 'STAGE', this%memoryPath) call mem_allocate(this%rainfall, this%nlakes, 'RAINFALL', this%memoryPath) - call mem_allocate(this%evaporation, this%nlakes, 'EVAPORATION', this%memoryPath) + call mem_allocate(this%evaporation, this%nlakes, 'EVAPORATION', & + this%memoryPath) call mem_allocate(this%runoff, this%nlakes, 'RUNOFF', this%memoryPath) call mem_allocate(this%inflow, this%nlakes, 'INFLOW', this%memoryPath) call mem_allocate(this%withdrawal, this%nlakes, 'WITHDRAWAL', this%memoryPath) - call mem_allocate(this%lauxvar, this%naux, this%nlakes, 'LAUXVAR', this%memoryPath) + call mem_allocate(this%lauxvar, this%naux, this%nlakes, 'LAUXVAR', & + this%memoryPath) call mem_allocate(this%avail, this%nlakes, 'AVAIL', this%memoryPath) call mem_allocate(this%lkgwsink, this%nlakes, 'LKGWSINK', this%memoryPath) call mem_allocate(this%ncncvr, this%nlakes, 'NCNCVR', this%memoryPath) @@ -538,14 +550,14 @@ subroutine lak_read_lakes(this) call mem_allocate(this%qgwf0, this%nlakes, 'QGWF0', this%memoryPath) ! ! -- allocate character storage not managed by the memory manager - allocate(this%lakename(this%nlakes)) ! ditch after boundnames allocated?? - allocate(this%status(this%nlakes)) + allocate (this%lakename(this%nlakes)) ! ditch after boundnames allocated?? + allocate (this%status(this%nlakes)) ! do n = 1, this%nlakes this%ntabrow(n) = 0 this%status(n) = 'ACTIVE' this%laketop(n) = -DEP20 - this%lakebot(n) = DEP20 + this%lakebot(n) = DEP20 this%sareamax(n) = DZERO this%iboundpak(n) = 1 this%xnewpak(n) = DEP20 @@ -561,11 +573,11 @@ subroutine lak_read_lakes(this) ! ! -- allocate local storage for aux variables if (this%naux > 0) then - allocate(caux(this%naux)) + allocate (caux(this%naux)) end if ! ! -- allocate and initialize temporary variables - allocate(nboundchk(this%nlakes)) + allocate (nboundchk(this%nlakes)) do n = 1, this%nlakes nboundchk(n) = 0 end do @@ -573,11 +585,11 @@ subroutine lak_read_lakes(this) ! -- read lake well data ! -- get lakes block call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse locations block if detected if (isfound) then - write(this%iout,'(/1x,a)') 'PROCESSING ' // trim(adjustl(this%text)) // & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' PACKAGEDATA' nlak = 0 nconn = 0 @@ -587,11 +599,11 @@ subroutine lak_read_lakes(this) n = this%parser%GetInteger() if (n < 1 .or. n > this%nlakes) then - write(errmsg,'(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes + write (errmsg, '(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes call store_error(errmsg) cycle end if - + ! -- increment nboundchk nboundchk(n) = nboundchk(n) + 1 @@ -602,7 +614,7 @@ subroutine lak_read_lakes(this) ival = this%parser%GetInteger() if (ival < 0) then - write(errmsg,'(a,1x,i6)') 'nlakeconn MUST BE >= 0 for lake ', n + write (errmsg, '(a,1x,i6)') 'nlakeconn MUST BE >= 0 for lake ', n call store_error(errmsg) end if @@ -615,15 +627,15 @@ subroutine lak_read_lakes(this) end do ! -- set default bndName - write(cno,'(i9.9)') n - bndName = 'Lake' // cno + write (cno, '(i9.9)') n + bndName = 'Lake'//cno ! -- lakename if (this%inamedbound /= 0) then call this%parser%GetStringCaps(bndNameTemp) if (bndNameTemp /= '') then bndName = bndNameTemp - endif + end if end if this%lakename(n) = bndName @@ -633,8 +645,9 @@ subroutine lak_read_lakes(this) text = caux(jj) ii = n bndElem => this%lauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & this%auxname(jj)) end do @@ -644,17 +657,17 @@ subroutine lak_read_lakes(this) ! -- check for duplicate or missing lakes do n = 1, this%nlakes if (nboundchk(n) == 0) then - write(errmsg,'(a,1x,i0)') 'NO DATA SPECIFIED FOR LAKE', n + write (errmsg, '(a,1x,i0)') 'NO DATA SPECIFIED FOR LAKE', n call store_error(errmsg) else if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'DATA FOR LAKE', n, 'SPECIFIED', nboundchk(n), 'TIMES' call store_error(errmsg) end if end do - write(this%iout,'(1x,a)') 'END OF ' // trim(adjustl(this%text)) // & - ' PACKAGEDATA' + write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))// & + ' PACKAGEDATA' else call store_error('REQUIRED PACKAGEDATA BLOCK NOT FOUND.') end if @@ -666,21 +679,21 @@ subroutine lak_read_lakes(this) ! ! -- set MAXBOUND this%MAXBOUND = nconn - write(this%iout,'(//4x,a,i7)') 'MAXBOUND = ', this%maxbound + write (this%iout, '(//4x,a,i7)') 'MAXBOUND = ', this%maxbound ! -- set idxlakeconn this%idxlakeconn(1) = 1 do n = 1, this%nlakes - this%idxlakeconn(n+1) = this%idxlakeconn(n) + this%nlakeconn(n) + this%idxlakeconn(n + 1) = this%idxlakeconn(n) + this%nlakeconn(n) end do ! ! -- deallocate local storage for aux variables if (this%naux > 0) then - deallocate(caux) + deallocate (caux) end if ! ! -- deallocate local storage for nboundchk - deallocate(nboundchk) + deallocate (nboundchk) ! ! -- return return @@ -696,7 +709,7 @@ subroutine lak_read_lake_connections(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: keyword, cellid integer(I4B) :: ierr, ival @@ -714,7 +727,7 @@ subroutine lak_read_lake_connections(this) ! -- code ! ! -- allocate local storage - allocate(nboundchk(this%MAXBOUND)) + allocate (nboundchk(this%MAXBOUND)) do n = 1, this%MAXBOUND nboundchk(n) = 0 end do @@ -729,22 +742,24 @@ subroutine lak_read_lake_connections(this) ! -- allocate connection data using memory manager call mem_allocate(this%imap, this%MAXBOUND, 'IMAP', this%memoryPath) call mem_allocate(this%cellid, this%MAXBOUND, 'CELLID', this%memoryPath) - call mem_allocate(this%nodesontop, this%MAXBOUND, 'NODESONTOP', this%memoryPath) + call mem_allocate(this%nodesontop, this%MAXBOUND, 'NODESONTOP', & + this%memoryPath) call mem_allocate(this%ictype, this%MAXBOUND, 'ICTYPE', this%memoryPath) call mem_allocate(this%bedleak, this%MAXBOUND, 'BEDLEAK', this%memoryPath) ! don't need to save this - use a temporary vector call mem_allocate(this%belev, this%MAXBOUND, 'BELEV', this%memoryPath) call mem_allocate(this%telev, this%MAXBOUND, 'TELEV', this%memoryPath) - call mem_allocate(this%connlength, this%MAXBOUND, 'CONNLENGTH', this%memoryPath) - call mem_allocate(this%connwidth, this%MAXBOUND, 'CONNWIDTH', this%memoryPath) + call mem_allocate(this%connlength, this%MAXBOUND, 'CONNLENGTH', & + this%memoryPath) + call mem_allocate(this%connwidth, this%MAXBOUND, 'CONNWIDTH', & + this%memoryPath) call mem_allocate(this%sarea, this%MAXBOUND, 'SAREA', this%memoryPath) call mem_allocate(this%warea, this%MAXBOUND, 'WAREA', this%memoryPath) call mem_allocate(this%satcond, this%MAXBOUND, 'SATCOND', this%memoryPath) call mem_allocate(this%simcond, this%MAXBOUND, 'SIMCOND', this%memoryPath) call mem_allocate(this%simlakgw, this%MAXBOUND, 'SIMLAKGW', this%memoryPath) - ! -- process the lake connection data - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' LAKE_CONNECTIONS' do call this%parser%GetNextLine(endOfBlock) @@ -752,7 +767,7 @@ subroutine lak_read_lake_connections(this) n = this%parser%GetInteger() if (n < 1 .or. n > this%nlakes) then - write(errmsg,'(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes + write (errmsg, '(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes call store_error(errmsg) cycle end if @@ -760,7 +775,7 @@ subroutine lak_read_lake_connections(this) ! -- read connection number ival = this%parser%GetInteger() if (ival < 1 .or. ival > this%nlakeconn(n)) then - write(errmsg,'(a,1x,i4,1x,a,1x,i6)') & + write (errmsg, '(a,1x,i4,1x,a,1x,i6)') & 'iconn FOR LAKE ', n, 'MUST BE > 1 and <= ', this%nlakeconn(n) call store_error(errmsg) cycle @@ -771,7 +786,7 @@ subroutine lak_read_lake_connections(this) ! -- set imap this%imap(ipos) = n - + ! ! -- increment nboundchk nboundchk(ipos) = nboundchk(ipos) + 1 @@ -779,11 +794,11 @@ subroutine lak_read_lake_connections(this) ! -- read gwfnodes from the line call this%parser%GetCellid(this%dis%ndim, cellid) nn = this%dis%noder_from_cellid(cellid, & - this%parser%iuactive, this%iout) + this%parser%iuactive, this%iout) ! ! -- determine if a valid cell location was provided if (nn < 1) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4)') & + write (errmsg, '(a,1x,i4,1x,a,1x,i4)') & 'INVALID cellid FOR LAKE ', n, 'connection', j call store_error(errmsg) end if @@ -795,33 +810,33 @@ subroutine lak_read_lake_connections(this) ! -- read ictype call this%parser%GetStringCaps(keyword) select case (keyword) - case ('VERTICAL') - this%ictype(ipos) = 0 - case ('HORIZONTAL') - this%ictype(ipos) = 1 - case ('EMBEDDEDH') - this%ictype(ipos) = 2 - case ('EMBEDDEDV') - this%ictype(ipos) = 3 - case default - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a,a,a)') & - 'UNKNOWN ctype FOR LAKE ', n, 'connection', j, & - '(', trim(keyword), ')' - call store_error(errmsg) + case ('VERTICAL') + this%ictype(ipos) = 0 + case ('HORIZONTAL') + this%ictype(ipos) = 1 + case ('EMBEDDEDH') + this%ictype(ipos) = 2 + case ('EMBEDDEDV') + this%ictype(ipos) = 3 + case default + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a,a,a)') & + 'UNKNOWN ctype FOR LAKE ', n, 'connection', j, & + '(', trim(keyword), ')' + call store_error(errmsg) end select ! -- bed leakance !this%bedleak(ipos) = this%parser%GetDouble() call this%parser%GetStringCaps(keyword) - select case(keyword) - case ('NONE') - this%bedleak(ipos) = -DONE - case default - read(keyword, *) this%bedleak(ipos) + select case (keyword) + case ('NONE') + this%bedleak(ipos) = -DONE + case default + read (keyword, *) this%bedleak(ipos) end select if (keyword /= 'NONE' .and. this%bedleak(ipos) < dzero) then - write(errmsg,'(a,1x,i4,1x,a)') 'bedleak FOR LAKE ', n, 'MUST BE >= 0' + write (errmsg, '(a,1x,i4,1x,a)') 'bedleak FOR LAKE ', n, 'MUST BE >= 0' call store_error(errmsg) end if @@ -833,11 +848,11 @@ subroutine lak_read_lake_connections(this) ! -- connection length rval = this%parser%GetDouble() - if (rval < dzero) then - if (this%ictype(ipos) == 1 .or. this%ictype(ipos) == 2 .or. & + if (rval < dzero) then + if (this%ictype(ipos) == 1 .or. this%ictype(ipos) == 2 .or. & this%ictype(ipos) == 3) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a)') & - 'connection length (connlength) FOR LAKE ', n, & + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a)') & + 'connection length (connlength) FOR LAKE ', n, & ' HORIZONTAL CONNECTION ', j, 'MUST BE >= 0' call store_error(errmsg) else @@ -848,11 +863,11 @@ subroutine lak_read_lake_connections(this) ! -- connection width rval = this%parser%GetDouble() - if (rval < dzero) then + if (rval < dzero) then if (this%ictype(ipos) == 1) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a)') & - 'cell width (connwidth) FOR LAKE ', n, & - ' HORIZONTAL CONNECTION ', j, 'MUST BE >= 0' + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a)') & + 'cell width (connwidth) FOR LAKE ', n, & + ' HORIZONTAL CONNECTION ', j, 'MUST BE >= 0' call store_error(errmsg) else rval = DZERO @@ -860,7 +875,7 @@ subroutine lak_read_lake_connections(this) end if this%connwidth(ipos) = rval end do - write(this%iout,'(1x,a)') & + write (this%iout, '(1x,a)') & 'END OF '//trim(adjustl(this%text))//' CONNECTIONDATA' else call store_error('REQUIRED CONNECTIONDATA BLOCK NOT FOUND.') @@ -874,13 +889,13 @@ subroutine lak_read_lake_connections(this) ! -- check that embedded lakes have only one connection do n = 1, this%nlakes j = 0 - do ipos = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do ipos = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 if (this%ictype(ipos) /= 2 .and. this%ictype(ipos) /= 3) cycle j = j + 1 if (j > 1) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a)') & - 'nlakeconn FOR LAKE', n, 'EMBEDDED CONNECTION', j, ' EXCEEDS 1.' - call store_error(errmsg) + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a)') & + 'nlakeconn FOR LAKE', n, 'EMBEDDED CONNECTION', j, ' EXCEEDS 1.' + call store_error(errmsg) end if end do end do @@ -893,16 +908,16 @@ subroutine lak_read_lake_connections(this) do nn = 1, this%nlakes if (nn == n) cycle j = 0 - do ipos = this%idxlakeconn(nn), this%idxlakeconn(nn+1)-1 + do ipos = this%idxlakeconn(nn), this%idxlakeconn(nn + 1) - 1 j = j + 1 icellid = this%cellid(ipos) if (icellid == icellid0) then if (this%ictype(ipos) == 0) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a,1x,i4,1x,a)') & - 'EMBEDDED LAKE', n, & - 'CANNOT COINCIDE WITH VERTICAL CONNECTION', j, & - 'IN LAKE', nn, '.' - call store_error(errmsg) + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a,1x,i4,1x,a)') & + 'EMBEDDED LAKE', n, & + 'CANNOT COINCIDE WITH VERTICAL CONNECTION', j, & + 'IN LAKE', nn, '.' + call store_error(errmsg) end if end if end do @@ -912,7 +927,7 @@ subroutine lak_read_lake_connections(this) ! -- process the data do n = 1, this%nlakes j = 0 - do ipos = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do ipos = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 j = j + 1 nn = this%cellid(ipos) top = this%dis%top(nn) @@ -922,32 +937,32 @@ subroutine lak_read_lake_connections(this) this%telev(ipos) = top + this%surfdep this%belev(ipos) = top this%lakebot(n) = min(this%belev(ipos), this%lakebot(n)) - ! horizontal connection + ! horizontal connection else if (this%ictype(ipos) == 1) then if (this%belev(ipos) == this%telev(ipos)) then this%telev(ipos) = top this%belev(ipos) = bot else if (this%belev(ipos) >= this%telev(ipos)) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a)') & - 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a)') & + 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & 'MUST BE >= belev' call store_error(errmsg) else if (this%belev(ipos) < bot) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a,1x,g15.7,1x,a)') & - 'belev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a,1x,g15.7,1x,a)') & + 'belev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & 'MUST BE >= cell bottom (', bot, ')' call store_error(errmsg) else if (this%telev(ipos) > top) then - write(errmsg,'(a,1x,i4,1x,a,1x,i4,1x,a,1x,g15.7,1x,a)') & - 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & + write (errmsg, '(a,1x,i4,1x,a,1x,i4,1x,a,1x,g15.7,1x,a)') & + 'telev FOR LAKE ', n, ' HORIZONTAL CONNECTION ', j, & 'MUST BE <= cell top (', top, ')' call store_error(errmsg) end if end if this%laketop(n) = max(this%telev(ipos), this%laketop(n)) this%lakebot(n) = min(this%belev(ipos), this%lakebot(n)) - ! embedded connections + ! embedded connections else if (this%ictype(ipos) == 2 .or. this%ictype(ipos) == 3) then this%telev(ipos) = top this%belev(ipos) = bot @@ -956,12 +971,12 @@ subroutine lak_read_lake_connections(this) ! ! -- check for missing or duplicate lake connections if (nboundchk(ipos) == 0) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0)') & 'NO DATA SPECIFIED FOR LAKE', n, 'CONNECTION', j call store_error(errmsg) else if (nboundchk(ipos) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'DATA FOR LAKE', n, 'CONNECTION', j, & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & + 'DATA FOR LAKE', n, 'CONNECTION', j, & 'SPECIFIED', nboundchk(ipos), 'TIMES' call store_error(errmsg) end if @@ -974,7 +989,7 @@ subroutine lak_read_lake_connections(this) end do ! ! -- deallocate local variable - deallocate(nboundchk) + deallocate (nboundchk) ! ! -- write summary of lake_connection error messages if (count_errors() > 0) then @@ -995,9 +1010,9 @@ subroutine lak_read_tables(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local - type (LakTabType), dimension(:), allocatable :: laketables + type(LakTabType), dimension(:), allocatable :: laketables character(len=LINELENGTH) :: line character(len=LINELENGTH) :: keyword integer(I4B) :: ierr @@ -1016,13 +1031,13 @@ subroutine lak_read_tables(this) if (this%ntables < 1) return ! ! -- allocate and initialize nboundchk - allocate(nboundchk(this%nlakes)) + allocate (nboundchk(this%nlakes)) do n = 1, this%nlakes nboundchk(n) = 0 end do ! ! -- allocate derived type for table data - allocate(laketables(this%nlakes)) + allocate (laketables(this%nlakes)) ! ! -- get lake_tables block call this%parser%GetBlock('TABLES', isfound, ierr, & @@ -1032,7 +1047,7 @@ subroutine lak_read_tables(this) if (isfound) then ntabs = 0 ! -- process the lake table data - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' LAKE_TABLES' readtable: do call this%parser%GetNextLine(endOfBlock) @@ -1040,11 +1055,11 @@ subroutine lak_read_tables(this) n = this%parser%GetInteger() if (n < 1 .or. n > this%nlakes) then - write(errmsg,'(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes + write (errmsg, '(a,1x,i6)') 'lakeno MUST BE > 0 and <= ', this%nlakes call store_error(errmsg) cycle readtable end if - + ! -- increment ntab and nboundchk ntabs = ntabs + 1 nboundchk(n) = nboundchk(n) + 1 @@ -1052,37 +1067,37 @@ subroutine lak_read_tables(this) ! -- read FILE keyword call this%parser%GetStringCaps(keyword) select case (keyword) - case('TAB6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TAB6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - cycle readtable - end if - call this%parser%GetString(line) - call this%lak_read_table(n, line, laketables(n)) - case default - write(errmsg,'(a,1x,i4,1x,a)') & - 'LAKE TABLE ENTRY for LAKE ', n, 'MUST INCLUDE TAB6 KEYWORD' + case ('TAB6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TAB6 keyword must be followed by "FILEIN" '// & + 'then by filename.' call store_error(errmsg) cycle readtable + end if + call this%parser%GetString(line) + call this%lak_read_table(n, line, laketables(n)) + case default + write (errmsg, '(a,1x,i4,1x,a)') & + 'LAKE TABLE ENTRY for LAKE ', n, 'MUST INCLUDE TAB6 KEYWORD' + call store_error(errmsg) + cycle readtable end select end do readtable - - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' LAKE_TABLES' + + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' LAKE_TABLES' ! ! -- check for missing or duplicate lake connections if (ntabs < this%ntables) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0)') & - 'TABLE DATA ARE SPECIFIED', ntabs, & + write (errmsg, '(a,1x,i0,1x,a,1x,i0)') & + 'TABLE DATA ARE SPECIFIED', ntabs, & 'TIMES BUT NTABLES IS SET TO', this%ntables call store_error(errmsg) end if do n = 1, this%nlakes if (this%ntabrow(n) > 0 .and. nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'TABLE DATA FOR LAKE', n, 'SPECIFIED', nboundchk(n), 'TIMES' call store_error(errmsg) end if @@ -1092,7 +1107,7 @@ subroutine lak_read_tables(this) end if ! ! -- deallocate local storage - deallocate(nboundchk) + deallocate (nboundchk) ! ! -- write summary of lake_table error messages if (count_errors() > 0) then @@ -1105,21 +1120,21 @@ subroutine lak_read_tables(this) ! -- destroy laketables do n = 1, this%nlakes if (this%ntabrow(n) > 0) then - deallocate(laketables(n)%tabstage) - deallocate(laketables(n)%tabvolume) - deallocate(laketables(n)%tabsarea) + deallocate (laketables(n)%tabstage) + deallocate (laketables(n)%tabvolume) + deallocate (laketables(n)%tabsarea) iconn = this%idxlakeconn(n) if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then - deallocate(laketables(n)%tabwarea) + deallocate (laketables(n)%tabwarea) end if end if end do - deallocate(laketables) + deallocate (laketables) ! ! -- return return end subroutine lak_read_tables - + subroutine laktables_to_vectors(this, laketables) ! ****************************************************************************** ! laktables_to_vectors -- Copy the laketables structure data into flattened @@ -1129,7 +1144,7 @@ subroutine laktables_to_vectors(this, laketables) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ class(LakType), intent(inout) :: this - type (LakTabType), intent(in), dimension(:), contiguous :: laketables + type(LakTabType), intent(in), dimension(:), contiguous :: laketables integer(I4B) :: n integer(I4B) :: ntabrows integer(I4B) :: j @@ -1190,8 +1205,8 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! -- dummy class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak - character (len=*), intent(in) :: filename - type (LakTabType), intent(inout) :: laketable + character(len=*), intent(in) :: filename + type(LakTabType), intent(inout) :: laketable ! -- local character(len=LINELENGTH) :: keyword integer(I4B) :: ierr @@ -1209,8 +1224,8 @@ subroutine lak_read_table(this, ilak, filename, laketable) real(DP) :: v0 type(BlockParserType) :: parser ! -- formats - character(len=*), parameter :: fmttaberr = & - '(a,1x,i4,1x,a,1x,g15.6,1x,a,1x,i6,1x,a,1x,i4,1x,a,1x,g15.6,1x,a)' + character(len=*), parameter :: fmttaberr = & + &'(a,1x,i4,1x,a,1x,g15.6,1x,a,1x,i6,1x,a,1x,i4,1x,a,1x,g15.6,1x,a)' ! ------------------------------------------------------------------------------ ! -- format @@ -1233,43 +1248,43 @@ subroutine lak_read_table(this, ilak, filename, laketable) if (isfound) then ! -- process the lake table dimension data if (this%iprpak /= 0) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS' end if readdims: do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('NROW') - n = parser%GetInteger() - - if (n < 1) then - write(errmsg,'(a)') 'LAKE TABLE NROW MUST BE > 0' - call store_error(errmsg) - end if - case ('NCOL') - j = parser%GetInteger() + case ('NROW') + n = parser%GetInteger() - if (this%ictype(ilak) == 2 .or. this%ictype(ilak) == 3) then - jmin = 4 - else - jmin = 3 - end if - if (j < jmin) then - write(errmsg,'(a,1x,i0)') 'LAKE TABLE NCOL MUST BE >= ', jmin - call store_error(errmsg) - end if + if (n < 1) then + write (errmsg, '(a)') 'LAKE TABLE NROW MUST BE > 0' + call store_error(errmsg) + end if + case ('NCOL') + j = parser%GetInteger() - case default - write(errmsg,'(a,a)') & - 'UNKNOWN '//trim(this%text)//' DIMENSIONS KEYWORD: ', trim(keyword) + if (this%ictype(ilak) == 2 .or. this%ictype(ilak) == 3) then + jmin = 4 + else + jmin = 3 + end if + if (j < jmin) then + write (errmsg, '(a,1x,i0)') 'LAKE TABLE NCOL MUST BE >= ', jmin call store_error(errmsg) + end if + + case default + write (errmsg, '(a,a)') & + 'UNKNOWN '//trim(this%text)//' DIMENSIONS KEYWORD: ', trim(keyword) + call store_error(errmsg) end select end do readdims if (this%iprpak /= 0) then - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' end if else call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') @@ -1277,12 +1292,12 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! ! -- check that ncol and nrow have been specified if (n < 1) then - write(errmsg,'(a)') & + write (errmsg, '(a)') & 'NROW NOT SPECIFIED IN THE LAKE TABLE DIMENSIONS BLOCK' call store_error(errmsg) end if if (j < 1) then - write(errmsg,'(a)') & + write (errmsg, '(a)') & 'NCOL NOT SPECIFIED IN THE LAKE TABLE DIMENSIONS BLOCK' call store_error(errmsg) end if @@ -1293,14 +1308,14 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! ! -- allocate space this%ntabrow(ilak) = n - allocate(laketable%tabstage(n)) - allocate(laketable%tabvolume(n)) - allocate(laketable%tabsarea(n)) + allocate (laketable%tabstage(n)) + allocate (laketable%tabvolume(n)) + allocate (laketable%tabsarea(n)) ipos = this%idxlakeconn(ilak) if (this%ictype(ipos) == 2 .or. this%ictype(ipos) == 3) then - allocate(laketable%tabwarea(n)) + allocate (laketable%tabwarea(n)) end if - + ! -- get table block call parser%GetBlock('TABLE', isfound, ierr, supportOpenClose=.true.) ! @@ -1309,7 +1324,7 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! -- process the table data if (this%iprpak /= 0) then - write(this%iout,'(/1x,a)') & + write (this%iout, '(/1x,a)') & 'PROCESSING '//trim(adjustl(this%text))//' TABLE' end if iconn = this%idxlakeconn(ilak) @@ -1328,9 +1343,9 @@ subroutine lak_read_table(this, ilak, filename, laketable) laketable%tabwarea(ipos) = parser%GetDouble() end if end do readtabledata - + if (this%iprpak /= 0) then - write(this%iout,'(1x,a)') & + write (this%iout, '(1x,a)') & 'END OF '//trim(adjustl(this%text))//' TABLE' end if else @@ -1339,7 +1354,7 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! ! -- error condition if number of rows read are not equal to nrow if (ipos /= this%ntabrow(ilak)) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'NROW SET TO', this%ntabrow(ilak), 'BUT', ipos, 'ROWS WERE READ' call store_error(errmsg) end if @@ -1366,44 +1381,44 @@ subroutine lak_read_table(this, ilak, filename, laketable) ! -- verify the table data do n = 2, this%ntabrow(ilak) v = laketable%tabstage(n) - v0 = laketable%tabstage(n-1) + v0 = laketable%tabstage(n - 1) if (v <= v0) then - write(errmsg,fmttaberr) & - 'TABLE STAGE ENTRY', n, '(', laketable%tabstage(n), & - ') FOR LAKE ', ilak, 'MUST BE GREATER THAN THE PREVIOUS STAGE ENTRY',& - n-1, '(', laketable%tabstage(n-1), ')' + write (errmsg, fmttaberr) & + 'TABLE STAGE ENTRY', n, '(', laketable%tabstage(n), ') FOR LAKE ', & + ilak, 'MUST BE GREATER THAN THE PREVIOUS STAGE ENTRY', & + n - 1, '(', laketable%tabstage(n - 1), ')' call store_error(errmsg) end if v = laketable%tabvolume(n) - v0 = laketable%tabvolume(n-1) + v0 = laketable%tabvolume(n - 1) if (v <= v0) then - write(errmsg,fmttaberr) & - 'TABLE VOLUME ENTRY', n, '(', laketable%tabvolume(n), & - ') FOR LAKE ', & - ilak, 'MUST BE GREATER THAN THE PREVIOUS VOLUME ENTRY', & - n-1, '(', laketable%tabvolume(n-1), ')' + write (errmsg, fmttaberr) & + 'TABLE VOLUME ENTRY', n, '(', laketable%tabvolume(n), & + ') FOR LAKE ', & + ilak, 'MUST BE GREATER THAN THE PREVIOUS VOLUME ENTRY', & + n - 1, '(', laketable%tabvolume(n - 1), ')' call store_error(errmsg) end if v = laketable%tabsarea(n) - v0 = laketable%tabsarea(n-1) + v0 = laketable%tabsarea(n - 1) if (v < v0) then - write(errmsg,fmttaberr) & - 'TABLE SURFACE AREA ENTRY', n, '(', & - laketable%tabsarea(n), ') FOR LAKE ', ilak, & - 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS SURFACE AREA ENTRY', & - n-1, '(', laketable%tabsarea(n-1), ')' + write (errmsg, fmttaberr) & + 'TABLE SURFACE AREA ENTRY', n, '(', & + laketable%tabsarea(n), ') FOR LAKE ', ilak, & + 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS SURFACE AREA ENTRY', & + n - 1, '(', laketable%tabsarea(n - 1), ')' call store_error(errmsg) end if iconn = this%idxlakeconn(ilak) if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then v = laketable%tabwarea(n) - v0 = laketable%tabwarea(n-1) + v0 = laketable%tabwarea(n - 1) if (v < v0) then - write(errmsg,fmttaberr) & - 'TABLE EXCHANGE AREA ENTRY', n, '(', & - laketable%tabwarea(n), ') FOR LAKE ', ilak, & - 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS EXCHANGE AREA ' // & - 'ENTRY', n-1, '(', laketable%tabwarea(n-1), ')' + write (errmsg, fmttaberr) & + 'TABLE EXCHANGE AREA ENTRY', n, '(', & + laketable%tabwarea(n), ') FOR LAKE ', ilak, & + 'MUST BE GREATER THAN OR EQUAL TO THE PREVIOUS EXCHANGE AREA '// & + 'ENTRY', n - 1, '(', laketable%tabwarea(n - 1), ')' call store_error(errmsg) end if end if @@ -1433,7 +1448,7 @@ subroutine lak_read_outlets(this) use SimModule, only: store_error, count_errors use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: text, keyword character(len=LENBOUNDNAME) :: bndName @@ -1451,7 +1466,7 @@ subroutine lak_read_outlets(this) ! ------------------------------------------------------------------------------ ! ! -- get well_connections block - call this%parser%GetBlock('OUTLETS', isfound, ierr, & + call this%parser%GetBlock('OUTLETS', isfound, ierr, & supportOpenClose=.true., blockRequired=.false.) ! ! -- parse outlets block if detected @@ -1459,7 +1474,7 @@ subroutine lak_read_outlets(this) if (this%noutlets > 0) then ! ! -- allocate and initialize local variables - allocate(nboundchk(this%noutlets)) + allocate (nboundchk(this%noutlets)) do n = 1, this%noutlets nboundchk(n) = 0 end do @@ -1467,14 +1482,18 @@ subroutine lak_read_outlets(this) ! -- allocate outlet data using memory manager call mem_allocate(this%lakein, this%NOUTLETS, 'LAKEIN', this%memoryPath) call mem_allocate(this%lakeout, this%NOUTLETS, 'LAKEOUT', this%memoryPath) - call mem_allocate(this%iouttype, this%NOUTLETS, 'IOUTTYPE', this%memoryPath) + call mem_allocate(this%iouttype, this%NOUTLETS, 'IOUTTYPE', & + this%memoryPath) call mem_allocate(this%outrate, this%NOUTLETS, 'OUTRATE', this%memoryPath) - call mem_allocate(this%outinvert, this%NOUTLETS, 'OUTINVERT', & + call mem_allocate(this%outinvert, this%NOUTLETS, 'OUTINVERT', & + this%memoryPath) + call mem_allocate(this%outwidth, this%NOUTLETS, 'OUTWIDTH', & + this%memoryPath) + call mem_allocate(this%outrough, this%NOUTLETS, 'OUTROUGH', & + this%memoryPath) + call mem_allocate(this%outslope, this%NOUTLETS, 'OUTSLOPE', & this%memoryPath) - call mem_allocate(this%outwidth, this%NOUTLETS, 'OUTWIDTH', this%memoryPath) - call mem_allocate(this%outrough, this%NOUTLETS, 'OUTROUGH', this%memoryPath) - call mem_allocate(this%outslope, this%NOUTLETS, 'OUTSLOPE', this%memoryPath) - call mem_allocate(this%simoutrate, this%NOUTLETS, 'SIMOUTRATE', & + call mem_allocate(this%simoutrate, this%NOUTLETS, 'SIMOUTRATE', & this%memoryPath) ! ! -- initialize outlet rate @@ -1483,15 +1502,15 @@ subroutine lak_read_outlets(this) end do ! -- process the lake connection data - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' OUTLETS' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' OUTLETS' readoutlet: do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit n = this%parser%GetInteger() if (n < 1 .or. n > this%noutlets) then - write(errmsg,'(a,1x,i6)') & + write (errmsg, '(a,1x,i6)') & 'outletno MUST BE > 0 and <= ', this%noutlets call store_error(errmsg) cycle readoutlet @@ -1502,8 +1521,8 @@ subroutine lak_read_outlets(this) ! ! -- read outlet lakein ival = this%parser%GetInteger() - if (ival <1 .or. ival > this%nlakes) then - write(errmsg,'(a,1x,i4,1x,a,1x,i6)') & + if (ival < 1 .or. ival > this%nlakes) then + write (errmsg, '(a,1x,i4,1x,a,1x,i6)') & 'lakein FOR OUTLET ', n, 'MUST BE > 0 and <= ', this%nlakes call store_error(errmsg) cycle readoutlet @@ -1512,8 +1531,8 @@ subroutine lak_read_outlets(this) ! -- read outlet lakeout ival = this%parser%GetInteger() - if (ival <0 .or. ival > this%nlakes) then - write(errmsg,'(a,1x,i4,1x,a,1x,i6)') & + if (ival < 0 .or. ival > this%nlakes) then + write (errmsg, '(a,1x,i4,1x,a,1x,i6)') & 'lakeout FOR OUTLET ', n, 'MUST BE >= 0 and <= ', this%nlakes call store_error(errmsg) cycle readoutlet @@ -1523,22 +1542,22 @@ subroutine lak_read_outlets(this) ! -- read ictype call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SPECIFIED') - this%iouttype(n) = 0 - case ('MANNING') - this%iouttype(n) = 1 - case ('WEIR') - this%iouttype(n) = 2 - case default - write(errmsg,'(a,1x,i4,1x,a,a,a)') & - 'UNKNOWN couttype FOR OUTLET ', n, '(', trim(keyword), ')' - call store_error(errmsg) - cycle readoutlet - end select + case ('SPECIFIED') + this%iouttype(n) = 0 + case ('MANNING') + this%iouttype(n) = 1 + case ('WEIR') + this%iouttype(n) = 2 + case default + write (errmsg, '(a,1x,i4,1x,a,a,a)') & + 'UNKNOWN couttype FOR OUTLET ', n, '(', trim(keyword), ')' + call store_error(errmsg) + cycle readoutlet + end select ! -- build bndname for outlet - write(citem,'(i9.9)') n - bndName = 'OUTLET' // citem + write (citem, '(i9.9)') n + bndName = 'OUTLET'//citem ! -- set a few variables for timeseries aware variables jj = 1 @@ -1546,55 +1565,56 @@ subroutine lak_read_outlets(this) ! -- outlet invert call this%parser%GetString(text) bndElem => this%outinvert(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & 'INVERT') ! ! -- outlet width call this%parser%GetString(text) bndElem => this%outwidth(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'WIDTH') + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'WIDTH') ! ! -- outlet roughness call this%parser%GetString(text) bndElem => this%outrough(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'ROUGH') + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'ROUGH') ! ! -- outlet slope call this%parser%GetString(text) bndElem => this%outslope(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'SLOPE') + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'SLOPE') end do readoutlet - write(this%iout,'(1x,a)') 'END OF ' // trim(adjustl(this%text)) // & - ' OUTLETS' + write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))// & + ' OUTLETS' ! ! -- check for duplicate or missing outlets do n = 1, this%noutlets if (nboundchk(n) == 0) then - write(errmsg,'(a,1x,i0)') 'NO DATA SPECIFIED FOR OUTLET', n + write (errmsg, '(a,1x,i0)') 'NO DATA SPECIFIED FOR OUTLET', n call store_error(errmsg) else if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'DATA FOR OUTLET', n, 'SPECIFIED', nboundchk(n), 'TIMES' call store_error(errmsg) end if end do ! ! -- deallocate local storage - deallocate(nboundchk) + deallocate (nboundchk) else - write(errmsg,'(a,1x,a)') & - 'AN OUTLETS BLOCK SHOULD NOT BE SPECIFIED IF NOUTLETS IS NOT', & + write (errmsg, '(a,1x,a)') & + 'AN OUTLETS BLOCK SHOULD NOT BE SPECIFIED IF NOUTLETS IS NOT', & 'SPECIFIED OR IS SPECIFIED TO BE 0.' - call store_error(errmsg) + call store_error(errmsg) end if - + else if (this%noutlets > 0) then call store_error('REQUIRED OUTLETS BLOCK NOT FOUND.') @@ -1621,7 +1641,7 @@ subroutine lak_read_dimensions(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: keyword integer(I4B) :: ierr @@ -1630,7 +1650,7 @@ subroutine lak_read_dimensions(this) ! ------------------------------------------------------------------------------ ! ! -- initialize dimensions to -1 - this%nlakes= -1 + this%nlakes = -1 this%maxbound = -1 ! ! -- get dimensions block @@ -1639,36 +1659,36 @@ subroutine lak_read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)') 'PROCESSING ' // trim(adjustl(this%text)) // & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('NLAKES') - this%nlakes = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NLAKES = ', this%nlakes - case ('NOUTLETS') - this%noutlets = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NOUTLETS = ', this%noutlets - case ('NTABLES') - this%ntables = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)')'NTABLES = ', this%ntables - case default - write(errmsg,'(a,a)') & - 'UNKNOWN '//trim(this%text)//' DIMENSION: ', trim(keyword) - call store_error(errmsg) + case ('NLAKES') + this%nlakes = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'NLAKES = ', this%nlakes + case ('NOUTLETS') + this%noutlets = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'NOUTLETS = ', this%noutlets + case ('NTABLES') + this%ntables = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'NTABLES = ', this%ntables + case default + write (errmsg, '(a,a)') & + 'UNKNOWN '//trim(this%text)//' DIMENSION: ', trim(keyword) + call store_error(errmsg) end select end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' else call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') end if if (this%nlakes < 0) then - write(errmsg, '(a)') & + write (errmsg, '(a)') & 'NLAKES WAS NOT SPECIFIED OR WAS SPECIFIED INCORRECTLY.' call store_error(errmsg) end if @@ -1704,7 +1724,6 @@ subroutine lak_read_dimensions(this) return end subroutine lak_read_dimensions - subroutine lak_read_initial_attr(this) ! ****************************************************************************** ! pak1read_dimensions -- Read the initial parameters for this package @@ -1717,7 +1736,7 @@ subroutine lak_read_initial_attr(this) use SimModule, only: store_error, count_errors use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: text integer(I4B) :: j, jj, n @@ -1738,27 +1757,27 @@ subroutine lak_read_initial_attr(this) real(DP) :: c1 real(DP) :: c2 real(DP), allocatable, dimension(:) :: clb, caq - character (len=14) :: cbedleak - character (len=14) :: cbedcond - character (len=10), dimension(0:3) :: ctype - character (len=15) :: nodestr + character(len=14) :: cbedleak + character(len=14) :: cbedcond + character(len=10), dimension(0:3) :: ctype + character(len=15) :: nodestr real(DP), pointer :: bndElem => null() ! -- data - data ctype(0) /'VERTICAL '/ - data ctype(1) /'HORIZONTAL'/ - data ctype(2) /'EMBEDDEDH '/ - data ctype(3) /'EMBEDDEDV '/ + data ctype(0)/'VERTICAL '/ + data ctype(1)/'HORIZONTAL'/ + data ctype(2)/'EMBEDDEDH '/ + data ctype(3)/'EMBEDDEDV '/ ! -- format ! ------------------------------------------------------------------------------ ! ! -- initialize xnewpak and set stage do n = 1, this%nlakes this%xnewpak(n) = this%strt(n) - write(text,'(g15.7)') this%strt(n) - jj = 1 ! For STAGE + write (text, '(g15.7)') this%strt(n) + jj = 1 ! For STAGE bndElem => this%stage(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, 'BND', & - this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'STAGE') end do ! @@ -1776,11 +1795,14 @@ subroutine lak_read_initial_attr(this) ! -- set boundname for each connection if (this%inamedbound /= 0) then do n = 1, this%nlakes - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 this%boundname(j) = this%lakename(n) end do end do - endif + end if + ! + ! -- copy boundname into boundname_cst + call this%copy_boundname() ! ! -- set pointer to gwf iss and gwf hk call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model)) @@ -1790,12 +1812,12 @@ subroutine lak_read_initial_attr(this) call mem_setptr(this%gwfsat, 'SAT', create_mem_path(this%name_model, 'NPF')) ! ! -- allocate temporary storage - allocate(clb(this%MAXBOUND)) - allocate(caq(this%MAXBOUND)) + allocate (clb(this%MAXBOUND)) + allocate (caq(this%MAXBOUND)) ! -- calculate saturated conductance for each connection do n = 1, this%nlakes - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 nn = this%cellid(j) top = this%dis%top(nn) bot = this%dis%bot(nn) @@ -1809,9 +1831,9 @@ subroutine lak_read_initial_attr(this) k = this%gwfk11(nn) else k = this%gwfk33(nn) - endif + end if length = DHALF * (top - bot) - ! horizontal connection + ! horizontal connection else if (this%ictype(j) == 1) then area = (this%telev(j) - this%belev(j)) * this%connwidth(j) ! -- recalculate area if connected cell is confined and lake @@ -1826,7 +1848,7 @@ subroutine lak_read_initial_attr(this) this%sareamax(n) = this%sareamax(n) + DZERO k = this%gwfk11(nn) length = this%connlength(j) - ! embedded horizontal connection + ! embedded horizontal connection else if (this%ictype(j) == 2) then area = DONE this%sarea(j) = DZERO @@ -1834,7 +1856,7 @@ subroutine lak_read_initial_attr(this) this%sareamax(n) = this%sareamax(n) + DZERO k = this%gwfk11(nn) length = this%connlength(j) - ! embedded vertical connection + ! embedded vertical connection else if (this%ictype(j) == 3) then area = DONE this%sarea(j) = DZERO @@ -1844,7 +1866,7 @@ subroutine lak_read_initial_attr(this) k = this%gwfk11(nn) else k = this%gwfk33(nn) - endif + end if length = this%connlength(j) end if if (this%bedleak(j) < DZERO) then @@ -1861,7 +1883,7 @@ subroutine lak_read_initial_attr(this) end if if (this%bedleak(j) < DZERO) then this%satcond(j) = area / caq(j) - else if (clb(j)*caq(j) > DZERO) then + else if (clb(j) * caq(j) > DZERO) then this%satcond(j) = area / (clb(j) + caq(j)) else this%satcond(j) = DZERO @@ -1871,17 +1893,18 @@ subroutine lak_read_initial_attr(this) ! ! -- write a summary of the conductance if (this%iprpak > 0) then - write(this%iout,'(//,29x,a,/)') 'INTERFACE CONDUCTANCE BETWEEN LAKE AND AQUIFER CELLS' - write(this%iout,'(1x,a)') & - & ' LAKE CONNECTION CONNECTION LAKEBED' // & + write (this%iout, '(//,29x,a,/)') & + 'INTERFACE CONDUCTANCE BETWEEN LAKE AND AQUIFER CELLS' + write (this%iout, '(1x,a)') & + & ' LAKE CONNECTION CONNECTION LAKEBED'// & & ' C O N D U C T A N C E S ' - write(this%iout,'(1x,a)') & - & ' NUMBER NUMBER CELLID DIRECTION LEAKANCE' // & + write (this%iout, '(1x,a)') & + & ' NUMBER NUMBER CELLID DIRECTION LEAKANCE'// & & ' LAKEBED AQUIFER COMBINED' - write(this%iout,"(1x,108('-'))") + write (this%iout, "(1x,108('-'))") do n = 1, this%nlakes idx = 0 - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 idx = idx + 1 fact = DONE if (this%ictype(j) == 1) then @@ -1898,36 +1921,43 @@ subroutine lak_read_initial_attr(this) cbedcond = ' NONE ' else if (clb(j) > DZERO) then c1 = area * fact / clb(j) - write(cbedleak,'(g14.5)') this%bedleak(j) - write(cbedcond,'(g14.5)') c1 + write (cbedleak, '(g14.5)') this%bedleak(j) + write (cbedcond, '(g14.5)') c1 else - write(cbedleak,'(g14.5)') c1 - write(cbedcond,'(g14.5)') c1 + write (cbedleak, '(g14.5)') c1 + write (cbedcond, '(g14.5)') c1 end if c2 = DZERO if (caq(j) > DZERO) then c2 = area * fact / caq(j) end if call this%dis%noder_to_string(nn, nodestr) - write(this%iout,'(1x,i10,1x,i10,1x,a15,1x,a10,2(1x,a14),2(1x,g14.5))') & - & n, idx, nodestr, ctype(this%ictype(j)), cbedleak, & - & cbedcond, c2, this%satcond(j) * fact + write (this%iout, & + '(1x,i10,1x,i10,1x,a15,1x,a10,2(1x,a14),2(1x,g14.5))') & + n, idx, nodestr, ctype(this%ictype(j)), cbedleak, & + cbedcond, c2, this%satcond(j) * fact end do end do - write(this%iout,"(1x,108('-'))") - write(this%iout,'(1x,a)') 'IF VERTICAL CONNECTION, CONDUCTANCE (L^2/T) IS BETWEEN AQUIFER CELL AND OVERLYING LAKE CELL.' - write(this%iout,'(1x,a)') 'IF HORIZONTAL CONNECTION, CONDUCTANCES ARE PER UNIT SATURATED THICKNESS (L/T).' - write(this%iout,'(1x,a)') 'IF EMBEDDED CONNECTION, CONDUCTANCES ARE PER UNIT EXCHANGE AREA (1/T).' + write (this%iout, "(1x,108('-'))") + write (this%iout, '(1x,a)') & + 'IF VERTICAL CONNECTION, CONDUCTANCE (L^2/T) IS & + &BETWEEN AQUIFER CELL AND OVERLYING LAKE CELL.' + write (this%iout, '(1x,a)') & + 'IF HORIZONTAL CONNECTION, CONDUCTANCES ARE PER & + &UNIT SATURATED THICKNESS (L/T).' + write (this%iout, '(1x,a)') & + 'IF EMBEDDED CONNECTION, CONDUCTANCES ARE PER & + &UNIT EXCHANGE AREA (1/T).' ! write(this%iout,*) n, idx, nodestr, this%sarea(j), this%warea(j) ! ! -- calculate stage, surface area, wetted area, volume relation do n = 1, this%nlakes - write(this%iout,'(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n - write(this%iout,'(/1x,5(a14))') ' STAGE', ' SURFACE AREA', & + write (this%iout, '(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n + write (this%iout, '(/1x,5(a14))') ' STAGE', ' SURFACE AREA', & & ' WETTED AREA', ' CONDUCTANCE', & & ' VOLUME' - write(this%iout,"(1x,70('-'))") + write (this%iout, "(1x,70('-'))") dx = (this%laketop(n) - this%lakebot(n)) / 150. s = this%lakebot(n) do j = 1, 151 @@ -1935,25 +1965,25 @@ subroutine lak_read_initial_attr(this) call this%lak_calculate_sarea(n, s, sa) call this%lak_calculate_warea(n, s, wa, s) call this%lak_calculate_vol(n, s, v) - write(this%iout,'(1x,5(E14.5))') s, sa, wa, c, v + write (this%iout, '(1x,5(E14.5))') s, sa, wa, c, v s = s + dx end do - write(this%iout,"(1x,70('-'))") + write (this%iout, "(1x,70('-'))") - write(this%iout,'(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n - write(this%iout,'(/1x,4(a14))') ' ', ' ', & + write (this%iout, '(//1x,a,1x,i10)') 'STAGE/VOLUME RELATION FOR LAKE ', n + write (this%iout, '(/1x,4(a14))') ' ', ' ', & & ' CALCULATED', ' STAGE' - write(this%iout,'(1x,4(a14))') ' STAGE', ' VOLUME', & + write (this%iout, '(1x,4(a14))') ' STAGE', ' VOLUME', & & ' STAGE', ' DIFFERENCE' - write(this%iout,"(1x,56('-'))") + write (this%iout, "(1x,56('-'))") s = this%lakebot(n) - dx do j = 1, 156 call this%lak_calculate_vol(n, s, v) call this%lak_vol2stage(n, v, c) - write(this%iout,'(1x,4(E14.5))') s, v, c, s-c + write (this%iout, '(1x,4(E14.5))') s, v, c, s - c s = s + dx end do - write(this%iout,"(1x,56('-'))") + write (this%iout, "(1x,56('-'))") end do end if ! @@ -1964,8 +1994,8 @@ subroutine lak_read_initial_attr(this) this%gwfik33 => null() ! ! -- deallocate temporary storage - deallocate(clb) - deallocate(caq) + deallocate (clb) + deallocate (caq) ! ! -- return return @@ -1975,7 +2005,7 @@ end subroutine lak_read_initial_attr ! function assumes x data is sorted in ascending order subroutine lak_linear_interpolation(this, n, x, y, z, v) ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: n real(DP), dimension(n), intent(in) :: x real(DP), dimension(n), intent(in) :: y @@ -1989,27 +2019,27 @@ subroutine lak_linear_interpolation(this, n, x, y, z, v) ! below bottom of range - set to lowest value if (z <= x(1)) then v = y(1) - ! above highest value - ! slope calculated from interval between n and n-1 + ! above highest value + ! slope calculated from interval between n and n-1 else if (z > x(n)) then - dx = x(n) - x(n-1) + dx = x(n) - x(n - 1) dydx = DZERO if (ABS(dx) > DZERO) then - dydx = ( y(n) - y(n-1) ) / dx + dydx = (y(n) - y(n - 1)) / dx end if - dx = (z - x(n)) + dx = (z - x(n)) v = y(n) + dydx * dx - ! between lowest and highest value in current interval + ! between lowest and highest value in current interval else do i = 2, n - dx = x(i) - x(i-1) + dx = x(i) - x(i - 1) dydx = DZERO - if (z >= x(i-1) .and. z <= x(i)) then + if (z >= x(i - 1) .and. z <= x(i)) then if (ABS(dx) > DZERO) then - dydx = ( y(i) - y(i-1) ) / dx + dydx = (y(i) - y(i - 1)) / dx end if - dx = (z - x(i-1)) - v = y(i-1) + dydx * dx + dx = (z - x(i - 1)) + v = y(i - 1) + dydx * dx exit end if end do @@ -2026,7 +2056,7 @@ subroutine lak_calculate_sarea(this, ilak, stage, sarea) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: sarea @@ -2050,12 +2080,12 @@ subroutine lak_calculate_sarea(this, ilak, stage, sarea) else if (stage >= this%tabstage(ilast)) then sarea = this%tabsarea(ilast) else - call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & - this%tabsarea(ifirst:ilast), & + call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & + this%tabsarea(ifirst:ilast), & stage, sarea) end if else - do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak+1)-1 + do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1 topl = this%telev(i) botl = this%belev(i) sat = sQuadraticSaturation(topl, botl, stage) @@ -2076,7 +2106,7 @@ subroutine lak_calculate_warea(this, ilak, stage, warea, hin) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: warea @@ -2089,7 +2119,7 @@ subroutine lak_calculate_warea(this, ilak, stage, warea, hin) ! -- formats ! ------------------------------------------------------------------------------ warea = DZERO - do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak+1)-1 + do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1 if (present(hin)) then head = hin else @@ -2113,7 +2143,7 @@ subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak integer(I4B), intent(in) :: iconn real(DP), intent(in) :: stage @@ -2144,8 +2174,8 @@ subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa) else if (vv >= this%tabstage(ilast)) then wa = this%tabwarea(ilast) else - call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & - this%tabwarea(ifirst:ilast), & + call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & + this%tabwarea(ifirst:ilast), & vv, wa) end if else @@ -2153,7 +2183,7 @@ subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa) ! -- confined cell if (this%icelltype(node) == 0) then sat = DONE - ! -- convertible cell + ! -- convertible cell else sat = sQuadraticSaturation(topl, botl, vv) end if @@ -2164,7 +2194,6 @@ subroutine lak_calculate_conn_warea(this, ilak, iconn, stage, head, wa) return end subroutine lak_calculate_conn_warea - subroutine lak_calculate_vol(this, ilak, stage, volume) ! ****************************************************************************** ! lak_calculate_vol -- Calculate the volume of a lake at a given stage. @@ -2173,7 +2202,7 @@ subroutine lak_calculate_vol(this, ilak, stage, volume) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: volume @@ -2201,12 +2230,12 @@ subroutine lak_calculate_vol(this, ilak, stage, volume) sa = this%tabsarea(ilast) volume = this%tabvolume(ilast) + ds * sa else - call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & - this%tabvolume(ifirst:ilast), & + call this%lak_linear_interpolation(i, this%tabstage(ifirst:ilast), & + this%tabvolume(ifirst:ilast), & stage, volume) end if else - do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak+1)-1 + do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1 topl = this%telev(i) botl = this%belev(i) sat = sQuadraticSaturation(topl, botl, stage) @@ -2226,7 +2255,6 @@ subroutine lak_calculate_vol(this, ilak, stage, volume) return end subroutine lak_calculate_vol - subroutine lak_calculate_conductance(this, ilak, stage, conductance) ! ****************************************************************************** ! lak_calculate_conductance -- Calculate the total conductance for a lake at a @@ -2236,7 +2264,7 @@ subroutine lak_calculate_conductance(this, ilak, stage, conductance) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: conductance @@ -2246,7 +2274,7 @@ subroutine lak_calculate_conductance(this, ilak, stage, conductance) ! -- formats ! ------------------------------------------------------------------------------ conductance = DZERO - do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak+1)-1 + do i = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1 call this%lak_calculate_conn_conductance(ilak, i, stage, stage, c) conductance = conductance + c end do @@ -2266,7 +2294,7 @@ subroutine lak_calculate_cond_head(this, iconn, stage, head, vv) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: iconn real(DP), intent(in) :: stage real(DP), intent(in) :: head @@ -2294,7 +2322,6 @@ subroutine lak_calculate_cond_head(this, iconn, stage, head, vv) return end subroutine lak_calculate_cond_head - subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond) ! ****************************************************************************** ! lak_calculate_conn_conductance -- Calculate the conductance for a lake @@ -2305,7 +2332,7 @@ subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak integer(I4B), intent(in) :: iconn real(DP), intent(in) :: stage @@ -2320,9 +2347,11 @@ subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond) real(DP) :: botl real(DP) :: sat real(DP) :: wa + real(DP) :: vscratio ! -- formats ! ------------------------------------------------------------------------------ cond = DZERO + vscratio = DONE topl = this%telev(iconn) botl = this%belev(iconn) call this%lak_calculate_cond_head(iconn, stage, head, vv) @@ -2331,17 +2360,17 @@ subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond) ! use full saturated conductance if top and bottom of the lake connection ! are equal if (this%ictype(iconn) == 0) then - if (ABS(topl-botl) < DPREC) then + if (ABS(topl - botl) < DPREC) then sat = DONE end if - ! horizontal connection - ! use full saturated conductance if the connected cell is not convertible + ! horizontal connection + ! use full saturated conductance if the connected cell is not convertible else if (this%ictype(iconn) == 1) then node = this%cellid(iconn) if (this%icelltype(node) == 0) then sat = DONE end if - ! embedded connection + ! embedded connection else if (this%ictype(iconn) == 2 .or. this%ictype(iconn) == 3) then node = this%cellid(iconn) if (this%icelltype(node) == 0) then @@ -2352,13 +2381,23 @@ subroutine lak_calculate_conn_conductance(this, ilak, iconn, stage, head, cond) end if sat = wa end if - cond = sat * this%satcond(iconn) + ! + ! -- account for viscosity effects (if vsc active) + if (this%ivsc == 1) then + ! flow from lake to aquifer + if (stage > head) then + vscratio = this%viscratios(1, iconn) + ! flow from aquifer to lake + else + vscratio = this%viscratios(2, iconn) + end if + end if + cond = sat * this%satcond(iconn) * vscratio ! ! -- return return end subroutine lak_calculate_conn_conductance - subroutine lak_calculate_exchange(this, ilak, stage, totflow) ! ****************************************************************************** ! lak_calculate_exchange -- Calculate the total groundwater-lake flow at a @@ -2368,19 +2407,19 @@ subroutine lak_calculate_exchange(this, ilak, stage, totflow) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: totflow ! -- local integer(I4B) :: j integer(I4B) :: igwfnode - real(DP) :: flow + real(DP) :: flow real(DP) :: hgwf ! -- formats ! ------------------------------------------------------------------------------ totflow = DZERO - do j = this%idxlakeconn(ilak), this%idxlakeconn(ilak+1)-1 + do j = this%idxlakeconn(ilak), this%idxlakeconn(ilak + 1) - 1 igwfnode = this%cellid(j) hgwf = this%xnew(igwfnode) call this%lak_calculate_conn_exchange(ilak, j, stage, hgwf, flow) @@ -2391,7 +2430,6 @@ subroutine lak_calculate_exchange(this, ilak, stage, totflow) return end subroutine lak_calculate_exchange - subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, & gwfhcof, gwfrhs) ! ****************************************************************************** @@ -2402,7 +2440,7 @@ subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak integer(I4B), intent(in) :: iconn real(DP), intent(in) :: stage @@ -2423,7 +2461,7 @@ subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, & call this%lak_calculate_conn_conductance(ilak, iconn, stage, head, cond) botl = this%belev(iconn) ! - ! -- Set ss to stage or botl + ! -- Set ss to stage or botl if (stage >= botl) then ss = stage else @@ -2447,7 +2485,7 @@ subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, & else gwfhcof0 = DZERO gwfrhs0 = flow - endif + end if ! ! Add density contributions, if active if (this%idense /= 0) then @@ -2463,7 +2501,6 @@ subroutine lak_calculate_conn_exchange(this, ilak, iconn, stage, head, flow, & return end subroutine lak_calculate_conn_exchange - subroutine lak_estimate_conn_exchange(this, iflag, ilak, iconn, idry, stage, & head, flow, source, gwfhcof, gwfrhs) ! ****************************************************************************** @@ -2474,7 +2511,7 @@ subroutine lak_estimate_conn_exchange(this, iflag, ilak, iconn, idry, stage, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: iflag integer(I4B), intent(in) :: ilak integer(I4B), intent(in) :: iconn @@ -2524,7 +2561,7 @@ subroutine lak_calculate_storagechange(this, ilak, stage, stage0, delt, dvr) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(in) :: stage0 @@ -2554,7 +2591,7 @@ subroutine lak_calculate_rainfall(this, ilak, stage, ra) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: ra @@ -2584,7 +2621,7 @@ subroutine lak_calculate_runoff(this, ilak, ro) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: ro ! -- formats @@ -2604,7 +2641,7 @@ subroutine lak_calculate_inflow(this, ilak, qin) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: qin ! -- formats @@ -2624,7 +2661,7 @@ subroutine lak_calculate_external(this, ilak, ex) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: ex ! -- local @@ -2651,7 +2688,7 @@ subroutine lak_calculate_withdrawal(this, ilak, avail, wr) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: avail real(DP), intent(inout) :: wr @@ -2682,7 +2719,7 @@ subroutine lak_calculate_evaporation(this, ilak, stage, avail, ev) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: avail @@ -2713,7 +2750,7 @@ subroutine lak_calculate_outlet_inflow(this, ilak, outinf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outinf ! -- local @@ -2743,7 +2780,7 @@ subroutine lak_calculate_outlet_outflow(this, ilak, stage, avail, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: stage real(DP), intent(inout) :: avail @@ -2769,28 +2806,28 @@ subroutine lak_calculate_outlet_outflow(this, ilak, stage, avail, outoutf) g = DGRAVITY * this%convlength * this%convtime * this%convtime select case (this%iouttype(n)) ! specified rate - case(0) - rate = this%outrate(n) - if (-rate > avail) then - rate = -avail - end if + case (0) + rate = this%outrate(n) + if (-rate > avail) then + rate = -avail + end if ! manning - case (1) - if (d > DZERO) then - c = (this%convlength**DONETHIRD) * this%convtime - gsm = DZERO - if (this%outrough(n) > DZERO) then - gsm = DONE / this%outrough(n) - end if - rate = -c * gsm * this%outwidth(n) * ( d**DFIVETHIRDS ) * & - sqrt(this%outslope(n)) + case (1) + if (d > DZERO) then + c = (this%convlength**DONETHIRD) * this%convtime + gsm = DZERO + if (this%outrough(n) > DZERO) then + gsm = DONE / this%outrough(n) end if + rate = -c * gsm * this%outwidth(n) * (d**DFIVETHIRDS) * & + sqrt(this%outslope(n)) + end if ! weir - case (2) - if (d > DZERO) then - rate = -DTWOTHIRDS * DCD * this%outwidth(n) * d * & - sqrt(DTWO * g * d) - end if + case (2) + if (d > DZERO) then + rate = -DTWOTHIRDS * DCD * this%outwidth(n) * d * & + sqrt(DTWO * g * d) + end if end select this%simoutrate(n) = rate avail = avail + rate @@ -2810,7 +2847,7 @@ subroutine lak_get_internal_inlet(this, ilak, outinf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outinf ! -- local @@ -2839,7 +2876,7 @@ subroutine lak_get_internal_outlet(this, ilak, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outoutf ! -- local @@ -2867,7 +2904,7 @@ subroutine lak_get_external_outlet(this, ilak, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outoutf ! -- local @@ -2895,7 +2932,7 @@ subroutine lak_get_external_mover(this, ilak, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outoutf ! -- local @@ -2924,7 +2961,7 @@ subroutine lak_get_internal_mover(this, ilak, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outoutf ! -- local @@ -2953,7 +2990,7 @@ subroutine lak_get_outlet_tomover(this, ilak, outoutf) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(inout) :: outoutf ! -- local @@ -2981,7 +3018,7 @@ subroutine lak_vol2stage(this, ilak, vol, stage) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak real(DP), intent(in) :: vol real(DP), intent(inout) :: stage @@ -3004,11 +3041,11 @@ subroutine lak_vol2stage(this, ilak, vol, stage) ! -- zero volume if (vol <= v0) then stage = s0 - ! -- linear relation between stage and volume above top of lake + ! -- linear relation between stage and volume above top of lake else if (vol >= v1) then call this%lak_calculate_sarea(ilak, s1, sa) stage = s1 + (vol - v1) / sa - ! -- use combination of secant and bisection + ! -- use combination of secant and bisection else en0 = s0 en1 = s1 @@ -3033,7 +3070,7 @@ subroutine lak_vol2stage(this, ilak, vol, stage) ! -- use bisection if secant method stagnates or if ! ds exceeds previous ds - bisection would occur ! after conditions exceeded in 13 iterations - if (ds*ds0 < DPREC .or. ABS(ds) > ABS(ds0)) ibs = ibs + 1 + if (ds * ds0 < DPREC .or. ABS(ds) > ABS(ds0)) ibs = ibs + 1 if (ibs > 12) then ds = DHALF * (s1 - s0) ibs = 0 @@ -3052,7 +3089,7 @@ subroutine lak_vol2stage(this, ilak, vol, stage) end do secantbisection stage = sm if (ABS(ds) >= DEM6) then - write(this%iout, '(1x,a,1x,i5,4(1x,a,1x,g15.6))') & + write (this%iout, '(1x,a,1x,i5,4(1x,a,1x,g15.6))') & & 'LAK_VOL2STAGE failed for lake', ilak, 'volume error =', fm, & & 'finding stage (', stage, ') for volume =', vol, & & 'final change in stage =', ds @@ -3063,7 +3100,6 @@ subroutine lak_vol2stage(this, ilak, vol, stage) return end subroutine lak_vol2stage - function lak_check_valid(this, itemno) result(ierr) ! ****************************************************************************** ! lak_check_valid -- Determine if a valid lake or outlet number has been @@ -3073,7 +3109,7 @@ function lak_check_valid(this, itemno) result(ierr) ! -- return integer(I4B) :: ierr ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: itemno ! -- local integer(I4B) :: ival @@ -3083,16 +3119,16 @@ function lak_check_valid(this, itemno) result(ierr) ival = abs(itemno) if (itemno > 0) then if (ival < 1 .or. ival > this%nlakes) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & - 'LAKENO', itemno, 'must be greater than 0 and less than or equal to', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & + 'LAKENO', itemno, 'must be greater than 0 and less than or equal to', & this%nlakes, '.' call store_error(errmsg) ierr = 1 end if else if (ival < 1 .or. ival > this%noutlets) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & - 'IOUTLET', itemno, 'must be greater than 0 and less than or equal to', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & + 'IOUTLET', itemno, 'must be greater than 0 and less than or equal to', & this%noutlets, '.' call store_error(errmsg) ierr = 1 @@ -3111,7 +3147,7 @@ subroutine lak_set_stressperiod(this, itemno) use TimeSeriesManagerModule, only: read_value_or_time_series_adv use SimModule, only: store_error ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: itemno ! -- local character(len=LINELENGTH) :: text @@ -3127,202 +3163,202 @@ subroutine lak_set_stressperiod(this, itemno) ! -- read line call this%parser%GetStringCaps(keyword) select case (keyword) - case ('STATUS') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetStringCaps(text) - this%status(itemno) = text(1:8) - if (text == 'CONSTANT') then - this%iboundpak(itemno) = -1 - else if (text == 'INACTIVE') then - this%iboundpak(itemno) = 0 - else if (text == 'ACTIVE') then - this%iboundpak(itemno) = 1 - else - write(errmsg,'(a,a)') & - 'Unknown ' // trim(this%text)//' lak status keyword: ', text // '.' - call store_error(errmsg) - end if - case ('STAGE') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For STAGE - bndElem => this%stage(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'STAGE') - case ('RAINFALL') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For RAINFALL - bndElem => this%rainfall(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RAINFALL') - if (this%rainfall(itemno) < DZERO) then - write(errmsg, '(a,i0,a,G0,a)') & - 'Lake ', itemno, ' was assigned a rainfall value of ', & - this%rainfall(itemno), '. Rainfall must be positive.' - call store_error(errmsg) - end if - case ('EVAPORATION') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For EVAPORATION - bndElem => this%evaporation(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'EVAPORATION') - if (this%evaporation(itemno) < DZERO) then - write(errmsg, '(a,i0,a,G0,a)') & - 'Lake ', itemno, ' was assigned an evaporation value of ', & - this%evaporation(itemno), '. Evaporation must be positive.' - call store_error(errmsg) - end if - case ('RUNOFF') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For RUNOFF - bndElem => this%runoff(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RUNOFF') - if (this%runoff(itemno) < DZERO) then - write(errmsg, '(a,i0,a,G0,a)') & - 'Lake ', itemno, ' was assigned a runoff value of ', & - this%runoff(itemno), '. Runoff must be positive.' - call store_error(errmsg) - end if - case ('INFLOW') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For specified INFLOW - bndElem => this%inflow(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'INFLOW') - if (this%inflow(itemno) < DZERO) then - write(errmsg, '(a,i0,a,G0,a)') & - 'Lake ', itemno, ' was assigned an inflow value of ', & - this%inflow(itemno), '. Inflow must be positive.' - call store_error(errmsg) - end if - case ('WITHDRAWAL') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For specified WITHDRAWAL - bndElem => this%withdrawal(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'WITHDRAWL') - if (this%withdrawal(itemno) < DZERO) then - write(errmsg, '(a,i0,a,G0,a)') & - 'Lake ', itemno, ' was assigned a withdrawal value of ', & - this%withdrawal(itemno), '. Withdrawal must be positive.' - call store_error(errmsg) - end if - case ('RATE') - ierr = this%lak_check_valid(-itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For specified OUTLET RATE - bndElem => this%outrate(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RATE') - case ('INVERT') - ierr = this%lak_check_valid(-itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For OUTLET INVERT - bndElem => this%outinvert(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'INVERT') - case ('WIDTH') - ierr = this%lak_check_valid(-itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For OUTLET WIDTH - bndElem => this%outwidth(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'WIDTH') - case ('ROUGH') - ierr = this%lak_check_valid(-itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 ! For OUTLET ROUGHNESS - bndElem => this%outrough(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'ROUGH') - case ('SLOPE') - ierr = this%lak_check_valid(-itemno) - if (ierr /= 0) then - goto 999 - end if + case ('STATUS') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetStringCaps(text) + this%status(itemno) = text(1:8) + if (text == 'CONSTANT') then + this%iboundpak(itemno) = -1 + else if (text == 'INACTIVE') then + this%iboundpak(itemno) = 0 + else if (text == 'ACTIVE') then + this%iboundpak(itemno) = 1 + else + write (errmsg, '(a,a)') & + 'Unknown '//trim(this%text)//' lak status keyword: ', text//'.' + call store_error(errmsg) + end if + case ('STAGE') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For STAGE + bndElem => this%stage(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'STAGE') + case ('RAINFALL') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For RAINFALL + bndElem => this%rainfall(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RAINFALL') + if (this%rainfall(itemno) < DZERO) then + write (errmsg, '(a,i0,a,G0,a)') & + 'Lake ', itemno, ' was assigned a rainfall value of ', & + this%rainfall(itemno), '. Rainfall must be positive.' + call store_error(errmsg) + end if + case ('EVAPORATION') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For EVAPORATION + bndElem => this%evaporation(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'EVAPORATION') + if (this%evaporation(itemno) < DZERO) then + write (errmsg, '(a,i0,a,G0,a)') & + 'Lake ', itemno, ' was assigned an evaporation value of ', & + this%evaporation(itemno), '. Evaporation must be positive.' + call store_error(errmsg) + end if + case ('RUNOFF') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For RUNOFF + bndElem => this%runoff(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RUNOFF') + if (this%runoff(itemno) < DZERO) then + write (errmsg, '(a,i0,a,G0,a)') & + 'Lake ', itemno, ' was assigned a runoff value of ', & + this%runoff(itemno), '. Runoff must be positive.' + call store_error(errmsg) + end if + case ('INFLOW') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For specified INFLOW + bndElem => this%inflow(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'INFLOW') + if (this%inflow(itemno) < DZERO) then + write (errmsg, '(a,i0,a,G0,a)') & + 'Lake ', itemno, ' was assigned an inflow value of ', & + this%inflow(itemno), '. Inflow must be positive.' + call store_error(errmsg) + end if + case ('WITHDRAWAL') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For specified WITHDRAWAL + bndElem => this%withdrawal(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'WITHDRAWL') + if (this%withdrawal(itemno) < DZERO) then + write (errmsg, '(a,i0,a,G0,a)') & + 'Lake ', itemno, ' was assigned a withdrawal value of ', & + this%withdrawal(itemno), '. Withdrawal must be positive.' + call store_error(errmsg) + end if + case ('RATE') + ierr = this%lak_check_valid(-itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For specified OUTLET RATE + bndElem => this%outrate(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RATE') + case ('INVERT') + ierr = this%lak_check_valid(-itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For OUTLET INVERT + bndElem => this%outinvert(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'INVERT') + case ('WIDTH') + ierr = this%lak_check_valid(-itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For OUTLET WIDTH + bndElem => this%outwidth(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'WIDTH') + case ('ROUGH') + ierr = this%lak_check_valid(-itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For OUTLET ROUGHNESS + bndElem => this%outrough(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'ROUGH') + case ('SLOPE') + ierr = this%lak_check_valid(-itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For OUTLET SLOPE + bndElem => this%outslope(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'SLOPE') + case ('AUXILIARY') + ierr = this%lak_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetStringCaps(caux) + do jj = 1, this%naux + if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle call this%parser%GetString(text) - jj = 1 ! For OUTLET SLOPE - bndElem => this%outslope(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'SLOPE') - case ('AUXILIARY') - ierr = this%lak_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetStringCaps(caux) - do jj = 1, this%naux - if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle - call this%parser%GetString(text) - ii = itemno - bndElem => this%lauxvar(jj, ii) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, & - this%packName, 'AUX', this%tsManager, & - this%iprpak, this%auxname(jj)) - exit - end do - case default - write(errmsg,'(2a)') & - 'Unknown ' // trim(this%text) // ' lak data keyword: ', & - trim(keyword) // '.' + ii = itemno + bndElem => this%lauxvar(jj, ii) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & + this%auxname(jj)) + exit + end do + case default + write (errmsg, '(2a)') & + 'Unknown '//trim(this%text)//' lak data keyword: ', & + trim(keyword)//'.' end select ! ! -- return 999 return end subroutine lak_set_stressperiod - subroutine lak_set_attribute_error(this, ilak, keyword, msg) ! ****************************************************************************** ! lak_set_attribute_error -- Issue a parameter error for lakweslls(ilak) @@ -3334,18 +3370,18 @@ subroutine lak_set_attribute_error(this, ilak, keyword, msg) ! ------------------------------------------------------------------------------ use SimModule, only: store_error ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: ilak - character (len=*), intent(in) :: keyword - character (len=*), intent(in) :: msg + character(len=*), intent(in) :: keyword + character(len=*), intent(in) :: msg ! -- local ! -- formats ! ------------------------------------------------------------------------------ if (len(msg) == 0) then - write(errmsg,'(a,1x,a,1x,i6,1x,a)') & + write (errmsg, '(a,1x,a,1x,i6,1x,a)') & keyword, ' for LAKE', ilak, 'has already been set.' else - write(errmsg,'(a,1x,a,1x,i6,1x,a)') keyword, ' for LAKE', ilak, msg + write (errmsg, '(a,1x,a,1x,i6,1x,a)') keyword, ' for LAKE', ilak, msg end if call store_error(errmsg) ! -- return @@ -3366,144 +3402,133 @@ subroutine lak_options(this, option, found) use SimModule, only: store_error use InputOutputModule, only: urword, getunit, openfile ! -- dummy - class(LakType), intent(inout) :: this + class(LakType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: fname, keyword real(DP) :: r ! -- formats - character(len=*),parameter :: fmtlengthconv = & - "(4x, 'LENGTH CONVERSION VALUE (',g15.7,') SPECIFIED.')" - character(len=*),parameter :: fmttimeconv = & - "(4x, 'TIME CONVERSION VALUE (',g15.7,') SPECIFIED.')" - character(len=*),parameter :: fmtoutdmax = & - "(4x, 'MAXIMUM OUTLET WATER DEPTH (',g15.7,') SPECIFIED.')" - character(len=*),parameter :: fmtlakeopt = & - "(4x, 'LAKE ', a, ' VALUE (',g15.7,') SPECIFIED.')" - character(len=*),parameter :: fmtlakbin = & - "(4x, 'LAK ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I0)" + character(len=*), parameter :: fmtlengthconv = & + &"(4x, 'LENGTH CONVERSION VALUE (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmttimeconv = & + &"(4x, 'TIME CONVERSION VALUE (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmtoutdmax = & + &"(4x, 'MAXIMUM OUTLET WATER DEPTH (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmtlakeopt = & + &"(4x, 'LAKE ', a, ' VALUE (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmtlakbin = & + "(4x, 'LAK ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', & + &a, /4x, 'OPENED ON UNIT: ', I0)" ! ------------------------------------------------------------------------------ ! + found = .true. select case (option) - case ('PRINT_STAGE') - this%iprhed = 1 - write(this%iout,'(4x,a)') trim(adjustl(this%text))// & - ' STAGES WILL BE PRINTED TO LISTING FILE.' - found = .true. - case('STAGE') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%istageout = getunit() - call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtlakbin) 'STAGE', fname, this%istageout - found = .true. - else - call store_error('OPTIONAL STAGE KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtlakbin) 'BUDGET', fname, this%ibudgetout - found = .true. - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtlakbin) 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case('PACKAGE_CONVERGENCE') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ipakcsv = getunit() - call openfile(this%ipakcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtlakbin) 'PACKAGE_CONVERGENCE', fname, this%ipakcsv - found = .true. - else - call store_error('OPTIONAL PACKAGE_CONVERGENCE KEYWORD MUST BE ' // & - 'FOLLOWED BY FILEOUT') - end if - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case('LENGTH_CONVERSION') - this%convlength = this%parser%GetDouble() - write(this%iout, fmtlengthconv) this%convlength - found = .true. - case('TIME_CONVERSION') - this%convtime = this%parser%GetDouble() - write(this%iout, fmttimeconv) this%convtime - found = .true. - case('SURFDEP') - r = this%parser%GetDouble() - if (r < DZERO) then - r = DZERO - end if - this%surfdep = r - write(this%iout, fmtlakeopt) 'SURFDEP', this%surfdep - found = .true. + case ('PRINT_STAGE') + this%iprhed = 1 + write (this%iout, '(4x,a)') trim(adjustl(this%text))// & + ' STAGES WILL BE PRINTED TO LISTING FILE.' + case ('STAGE') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%istageout = getunit() + call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtlakbin) 'STAGE', fname, this%istageout + else + call store_error('OPTIONAL STAGE KEYWORD MUST BE FOLLOWED BY FILEOUT') + end if + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtlakbin) 'BUDGET', fname, this%ibudgetout + else + call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtlakbin) 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('PACKAGE_CONVERGENCE') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ipakcsv = getunit() + call openfile(this%ipakcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtlakbin) 'PACKAGE_CONVERGENCE', fname, this%ipakcsv + else + call store_error('OPTIONAL PACKAGE_CONVERGENCE KEYWORD MUST BE '// & + 'FOLLOWED BY FILEOUT') + end if + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + case ('LENGTH_CONVERSION') + this%convlength = this%parser%GetDouble() + write (this%iout, fmtlengthconv) this%convlength + case ('TIME_CONVERSION') + this%convtime = this%parser%GetDouble() + write (this%iout, fmttimeconv) this%convtime + case ('SURFDEP') + r = this%parser%GetDouble() + if (r < DZERO) then + r = DZERO + end if + this%surfdep = r + write (this%iout, fmtlakeopt) 'SURFDEP', this%surfdep ! ! -- right now these are options that are only available in the ! development version and are not included in the documentation. ! These options are only available when IDEVELOPMODE in ! constants module is set to 1 - case('DEV_GROUNDWATER_HEAD_CONDUCTANCE') - call this%parser%DevOpt() - this%igwhcopt = 1 - write(this%iout, '(4x,a)') & - & 'CONDUCTANCE FOR HORIZONTAL CONNECTIONS WILL BE CALCULATED ' // & - & 'USING THE GROUNDWATER HEAD' - found = .true. - case('DEV_MAXIMUM_OUTLET_DEPTH') - call this%parser%DevOpt() - this%outdmax = this%parser%GetDouble() - write(this%iout, fmtoutdmax) this%outdmax - found = .true. - case('DEV_NO_FINAL_CHECK') - call this%parser%DevOpt() - this%iconvchk = 0 - write(this%iout, '(4x,a)') & - & 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN LAKE STAGES ' // & - & 'WILL NOT BE MADE' - found = .true. - case('DEV_NO_FINAL_RESIDUAL_CHECK') - call this%parser%DevOpt() - this%iconvresidchk = 0 - write(this%iout, '(4x,a)') & - & 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN LAKE RESIDUALS ' // & - & 'WILL NOT BE MADE' - found = .true. - case('DEV_MAXIMUM_PERCENT_DIFFERENCE') - call this%parser%DevOpt() - r = this%parser%GetDouble() - if (r < DZERO) then - r = DEM1 - end if - this%pdmax = r - write(this%iout, fmtlakeopt) 'MAXIMUM_PERCENT_DIFFERENCE', this%pdmax - found = .true. - case default - ! - ! -- No options found - found = .false. + case ('DEV_GROUNDWATER_HEAD_CONDUCTANCE') + call this%parser%DevOpt() + this%igwhcopt = 1 + write (this%iout, '(4x,a)') & + 'CONDUCTANCE FOR HORIZONTAL CONNECTIONS WILL BE CALCULATED & + &USING THE GROUNDWATER HEAD' + case ('DEV_MAXIMUM_OUTLET_DEPTH') + call this%parser%DevOpt() + this%outdmax = this%parser%GetDouble() + write (this%iout, fmtoutdmax) this%outdmax + case ('DEV_NO_FINAL_CHECK') + call this%parser%DevOpt() + this%iconvchk = 0 + write (this%iout, '(4x,a)') & + 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN LAKE STAGES & + &WILL NOT BE MADE' + case ('DEV_NO_FINAL_RESIDUAL_CHECK') + call this%parser%DevOpt() + this%iconvresidchk = 0 + write (this%iout, '(4x,a)') & + 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN LAKE RESIDUALS & + &WILL NOT BE MADE' + case ('DEV_MAXIMUM_PERCENT_DIFFERENCE') + call this%parser%DevOpt() + r = this%parser%GetDouble() + if (r < DZERO) then + r = DEM1 + end if + this%pdmax = r + write (this%iout, fmtlakeopt) 'MAXIMUM_PERCENT_DIFFERENCE', this%pdmax + case default + ! + ! -- No options found + found = .false. end select ! ! -- return @@ -3511,19 +3536,19 @@ subroutine lak_options(this, option, found) end subroutine lak_options subroutine lak_ar(this) - ! ****************************************************************************** - ! lak_ar -- Allocate and Read - ! Subroutine: (1) create new-style package - ! (2) point bndobj to the new package - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - ! -- dummy - class(LakType),intent(inout) :: this - ! -- local - ! -- format - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! lak_ar -- Allocate and Read + ! Subroutine: (1) create new-style package + ! (2) point bndobj to the new package + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + ! -- dummy + class(LakType), intent(inout) :: this + ! -- local + ! -- format + ! ------------------------------------------------------------------------------ ! call this%obs%obs_ar() ! @@ -3535,15 +3560,14 @@ subroutine lak_ar(this) ! ! -- setup pakmvrobj if (this%imover /= 0) then - allocate(this%pakmvrobj) + allocate (this%pakmvrobj) call this%pakmvrobj%ar(this%noutlets, this%nlakes, this%memoryPath) - endif + end if ! ! -- return return end subroutine lak_ar - subroutine lak_rp(this) ! ****************************************************************************** ! lak_rp -- Read and Prepare @@ -3557,7 +3581,7 @@ subroutine lak_rp(this) use TdisModule, only: kper, nper use SimModule, only: store_error, count_errors ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: line @@ -3570,10 +3594,10 @@ subroutine lak_rp(this) integer(I4B) :: itemno integer(I4B) :: j ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" ! ------------------------------------------------------------------------------ ! ! -- set nbound to maxbound @@ -3581,15 +3605,16 @@ subroutine lak_rp(this) ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -3602,23 +3627,23 @@ subroutine lak_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- Read data if ionper == kper - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- setup table for period data if (this%iprpak /= 0) then ! ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(1, 4, this%iout, finalize=.FALSE.) text = 'NUMBER' @@ -3626,7 +3651,7 @@ subroutine lak_rp(this) text = 'KEYWORD' call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) do n = 1, 2 - write(text, '(a,1x,i6)') 'VALUE', n + write (text, '(a,1x,i6)') 'VALUE', n call this%inputtab%initialize_column(text, 15, alignment=TABCENTER) end do end if @@ -3653,11 +3678,11 @@ subroutine lak_rp(this) if (this%iprpak /= 0) then call this%inputtab%finalize_table() end if - ! - ! -- using stress period data from the previous stress period + ! + ! -- using stress period data from the previous stress period else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + write (this%iout, fmtlsp) trim(this%filtyp) + end if ! ! -- write summary of lake stress period error messages if (count_errors() > 0) then @@ -3666,12 +3691,12 @@ subroutine lak_rp(this) ! ! -- fill bound array with lake stage, conductance, and bottom elevation do n = 1, this%nlakes - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 node = this%cellid(j) this%nodelist(j) = node - this%bound(1,j) = this%xnewpak(n) - this%bound(2,j) = this%satcond(j) - this%bound(3,j) = this%belev(j) + this%bound(1, j) = this%xnewpak(n) + this%bound(2, j) = this%satcond(j) + this%bound(3, j) = this%belev(j) end do end do ! @@ -3735,7 +3760,7 @@ subroutine lak_ad(this) end do else ! - ! -- copy xold back into xnew as this is a + ! -- copy xold back into xnew as this is a ! retry of this time step do n = 1, this%nlakes this%xnewpak(n) = this%xoldpak(n) @@ -3744,7 +3769,7 @@ subroutine lak_ad(this) this%xnewpak(n) = this%stage(n) end if this%seep0(n) = DZERO - end do + end do end if ! ! -- pakmvrobj ad @@ -3762,23 +3787,23 @@ subroutine lak_ad(this) end subroutine lak_ad subroutine lak_cf(this, reset_mover) - ! ****************************************************************************** - ! lak_cf -- Formulate the HCOF and RHS terms - ! Subroutine: (1) skip if no lakes - ! (2) calculate hcof and rhs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! lak_cf -- Formulate the HCOF and RHS terms + ! Subroutine: (1) skip if no lakes + ! (2) calculate hcof and rhs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ ! -- dummy class(LakType) :: this logical, intent(in), optional :: reset_mover ! -- local integer(I4B) :: j, n integer(I4B) :: igwfnode - real(DP) :: hlak, blak + real(DP) :: hlak, blak logical :: lrm - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ !! !! -- Calculate lak conductance and update package RHS and HCOF !call this%lak_cfupdate() @@ -3797,13 +3822,13 @@ subroutine lak_cf(this, reset_mover) ! -- pakmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() end if ! ! -- find highest active cell do n = 1, this%nlakes - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 ! -- skip horizontal connections if (this%ictype(j) /= 0) then cycle @@ -3818,14 +3843,14 @@ subroutine lak_cf(this, reset_mover) end do ! ! -- reset ibound for cells where lake stage is above the bottom - ! of the lake in the cell or the lake is inactive - only applied to + ! of the lake in the cell or the lake is inactive - only applied to ! vertical connections do n = 1, this%nlakes ! hlak = this%xnewpak(n) ! ! -- Go through lake connections - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 ! ! -- assign gwf node number igwfnode = this%cellid(j) @@ -3865,12 +3890,12 @@ subroutine lak_cf(this, reset_mover) end subroutine lak_cf subroutine lak_fc(this, rhs, ia, idxglo, amatsln) - ! ************************************************************************** - ! lak_fc -- Copy rhs and hcof into solution rhs and amat - ! ************************************************************************** - ! - ! SPECIFICATIONS: - ! -------------------------------------------------------------------------- + ! ************************************************************************** + ! lak_fc -- Copy rhs and hcof into solution rhs and amat + ! ************************************************************************** + ! + ! SPECIFICATIONS: + ! -------------------------------------------------------------------------- ! -- dummy class(LakType) :: this real(DP), dimension(:), intent(inout) :: rhs @@ -3884,7 +3909,7 @@ subroutine lak_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() end if ! @@ -3893,7 +3918,7 @@ subroutine lak_fc(this, rhs, ia, idxglo, amatsln) ! ! -- add terms to the gwf matrix do n = 1, this%nlakes - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 igwfnode = this%cellid(j) if (this%ibound(igwfnode) < 1) cycle ipossymd = idxglo(ia(igwfnode)) @@ -3941,7 +3966,7 @@ subroutine lak_fn(this, rhs, ia, idxglo, amatsln) hlak = this%xnewpak(n) call this%lak_calculate_available(n, hlak, avail, & ra, ro, qinf, ex, this%delh) - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 igwfnode = this%cellid(j) ipos = ia(igwfnode) head = this%xnew(igwfnode) @@ -3950,7 +3975,8 @@ subroutine lak_fn(this, rhs, ia, idxglo, amatsln) ! -- estimate lake-aquifer exchange with perturbed groundwater head ! exchange is relative to the lake !avail = DEP20 - call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, head+this%delh, q1, avail) + call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, & + head + this%delh, q1, avail) q1 = -q1 ! -- calculate unperturbed lake-aquifer exchange q = this%hcof(j) * head - this%rhs(j) @@ -4037,8 +4063,8 @@ subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) if (icnvgmod == 0) then icheck = 0 end if - ! - ! -- saving package convergence data + ! + ! -- saving package convergence data else ! ! -- header for package csv @@ -4053,8 +4079,8 @@ subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! ! -- setup table call table_cr(this%pakcsvtab, this%packName, '') - call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & - lineseparator=.FALSE., separator=',', & + call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & + lineseparator=.FALSE., separator=',', & finalize=.FALSE.) ! ! -- add columns to package csv @@ -4148,14 +4174,14 @@ subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) if (ABS(dhmax) > abs(dpak)) then ipak = locdhmax dpak = dhmax - write(cloc, "(a,'-',a)") & + write (cloc, "(a,'-',a)") & trim(this%packName), 'stage' cpak = trim(cloc) end if if (ABS(dgwfmax) > abs(dpak)) then ipak = locdgwfmax dpak = dgwfmax - write(cloc, "(a,'-',a)") & + write (cloc, "(a,'-',a)") & trim(this%packName), 'gwf' cpak = trim(cloc) end if @@ -4163,8 +4189,8 @@ subroutine lak_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) if (ABS(dqoutmax) > abs(dpak)) then ipak = locdqoutmax dpak = dqoutmax - write(cloc, "(a,'-',a)") & - trim(this%packName), 'outlet' + write (cloc, "(a,'-',a)") & + trim(this%packName), 'outlet' cpak = trim(cloc) end if end if @@ -4282,7 +4308,7 @@ subroutine lak_cq(this, x, flowja, iadv) rrate = DZERO end if call this%lak_accumulate_chterm(n, rrate, chratin, chratout) - endif + end if end if end do ! @@ -4290,9 +4316,12 @@ subroutine lak_cq(this, x, flowja, iadv) do n = 1, this%nlakes if (this%iboundpak(n) == 0) cycle rrate = DZERO - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 - rrate = this%simvals(j) - this%qleak(j) = -rrate + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 + ! simvals is from aquifer perspective, and so it is positive + ! for flow into the aquifer. Need to switch sign for lake + ! perspective. + rrate = -this%simvals(j) + this%qleak(j) = rrate call this%lak_accumulate_chterm(n, rrate, chratin, chratout) end do end do @@ -4313,10 +4342,10 @@ subroutine lak_ot_package_flows(this, icbcfl, ibudfl) ! ! -- write the flows from the budobj ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & pertim, totim, this%iout) @@ -4326,7 +4355,7 @@ subroutine lak_ot_package_flows(this, icbcfl, ibudfl) if (ibudfl /= 0 .and. this%iprflow /= 0) then call this%budobj%write_flowtable(this%dis, kstp, kper) end if - + end subroutine lak_ot_package_flows subroutine lak_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) @@ -4358,10 +4387,10 @@ subroutine lak_ot_dv(this, idvsave, idvprint) ! ! -- set unit number for binary dependent variable output ibinun = 0 - if(this%istageout /= 0) then + if (this%istageout /= 0) then ibinun = this%istageout end if - if(idvsave == 0) ibinun = 0 + if (idvsave == 0) ibinun = 0 ! ! -- write lake binary output if (ibinun > 0) then @@ -4375,7 +4404,7 @@ subroutine lak_ot_dv(this, idvsave, idvprint) end if this%dbuff(n) = v end do - call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, & + call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, & this%nlakes, 1, 1, ibinun) end if ! @@ -4391,7 +4420,7 @@ subroutine lak_ot_dv(this, idvsave, idvprint) call this%lak_calculate_sarea(n, stage, sa) call this%lak_calculate_warea(n, stage, wa) call this%lak_calculate_vol(n, stage, v) - if(this%inamedbound==1) then + if (this%inamedbound == 1) then call this%stagetab%add_term(this%lakename(n)) end if call this%stagetab%add_term(n) @@ -4401,24 +4430,24 @@ subroutine lak_ot_dv(this, idvsave, idvprint) call this%stagetab%add_term(v) end do end if - + end subroutine lak_ot_dv - + subroutine lak_ot_bdsummary(this, kstp, kper, iout, ibudfl) ! -- module use TdisModule, only: totim ! -- dummy - class(LakType) :: this !< LakType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + class(LakType) :: this !< LakType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written ! call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) ! return end subroutine lak_ot_bdsummary - + subroutine lak_da(this) ! ************************************************************************** ! lak_da -- Deallocate objects @@ -4435,15 +4464,16 @@ subroutine lak_da(this) ! -------------------------------------------------------------------------- ! ! -- arrays - deallocate(this%lakename) - deallocate(this%status) - deallocate(this%clakbudget) + deallocate (this%lakename) + deallocate (this%status) + deallocate (this%clakbudget) call mem_deallocate(this%dbuff) - deallocate(this%cauxcbc) + deallocate (this%cauxcbc) call mem_deallocate(this%qauxcbc) call mem_deallocate(this%qleak) call mem_deallocate(this%qsto) call mem_deallocate(this%denseterms) + call mem_deallocate(this%viscratios) ! ! -- tables if (this%ntables > 0) then @@ -4456,8 +4486,8 @@ subroutine lak_da(this) ! ! -- budobj call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- outlets if (this%noutlets > 0) then @@ -4470,20 +4500,20 @@ subroutine lak_da(this) call mem_deallocate(this%outrough) call mem_deallocate(this%outslope) call mem_deallocate(this%simoutrate) - endif + end if ! ! -- stage table if (this%iprhed > 0) then call this%stagetab%table_da() - deallocate(this%stagetab) - nullify(this%stagetab) + deallocate (this%stagetab) + nullify (this%stagetab) end if ! ! -- package csv table if (this%ipakcsv > 0) then call this%pakcsvtab%table_da() - deallocate(this%pakcsvtab) - nullify(this%pakcsvtab) + deallocate (this%pakcsvtab) + nullify (this%pakcsvtab) end if ! ! -- scalars @@ -4578,7 +4608,7 @@ subroutine lak_da(this) call mem_deallocate(this%simlakgw) ! ! -- pointers to gwf variables - nullify(this%gwfiss) + nullify (this%gwfiss) ! ! -- Parent object call this%BndType%bnd_da() @@ -4587,7 +4617,6 @@ subroutine lak_da(this) return end subroutine lak_da - subroutine define_listlabel(this) ! ****************************************************************************** ! define_listlabel -- Define the list heading that is written to iout when @@ -4600,27 +4629,26 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return end subroutine define_listlabel - subroutine lak_set_pointers(this, neq, ibound, xnew, xold, flowja) ! ****************************************************************************** ! set_pointers -- Set pointers to model arrays and variables so that a package @@ -4660,35 +4688,34 @@ end subroutine lak_set_pointers ! ! -- Procedures related to observations (type-bound) logical function lak_obs_supported(this) - ! ****************************************************************************** - ! lak_obs_supported - ! -- Return true because LAK package supports observations. - ! -- Overrides BndType%bnd_obs_supported() - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! lak_obs_supported + ! -- Return true because LAK package supports observations. + ! -- Overrides BndType%bnd_obs_supported() + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ class(LakType) :: this lak_obs_supported = .true. return end function lak_obs_supported - subroutine lak_df_obs(this) - ! ****************************************************************************** - ! lak_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by LAK package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! lak_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by LAK package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ ! -- dummy class(LakType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ ! ! -- Store obs type and assign procedure pointer ! for stage observation type. @@ -4788,7 +4815,6 @@ subroutine lak_df_obs(this) return end subroutine lak_df_obs - subroutine lak_bd_obs(this) ! ************************************************************************** ! lak_bd_obs @@ -4822,123 +4848,123 @@ subroutine lak_bd_obs(this) v = DNODATA jj = obsrv%indxbnds(j) select case (obsrv%ObsTypeId) - case ('STAGE') - if (this%iboundpak(jj) /= 0) then - v = this%xnewpak(jj) - end if - case ('EXT-INFLOW') - if (this%iboundpak(jj) /= 0) then - call this%lak_calculate_inflow(jj, v) - end if - case ('OUTLET-INFLOW') - if (this%iboundpak(jj) /= 0) then - call this%lak_calculate_outlet_inflow(jj, v) - end if - case ('INFLOW') - if (this%iboundpak(jj) /= 0) then - call this%lak_calculate_inflow(jj, v) - call this%lak_calculate_outlet_inflow(jj, v2) - v = v + v2 - end if - case ('FROM-MVR') - if (this%iboundpak(jj) /= 0) then - if (this%imover == 1) then - v = this%pakmvrobj%get_qfrommvr(jj) - end if - end if - case ('RAINFALL') - if (this%iboundpak(jj) /= 0) then - v = this%precip(jj) - end if - case ('RUNOFF') - if (this%iboundpak(jj) /= 0) then - v = this%runoff(jj) - end if - case ('LAK') - n = this%imap(jj) - if (this%iboundpak(n) /= 0) then - igwfnode = this%cellid(jj) - hgwf = this%xnew(igwfnode) - if (this%hcof(jj) /= DZERO) then - v = -(this%hcof(jj) * (this%xnewpak(n) - hgwf)) - else - v = -this%rhs(jj) - end if - end if - case ('EVAPORATION') - if (this%iboundpak(jj) /= 0) then - v = this%evap(jj) + case ('STAGE') + if (this%iboundpak(jj) /= 0) then + v = this%xnewpak(jj) + end if + case ('EXT-INFLOW') + if (this%iboundpak(jj) /= 0) then + call this%lak_calculate_inflow(jj, v) + end if + case ('OUTLET-INFLOW') + if (this%iboundpak(jj) /= 0) then + call this%lak_calculate_outlet_inflow(jj, v) + end if + case ('INFLOW') + if (this%iboundpak(jj) /= 0) then + call this%lak_calculate_inflow(jj, v) + call this%lak_calculate_outlet_inflow(jj, v2) + v = v + v2 + end if + case ('FROM-MVR') + if (this%iboundpak(jj) /= 0) then + if (this%imover == 1) then + v = this%pakmvrobj%get_qfrommvr(jj) end if - case ('WITHDRAWAL') - if (this%iboundpak(jj) /= 0) then - v = this%withr(jj) + end if + case ('RAINFALL') + if (this%iboundpak(jj) /= 0) then + v = this%precip(jj) + end if + case ('RUNOFF') + if (this%iboundpak(jj) /= 0) then + v = this%runoff(jj) + end if + case ('LAK') + n = this%imap(jj) + if (this%iboundpak(n) /= 0) then + igwfnode = this%cellid(jj) + hgwf = this%xnew(igwfnode) + if (this%hcof(jj) /= DZERO) then + v = -(this%hcof(jj) * (this%xnewpak(n) - hgwf)) + else + v = -this%rhs(jj) end if - case ('EXT-OUTFLOW') - n = this%lakein(jj) - if (this%iboundpak(n) /= 0) then - if (this%lakeout(jj) == 0) then - v = this%simoutrate(jj) - if (v < DZERO) then - if (this%imover == 1) then - v = v + this%pakmvrobj%get_qtomvr(jj) - end if + end if + case ('EVAPORATION') + if (this%iboundpak(jj) /= 0) then + v = this%evap(jj) + end if + case ('WITHDRAWAL') + if (this%iboundpak(jj) /= 0) then + v = this%withr(jj) + end if + case ('EXT-OUTFLOW') + n = this%lakein(jj) + if (this%iboundpak(n) /= 0) then + if (this%lakeout(jj) == 0) then + v = this%simoutrate(jj) + if (v < DZERO) then + if (this%imover == 1) then + v = v + this%pakmvrobj%get_qtomvr(jj) end if end if end if - case ('TO-MVR') - n = this%lakein(jj) - if (this%iboundpak(n) /= 0) then - if (this%imover == 1) then - v = this%pakmvrobj%get_qtomvr(jj) - if (v > DZERO) then - v = -v - end if + end if + case ('TO-MVR') + n = this%lakein(jj) + if (this%iboundpak(n) /= 0) then + if (this%imover == 1) then + v = this%pakmvrobj%get_qtomvr(jj) + if (v > DZERO) then + v = -v end if end if - case ('STORAGE') - if (this%iboundpak(jj) /= 0) then - v = this%qsto(jj) - end if - case ('CONSTANT') - if (this%iboundpak(jj) /= 0) then - v = this%chterm(jj) - end if - case ('OUTLET') - n = this%lakein(jj) - if (this%iboundpak(jj) /= 0) then - v = this%simoutrate(jj) - !if (this%imover == 1) then - ! v = v + this%pakmvrobj%get_qtomvr(jj) - !end if - end if - case ('VOLUME') - if (this%iboundpak(jj) /= 0) then - call this%lak_calculate_vol(jj, this%xnewpak(jj), v) - end if - case ('SURFACE-AREA') - if (this%iboundpak(jj) /= 0) then - hlak = this%xnewpak(jj) - call this%lak_calculate_sarea(jj, hlak, v) - end if - case ('WETTED-AREA') - n = this%imap(jj) - if (this%iboundpak(n) /= 0) then - hlak = this%xnewpak(n) - igwfnode = this%cellid(jj) - hgwf = this%xnew(igwfnode) - call this%lak_calculate_conn_warea(n, jj, hlak, hgwf, v) - end if - case ('CONDUCTANCE') - n = this%imap(jj) - if (this%iboundpak(n) /= 0) then - hlak = this%xnewpak(n) - igwfnode = this%cellid(jj) - hgwf = this%xnew(igwfnode) - call this%lak_calculate_conn_conductance(n, jj, hlak, hgwf, v) - end if - case default - errmsg = 'Unrecognized observation type: ' // trim(obsrv%ObsTypeId) - call store_error(errmsg) + end if + case ('STORAGE') + if (this%iboundpak(jj) /= 0) then + v = this%qsto(jj) + end if + case ('CONSTANT') + if (this%iboundpak(jj) /= 0) then + v = this%chterm(jj) + end if + case ('OUTLET') + n = this%lakein(jj) + if (this%iboundpak(jj) /= 0) then + v = this%simoutrate(jj) + !if (this%imover == 1) then + ! v = v + this%pakmvrobj%get_qtomvr(jj) + !end if + end if + case ('VOLUME') + if (this%iboundpak(jj) /= 0) then + call this%lak_calculate_vol(jj, this%xnewpak(jj), v) + end if + case ('SURFACE-AREA') + if (this%iboundpak(jj) /= 0) then + hlak = this%xnewpak(jj) + call this%lak_calculate_sarea(jj, hlak, v) + end if + case ('WETTED-AREA') + n = this%imap(jj) + if (this%iboundpak(n) /= 0) then + hlak = this%xnewpak(n) + igwfnode = this%cellid(jj) + hgwf = this%xnew(igwfnode) + call this%lak_calculate_conn_warea(n, jj, hlak, hgwf, v) + end if + case ('CONDUCTANCE') + n = this%imap(jj) + if (this%iboundpak(n) /= 0) then + hlak = this%xnewpak(n) + igwfnode = this%cellid(jj) + hgwf = this%xnew(igwfnode) + call this%lak_calculate_conn_conductance(n, jj, hlak, hgwf, v) + end if + case default + errmsg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId) + call store_error(errmsg) end select call this%obs%SaveOneSimval(obsrv, v) end do @@ -4953,7 +4979,6 @@ subroutine lak_bd_obs(this) return end subroutine lak_bd_obs - subroutine lak_rp_obs(this) use TdisModule, only: kper ! -- dummy @@ -4966,11 +4991,11 @@ subroutine lak_rp_obs(this) integer(I4B) :: jj character(len=LENBOUNDNAME) :: bname logical :: jfound - class(ObserveType), pointer :: obsrv => null() + class(ObserveType), pointer :: obsrv => null() ! -------------------------------------------------------------------------- ! -- formats -10 format('Boundary "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') +10 format('Boundary "', a, '" for observation "', a, & + '" is invalid in package "', a, '"') ! ! -- process each package observation ! only done the first stress period since boundaries are fixed @@ -4988,20 +5013,20 @@ subroutine lak_rp_obs(this) ! Iterate through all lakes to identify and store ! corresponding index in bound array. jfound = .false. - if (obsrv%ObsTypeId=='LAK' .or. & - obsrv%ObsTypeId=='CONDUCTANCE' .or. & - obsrv%ObsTypeId=='WETTED-AREA') then + if (obsrv%ObsTypeId == 'LAK' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE' .or. & + obsrv%ObsTypeId == 'WETTED-AREA') then do j = 1, this%nlakes - do jj = this%idxlakeconn(j), this%idxlakeconn(j+1) - 1 + do jj = this%idxlakeconn(j), this%idxlakeconn(j + 1) - 1 if (this%boundname(jj) == bname) then jfound = .true. call obsrv%AddObsIndex(jj) end if end do end do - else if (obsrv%ObsTypeId=='EXT-OUTFLOW' .or. & - obsrv%ObsTypeId=='TO-MVR' .or. & - obsrv%ObsTypeId=='OUTLET') then + else if (obsrv%ObsTypeId == 'EXT-OUTFLOW' .or. & + obsrv%ObsTypeId == 'TO-MVR' .or. & + obsrv%ObsTypeId == 'OUTLET') then do j = 1, this%noutlets jj = this%lakein(j) if (this%lakename(jj) == bname) then @@ -5018,15 +5043,16 @@ subroutine lak_rp_obs(this) end do end if if (.not. jfound) then - write(errmsg,10)trim(bname), trim(obsrv%Name), trim(this%packName) + write (errmsg, 10) & + trim(bname), trim(obsrv%Name), trim(this%packName) call store_error(errmsg) end if end if else if (obsrv%indxbnds_count == 0) then - if (obsrv%ObsTypeId=='LAK' .or. & - obsrv%ObsTypeId=='CONDUCTANCE' .or. & - obsrv%ObsTypeId=='WETTED-AREA') then + if (obsrv%ObsTypeId == 'LAK' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE' .or. & + obsrv%ObsTypeId == 'WETTED-AREA') then nn2 = obsrv%NodeNumber2 j = this%idxlakeconn(nn1) + nn2 - 1 call obsrv%AddObsIndex(j) @@ -5036,55 +5062,55 @@ subroutine lak_rp_obs(this) else errmsg = 'Programming error in lak_rp_obs' call store_error(errmsg) - endif + end if end if ! ! -- catch non-cumulative observation assigned to observation defined ! by a boundname that is assigned to more than one element if (obsrv%ObsTypeId == 'STAGE') then if (obsrv%indxbnds_count > 1) then - write(errmsg, '(a,3(1x,a))') & - trim(adjustl(obsrv%ObsTypeId)), & - 'for observation', trim(adjustl(obsrv%Name)), & + write (errmsg, '(a,3(1x,a))') & + trim(adjustl(obsrv%ObsTypeId)), & + 'for observation', trim(adjustl(obsrv%Name)), & ' must be assigned to a lake with a unique boundname.' call store_error(errmsg) end if end if ! ! -- check that index values are valid - if (obsrv%ObsTypeId=='TO-MVR' .or. & - obsrv%ObsTypeId=='EXT-OUTFLOW' .or. & - obsrv%ObsTypeId=='OUTLET') then + if (obsrv%ObsTypeId == 'TO-MVR' .or. & + obsrv%ObsTypeId == 'EXT-OUTFLOW' .or. & + obsrv%ObsTypeId == 'OUTLET') then do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) + nn1 = obsrv%indxbnds(j) if (nn1 < 1 .or. nn1 > this%noutlets) then - write(errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - ' outlet must be > 0 and <=', this%noutlets, & + write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + ' outlet must be > 0 and <=', this%noutlets, & '(specified value is ', nn1, ')' call store_error(errmsg) end if end do - else if (obsrv%ObsTypeId=='LAK' .or. & - obsrv%ObsTypeId=='CONDUCTANCE' .or. & - obsrv%ObsTypeId=='WETTED-AREA') then + else if (obsrv%ObsTypeId == 'LAK' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE' .or. & + obsrv%ObsTypeId == 'WETTED-AREA') then do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) + nn1 = obsrv%indxbnds(j) if (nn1 < 1 .or. nn1 > this%maxbound) then - write(errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - 'lake connection number must be > 0 and <=', this%maxbound, & + write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + 'lake connection number must be > 0 and <=', this%maxbound, & '(specified value is ', nn1, ')' call store_error(errmsg) end if end do else do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) + nn1 = obsrv%indxbnds(j) if (nn1 < 1 .or. nn1 > this%nlakes) then - write(errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - ' lake must be > 0 and <=', this%nlakes, & + write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + ' lake must be > 0 and <=', this%nlakes, & '(specified value is ', nn1, ')' call store_error(errmsg) end if @@ -5101,17 +5127,16 @@ subroutine lak_rp_obs(this) return end subroutine lak_rp_obs - ! ! -- Procedures related to observations (NOT type-bound) subroutine lak_process_obsID(obsrv, dis, inunitobs, iout) ! -- This procedure is pointed to by ObsDataType%ProcesssIdPtr. It processes ! the ID string of an observation definition for LAK package observations. ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1, nn2 integer(I4B) :: icol, istart, istop @@ -5129,15 +5154,15 @@ subroutine lak_process_obsID(obsrv, dis, inunitobs, iout) if (nn1 == NAMEDBOUNDFLAG) then obsrv%FeatureName = bndname else - if (obsrv%ObsTypeId=='LAK' .or. obsrv%ObsTypeId=='CONDUCTANCE' .or. & - obsrv%ObsTypeId=='WETTED-AREA') then + if (obsrv%ObsTypeId == 'LAK' .or. obsrv%ObsTypeId == 'CONDUCTANCE' .or. & + obsrv%ObsTypeId == 'WETTED-AREA') then call extract_idnum_or_bndname(strng, icol, istart, istop, nn2, bndname) if (len_trim(bndName) < 1 .and. nn2 < 0) then - write(errmsg, '(a,1x,a,a,1x,a,1x,a)') & - 'For observation type', trim(adjustl(obsrv%ObsTypeId)), & - ', ID given as an integer and not as boundname,',& - 'but ID2 (iconn) is missing. Either change ID to valid', & - 'boundname or supply valid entry for ID2.' + write (errmsg, '(a,1x,a,a,1x,a,1x,a)') & + 'For observation type', trim(adjustl(obsrv%ObsTypeId)), & + ', ID given as an integer and not as boundname,', & + 'but ID2 (iconn) is missing. Either change ID to valid', & + 'boundname or supply valid entry for ID2.' call store_error(errmsg) end if if (nn2 == NAMEDBOUNDFLAG) then @@ -5147,10 +5172,8 @@ subroutine lak_process_obsID(obsrv, dis, inunitobs, iout) else obsrv%NodeNumber2 = nn2 end if - !! -- store connection number (NodeNumber2) - !obsrv%NodeNumber2 = nn2 - endif - endif + end if + end if ! -- store lake number (NodeNumber) obsrv%NodeNumber = nn1 ! @@ -5196,95 +5219,94 @@ subroutine lak_accumulate_chterm(this, ilak, rrate, chratin, chratout) return end subroutine lak_accumulate_chterm - subroutine lak_cfupdate(this) - ! ****************************************************************************** - ! lak_cfupdate -- Update LAK satcond and package rhs and hcof - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - class(LakType), intent(inout) :: this - integer(I4B) :: j, n, node - real(DP) :: hlak, head, clak, blak - ! ------------------------------------------------------------------------------ - ! - ! -- Return if no lak lakes - if(this%nbound.eq.0) return - ! - ! -- Calculate hcof and rhs for each lak entry - do n = 1, this%nlakes - hlak = this%xnewpak(n) - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 - node = this%cellid(j) - head = this%xnew(node) + ! ****************************************************************************** + ! lak_cfupdate -- Update LAK satcond and package rhs and hcof + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + class(LakType), intent(inout) :: this + integer(I4B) :: j, n, node + real(DP) :: hlak, head, clak, blak + ! ------------------------------------------------------------------------------ + ! + ! -- Return if no lak lakes + if (this%nbound .eq. 0) return + ! + ! -- Calculate hcof and rhs for each lak entry + do n = 1, this%nlakes + hlak = this%xnewpak(n) + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 + node = this%cellid(j) + head = this%xnew(node) - this%hcof(j) = DZERO - this%rhs(j) = DZERO - ! - ! -- set bound, hcof, and rhs components - call this%lak_calculate_conn_conductance(n, j, hlak, head, clak) - this%simcond(j) = clak + this%hcof(j) = DZERO + this%rhs(j) = DZERO + ! + ! -- set bound, hcof, and rhs components + call this%lak_calculate_conn_conductance(n, j, hlak, head, clak) + this%simcond(j) = clak - this%bound(2,j) = clak + this%bound(2, j) = clak - blak = this%bound(3,j) + blak = this%bound(3, j) - this%hcof(j) = -clak - ! - ! -- fill rhs - if (hlak < blak) then - this%rhs(j) = -clak * blak - else - this%rhs(j) = -clak * hlak - end if - end do + this%hcof(j) = -clak + ! + ! -- fill rhs + if (hlak < blak) then + this%rhs(j) = -clak * blak + else + this%rhs(j) = -clak * hlak + end if end do - ! - ! -- Return - return + end do + ! + ! -- Return + return end subroutine lak_cfupdate subroutine lak_bound_update(this) - ! ****************************************************************************** - ! lak_bound_update -- store the lake head and connection conductance in the - ! bound array - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - class(LakType), intent(inout) :: this - integer(I4B) :: j, n, node - real(DP) :: hlak, head, clak - ! ------------------------------------------------------------------------------ - ! - ! -- Return if no lak lakes - if (this%nbound == 0) return - ! - ! -- Calculate hcof and rhs for each lak entry - do n = 1, this%nlakes - hlak = this%xnewpak(n) - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 - node = this%cellid(j) - head = this%xnew(node) - call this%lak_calculate_conn_conductance(n, j, hlak, head, clak) - this%bound(1, j) = hlak - this%bound(2, j) = clak - end do + ! ****************************************************************************** + ! lak_bound_update -- store the lake head and connection conductance in the + ! bound array + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + class(LakType), intent(inout) :: this + integer(I4B) :: j, n, node + real(DP) :: hlak, head, clak + ! ------------------------------------------------------------------------------ + ! + ! -- Return if no lak lakes + if (this%nbound == 0) return + ! + ! -- Calculate hcof and rhs for each lak entry + do n = 1, this%nlakes + hlak = this%xnewpak(n) + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 + node = this%cellid(j) + head = this%xnew(node) + call this%lak_calculate_conn_conductance(n, j, hlak, head, clak) + this%bound(1, j) = hlak + this%bound(2, j) = clak end do - ! - ! -- Return - return + end do + ! + ! -- Return + return end subroutine lak_bound_update subroutine lak_solve(this, update) - ! ************************************************************************** - ! lak_solve -- Solve for lake stage - ! ************************************************************************** - ! - ! SPECIFICATIONS: - ! -------------------------------------------------------------------------- - use TdisModule,only:delt + ! ************************************************************************** + ! lak_solve -- Solve for lake stage + ! ************************************************************************** + ! + ! SPECIFICATIONS: + ! -------------------------------------------------------------------------- + use TdisModule, only: delt logical, intent(in), optional :: update ! -- dummy class(LakType), intent(inout) :: this @@ -5431,17 +5453,17 @@ subroutine lak_solve(this, update) this%xoldpak(n) = this%xnewpak(n) end if hlak = this%xnewpak(n) - calcconnseep: do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + calcconnseep: do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 igwfnode = this%cellid(j) head = this%xnew(igwfnode) if (this%ncncvr(n) /= 2) then if (this%ibound(igwfnode) > 0) then - call this%lak_estimate_conn_exchange(i, n, j, idry, hlak, & - head, qlakgw, & - this%flwiter(n), & + call this%lak_estimate_conn_exchange(i, n, j, idry, hlak, & + head, qlakgw, & + this%flwiter(n), & gwfhcof, gwfrhs) - call this%lak_estimate_conn_exchange(i, n, j, idry1, hlak+delh,& - head, qlakgw1, & + call this%lak_estimate_conn_exchange(i, n, j, idry1, & + hlak + delh, head, qlakgw1, & this%flwiter1(n)) ! ! -- add to gwf matrix @@ -5477,27 +5499,27 @@ subroutine lak_solve(this, update) call this%lak_calculate_rainfall(n, hlak, ra) this%precip(n) = ra this%flwiter(n) = this%flwiter(n) + ra - call this%lak_calculate_rainfall(n, hlak+delh, ra) + call this%lak_calculate_rainfall(n, hlak + delh, ra) this%precip1(n) = ra this%flwiter1(n) = this%flwiter1(n) + ra ! ! -- limit withdrawals to lake inflows and lake storage call this%lak_calculate_withdrawal(n, this%flwiter(n), wr) - this%withr = wr + this%withr(n) = wr call this%lak_calculate_withdrawal(n, this%flwiter1(n), wr) - this%withr1 = wr + this%withr1(n) = wr ! ! -- limit evaporation to lake inflows and lake storage call this%lak_calculate_evaporation(n, hlak, this%flwiter(n), ev) this%evap(n) = ev - call this%lak_calculate_evaporation(n, hlak+delh, this%flwiter1(n), ev) + call this%lak_calculate_evaporation(n, hlak + delh, this%flwiter1(n), ev) this%evap1(n) = ev ! ! -- no outlet flow if evaporation consumes all water - call this%lak_calculate_outlet_outflow(n, hlak+delh, & - this%flwiter1(n), & + call this%lak_calculate_outlet_outflow(n, hlak + delh, & + this%flwiter1(n), & this%surfout1(n)) - call this%lak_calculate_outlet_outflow(n, hlak, this%flwiter(n), & + call this%lak_calculate_outlet_outflow(n, hlak, this%flwiter(n), & this%surfout(n)) ! ! -- update the surface inflow values @@ -5516,11 +5538,11 @@ subroutine lak_solve(this, update) this%flwin(n) = this%surfin(n) + ro + qinf + ex + v0 / delt ! ! -- compute new lake stage using Newton's method - resid = this%precip(n) + this%evap(n) + this%withr(n) + ro + & - qinf + ex + this%surfin(n) + & + resid = this%precip(n) + this%evap(n) + this%withr(n) + ro + & + qinf + ex + this%surfin(n) + & this%surfout(n) + this%seep(n) - resid1 = this%precip1(n) + this%evap1(n) + this%withr1(n) + ro + & - qinf + ex + this%surfin(n) + & + resid1 = this%precip1(n) + this%evap1(n) + this%withr1(n) + ro + & + qinf + ex + this%surfin(n) + & this%surfout1(n) + this%seep1(n) !call this%lak_calculate_residual(n, this%xnewpak(n), residb) @@ -5530,18 +5552,18 @@ subroutine lak_solve(this, update) if (this%gwfiss /= 1) then call this%lak_calculate_vol(n, hlak, v1) resid = resid + (v0 - v1) / delt - call this%lak_calculate_vol(n, hlak+delh, v1) + call this%lak_calculate_vol(n, hlak + delh, v1) resid1 = resid1 + (v0 - v1) / delt - !else - ! call this%lak_calculate_vol(n, hlak, v1) - ! resid = resid - v1 / delt - ! call this%lak_calculate_vol(n, hlak+delh, v1) - ! resid1 = resid1 - v1 / delt + !else + ! call this%lak_calculate_vol(n, hlak, v1) + ! resid = resid - v1 / delt + ! call this%lak_calculate_vol(n, hlak+delh, v1) + ! resid1 = resid1 - v1 / delt end if ! ! -- determine the derivative and the stage change - if (ABS(resid1-resid) > DZERO) then + if (ABS(resid1 - resid) > DZERO) then derv = (resid1 - resid) / delh dh = DZERO if (ABS(derv) > DPREC) then @@ -5557,14 +5579,14 @@ subroutine lak_solve(this, update) end if ! ! -- determine if the updated stage is outside the endpoints - ts = hlak-dh + ts = hlak - dh if (iter == 1) this%dh0(n) = dh adh = ABS(dh) adh0 = ABS(this%dh0(n)) if ((ts >= this%en2(n)) .or. (ts <= this%en1(n))) then ! -- use bisection if dh is increasing or updated stage is below the ! bottom of the lake - if ((adh > adh0) .or. (ts-this%lakebot(n)) < DPREC) then + if ((adh > adh0) .or. (ts - this%lakebot(n)) < DPREC) then ibflg = 1 ts = DHALF * (this%en1(n) + this%en2(n)) call this%lak_calculate_residual(n, ts, residb) @@ -5578,14 +5600,14 @@ subroutine lak_solve(this, update) end if ! ! -- check for slow convergence - if (this%seep(n)*this%seep0(n) < DPREC) then + if (this%seep(n) * this%seep0(n) < DPREC) then this%iseepc(n) = this%iseepc(n) + 1 else this%iseepc(n) = 0 end if ! -- determine of convergence is slow and oscillating idhp = 0 - if (dh*this%dh0(n) < DPREC) idhp = 1 + if (dh * this%dh0(n) < DPREC) idhp = 1 ! -- determine if stage change is increasing adh = ABS(dh) if (adh > adh0) idhp = 1 @@ -5607,10 +5629,10 @@ subroutine lak_solve(this, update) if (ibflg == 1) then ! -- change end points ! -- root is between r1 and residb - if (this%r1(n)*residb < DZERO) then + if (this%r1(n) * residb < DZERO) then this%en2(n) = ts this%r2(n) = residb - ! -- root is between fp and f2 + ! -- root is between fp and f2 else this%en1(n) = ts this%r1(n) = residb @@ -5653,7 +5675,6 @@ subroutine lak_solve(this, update) return end subroutine lak_solve - subroutine lak_calculate_available(this, n, hlak, avail, & ra, ro, qinf, ex, headp) ! ************************************************************************** @@ -5663,16 +5684,16 @@ subroutine lak_calculate_available(this, n, hlak, avail, & ! ! SPECIFICATIONS: ! -------------------------------------------------------------------------- - use TdisModule,only:delt + use TdisModule, only: delt ! -- dummy class(LakType), intent(inout) :: this integer(I4B), intent(in) :: n real(DP), intent(in) :: hlak real(DP), intent(inout) :: avail - real(DP), intent(inout) :: ra - real(DP), intent(inout) :: ro - real(DP), intent(inout) :: qinf - real(DP), intent(inout) :: ex + real(DP), intent(inout) :: ra + real(DP), intent(inout) :: ro + real(DP), intent(inout) :: qinf + real(DP), intent(inout) :: ex real(DP), intent(in), optional :: headp ! -- local integer(I4B) :: j @@ -5695,11 +5716,12 @@ subroutine lak_calculate_available(this, n, hlak, avail, & avail = DZERO ! ! -- calculate the aquifer sources to the lake - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 igwfnode = this%cellid(j) if (this%ibound(igwfnode) == 0) cycle head = this%xnew(igwfnode) + hp - call this%lak_estimate_conn_exchange(1, n, j, idry, hlak, head, qlakgw, avail) + call this%lak_estimate_conn_exchange(1, n, j, idry, hlak, head, qlakgw, & + avail) end do ! ! -- add rainfall @@ -5726,7 +5748,6 @@ subroutine lak_calculate_available(this, n, hlak, avail, & return end subroutine lak_calculate_available - subroutine lak_calculate_residual(this, n, hlak, resid, headp) ! ************************************************************************** ! lak_calculate_residual -- Calculate the residual for a lake given a @@ -5735,7 +5756,7 @@ subroutine lak_calculate_residual(this, n, hlak, resid, headp) ! ! SPECIFICATIONS: ! -------------------------------------------------------------------------- - use TdisModule,only:delt + use TdisModule, only: delt ! -- dummy class(LakType), intent(inout) :: this integer(I4B), intent(in) :: n @@ -5782,11 +5803,12 @@ subroutine lak_calculate_residual(this, n, hlak, resid, headp) ra, ro, qinf, ex, hp) ! ! -- calculate groundwater seepage - do j = this%idxlakeconn(n), this%idxlakeconn(n+1)-1 + do j = this%idxlakeconn(n), this%idxlakeconn(n + 1) - 1 igwfnode = this%cellid(j) if (this%ibound(igwfnode) == 0) cycle head = this%xnew(igwfnode) + hp - call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, head, qlakgw, avail) + call this%lak_estimate_conn_exchange(2, n, j, idry, hlak, head, qlakgw, & + avail) seep = seep + qlakgw end do ! @@ -5839,7 +5861,7 @@ subroutine lak_setup_budobj(this) character(len=LENBUDTXT), dimension(1) :: auxtxt ! ------------------------------------------------------------------------------ ! - ! -- Determine the number of lake budget terms. These are fixed for + ! -- Determine the number of lake budget terms. These are fixed for ! the simulation and cannot change nbudterm = 9 nlen = 0 @@ -5858,11 +5880,12 @@ subroutine lak_setup_budobj(this) ibudcsv=this%ibudcsv) idx = 0 ! - ! -- Go through and set up each budget term + ! -- Go through and set up each budget term. nlen is the number + ! of outlets that discharge into another lake if (nlen > 0) then text = ' FLOW-JA-FACE' idx = idx + 1 - maxlist = 2 * this%noutlets + maxlist = 2 * nlen naux = 0 call this%budobj%budterm(idx)%initialize(text, & this%name_model, & @@ -5885,10 +5908,10 @@ subroutine lak_setup_budobj(this) end do end if ! - ! -- + ! -- text = ' GWF' idx = idx + 1 - maxlist = this%maxbound + maxlist = this%maxbound naux = 1 auxtxt(1) = ' FLOW-AREA' call this%budobj%budterm(idx)%initialize(text, & @@ -5907,7 +5930,7 @@ subroutine lak_setup_budobj(this) end do end do ! - ! -- + ! -- text = ' RAINFALL' idx = idx + 1 maxlist = this%nlakes @@ -5920,7 +5943,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EVAPORATION' idx = idx + 1 maxlist = this%nlakes @@ -5933,7 +5956,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' RUNOFF' idx = idx + 1 maxlist = this%nlakes @@ -5946,7 +5969,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-INFLOW' idx = idx + 1 maxlist = this%nlakes @@ -5959,7 +5982,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' WITHDRAWAL' idx = idx + 1 maxlist = this%nlakes @@ -5972,7 +5995,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-OUTFLOW' idx = idx + 1 maxlist = this%nlakes @@ -5985,7 +6008,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' STORAGE' idx = idx + 1 maxlist = this%nlakes @@ -5999,7 +6022,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux, auxtxt) ! - ! -- + ! -- text = ' CONSTANT' idx = idx + 1 maxlist = this%nlakes @@ -6012,10 +6035,10 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- if (this%imover == 1) then ! - ! -- + ! -- text = ' FROM-MVR' idx = idx + 1 maxlist = this%nlakes @@ -6028,7 +6051,7 @@ subroutine lak_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' TO-MVR' idx = idx + 1 maxlist = this%noutlets @@ -6040,13 +6063,21 @@ subroutine lak_setup_budobj(this) this%packName, & maxlist, .false., .false., & naux, ordered_id1=.false.) + ! + ! -- store to-mvr connection information + call this%budobj%budterm(idx)%reset(this%noutlets) + q = DZERO + do n = 1, this%noutlets + n1 = this%lakein(n) + call this%budobj%budterm(idx)%update_term(n1, n1, q) + end do end if ! - ! -- + ! -- naux = this%naux if (naux > 0) then ! - ! -- + ! -- text = ' AUXILIARY' idx = idx + 1 maxlist = this%nlakes @@ -6098,7 +6129,6 @@ subroutine lak_fill_budobj(this) ! -- initialize counter idx = 0 - ! -- FLOW JA FACE nlen = 0 do n = 1, this%noutlets @@ -6123,7 +6153,6 @@ subroutine lak_fill_budobj(this) end do end if - ! -- GWF (LEAKAGE) idx = idx + 1 call this%budobj%budterm(idx)%reset(this%maxbound) @@ -6135,7 +6164,6 @@ subroutine lak_fill_budobj(this) end do end do - ! -- RAIN idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6143,8 +6171,7 @@ subroutine lak_fill_budobj(this) q = this%precip(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do - - + ! -- EVAPORATION idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6152,7 +6179,6 @@ subroutine lak_fill_budobj(this) q = this%evap(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do - ! -- RUNOFF idx = idx + 1 @@ -6162,7 +6188,6 @@ subroutine lak_fill_budobj(this) call this%budobj%budterm(idx)%update_term(n, n, q) end do - ! -- INFLOW idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6170,8 +6195,7 @@ subroutine lak_fill_budobj(this) q = this%inflow(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do - - + ! -- WITHDRAWAL idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6180,7 +6204,6 @@ subroutine lak_fill_budobj(this) call this%budobj%budterm(idx)%update_term(n, n, q) end do - ! -- EXTERNAL OUTFLOW idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6192,7 +6215,6 @@ subroutine lak_fill_budobj(this) call this%budobj%budterm(idx)%update_term(n, n, q) end do - ! -- STORAGE idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6202,8 +6224,7 @@ subroutine lak_fill_budobj(this) this%qauxcbc(1) = v1 call this%budobj%budterm(idx)%update_term(n, n, q, this%qauxcbc) end do - - + ! -- CONSTANT FLOW idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6211,11 +6232,10 @@ subroutine lak_fill_budobj(this) q = this%chterm(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do - - + ! -- MOVER if (this%imover == 1) then - + ! -- FROM MOVER idx = idx + 1 call this%budobj%budterm(idx)%reset(this%nlakes) @@ -6223,8 +6243,7 @@ subroutine lak_fill_budobj(this) q = this%pakmvrobj%get_qfrommvr(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do - - + ! -- TO MOVER idx = idx + 1 call this%budobj%budterm(idx)%reset(this%noutlets) @@ -6236,15 +6255,14 @@ subroutine lak_fill_budobj(this) end if call this%budobj%budterm(idx)%update_term(n1, n1, q) end do - + end if - - + ! -- AUXILIARY VARIABLES naux = this%naux if (naux > 0) then idx = idx + 1 - allocate(auxvartmp(naux)) + allocate (auxvartmp(naux)) call this%budobj%budterm(idx)%reset(this%nlakes) do n = 1, this%nlakes q = DZERO @@ -6254,7 +6272,7 @@ subroutine lak_fill_budobj(this) end do call this%budobj%budterm(idx)%update_term(n, n, q, auxvartmp) end do - deallocate(auxvartmp) + deallocate (auxvartmp) end if ! ! --Terms are filled, now accumulate them for this time step @@ -6266,9 +6284,9 @@ end subroutine lak_fill_budobj subroutine lak_setup_tableobj(this) ! ****************************************************************************** -! lak_setup_tableobj -- Set up the table object that is used to write the lak -! stage data. The terms listed here must correspond in -! number and order to the ones written to the stage table +! lak_setup_tableobj -- Set up the table object that is used to write the lak +! stage data. The terms listed here must correspond in +! number and order to the ones written to the stage table ! in the lak_ot method. ! ****************************************************************************** ! @@ -6287,7 +6305,7 @@ subroutine lak_setup_tableobj(this) ! -- setup stage table if (this%iprhed > 0) then ! - ! -- Determine the number of lake stage terms. These are fixed for + ! -- Determine the number of lake stage terms. These are fixed for ! the simulation and cannot change. This includes FLOW-JA-FACE ! so they can be written to the binary budget files, but these internal ! flows are not included as part of the budget table. @@ -6297,12 +6315,12 @@ subroutine lak_setup_tableobj(this) end if ! ! -- set up table title - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STAGES FOR EACH CONTROL VOLUME' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STAGES FOR EACH CONTROL VOLUME' ! ! -- set up stage tableobj call table_cr(this%stagetab, this%packName, title) - call this%stagetab%table_df(this%nlakes, nterms, this%iout, & + call this%stagetab%table_df(this%nlakes, nterms, this%iout, & transient=.TRUE.) ! ! -- Go through and set up table budget term @@ -6335,7 +6353,7 @@ subroutine lak_setup_tableobj(this) ! -- return return end subroutine lak_setup_tableobj - + subroutine lak_activate_density(this) ! ****************************************************************************** ! lak_activate_density -- Activate addition of density terms @@ -6344,7 +6362,7 @@ subroutine lak_activate_density(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this ! -- local integer(I4B) :: i, j ! -- formats @@ -6359,17 +6377,47 @@ subroutine lak_activate_density(this) this%denseterms(j, i) = DZERO end do end do - write(this%iout,'(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR LAKE & - &PACKAGE: ' // trim(adjustl(this%packName)) + write (this%iout, '(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR LAKE & + &PACKAGE: '//trim(adjustl(this%packName)) ! ! -- return return end subroutine lak_activate_density - subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & + !> @brief Activate viscosity terms + !! + !! Method to activate addition of viscosity terms for a LAK package reach. + !! + !< + subroutine lak_activate_viscosity(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(LakType), intent(inout) :: this !< LakType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND + this%ivsc = 1 + call mem_reallocate(this%viscratios, 2, this%MAXBOUND, 'VISCRATIOS', & + this%memoryPath) + do i = 1, this%maxbound + do j = 1, 2 + this%viscratios(j, i) = DONE + end do + end do + write (this%iout, '(/1x,a)') 'VISCOSITY HAS BEEN ACTIVATED FOR LAK & + &PACKAGE: '//trim(adjustl(this%packName)) + ! + ! -- return + return + end subroutine lak_activate_viscosity + + subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & botl, flow, gwfhcof, gwfrhs) ! ****************************************************************************** -! lak_calculate_density_exchange -- Calculate the groundwater-lake density +! lak_calculate_density_exchange -- Calculate the groundwater-lake density ! exchange terms. ! ! -- Arguments are as follows: @@ -6393,7 +6441,7 @@ subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(LakType),intent(inout) :: this + class(LakType), intent(inout) :: this integer(I4B), intent(in) :: iconn real(DP), intent(in) :: stage real(DP), intent(in) :: head @@ -6423,22 +6471,22 @@ subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & if (stage >= botl) then ss = stage stage_below_bot = .false. - rdenselak = this%denseterms(1, iconn) ! lak rel density + rdenselak = this%denseterms(1, iconn) ! lak rel density else ss = botl stage_below_bot = .true. - rdenselak = this%denseterms(2, iconn) ! gwf rel density + rdenselak = this%denseterms(2, iconn) ! gwf rel density end if ! ! -- set hh to head or botl if (head >= botl) then hh = head head_below_bot = .false. - rdensegwf = this%denseterms(2, iconn) ! gwf rel density + rdensegwf = this%denseterms(2, iconn) ! gwf rel density else hh = botl head_below_bot = .true. - rdensegwf = this%denseterms(1, iconn) ! lak rel density + rdensegwf = this%denseterms(1, iconn) ! lak rel density end if ! ! -- todo: hack because denseterms not updated in a cf calculation @@ -6454,9 +6502,9 @@ subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & ! -- calulate average relative density rdenseavg = DHALF * (rdenselak + rdensegwf) ! - ! -- Add contribution of first density term: + ! -- Add contribution of first density term: ! cond * (denseavg/denseref - 1) * (hgwf - hlak) - d1 = cond * (rdenseavg - DONE) + d1 = cond * (rdenseavg - DONE) gwfhcof = gwfhcof - d1 gwfrhs = gwfrhs - d1 * ss d1 = d1 * (hh - ss) @@ -6487,5 +6535,4 @@ subroutine lak_calculate_density_exchange(this, iconn, stage, head, cond, & return end subroutine lak_calculate_density_exchange - end module LakModule diff --git a/src/Model/GroundWaterFlow/gwf3maw8.f90 b/src/Model/GroundWaterFlow/gwf3maw8.f90 index 8914fb6c28a..295b84d8472 100644 --- a/src/Model/GroundWaterFlow/gwf3maw8.f90 +++ b/src/Model/GroundWaterFlow/gwf3maw8.f90 @@ -1,41 +1,41 @@ module MawModule ! use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & - LENBUDTXT, & - DZERO, DEM6, DEM4, DEM2, DQUARTER, DHALF, DP7, & - DP9, DONE, DTWO, DPI, DTWOPI, DEIGHT, DHUNDRED, & - DEP20, NAMEDBOUNDFLAG, LENPACKAGENAME, LENAUXNAME, & - LENFTYPE, DHNOFLO, DHDRY, DNODATA, MAXCHARLEN, & - TABLEFT, TABCENTER, TABRIGHT, & + use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & + LENBUDTXT, DZERO, DEM9, DEM6, DEM4, DEM2, DQUARTER, & + DHALF, DP7, DP9, DONE, DTWO, DPI, DTWOPI, DEIGHT, & + DHUNDRED, DEP20, NAMEDBOUNDFLAG, LENPACKAGENAME, & + LENAUXNAME, LENFTYPE, DHNOFLO, DHDRY, DNODATA, & + MAXCHARLEN, TABLEFT, TABCENTER, TABRIGHT, & TABSTRING, TABUCSTRING, TABINTEGER, TABREAL - use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & - sQuadraticSaturationDerivative, & - sQSaturationDerivative, & - sQuadratic0sp, & - sQuadratic0spDerivative + use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & + sQuadraticSaturationDerivative, & + sQSaturationDerivative, & + sQuadratic0sp, & + sQuadratic0spDerivative use BndModule, only: BndType use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr use TableModule, only: TableType, table_cr - use ObserveModule, only: ObserveType + use ObserveModule, only: ObserveType use ObsModule, only: ObsType - use InputOutputModule, only: get_node, URWORD, extract_idnum_or_bndname + use InputOutputModule, only: get_node, URWORD, extract_idnum_or_bndname, & + GetUnit, openfile use BaseDisModule, only: DisBaseType - use SimModule, only: count_errors, store_error, store_error_unit, & - store_warning - use BlockParserModule, only: BlockParserType + use SimModule, only: count_errors, store_error, store_error_unit, & + store_warning + use BlockParserModule, only: BlockParserType use SimVariablesModule, only: errmsg, warnmsg - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & + use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & mem_deallocate use MemoryHelperModule, only: create_mem_path ! implicit none - + public :: MawType - + ! - character(len=LENFTYPE) :: ftype = 'MAW' - character(len=LENPACKAGENAME) :: text = ' MAW' + character(len=LENFTYPE) :: ftype = 'MAW' + character(len=LENPACKAGENAME) :: text = ' MAW' private public :: maw_create @@ -45,10 +45,10 @@ module MawModule ! -- scalars ! -- characters ! - character(len=LENBUDTXT), dimension(:), pointer, & - contiguous :: cmawbudget => NULL() - character(len=LENAUXNAME), dimension(:), pointer, & - contiguous :: cauxcbc => NULL() + character(len=LENBUDTXT), dimension(:), pointer, & + contiguous :: cmawbudget => NULL() + character(len=LENAUXNAME), dimension(:), pointer, & + contiguous :: cauxcbc => NULL() ! ! -- logical logical(LGP), pointer :: correct_flow => null() @@ -66,6 +66,7 @@ module MawModule integer(I4B), pointer :: check_attr => NULL() integer(I4B), pointer :: ishutoffcnt => NULL() integer(I4B), pointer :: ieffradopt => NULL() + integer(I4B), pointer :: ioutredflowcsv => NULL() !< unit number for CSV output file containing MAWs with reduced extraction/injection rates real(DP), pointer :: satomega => null() ! ! -- for underrelaxation of estimated well q if using shutoff @@ -73,7 +74,7 @@ module MawModule real(DP), pointer :: kappa => NULL() ! ! -- vector data for each well - character (len=8), dimension(:), pointer, contiguous :: status => null() + character(len=8), dimension(:), pointer, contiguous :: status => null() integer(I4B), dimension(:), pointer, contiguous :: ngwfnodes => null() integer(I4B), dimension(:), pointer, contiguous :: ieqn => null() integer(I4B), dimension(:), pointer, contiguous :: ishutoff => null() @@ -97,13 +98,13 @@ module MawModule real(DP), dimension(:), pointer, contiguous :: shutoffweight => null() real(DP), dimension(:), pointer, contiguous :: shutoffdq => null() real(DP), dimension(:), pointer, contiguous :: shutoffqold => null() - character (len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: cmawname => null() + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: cmawname => null() ! ! -- time-series aware data real(DP), dimension(:), pointer, contiguous :: rate => null() real(DP), dimension(:), pointer, contiguous :: well_head => null() - real(DP), dimension(:,:), pointer, contiguous :: mauxvar => null() + real(DP), dimension(:, :), pointer, contiguous :: mauxvar => null() ! ! -- ia vector for connections integer(I4B), dimension(:), pointer, contiguous :: iaconn => null() @@ -144,21 +145,24 @@ module MawModule real(DP), dimension(:), pointer, contiguous :: gwfsat => NULL() ! ! -- arrays for handling the rows added to the solution matrix - integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !map position in global rhs and x array of pack entry - integer(I4B), dimension(:), pointer, contiguous :: idxdglo => null() !map position in global array of package diagonal row entries - integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !map position in global array of package off diagonal row entries - integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !map position in global array of package diagonal entries to model rows - integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !map position in global array of package off diagonal entries to model rows - integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !package ibound - real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !package x vector - real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !package xold vector + integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !map position in global rhs and x array of pack entry + integer(I4B), dimension(:), pointer, contiguous :: idxdglo => null() !map position in global array of package diagonal row entries + integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !map position in global array of package off diagonal row entries + integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !map position in global array of package diagonal entries to model rows + integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !map position in global array of package off diagonal entries to model rows + integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !package ibound + real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !package x vector + real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !package xold vector ! ! -- density variables integer(I4B), pointer :: idense - real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() + real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() + ! + ! -- viscosity variables + real(DP), dimension(:, :), pointer, contiguous :: viscratios => null() !< viscosity ratios (1: maw vsc ratio; 2: gwf vsc ratio) ! ! -- type bound procedures - contains + contains procedure :: maw_allocate_scalars procedure :: maw_allocate_well_conn_arrays procedure :: maw_allocate_arrays @@ -209,6 +213,11 @@ module MawModule ! -- density procedure :: maw_activate_density procedure, private :: maw_calculate_density_exchange + ! -- MAW reduced flow outputs + procedure, private :: maw_redflow_csv_init + procedure, private :: maw_redflow_csv_write + ! -- viscosity + procedure :: maw_activate_viscosity end type MawType contains @@ -223,17 +232,17 @@ subroutine maw_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(MawType), pointer :: mawobj ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(mawobj) + allocate (mawobj) packobj => mawobj ! ! -- create name and memory path @@ -251,9 +260,9 @@ subroutine maw_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%id = id packobj%ibcnum = ibcnum packobj%ncolbnd = 4 - packobj%iscloc = 0 ! not supported + packobj%iscloc = 0 ! not supported packobj%isadvpak = 1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return @@ -269,7 +278,7 @@ subroutine maw_allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(MawType), intent(inout) :: this + class(MawType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars @@ -288,6 +297,7 @@ subroutine maw_allocate_scalars(this) call mem_allocate(this%check_attr, 'CHECK_ATTR', this%memoryPath) call mem_allocate(this%ishutoffcnt, 'ISHUTOFFCNT', this%memoryPath) call mem_allocate(this%ieffradopt, 'IEFFRADOPT', this%memoryPath) + call mem_allocate(this%ioutredflowcsv, 'IOUTREDFLOWCSV', this%memoryPath) !for writing reduced MAW flows to csv file call mem_allocate(this%satomega, 'SATOMEGA', this%memoryPath) call mem_allocate(this%bditems, 'BDITEMS', this%memoryPath) call mem_allocate(this%theta, 'THETA', this%memoryPath) @@ -306,12 +316,14 @@ subroutine maw_allocate_scalars(this) this%imawiss = 0 this%imawissopt = 0 this%ieffradopt = 0 + this%ioutredflowcsv = 0 this%satomega = DZERO this%bditems = 8 this%theta = DP7 this%kappa = DEM4 this%cbcauxitems = 1 this%idense = 0 + this%ivsc = 0 ! ! -- return return @@ -327,7 +339,7 @@ subroutine maw_allocate_well_conn_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(MawType), intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local integer(I4B) :: j integer(I4B) :: n @@ -335,7 +347,7 @@ subroutine maw_allocate_well_conn_arrays(this) ! ------------------------------------------------------------------------------ ! ! -- allocate character array for budget text - call mem_allocate(this%cmawbudget, LENBUDTXT, this%bditems, 'CMAWBUDGET', & + call mem_allocate(this%cmawbudget, LENBUDTXT, this%bditems, 'CMAWBUDGET', & this%memoryPath) ! !-- fill cmawbudget @@ -349,15 +361,16 @@ subroutine maw_allocate_well_conn_arrays(this) this%cmawbudget(8) = ' FW-RATE-TO-MVR' ! ! -- allocate character arrays - call mem_allocate(this%cmawname, LENBOUNDNAME, this%nmawwells, 'CMAWNAME', & + call mem_allocate(this%cmawname, LENBOUNDNAME, this%nmawwells, 'CMAWNAME', & this%memoryPath) call mem_allocate(this%status, 8, this%nmawwells, 'STATUS', this%memoryPath) ! ! -- allocate well data pointers in memory manager - call mem_allocate(this%ngwfnodes, this%nmawwells, 'NGWFNODES', this%memoryPath) + call mem_allocate(this%ngwfnodes, this%nmawwells, 'NGWFNODES', & + this%memoryPath) call mem_allocate(this%ieqn, this%nmawwells, 'IEQN', this%memoryPath) call mem_allocate(this%ishutoff, this%nmawwells, 'ISHUTOFF', this%memoryPath) - call mem_allocate(this%ifwdischarge, this%nmawwells, 'IFWDISCHARGE', & + call mem_allocate(this%ifwdischarge, this%nmawwells, 'IFWDISCHARGE', & this%memoryPath) call mem_allocate(this%strt, this%nmawwells, 'STRT', this%memoryPath) call mem_allocate(this%radius, this%nmawwells, 'RADIUS', this%memoryPath) @@ -370,28 +383,33 @@ subroutine maw_allocate_well_conn_arrays(this) call mem_allocate(this%fwelev, this%nmawwells, 'FWELEV', this%memoryPath) call mem_allocate(this%fwcond, this%nmawwells, 'FWCONDS', this%memoryPath) call mem_allocate(this%fwrlen, this%nmawwells, 'FWRLEN', this%memoryPath) - call mem_allocate(this%fwcondsim, this%nmawwells, 'FWCONDSIM', this%memoryPath) + call mem_allocate(this%fwcondsim, this%nmawwells, 'FWCONDSIM', & + this%memoryPath) call mem_allocate(this%xsto, this%nmawwells, 'XSTO', this%memoryPath) call mem_allocate(this%xoldsto, this%nmawwells, 'XOLDSTO', this%memoryPath) - call mem_allocate(this%shutoffmin, this%nmawwells, 'SHUTOFFMIN', this%memoryPath) - call mem_allocate(this%shutoffmax, this%nmawwells, 'SHUTOFFMAX', this%memoryPath) - call mem_allocate(this%shutofflevel, this%nmawwells, 'SHUTOFFLEVEL', & + call mem_allocate(this%shutoffmin, this%nmawwells, 'SHUTOFFMIN', & + this%memoryPath) + call mem_allocate(this%shutoffmax, this%nmawwells, 'SHUTOFFMAX', & + this%memoryPath) + call mem_allocate(this%shutofflevel, this%nmawwells, 'SHUTOFFLEVEL', & this%memoryPath) - call mem_allocate(this%shutoffweight, this%nmawwells, 'SHUTOFFWEIGHT', & + call mem_allocate(this%shutoffweight, this%nmawwells, 'SHUTOFFWEIGHT', & this%memoryPath) - call mem_allocate(this%shutoffdq, this%nmawwells, 'SHUTOFFDQ', this%memoryPath) - call mem_allocate(this%shutoffqold, this%nmawwells, 'SHUTOFFQOLD', & + call mem_allocate(this%shutoffdq, this%nmawwells, 'SHUTOFFDQ', & + this%memoryPath) + call mem_allocate(this%shutoffqold, this%nmawwells, 'SHUTOFFQOLD', & this%memoryPath) ! ! -- timeseries aware variables call mem_allocate(this%rate, this%nmawwells, 'RATE', this%memoryPath) - call mem_allocate(this%well_head, this%nmawwells, 'WELL_HEAD', this%memoryPath) + call mem_allocate(this%well_head, this%nmawwells, 'WELL_HEAD', & + this%memoryPath) if (this%naux > 0) then jj = this%naux else jj = 1 end if - call mem_allocate(this%mauxvar, jj, this%nmawwells, 'MAUXVAR', & + call mem_allocate(this%mauxvar, jj, this%nmawwells, 'MAUXVAR', & this%memoryPath) ! ! -- allocate and initialize dbuff @@ -402,7 +420,7 @@ subroutine maw_allocate_well_conn_arrays(this) end if ! ! -- allocate iaconn - call mem_allocate(this%iaconn, this%nmawwells+1, 'IACONN', this%memoryPath) + call mem_allocate(this%iaconn, this%nmawwells + 1, 'IACONN', this%memoryPath) ! ! -- allocate imap call mem_allocate(this%imap, this%MAXBOUND, 'IMAP', this%memoryPath) @@ -465,7 +483,7 @@ subroutine maw_allocate_well_conn_arrays(this) end do ! ! -- allocate character array for budget text - call mem_allocate(this%cauxcbc, LENAUXNAME, this%cbcauxitems, 'CAUXCBC', & + call mem_allocate(this%cauxcbc, LENAUXNAME, this%cbcauxitems, 'CAUXCBC', & this%memoryPath) ! ! -- allocate and initialize qauxcbc @@ -509,6 +527,9 @@ subroutine maw_allocate_well_conn_arrays(this) ! -- allocate denseterms to size 0 call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath) ! + ! -- allocate viscratios to size 0 + call mem_allocate(this%viscratios, 2, 0, 'VISCRATIOS', this%memoryPath) + ! ! -- return return end subroutine maw_allocate_well_conn_arrays @@ -523,7 +544,7 @@ subroutine maw_allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(MawType), intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local !integer(I4B) :: i ! ------------------------------------------------------------------------------ @@ -545,7 +566,7 @@ subroutine maw_read_wells(this) use ConstantsModule, only: LINELENGTH use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: text character(len=LINELENGTH) :: keyword @@ -569,31 +590,31 @@ subroutine maw_read_wells(this) ! -- local allocatable arrays character(len=LINELENGTH), dimension(:), allocatable :: strttext character(len=LENBOUNDNAME), dimension(:), allocatable :: nametxt - character(len=50), dimension(:,:), allocatable :: caux + character(len=50), dimension(:, :), allocatable :: caux integer(I4B), dimension(:), allocatable :: nboundchk integer(I4B), dimension(:), allocatable :: wellieqn integer(I4B), dimension(:), allocatable :: ngwfnodes real(DP), dimension(:), allocatable :: radius real(DP), dimension(:), allocatable :: bottom ! -- format - character(len=*), parameter :: fmthdbot = & - "('well head (', G0, ') must be greater than or equal to the & - &BOTTOM_ELEVATION (', G0, ').')" + character(len=*), parameter :: fmthdbot = & + "('well head (', G0, ') must be greater than or equal to the & + &BOTTOM_ELEVATION (', G0, ').')" ! ------------------------------------------------------------------------------ ! ! -- code ! ! -- allocate and initialize temporary variables - allocate(strttext(this%nmawwells)) - allocate(nametxt(this%nmawwells)) + allocate (strttext(this%nmawwells)) + allocate (nametxt(this%nmawwells)) if (this%naux > 0) then - allocate(caux(this%naux, this%nmawwells)) + allocate (caux(this%naux, this%nmawwells)) end if - allocate(nboundchk(this%nmawwells)) - allocate(wellieqn(this%nmawwells)) - allocate(ngwfnodes(this%nmawwells)) - allocate(radius(this%nmawwells)) - allocate(bottom(this%nmawwells)) + allocate (nboundchk(this%nmawwells)) + allocate (wellieqn(this%nmawwells)) + allocate (ngwfnodes(this%nmawwells)) + allocate (radius(this%nmawwells)) + allocate (bottom(this%nmawwells)) ! ! -- initialize temporary variables do n = 1, this%nmawwells @@ -608,13 +629,13 @@ subroutine maw_read_wells(this) ! ! -- read maw well data ! -- get wells block - call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & supportopenclose=.true.) ! ! -- parse locations block if detected if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' PACKAGEDATA' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' PACKAGEDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -622,8 +643,8 @@ subroutine maw_read_wells(this) n = ival if (n < 1 .or. n > this%nmawwells) then - write(errmsg,'(a,1x,i0,a)') & - 'IMAW must be greater than 0 and less than or equal to', & + write (errmsg, '(a,1x,i0,a)') & + 'IMAW must be greater than 0 and less than or equal to', & this%nmawwells, '.' call store_error(errmsg) cycle @@ -635,7 +656,7 @@ subroutine maw_read_wells(this) ! -- radius rval = this%parser%GetDouble() if (rval <= DZERO) then - write(errmsg,'(a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a)') & 'Radius for well', n, 'must be greater than zero.' call store_error(errmsg) end if @@ -649,20 +670,20 @@ subroutine maw_read_wells(this) ! ! -- ieqn call this%parser%GetStringCaps(keyword) - if (keyword=='SPECIFIED') then + if (keyword == 'SPECIFIED') then ieqn = 0 - else if (keyword=='THEIM' .or. keyword=='THIEM') then + else if (keyword == 'THEIM' .or. keyword == 'THIEM') then ieqn = 1 - else if (keyword=='SKIN') then + else if (keyword == 'SKIN') then ieqn = 2 - else if (keyword=='CUMULATIVE') then + else if (keyword == 'CUMULATIVE') then ieqn = 3 - else if (keyword=='MEAN') then + else if (keyword == 'MEAN') then ieqn = 4 else - write(errmsg,'(a,1x,i0,1x,a)') & - 'CONDEQN for well', n, & - "must be 'CONDUCTANCE', 'THIEM', 'MEAN', or 'SKIN'." + write (errmsg, '(a,1x,i0,1x,a)') & + 'CONDEQN for well', n, & + "must be 'CUMULATIVE', 'THIEM', 'MEAN', or 'SKIN'." end if wellieqn(n) = ieqn ! @@ -670,11 +691,11 @@ subroutine maw_read_wells(this) ival = this%parser%GetInteger() if (ival < 1) then ival = 0 - write(errmsg,'(a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a)') & 'NGWFNODES for well', n, 'must be greater than zero.' call store_error(errmsg) end if - + if (ival > 0) then ngwfnodes(n) = ival end if @@ -688,8 +709,8 @@ subroutine maw_read_wells(this) end do ! ! -- set default bndName - write (cno,'(i9.9)') n - bndName = 'MAWWELL' // cno + write (cno, '(i9.9)') n + bndName = 'MAWWELL'//cno ! ! -- read well name if (this%inamedbound /= 0) then @@ -701,16 +722,16 @@ subroutine maw_read_wells(this) nametxt(n) = bndName end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' PACKAGEDATA' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' PACKAGEDATA' ! ! -- check for duplicate or missing wells - do n = 1, this%nmawwells + do n = 1, this%nmawwells if (nboundchk(n) == 0) then - write(errmsg,'(a,1x,i0,a)') 'No data specified for maw well', n, '.' + write (errmsg, '(a,1x,i0,a)') 'No data specified for maw well', n, '.' call store_error(errmsg) else if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'Data for maw well', n, 'specified', nboundchk(n), 'times.' call store_error(errmsg) end if @@ -726,13 +747,13 @@ subroutine maw_read_wells(this) ! ! -- set MAXBOUND this%maxbound = itmp - write(this%iout,'(//4x,a,i7)') 'MAXBOUND = ', this%maxbound + write (this%iout, '(//4x,a,i7)') 'MAXBOUND = ', this%maxbound ! ! -- allocate well and connection data call this%maw_allocate_well_conn_arrays() ! ! -- fill well data with data stored in temporary local arrays - do n = 1, this%nmawwells + do n = 1, this%nmawwells rval = radius(n) this%radius(n) = rval this%area(n) = DPI * rval**DTWO @@ -744,18 +765,18 @@ subroutine maw_read_wells(this) ! fill timeseries aware data ! ! -- well_head and strt - jj = 1 ! For WELL_HEAD + jj = 1 ! For WELL_HEAD bndElem => this%well_head(n) - call read_value_or_time_series_adv(strttext(n), n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'WELL_HEAD') + call read_value_or_time_series_adv(strttext(n), n, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'WELL_HEAD') ! ! -- set starting head value this%strt(n) = this%well_head(n) ! ! -- check for error condition if (this%strt(n) < this%bot(n)) then - write(cstr, fmthdbot) this%strt(n), this%bot(n) + write (cstr, fmthdbot) this%strt(n), this%bot(n) call this%maw_set_attribute_error(n, 'STRT', trim(cstr)) end if ! @@ -764,11 +785,11 @@ subroutine maw_read_wells(this) text = caux(jj, n) ii = n bndElem => this%mauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & + 'AUX', this%tsManager, this%iprpak, & this%auxname(jj)) end do - end do + end do ! ! -- set iaconn and imap for each connection idx = 0 @@ -778,20 +799,20 @@ subroutine maw_read_wells(this) idx = idx + 1 this%imap(idx) = n end do - this%iaconn(n+1) = idx + 1 + this%iaconn(n + 1) = idx + 1 end do ! ! -- deallocate local storage - deallocate(strttext) - deallocate(nametxt) + deallocate (strttext) + deallocate (nametxt) if (this%naux > 0) then - deallocate(caux) + deallocate (caux) end if - deallocate(nboundchk) - deallocate(wellieqn) - deallocate(ngwfnodes) - deallocate(radius) - deallocate(bottom) + deallocate (nboundchk) + deallocate (wellieqn) + deallocate (ngwfnodes) + deallocate (radius) + deallocate (bottom) ! ! -- return return @@ -806,7 +827,7 @@ subroutine maw_read_well_connections(this) ! ------------------------------------------------------------------------------ use ConstantsModule, only: LINELENGTH ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: cellid character(len=30) :: nodestr @@ -830,7 +851,7 @@ subroutine maw_read_well_connections(this) real(DP) :: botw integer(I4B), dimension(:), pointer, contiguous :: nboundchk integer(I4B), dimension(:), pointer, contiguous :: iachk - + ! ------------------------------------------------------------------------------ ! -- format ! @@ -842,12 +863,12 @@ subroutine maw_read_well_connections(this) ireset_wellbot = 0 ! ! -- allocate and initialize local storage - allocate(iachk(this%nmawwells+1)) + allocate (iachk(this%nmawwells + 1)) iachk(1) = 1 do n = 1, this%nmawwells - iachk(n+1) = iachk(n) + this%ngwfnodes(n) + iachk(n + 1) = iachk(n) + this%ngwfnodes(n) end do - allocate(nboundchk(this%maxbound)) + allocate (nboundchk(this%maxbound)) do n = 1, this%maxbound nboundchk(n) = 0 end do @@ -858,7 +879,7 @@ subroutine maw_read_well_connections(this) ! ! -- parse well_connections block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' CONNECTIONDATA' do call this%parser%GetNextLine(endOfBlock) @@ -870,8 +891,8 @@ subroutine maw_read_well_connections(this) ! ! -- check for error condition if (n < 1 .or. n > this%nmawwells) then - write(errmsg,'(a,1x,i0,a)') & - 'IMAW must be greater than 0 and less than or equal to ', & + write (errmsg, '(a,1x,i0,a)') & + 'IMAW must be greater than 0 and less than or equal to ', & this%nmawwells, '.' call store_error(errmsg) cycle @@ -880,23 +901,23 @@ subroutine maw_read_well_connections(this) ! -- read connection number ival = this%parser%GetInteger() if (ival < 1 .or. ival > this%ngwfnodes(n)) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & - 'JCONN for well ', n, & - 'must be greater than 1 and less than or equal to ', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & + 'JCONN for well ', n, & + 'must be greater than 1 and less than or equal to ', & this%ngwfnodes(n), '.' call store_error(errmsg) cycle end if - + ipos = iachk(n) + ival - 1 nboundchk(ipos) = nboundchk(ipos) + 1 - + j = ival jpos = this%get_jpos(n, ival) ! ! -- read gwfnodes from the line call this%parser%GetCellid(this%dis%ndim, cellid) - nn = this%dis%noder_from_cellid(cellid, this%inunit, this%iout) + nn = this%dis%noder_from_cellid(cellid, this%inunit, this%iout) topnn = this%dis%top(nn) botnn = this%dis%bot(nn) botw = this%bot(n) @@ -936,9 +957,9 @@ subroutine maw_read_well_connections(this) botw = rval this%bot(n) = rval else - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a,g0,a,g0,a)') & - 'Screen bottom for maw well', n, 'connection', j, '(', & - this%botscrn(jpos), ') is less than the well bottom (', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,g0,a,g0,a)') & + 'Screen bottom for maw well', n, 'connection', j, '(', & + this%botscrn(jpos), ') is less than the well bottom (', & this%bot(n), ').' call store_error(errmsg) end if @@ -948,28 +969,29 @@ subroutine maw_read_well_connections(this) rval = this%parser%GetDouble() if (this%ieqn(n) == 0) then this%satcond(jpos) = rval - else if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & + else if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & this%ieqn(n) == 4) then this%hk(jpos) = rval end if ! ! -- skin radius rval = this%parser%GetDouble() - if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & + if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & this%ieqn(n) == 4) then this%sradius(jpos) = rval if (this%sradius(jpos) <= this%radius(n)) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a,g0,a,g0,a)') & - 'Screen radius for maw well', n, 'connection', j, '(', & - this%sradius(jpos),') is less than or equal to the well radius (', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,g0,a,g0,a)') & + 'Screen radius for maw well', n, 'connection', j, '(', & + this%sradius(jpos), & + ') is less than or equal to the well radius (', & this%radius(n), ').' call store_error(errmsg) end if end if end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' CONNECTIONDATA' - + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' CONNECTIONDATA' + ipos = 0 do n = 1, this%nmawwells do j = 1, this%ngwfnodes(n) @@ -977,19 +999,19 @@ subroutine maw_read_well_connections(this) ! ! -- check for missing or duplicate maw well connections if (nboundchk(ipos) == 0) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & 'No data specified for maw well', n, 'connection', j, '.' call store_error(errmsg) else if (nboundchk(ipos) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'Data for maw well', n, 'connection', j, & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & + 'Data for maw well', n, 'connection', j, & 'specified', nboundchk(n), 'times.' call store_error(errmsg) end if end do end do ! - ! -- make sure that more than one connection per cell is only specified + ! -- make sure that more than one connection per cell is only specified ! wells using the mean conducance type do n = 1, this%nmawwells if (this%ieqn(n) /= 4) then @@ -1004,9 +1026,9 @@ subroutine maw_read_well_connections(this) nn2 = this%get_gwfnode(n, jj) if (nn2 == nn) then call this%dis%noder_to_string(nn, nodestr) - write(errmsg,'(a,1x,i0,1x,a,1x,i0,3(1x,a))') & - 'Only one connection can be specified for maw well', & - n, 'connection', j, 'to gwf cell', trim(adjustl(nodestr)), & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,3(1x,a))') & + 'Only one connection can be specified for maw well', & + n, 'connection', j, 'to gwf cell', trim(adjustl(nodestr)), & 'unless the mean condeqn is specified.' call store_error(errmsg) end if @@ -1019,27 +1041,27 @@ subroutine maw_read_well_connections(this) end if ! ! -- deallocate local variable - deallocate(iachk) - deallocate(nboundchk) + deallocate (iachk) + deallocate (nboundchk) ! ! -- add warning messages if (ireset_scrntop > 0) then - write(warnmsg,'(a,1x,a,1x,a,1x,i0,1x,a)') & - 'The screen tops in multi-aquifer well package', trim(this%packName), & + write (warnmsg, '(a,1x,a,1x,a,1x,i0,1x,a)') & + 'The screen tops in multi-aquifer well package', trim(this%packName), & 'were reset to the top of the connected cell', ireset_scrntop, 'times.' call store_warning(warnmsg) end if if (ireset_scrnbot > 0) then - write(warnmsg,'(a,1x,a,1x,a,1x,i0,1x,a)') & + write (warnmsg, '(a,1x,a,1x,a,1x,i0,1x,a)') & 'The screen bottoms in multi-aquifer well package', trim(this%packName), & - 'were reset to the bottom of the connected cell', ireset_scrnbot, & + 'were reset to the bottom of the connected cell', ireset_scrnbot, & 'times.' call store_warning(warnmsg) end if if (ireset_wellbot > 0) then - write(warnmsg,'(a,1x,a,1x,a,1x,i0,1x,a)') & - 'The well bottoms in multi-aquifer well package', trim(this%packName), & - 'were reset to the bottom of the connected cell', ireset_wellbot, & + write (warnmsg, '(a,1x,a,1x,a,1x,i0,1x,a)') & + 'The well bottoms in multi-aquifer well package', trim(this%packName), & + 'were reset to the bottom of the connected cell', ireset_wellbot, & 'times.' call store_warning(warnmsg) end if @@ -1053,7 +1075,6 @@ subroutine maw_read_well_connections(this) return end subroutine maw_read_well_connections - subroutine maw_read_dimensions(this) ! ****************************************************************************** ! pak1read_dimensions -- Read the dimensions for this package @@ -1063,7 +1084,7 @@ subroutine maw_read_dimensions(this) ! ------------------------------------------------------------------------------ use ConstantsModule, only: LINELENGTH ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LENBOUNDNAME) :: keyword integer(I4B) :: ierr @@ -1072,7 +1093,7 @@ subroutine maw_read_dimensions(this) ! ------------------------------------------------------------------------------ ! ! -- initialize dimensions to -1 - this%nmawwells= -1 + this%nmawwells = -1 this%maxbound = -1 ! ! -- get dimensions block @@ -1081,31 +1102,31 @@ subroutine maw_read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('NMAWWELLS') - this%nmawwells = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NMAWWELLS = ', this%nmawwells - case default - write(errmsg,'(3a)') & - 'Unknown ' // trim(this%text) // ' dimension: ', trim(keyword), '.' - call store_error(errmsg) + case ('NMAWWELLS') + this%nmawwells = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NMAWWELLS = ', this%nmawwells + case default + write (errmsg, '(3a)') & + 'Unknown '//trim(this%text)//' dimension: ', trim(keyword), '.' + call store_error(errmsg) end select end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' else call store_error('Required dimensions block not found.', terminate=.TRUE.) end if ! ! -- verify dimensions were set correctly if (this%nmawwells < 0) then - write(errmsg, '(a)') & + write (errmsg, '(a)') & 'NMAWWELLS was not specified or was specified incorrectly.' call store_error(errmsg) end if @@ -1135,7 +1156,6 @@ subroutine maw_read_dimensions(this) return end subroutine maw_read_dimensions - subroutine maw_read_initial_attr(this) ! ****************************************************************************** ! maw_read_initial_attr -- Read the initial parameters for this package @@ -1147,7 +1167,7 @@ subroutine maw_read_initial_attr(this) use ConstantsModule, only: LINELENGTH use MemoryManagerModule, only: mem_setptr ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -1160,29 +1180,29 @@ subroutine maw_read_initial_attr(this) integer(I4B) :: idx real(DP) :: k11 real(DP) :: k22 - character (len=10), dimension(0:4) :: ccond - character (len=30) :: nodestr + character(len=10), dimension(0:4) :: ccond + character(len=30) :: nodestr ! -- data - data ccond(0) /'SPECIFIED '/ - data ccond(1) /'THIEM '/ - data ccond(2) /'SKIN '/ - data ccond(3) /'CUMULATIVE'/ - data ccond(4) /'MEAN '/ + data ccond(0)/'SPECIFIED '/ + data ccond(1)/'THIEM '/ + data ccond(2)/'SKIN '/ + data ccond(3)/'CUMULATIVE'/ + data ccond(4)/'MEAN '/ ! -- format character(len=*), parameter :: fmtwelln = & - "(1X,//43X,'MULTI-AQUIFER WELL DATA'" // & - "/1X,109('-')," // & - "/1X,7(A10,1X),A16)" + "(1X,//43X,'MULTI-AQUIFER WELL DATA'& + &/1X,109('-'),& + &/1X,7(A10,1X),A16)" character(len=*), parameter :: fmtwelld = & - "(1X,I10,1X,4(G10.3,1X),I10,1X,A10,1X,A16)" + &"(1X,I10,1X,4(G10.3,1X),I10,1X,A10,1X,A16)" character(len=*), parameter :: fmtline = & - "(1X,119('-'),//)" + &"(1X,119('-'),//)" character(len=*), parameter :: fmtwellcn = & - "(1X,//37X,'MULTI-AQUIFER WELL CONNECTION DATA'" // & - "/1X,119('-')," // & - "/1X,2(A10,1X),A20,7(A10,1X))" + "(1X,//37X,'MULTI-AQUIFER WELL CONNECTION DATA'& + &/1X,119('-'),& + &/1X,2(A10,1X),A20,7(A10,1X))" character(len=*), parameter :: fmtwellcd = & - "(1X,2(I10,1X),A20,1X,2(G10.3,1X),2(A10,1X),3(G10.3,1X))" + &"(1X,2(I10,1X),A20,1X,2(G10.3,1X),2(A10,1X),3(G10.3,1X))" ! ------------------------------------------------------------------------------ ! ! -- initialize xnewpak @@ -1194,22 +1214,23 @@ subroutine maw_read_initial_attr(this) ! -- initialize status (iboundpak) of maw wells to active do n = 1, this%nmawwells select case (this%status(n)) - case('CONSTANT') - this%iboundpak(n) = -1 - case('INACTIVE') - this%iboundpak(n) = 0 - case('ACTIVE') - this%iboundpak(n) = 1 + case ('CONSTANT') + this%iboundpak(n) = -1 + case ('INACTIVE') + this%iboundpak(n) = 0 + case ('ACTIVE') + this%iboundpak(n) = 1 end select end do ! - ! -- set boundname for each connection + ! -- set imap and boundname for each connection if (this%inamedbound /= 0) then idx = 0 do n = 1, this%nmawwells do j = 1, this%ngwfnodes(n) idx = idx + 1 this%boundname(idx) = this%cmawname(n) + this%imap(idx) = n end do end do else @@ -1218,17 +1239,8 @@ subroutine maw_read_initial_attr(this) end do end if ! - ! -- set imap and boundname for each connection - if (this%inamedbound /= 0) then - idx = 0 - do n = 1, this%nmawwells - do j = 1, this%ngwfnodes(n) - idx = idx + 1 - this%boundname(idx) = this%cmawname(n) - this%imap(idx) = n - end do - end do - end if + ! -- copy boundname into boundname_cst + call this%copy_boundname() ! ! -- set pointer to gwf iss and gwf hk call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model)) @@ -1260,8 +1272,8 @@ subroutine maw_read_initial_attr(this) if (this%inamedbound /= 0) then ntabcols = ntabcols + 1 end if - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC WELL DATA' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC WELL DATA' call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(this%nmawwells, ntabcols, this%iout) text = 'NUMBER' @@ -1281,7 +1293,7 @@ subroutine maw_read_initial_attr(this) if (this%inamedbound /= 0) then text = 'NAME' call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) - end if + end if do n = 1, this%nmawwells call this%inputtab%add_term(n) call this%inputtab%add_term(this%radius(n)) @@ -1290,7 +1302,7 @@ subroutine maw_read_initial_attr(this) call this%inputtab%add_term(this%strt(n)) call this%inputtab%add_term(this%ngwfnodes(n)) call this%inputtab%add_term(ccond(this%ieqn(n))) - if (this%inamedbound /= 0) then + if (this%inamedbound /= 0) then call this%inputtab%add_term(this%cmawname(n)) end if end do @@ -1299,8 +1311,8 @@ subroutine maw_read_initial_attr(this) ! -- write well connection data if (this%iprpak /= 0) then ntabcols = 10 - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC WELL CONNECTION DATA' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC WELL CONNECTION DATA' call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(this%maxbound, ntabcols, this%iout) text = 'NUMBER' @@ -1335,17 +1347,17 @@ subroutine maw_read_initial_attr(this) call this%inputtab%add_term(nodestr) call this%inputtab%add_term(this%topscrn(jpos)) call this%inputtab%add_term(this%botscrn(jpos)) - if (this%ieqn(n) == 2 .or. & - this%ieqn(n) == 3 .or. & + if (this%ieqn(n) == 2 .or. & + this%ieqn(n) == 3 .or. & this%ieqn(n) == 4) then call this%inputtab%add_term(this%sradius(jpos)) call this%inputtab%add_term(this%hk(jpos)) else - call this%inputtab%add_term(' ') - call this%inputtab%add_term(' ') - end if - if (this%ieqn(n) == 1 .or. & - this%ieqn(n) == 2 .or. & + call this%inputtab%add_term(' ') + call this%inputtab%add_term(' ') + end if + if (this%ieqn(n) == 1 .or. & + this%ieqn(n) == 2 .or. & this%ieqn(n) == 3) then k11 = this%gwfk11(nn) if (this%gwfik22 == 0) then @@ -1379,7 +1391,6 @@ subroutine maw_read_initial_attr(this) return end subroutine maw_read_initial_attr - subroutine maw_set_stressperiod(this, imaw, iheadlimit_warning) ! ****************************************************************************** ! maw_set_stressperiod -- Set a stress period attribute for mawweslls(imaw) @@ -1391,7 +1402,7 @@ subroutine maw_set_stressperiod(this, imaw, iheadlimit_warning) ! -- modules use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: imaw integer(I4B), intent(inout) :: iheadlimit_warning ! -- local @@ -1406,121 +1417,121 @@ subroutine maw_set_stressperiod(this, imaw, iheadlimit_warning) real(DP), pointer :: bndElem => null() integer(I4B) :: istat ! -- formats - character(len=*),parameter :: fmthdbot = & - "('well head (',G0,') must be >= BOTTOM_ELEVATION (',G0, ').')" + character(len=*), parameter :: fmthdbot = & + &"('well head (',G0,') must be >= BOTTOM_ELEVATION (',G0, ').')" ! ------------------------------------------------------------------------------ ! ! -- read remainder of variables on the line call this%parser%GetStringCaps(keyword) select case (keyword) - case ('STATUS') - call this%parser%GetStringCaps(text) - this%status(imaw) = text(1:8) - select case(text) - case('CONSTANT') - this%iboundpak(imaw) = -1 - case('INACTIVE') - this%iboundpak(imaw) = 0 - case('ACTIVE') - this%iboundpak(imaw) = 1 - case default - write(errmsg,'(2a)') & - 'Unknown ' // trim(this%text) // " maw status keyword: '", & - trim(text) // "'." - call store_error(errmsg) - end select - case ('RATE') - call this%parser%GetString(text) - jj = 1 ! For RATE - bndElem => this%rate(imaw) - call read_value_or_time_series_adv(text, imaw, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RATE') - case ('WELL_HEAD') - call this%parser%GetString(text) - jj = 1 ! For WELL_HEAD - bndElem => this%well_head(imaw) - call read_value_or_time_series_adv(text, imaw, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'WELL_HEAD') - ! - ! -- set xnewpak to well_head - this%xnewpak(imaw) = this%well_head(imaw) - ! - ! -- check for error condition - if (this%well_head(imaw) < this%bot(imaw)) then - write(cstr, fmthdbot) & - this%well_head(imaw), this%bot(imaw) - call this%maw_set_attribute_error(imaw, 'WELL HEAD', trim(cstr)) - end if - case ('FLOWING_WELL') - this%fwelev(imaw) = this%parser%GetDouble() - this%fwcond(imaw) = this%parser%GetDouble() - this%fwrlen(imaw) = this%parser%GetDouble() - ! - ! -- test for condition where flowing well data is specified but - ! flowing_wells is not specified in the options block - if (this%iflowingwells == 0) then - this%iflowingwells = -1 - text = 'Flowing well data is specified in the ' // trim(this%packName) // & - ' package but FLOWING_WELL was not specified in the ' // & - 'OPTIONS block.' - call store_warning(text) - end if - case ('RATE_SCALING') - rval = this%parser%GetDouble() - this%pumpelev(imaw) = rval - rval = this%parser%GetDouble() - this%reduction_length(imaw) = rval - if (rval < DZERO) then - call this%maw_set_attribute_error(imaw, trim(keyword), & - 'must be greater than or equal to 0.') - end if - case ('HEAD_LIMIT') - call this%parser%GetString(text) - if (trim(text) == 'OFF') then - this%shutofflevel(imaw) = DEP20 - else - read (text, *, iostat=istat, iomsg=errmsgr) & - this%shutofflevel(imaw) - if (istat /= 0) then - errmsg = 'Could not read HEAD_LIMIT value. ' // trim(errmsgr) - call store_error(errmsg) - end if - if (this%shutofflevel(imaw) <= this%bot(imaw)) then - iheadlimit_warning = iheadlimit_warning + 1 - end if - end if - case ('SHUT_OFF') - rval = this%parser%GetDouble() - this%shutoffmin(imaw) = rval - rval = this%parser%GetDouble() - this%shutoffmax(imaw) = rval - case ('AUXILIARY') - call this%parser%GetStringCaps(caux) - do jj = 1, this%naux - if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle - call this%parser%GetString(text) - ii = imaw - bndElem => this%mauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & - this%auxname(jj)) - exit - end do + case ('STATUS') + call this%parser%GetStringCaps(text) + this%status(imaw) = text(1:8) + select case (text) + case ('CONSTANT') + this%iboundpak(imaw) = -1 + case ('INACTIVE') + this%iboundpak(imaw) = 0 + case ('ACTIVE') + this%iboundpak(imaw) = 1 case default - write(errmsg,'(2a)') & - 'Unknown ' // trim(this%text) // " maw data keyword: '", & - trim(keyword) // "'." + write (errmsg, '(2a)') & + 'Unknown '//trim(this%text)//" maw status keyword: '", & + trim(text)//"'." call store_error(errmsg) end select + case ('RATE') + call this%parser%GetString(text) + jj = 1 ! For RATE + bndElem => this%rate(imaw) + call read_value_or_time_series_adv(text, imaw, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RATE') + case ('WELL_HEAD') + call this%parser%GetString(text) + jj = 1 ! For WELL_HEAD + bndElem => this%well_head(imaw) + call read_value_or_time_series_adv(text, imaw, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'WELL_HEAD') + ! + ! -- set xnewpak to well_head + this%xnewpak(imaw) = this%well_head(imaw) + ! + ! -- check for error condition + if (this%well_head(imaw) < this%bot(imaw)) then + write (cstr, fmthdbot) & + this%well_head(imaw), this%bot(imaw) + call this%maw_set_attribute_error(imaw, 'WELL HEAD', trim(cstr)) + end if + case ('FLOWING_WELL') + this%fwelev(imaw) = this%parser%GetDouble() + this%fwcond(imaw) = this%parser%GetDouble() + this%fwrlen(imaw) = this%parser%GetDouble() + ! + ! -- test for condition where flowing well data is specified but + ! flowing_wells is not specified in the options block + if (this%iflowingwells == 0) then + this%iflowingwells = -1 + text = 'Flowing well data is specified in the '//trim(this%packName)// & + ' package but FLOWING_WELL was not specified in the '// & + 'OPTIONS block.' + call store_warning(text) + end if + case ('RATE_SCALING') + rval = this%parser%GetDouble() + this%pumpelev(imaw) = rval + rval = this%parser%GetDouble() + this%reduction_length(imaw) = rval + if (rval < DZERO) then + call this%maw_set_attribute_error(imaw, trim(keyword), & + 'must be greater than or equal to 0.') + end if + case ('HEAD_LIMIT') + call this%parser%GetString(text) + if (trim(text) == 'OFF') then + this%shutofflevel(imaw) = DEP20 + else + read (text, *, iostat=istat, iomsg=errmsgr) & + this%shutofflevel(imaw) + if (istat /= 0) then + errmsg = 'Could not read HEAD_LIMIT value. '//trim(errmsgr) + call store_error(errmsg) + end if + if (this%shutofflevel(imaw) <= this%bot(imaw)) then + iheadlimit_warning = iheadlimit_warning + 1 + end if + end if + case ('SHUT_OFF') + rval = this%parser%GetDouble() + this%shutoffmin(imaw) = rval + rval = this%parser%GetDouble() + this%shutoffmax(imaw) = rval + case ('AUXILIARY') + call this%parser%GetStringCaps(caux) + do jj = 1, this%naux + if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle + call this%parser%GetString(text) + ii = imaw + bndElem => this%mauxvar(jj, ii) + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & + this%auxname(jj)) + exit + end do + case default + write (errmsg, '(2a)') & + 'Unknown '//trim(this%text)//" maw data keyword: '", & + trim(keyword)//"'." + call store_error(errmsg) + end select ! ! -- return return end subroutine maw_set_stressperiod - subroutine maw_set_attribute_error(this, imaw, keyword, msg) ! ****************************************************************************** ! maw_set_attribute_error -- Issue a parameter error for mawweslls(imaw) @@ -1532,18 +1543,18 @@ subroutine maw_set_attribute_error(this, imaw, keyword, msg) ! ------------------------------------------------------------------------------ use SimModule, only: store_error ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: imaw - character (len=*), intent(in) :: keyword - character (len=*), intent(in) :: msg + character(len=*), intent(in) :: keyword + character(len=*), intent(in) :: msg ! -- local ! -- formats ! ------------------------------------------------------------------------------ if (len(msg) == 0) then - write(errmsg,'(a,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,a,1x,i0,1x,a)') & keyword, ' for MAW well', imaw, 'has already been set.' else - write(errmsg,'(a,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,a,1x,i0,1x,a)') & keyword, ' for MAW well', imaw, msg end if call store_error(errmsg) @@ -1552,7 +1563,6 @@ subroutine maw_set_attribute_error(this, imaw, keyword, msg) return end subroutine maw_set_attribute_error - subroutine maw_check_attributes(this) ! ****************************************************************************** ! maw_check_attributes -- Issue parameter errors for mawwells(imaw) @@ -1564,7 +1574,7 @@ subroutine maw_check_attributes(this) ! ------------------------------------------------------------------------------ use SimModule, only: store_error ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: cgwfnode integer(I4B) :: idx @@ -1576,7 +1586,7 @@ subroutine maw_check_attributes(this) idx = 1 do n = 1, this%nmawwells if (this%ngwfnodes(n) < 1) then - call this%maw_set_attribute_error(n, 'NGWFNODES', 'must be greater ' // & + call this%maw_set_attribute_error(n, 'NGWFNODES', 'must be greater '// & 'than 0.') end if if (this%radius(n) == DEP20) then @@ -1584,7 +1594,7 @@ subroutine maw_check_attributes(this) end if if (this%shutoffmin(n) > DZERO) then if (this%shutoffmin(n) >= this%shutoffmax(n)) then - call this%maw_set_attribute_error(n, 'SHUT_OFF', 'shutoffmax must ' // & + call this%maw_set_attribute_error(n, 'SHUT_OFF', 'shutoffmax must '// & 'be greater than shutoffmin.') end if end if @@ -1594,34 +1604,34 @@ subroutine maw_check_attributes(this) jpos = this%get_jpos(n, j) ! ! -- write gwfnode number - write(cgwfnode,'(a,i0,a)') 'gwfnode(', j,')' + write (cgwfnode, '(a,i0,a)') 'gwfnode(', j, ')' ! ! -- connection screen data if (this%botscrn(jpos) >= this%topscrn(jpos)) then - call this%maw_set_attribute_error(n, 'SCREEN_TOP', 'screen bottom ' // & - 'must be less tha screen top. ' // & + call this%maw_set_attribute_error(n, 'SCREEN_TOP', 'screen bottom '// & + 'must be less tha screen top. '// & trim(cgwfnode)) end if ! ! -- connection skin hydraulic conductivity - if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & + if (this%ieqn(n) == 2 .OR. this%ieqn(n) == 3 .OR. & this%ieqn(n) == 4) then if (this%hk(jpos) <= DZERO) then - call this%maw_set_attribute_error(n, 'HK_SKIN', 'skin hyraulic ' // & - 'conductivity must be greater ' // & - 'than zero. ' // trim(cgwfnode)) + call this%maw_set_attribute_error(n, 'HK_SKIN', 'skin hyraulic '// & + 'conductivity must be greater '// & + 'than zero. '//trim(cgwfnode)) end if else if (this%ieqn(n) == 0) then ! ! -- saturated conductance if (this%satcond(jpos) < DZERO) then - call this%maw_set_attribute_error(n, 'HK_SKIN', & - 'skin hyraulic conductivity ' // & - 'must be greater than or ' // & - 'equal to zero when using ' // & - 'SPECIFIED condeqn. ' // & + call this%maw_set_attribute_error(n, 'HK_SKIN', & + 'skin hyraulic conductivity '// & + 'must be greater than or '// & + 'equal to zero when using '// & + 'SPECIFIED condeqn. '// & trim(cgwfnode)) - end if + end if end if idx = idx + 1 end do @@ -1641,7 +1651,7 @@ subroutine maw_ac(this, moffset, sparse) ! ------------------------------------------------------------------------------ use SparseModule, only: sparsematrix ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: moffset type(sparsematrix), intent(inout) :: sparse ! -- local @@ -1681,7 +1691,7 @@ subroutine maw_mc(this, moffset, iasln, jasln) use SparseModule, only: sparsematrix use MemoryManagerModule, only: mem_allocate ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: moffset integer(I4B), dimension(:), intent(in) :: iasln integer(I4B), dimension(:), intent(in) :: jasln @@ -1697,11 +1707,14 @@ subroutine maw_mc(this, moffset, iasln, jasln) ! ------------------------------------------------------------------------------ ! ! -- allocate connection mapping vectors - call mem_allocate(this%idxlocnode, this%nmawwells, 'IDXLOCNODE', this%memoryPath) + call mem_allocate(this%idxlocnode, this%nmawwells, 'IDXLOCNODE', & + this%memoryPath) call mem_allocate(this%idxdglo, this%maxbound, 'IDXDGLO', this%memoryPath) - call mem_allocate(this%idxoffdglo, this%maxbound, 'IDXOFFDGLO', this%memoryPath) - call mem_allocate(this%idxsymdglo, this%maxbound, 'IDXSYMDGLO', this%memoryPath) - call mem_allocate(this%idxsymoffdglo, this%maxbound, 'IDXSYMOFFDGLO', & + call mem_allocate(this%idxoffdglo, this%maxbound, 'IDXOFFDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymdglo, this%maxbound, 'IDXSYMDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymoffdglo, this%maxbound, 'IDXSYMOFFDGLO', & this%memoryPath) ! ! -- Find the position of each connection in the global ia, ja structure @@ -1716,7 +1729,7 @@ subroutine maw_mc(this, moffset, iasln, jasln) j = this%get_gwfnode(n, ii) jglo = j + moffset searchloop: do jj = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(jj)) then + if (jglo == jasln(jj)) then this%idxdglo(ipos) = iasln(iglo) this%idxoffdglo(ipos) = jj exit searchloop @@ -1732,7 +1745,7 @@ subroutine maw_mc(this, moffset, iasln, jasln) iglo = this%get_gwfnode(n, ii) + moffset jglo = moffset + this%dis%nodes + this%ioffset + n symsearchloop: do jj = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(jj)) then + if (jglo == jasln(jj)) then this%idxsymdglo(ipos) = iasln(iglo) this%idxsymoffdglo(ipos) = jj exit symsearchloop @@ -1748,7 +1761,7 @@ end subroutine maw_mc subroutine maw_read_options(this, option, found) ! ****************************************************************************** -! maw_read_options -- set options specific to MawType. +! maw_read_options -- set options specific to MawType. ! Overrides BndType%bnd_options ! ****************************************************************************** ! @@ -1758,110 +1771,110 @@ subroutine maw_read_options(this, option, found) use OpenSpecModule, only: access, form use InputOutputModule, only: urword, getunit, openfile ! -- dummy - class(MawType), intent(inout) :: this + class(MawType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: fname, keyword ! -- formats - character(len=*),parameter :: fmtflowingwells = & - "(4x, 'FLOWING WELLS WILL BE SIMULATED.')" - character(len=*),parameter :: fmtshutdown = & - "(4x, 'SHUTDOWN ', a, ' VALUE (',g15.7,') SPECIFIED.')" - character(len=*),parameter :: fmtnostoragewells = & - "(4x, 'WELL STORAGE WILL NOT BE SIMULATED.')" - character(len=*),parameter :: fmtmawbin = & - "(4x, 'MAW ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, & + character(len=*), parameter :: fmtflowingwells = & + &"(4x, 'FLOWING WELLS WILL BE SIMULATED.')" + character(len=*), parameter :: fmtshutdown = & + &"(4x, 'SHUTDOWN ', a, ' VALUE (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmtnostoragewells = & + &"(4x, 'WELL STORAGE WILL NOT BE SIMULATED.')" + character(len=*), parameter :: fmtmawbin = & + "(4x, 'MAW ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, & &'OPENED ON UNIT: ', I0)" ! ------------------------------------------------------------------------------ ! ! -- Check for 'FLOWING_WELLS' and set this%iflowingwells + found = .true. select case (option) - case ('PRINT_HEAD') - this%iprhed = 1 - write(this%iout,'(4x,a)') & - trim(adjustl(this%text)) // ' heads will be printed to listing file.' - found = .true. - case('HEAD') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%iheadout = getunit() - call openfile(this%iheadout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtmawbin) 'HEAD', fname, this%iheadout - found = .true. - else - call store_error('Optional maw stage keyword must be ' // & - 'followed by fileout.') - end if - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtmawbin) 'BUDGET', fname, this%ibudgetout - found = .true. - else - call store_error('Optional maw budget keyword must be ' // & - 'followed by fileout.') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtmawbin) 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case('FLOWING_WELLS') - this%iflowingwells = 1 - write(this%iout, fmtflowingwells) - found = .true. - case('SHUTDOWN_THETA') - this%theta = this%parser%GetDouble() - write(this%iout, fmtshutdown) 'THETA', this%theta - found = .true. - case('SHUTDOWN_KAPPA') - this%kappa = this%parser%GetDouble() - write(this%iout, fmtshutdown) 'KAPPA', this%kappa - found = .true. - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case('NO_WELL_STORAGE') - this%imawissopt = 1 - write(this%iout, fmtnostoragewells) - found = .true. - case('FLOW_CORRECTION') - this%correct_flow = .TRUE. - write(this%iout, '(4x,a,/,4x,a)') & - 'MAW-GWF FLOW CORRECTIONS WILL BE APPLIED WHEN MAW HEADS ARE BELOW', & - 'OR GWF HEADS IN CONNECTED CELLS ARE BELOW THE CELL BOTTOM.' - found = .true. + case ('PRINT_HEAD') + this%iprhed = 1 + write (this%iout, '(4x,a)') & + trim(adjustl(this%text))//' heads will be printed to listing file.' + case ('HEAD') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%iheadout = getunit() + call openfile(this%iheadout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtmawbin) 'HEAD', fname, this%iheadout + else + call store_error('Optional maw stage keyword must be '// & + 'followed by fileout.') + end if + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtmawbin) 'BUDGET', fname, this%ibudgetout + else + call store_error('Optional maw budget keyword must be '// & + 'followed by fileout.') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtmawbin) 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('FLOWING_WELLS') + this%iflowingwells = 1 + write (this%iout, fmtflowingwells) + case ('SHUTDOWN_THETA') + this%theta = this%parser%GetDouble() + write (this%iout, fmtshutdown) 'THETA', this%theta + case ('SHUTDOWN_KAPPA') + this%kappa = this%parser%GetDouble() + write (this%iout, fmtshutdown) 'KAPPA', this%kappa + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + case ('NO_WELL_STORAGE') + this%imawissopt = 1 + write (this%iout, fmtnostoragewells) + case ('FLOW_CORRECTION') + this%correct_flow = .TRUE. + write (this%iout, '(4x,a,/,4x,a)') & + 'MAW-GWF FLOW CORRECTIONS WILL BE APPLIED WHEN MAW HEADS ARE BELOW', & + 'OR GWF HEADS IN CONNECTED CELLS ARE BELOW THE CELL BOTTOM.' + case ('MAW_FLOW_REDUCE_CSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + call this%maw_redflow_csv_init(fname) + else + call store_error('OPTIONAL MAW_FLOW_REDUCE_CSV KEYWORD MUST BE & + &FOLLOWED BY FILEOUT') + end if ! ! -- right now these are options that are only available in the ! development version and are not included in the documentation. ! These options are only available when IDEVELOPMODE in ! constants module is set to 1 - case('DEV_PEACEMAN_EFFECTIVE_RADIUS') - call this%parser%DevOpt() - this%ieffradopt = 1 - write(this%iout, '(4x,a)') & - & 'EFFECTIVE RADIUS FOR STRUCTURED GRIDS WILL BE CALCULATED ' // & - & 'USING PEACEMAN 1983' - found = .true. - case default - ! - ! -- No options found - found = .false. + case ('DEV_PEACEMAN_EFFECTIVE_RADIUS') + call this%parser%DevOpt() + this%ieffradopt = 1 + write (this%iout, '(4x,a)') & + 'EFFECTIVE RADIUS FOR STRUCTURED GRIDS WILL BE CALCULATED & + &USING PEACEMAN 1983' + case default + ! + ! -- No options found + found = .false. end select ! ! -- return @@ -1869,19 +1882,19 @@ subroutine maw_read_options(this, option, found) end subroutine maw_read_options subroutine maw_ar(this) - ! ****************************************************************************** - ! maw_ar -- Allocate and Read - ! Subroutine: (1) create new-style package - ! (2) point bndobj to the new package - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - ! -- dummy - class(MawType),intent(inout) :: this - ! -- local - ! -- format - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! maw_ar -- Allocate and Read + ! Subroutine: (1) create new-style package + ! (2) point bndobj to the new package + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + ! -- dummy + class(MawType), intent(inout) :: this + ! -- local + ! -- format + ! ------------------------------------------------------------------------------ ! call this%obs%obs_ar() ! @@ -1898,7 +1911,7 @@ subroutine maw_ar(this) ! ! -- setup pakmvrobj if (this%imover /= 0) then - allocate(this%pakmvrobj) + allocate (this%pakmvrobj) call this%pakmvrobj%ar(this%nmawwells, this%nmawwells, this%memoryPath) end if ! @@ -1906,7 +1919,6 @@ subroutine maw_ar(this) return end subroutine maw_ar - subroutine maw_rp(this) ! ****************************************************************************** ! maw_rp -- Read and Prepare @@ -1919,12 +1931,12 @@ subroutine maw_rp(this) use ConstantsModule, only: LINELENGTH use TdisModule, only: kper, nper ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: line character(len=LINELENGTH) :: text - character (len=16) :: csteady + character(len=16) :: csteady logical :: isfound logical :: endOfBlock integer(I4B) :: ierr @@ -1938,10 +1950,10 @@ subroutine maw_rp(this) integer(I4B) :: jpos integer(I4B) :: iheadlimit_warning ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" ! ------------------------------------------------------------------------------ ! ! -- initialize counters @@ -1960,15 +1972,16 @@ subroutine maw_rp(this) ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -1981,22 +1994,22 @@ subroutine maw_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg, terminate=.TRUE.) end if end if end if ! ! -- Read data if ionper == kper - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- setup table for period data if (this%iprpak /= 0) then ! ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(1, 5, this%iout, finalize=.FALSE.) text = 'NUMBER' @@ -2004,7 +2017,7 @@ subroutine maw_rp(this) text = 'KEYWORD' call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) do n = 1, 3 - write(text, '(a,1x,i6)') 'VALUE', n + write (text, '(a,1x,i6)') 'VALUE', n call this%inputtab%initialize_column(text, 15, alignment=TABCENTER) end do end if @@ -2017,8 +2030,8 @@ subroutine maw_rp(this) imaw = this%parser%GetInteger() if (imaw < 1 .or. imaw > this%nmawwells) then - write(errmsg,'(2(a,1x),i0,a)') & - 'IMAW must be greater than 0 and', & + write (errmsg, '(2(a,1x),i0,a)') & + 'IMAW must be greater than 0 and', & 'less than or equal to ', this%nmawwells, '.' call store_error(errmsg) cycle @@ -2036,17 +2049,17 @@ subroutine maw_rp(this) if (this%iprpak /= 0) then call this%inputtab%finalize_table() end if - ! - ! -- using data from the last stress period + ! + ! -- using data from the last stress period else - write(this%iout,fmtlsp) trim(this%filtyp) + write (this%iout, fmtlsp) trim(this%filtyp) end if ! ! -- issue warning messages if (iheadlimit_warning > 0) then - write(warnmsg, '(a,a,a,1x,a,1x,a)') & - "HEAD_LIMIT in '", trim(this%packName),"' was below the well bottom", & - "for one or more multi-aquifer well(s). This may result in", & + write (warnmsg, '(a,a,a,1x,a,1x,a)') & + "HEAD_LIMIT in '", trim(this%packName), "' was below the well bottom", & + "for one or more multi-aquifer well(s). This may result in", & "convergence failures for some models." call store_warning(warnmsg, substring=warnmsg(:50)) end if @@ -2069,23 +2082,23 @@ subroutine maw_rp(this) end if ! ! -- reset the input table object for rate data - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') ' // trim(adjustl(csteady)) // & + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') '//trim(adjustl(csteady))// & ' RATE DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + write (title, '(a,1x,i6)') trim(adjustl(title)), kper ntabcols = 6 call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(this%nmawwells, ntabcols, this%iout) text = 'NUMBER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'STATUS' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'RATE' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'SPECIFIED HEAD' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'PUMP ELEVATION' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'REDUCTION LENGTH' call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) do n = 1, this%nmawwells @@ -2109,10 +2122,10 @@ subroutine maw_rp(this) if (this%iflowingwells > 0) then ! ! -- reset the input table object for flowing well data - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') ' // trim(adjustl(csteady)) // & + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') '//trim(adjustl(csteady))// & ' FLOWING WELL DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + write (title, '(a,1x,i6)') trim(adjustl(title)), kper ntabcols = 4 ntabrows = 0 do n = 1, this%nmawwells @@ -2124,11 +2137,11 @@ subroutine maw_rp(this) call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(ntabrows, ntabcols, this%iout) text = 'NUMBER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'ELEVATION' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'CONDUCT.' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'REDUCTION LENGTH' call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) do n = 1, this%nmawwells @@ -2143,10 +2156,10 @@ subroutine maw_rp(this) end if ! ! -- reset the input table object for shutoff data - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') '// trim(adjustl(csteady)) // & + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') '//trim(adjustl(csteady))// & ' WELL SHUTOFF DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + write (title, '(a,1x,i6)') trim(adjustl(title)), kper ntabcols = 4 ntabrows = 0 do n = 1, this%nmawwells @@ -2158,11 +2171,11 @@ subroutine maw_rp(this) call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(ntabrows, ntabcols, this%iout) text = 'NUMBER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'ELEVATION' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'MINIMUM. Q' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) text = 'MAXIMUM Q' call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) do n = 1, this%nmawwells @@ -2184,13 +2197,13 @@ subroutine maw_rp(this) jpos = this%get_jpos(n, j) node = this%get_gwfnode(n, j) this%nodelist(ibnd) = node - this%bound(1,ibnd) = this%xnewpak(n) - this%bound(2,ibnd) = this%satcond(jpos) - this%bound(3,ibnd) = this%botscrn(jpos) + this%bound(1, ibnd) = this%xnewpak(n) + this%bound(2, ibnd) = this%satcond(jpos) + this%bound(3, ibnd) = this%botscrn(jpos) if (this%iboundpak(n) > 0) then - this%bound(4,ibnd) = this%rate(n) + this%bound(4, ibnd) = this%rate(n) else - this%bound(4,ibnd) = DZERO + this%bound(4, ibnd) = DZERO end if ibnd = ibnd + 1 end do @@ -2207,7 +2220,7 @@ subroutine maw_ad(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use TdisModule, only : kper, kstp + use TdisModule, only: kper, kstp ! -- dummy class(MawType) :: this ! -- local @@ -2247,7 +2260,7 @@ subroutine maw_ad(this) ! !--use the appropriate xoldsto if intial heads are above the ! specified flowing well discharge elevation - if (kper==1 .and. kstp==1) then + if (kper == 1 .and. kstp == 1) then do n = 1, this%nmawwells if (this%fwcond(n) > DZERO) then if (this%xoldsto(n) > this%fwelev(n)) then @@ -2261,7 +2274,7 @@ subroutine maw_ad(this) this%ishutoffcnt = 0 ! ! -- pakmvrobj ad - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%ad() end if ! @@ -2275,20 +2288,20 @@ subroutine maw_ad(this) end subroutine maw_ad subroutine maw_cf(this, reset_mover) - ! ****************************************************************************** - ! maw_cf -- Formulate the HCOF and RHS terms - ! Subroutine: (1) skip if no multi-aquifer wells - ! (2) calculate hcof and rhs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! maw_cf -- Formulate the HCOF and RHS terms + ! Subroutine: (1) skip if no multi-aquifer wells + ! (2) calculate hcof and rhs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ ! -- dummy class(MawType) :: this logical, intent(in), optional :: reset_mover ! -- local logical :: lrm - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ ! ! -- Calculate maw conductance and update package RHS and HCOF call this%maw_cfupdate() @@ -2296,7 +2309,7 @@ subroutine maw_cf(this, reset_mover) ! -- pakmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() end if ! @@ -2348,7 +2361,7 @@ subroutine maw_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() end if ! @@ -2408,12 +2421,12 @@ subroutine maw_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active, add receiver water to rhs and ! store available water (as positive value) - if(this%imover == 1) then + if (this%imover == 1) then rhs(iloc) = rhs(iloc) - this%pakmvrobj%get_qfrommvr(n) ! ! -- add pumping rate to mover if not injection if (rate < 0) then - call this%pakmvrobj%accumulate_qformvr(n, -rate) !pumped water + call this%pakmvrobj%accumulate_qformvr(n, -rate) !pumped water end if ! ! -- add flowing well flow to mover @@ -2430,7 +2443,7 @@ subroutine maw_fc(this, rhs, ia, idxglo, amatsln) hgwf = this%xnew(igwfnode) ! ! -- calculate connection terms - call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, term, & + call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, term, & flow) this%simcond(jpos) = cmaw ! @@ -2451,7 +2464,7 @@ subroutine maw_fc(this, rhs, ia, idxglo, amatsln) amatsln(ipossymd) = amatsln(ipossymd) - term amatsln(ipossymoffd) = term ! - ! -- add correction term to gwf row + ! -- add correction term to gwf row rhs(isymnode) = rhs(isymnode) + cterm end if ! @@ -2525,7 +2538,7 @@ subroutine maw_fn(this, rhs, ia, idxglo, amatsln) rate = this%ratesim(n) ! !-- calculate final derivative for pumping rate - call this%maw_calculate_wellq(n, hmaw+DEM4, rate2) + call this%maw_calculate_wellq(n, hmaw + DEM4, rate2) drterm = (rate2 - rate) / DEM4 ! !-- fill amat and rhs with newton-raphson terms @@ -2553,7 +2566,7 @@ subroutine maw_fn(this, rhs, ia, idxglo, amatsln) drterm = -(cfw + this%fwcond(n) * derv * (hmaw - bt)) ! ! -- fill amat and rhs with newton-raphson terms - amatsln(iposd) = amatsln(iposd) - & + amatsln(iposd) = amatsln(iposd) - & this%fwcond(n) * derv * (hmaw - bt) rhs(iloc) = rhs(iloc) - rterm + drterm * hmaw end if @@ -2579,7 +2592,7 @@ subroutine maw_fn(this, rhs, ia, idxglo, amatsln) ipossymoffd = this%idxsymoffdglo(idx) ! ! -- calculate newton terms - call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, term, & + call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, term, & flow, term2) ! ! -- maw is upstream @@ -2602,8 +2615,8 @@ subroutine maw_fn(this, rhs, ia, idxglo, amatsln) amatsln(ipossymoffd) = amatsln(ipossymoffd) - term end if end if - ! - ! -- gwf is upstream + ! + ! -- gwf is upstream else if (icflow /= 0) then rhsterm = term2 * hmaw + term * hgwf @@ -2635,7 +2648,6 @@ subroutine maw_fn(this, rhs, ia, idxglo, amatsln) return end subroutine maw_fn - subroutine maw_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax) ! ****************************************************************************** ! maw_nur -- under-relaxation @@ -2671,7 +2683,7 @@ subroutine maw_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax) ! solution head is below the bottom of the well if (x(n) < botw) then inewtonur = 1 - xx = xtemp(n)*(DONE-DP9) + botw*DP9 + xx = xtemp(n) * (DONE - DP9) + botw * DP9 dxx = x(n) - xx if (abs(dxx) > abs(dxmax)) then locmax = n @@ -2696,7 +2708,6 @@ subroutine maw_cq(this, x, flowja, iadv) ! -- modules use TdisModule, only: delt use ConstantsModule, only: LENBOUNDNAME - use InputOutputModule, only: ulasav, ubdsv06 use BudgetModule, only: BudgetType ! -- dummy class(MawType), intent(inout) :: this @@ -2832,10 +2843,10 @@ subroutine maw_ot_package_flows(this, icbcfl, ibudfl) ! ! -- write the flows from the budobj ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & pertim, totim, this%iout) @@ -2845,7 +2856,7 @@ subroutine maw_ot_package_flows(this, icbcfl, ibudfl) if (ibudfl /= 0 .and. this%iprflow /= 0) then call this%budobj%write_flowtable(this%dis, kstp, kper) end if - + end subroutine maw_ot_package_flows subroutine maw_ot_dv(this, idvsave, idvprint) @@ -2862,10 +2873,10 @@ subroutine maw_ot_dv(this, idvsave, idvprint) ! ! -- set unit number for binary dependent variable output ibinun = 0 - if(this%iheadout /= 0) then + if (this%iheadout /= 0) then ibinun = this%iheadout end if - if(idvsave == 0) ibinun = 0 + if (idvsave == 0) ibinun = 0 ! ! -- write maw binary output if (ibinun > 0) then @@ -2879,45 +2890,45 @@ subroutine maw_ot_dv(this, idvsave, idvprint) end if this%dbuff(n) = v end do - call ulasav(this%dbuff, ' HEAD', & - kstp, kper, pertim, totim, & + call ulasav(this%dbuff, ' HEAD', & + kstp, kper, pertim, totim, & this%nmawwells, 1, 1, ibinun) end if - ! - ! -- write maw head table - if (idvprint /= 0 .and. this%iprhed /= 0) then + ! + ! -- write maw head table + if (idvprint /= 0 .and. this%iprhed /= 0) then ! ! -- set table kstp and kper call this%headtab%set_kstpkper(kstp, kper) ! ! -- fill stage data do n = 1, this%nmawwells - if(this%inamedbound==1) then + if (this%inamedbound == 1) then call this%headtab%add_term(this%cmawname(n)) end if call this%headtab%add_term(n) call this%headtab%add_term(this%xnewpak(n)) end do - end if - + end if + end subroutine maw_ot_dv - + subroutine maw_ot_bdsummary(this, kstp, kper, iout, ibudfl) ! -- module use TdisModule, only: totim ! -- dummy - class(MawType) :: this !< MawType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + class(MawType) :: this !< MawType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written ! call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) ! ! -- return return end subroutine maw_ot_bdsummary - + subroutine maw_da(this) ! ****************************************************************************** ! maw_da -- deallocate @@ -2935,14 +2946,14 @@ subroutine maw_da(this) ! ! -- budobj call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- head table if (this%iprhed > 0) then call this%headtab%table_da() - deallocate(this%headtab) - nullify(this%headtab) + deallocate (this%headtab) + nullify (this%headtab) end if ! ! -- character arrays @@ -3001,6 +3012,7 @@ subroutine maw_da(this) call mem_deallocate(this%qsto) call mem_deallocate(this%qconst) call mem_deallocate(this%denseterms) + call mem_deallocate(this%viscratios) call mem_deallocate(this%idxlocnode) call mem_deallocate(this%idxdglo) call mem_deallocate(this%idxoffdglo) @@ -3024,6 +3036,7 @@ subroutine maw_da(this) call mem_deallocate(this%check_attr) call mem_deallocate(this%ishutoffcnt) call mem_deallocate(this%ieffradopt) + call mem_deallocate(this%ioutredflowcsv) call mem_deallocate(this%satomega) call mem_deallocate(this%bditems) call mem_deallocate(this%theta) @@ -3032,7 +3045,7 @@ subroutine maw_da(this) call mem_deallocate(this%idense) ! ! -- pointers to gwf variables - nullify(this%gwfiss) + nullify (this%gwfiss) ! ! -- call standard BndType deallocate call this%BndType%bnd_da() @@ -3053,27 +3066,26 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' end if - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' end if ! ! -- return return end subroutine define_listlabel - subroutine maw_set_pointers(this, neq, ibound, xnew, xold, flowja) ! ****************************************************************************** ! set_pointers -- Set pointers to model arrays and variables so that a package @@ -3106,7 +3118,8 @@ subroutine maw_set_pointers(this, neq, ibound, xnew, xold, flowja) iend = istart + this%nmawwells - 1 this%iboundpak => this%ibound(istart:iend) this%xnewpak => this%xnew(istart:iend) - call mem_checkin(this%xnewpak, 'HEAD', this%memoryPath, 'X', this%memoryPathModel) + call mem_checkin(this%xnewpak, 'HEAD', this%memoryPath, 'X', & + this%memoryPathModel) call mem_allocate(this%xoldpak, this%nmawwells, 'XOLDPAK', this%memoryPath) ! ! -- initialize xnewpak @@ -3120,35 +3133,34 @@ end subroutine maw_set_pointers ! ! -- Procedures related to observations (type-bound) logical function maw_obs_supported(this) - ! ****************************************************************************** - ! maw_obs_supported - ! -- Return true because MAW package supports observations. - ! -- Overrides BndType%bnd_obs_supported() - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! maw_obs_supported + ! -- Return true because MAW package supports observations. + ! -- Overrides BndType%bnd_obs_supported() + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ class(MawType) :: this - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ maw_obs_supported = .true. return end function maw_obs_supported - subroutine maw_df_obs(this) - ! ****************************************************************************** - ! maw_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by MAW package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! maw_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by MAW package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ ! -- dummy class(MawType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ ! ! -- Store obs type and assign procedure pointer ! for head observation type. @@ -3208,7 +3220,6 @@ subroutine maw_df_obs(this) return end subroutine maw_df_obs - subroutine maw_bd_obs(this) ! ************************************************************************** ! maw_bd_obs @@ -3243,95 +3254,95 @@ subroutine maw_bd_obs(this) v = DNODATA jj = obsrv%indxbnds(j) select case (obsrv%ObsTypeId) - case ('HEAD') - if (this%iboundpak(jj) /= 0) then - v = this%xnewpak(jj) + case ('HEAD') + if (this%iboundpak(jj) /= 0) then + v = this%xnewpak(jj) + end if + case ('FROM-MVR') + if (this%iboundpak(jj) /= 0) then + if (this%imover == 1) then + v = this%pakmvrobj%get_qfrommvr(jj) end if - case ('FROM-MVR') - if (this%iboundpak(jj) /= 0) then + end if + case ('MAW') + n = this%imap(jj) + if (this%iboundpak(n) /= 0) then + v = this%qleak(jj) + end if + case ('RATE') + if (this%iboundpak(jj) /= 0) then + v = this%ratesim(jj) + if (v < DZERO .and. this%qout(jj) < DZERO) then + qfact = v / this%qout(jj) if (this%imover == 1) then - v = this%pakmvrobj%get_qfrommvr(jj) + v = v + this%pakmvrobj%get_qtomvr(jj) * qfact end if end if - case ('MAW') - n = this%imap(jj) - if (this%iboundpak(n) /= 0) then - v = this%qleak(jj) - end if - case ('RATE') - if (this%iboundpak(jj) /= 0) then + end if + case ('RATE-TO-MVR') + if (this%iboundpak(jj) /= 0) then + if (this%imover == 1) then v = this%ratesim(jj) + qfact = DZERO if (v < DZERO .and. this%qout(jj) < DZERO) then qfact = v / this%qout(jj) - if (this%imover == 1) then - v = v + this%pakmvrobj%get_qtomvr(jj) * qfact - end if + end if + v = this%pakmvrobj%get_qtomvr(jj) * qfact + if (v > DZERO) then + v = -v end if end if - case ('RATE-TO-MVR') - if (this%iboundpak(jj) /= 0) then + end if + case ('FW-RATE') + if (this%iboundpak(jj) /= 0 .and. this%iflowingwells > 0) then + hmaw = this%xnewpak(jj) + cmaw = this%fwcondsim(jj) + v = cmaw * (this%fwelev(jj) - hmaw) + if (v < DZERO .and. this%qout(jj) < DZERO) then + qfact = v / this%qout(jj) if (this%imover == 1) then - v = this%ratesim(jj) - qfact = DZERO - if (v < DZERO .and. this%qout(jj) < DZERO) then - qfact = v / this%qout(jj) - end if - v = this%pakmvrobj%get_qtomvr(jj) * qfact - if (v > DZERO) then - v = -v - end if + v = v + this%pakmvrobj%get_qtomvr(jj) * qfact end if end if - case ('FW-RATE') - if (this%iboundpak(jj) /= 0 .and. this%iflowingwells > 0) then + end if + case ('FW-TO-MVR') + if (this%iboundpak(jj) /= 0 .and. this%iflowingwells > 0) then + if (this%imover == 1) then hmaw = this%xnewpak(jj) cmaw = this%fwcondsim(jj) v = cmaw * (this%fwelev(jj) - hmaw) + qfact = DZERO if (v < DZERO .and. this%qout(jj) < DZERO) then qfact = v / this%qout(jj) - if (this%imover == 1) then - v = v + this%pakmvrobj%get_qtomvr(jj) * qfact - end if end if - end if - case ('FW-TO-MVR') - if (this%iboundpak(jj) /= 0 .and. this%iflowingwells > 0) then - if (this%imover == 1) then - hmaw = this%xnewpak(jj) - cmaw = this%fwcondsim(jj) - v = cmaw * (this%fwelev(jj) - hmaw) - qfact = DZERO - if (v < DZERO .and. this%qout(jj) < DZERO) then - qfact = v / this%qout(jj) - end if - v = this%pakmvrobj%get_qtomvr(jj) * qfact - if (v > DZERO) then - v = -v - end if + v = this%pakmvrobj%get_qtomvr(jj) * qfact + if (v > DZERO) then + v = -v end if end if - case ('STORAGE') - if (this%iboundpak(jj) /= 0 .and. this%imawissopt /= 1) then - v = this%qsto(jj) - end if - case ('CONSTANT') - if (this%iboundpak(jj) /= 0) then - v = this%qconst(jj) - end if - case ('CONDUCTANCE') - n = this%imap(jj) - if (this%iboundpak(n) /= 0) then - nn = jj - this%iaconn(n) + 1 - jpos = this%get_jpos(n, nn) - v = this%simcond(jpos) - end if - case ('FW-CONDUCTANCE') - if (this%iboundpak(jj) /= 0) then - v = this%fwcondsim(jj) - end if - case default - errmsg = 'Unrecognized observation type: ' // trim(obsrv%ObsTypeId) - call store_error(errmsg) + end if + case ('STORAGE') + if (this%iboundpak(jj) /= 0 .and. this%imawissopt /= 1) then + v = this%qsto(jj) + end if + case ('CONSTANT') + if (this%iboundpak(jj) /= 0) then + v = this%qconst(jj) + end if + case ('CONDUCTANCE') + n = this%imap(jj) + if (this%iboundpak(n) /= 0) then + nn = jj - this%iaconn(n) + 1 + jpos = this%get_jpos(n, nn) + v = this%simcond(jpos) + end if + case ('FW-CONDUCTANCE') + if (this%iboundpak(jj) /= 0) then + v = this%fwcondsim(jj) + end if + case default + errmsg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId) + call store_error(errmsg) end select call this%obs%SaveOneSimval(obsrv, v) end do @@ -3343,11 +3354,15 @@ subroutine maw_bd_obs(this) end if end if ! + ! -- Write the MAW reduced flows to csv file entries for this step + if (this%ioutredflowcsv > 0) then + call this%maw_redflow_csv_write() + end if + ! ! -- return return end subroutine maw_bd_obs - subroutine maw_rp_obs(this) use TdisModule, only: kper ! -- dummy @@ -3361,11 +3376,11 @@ subroutine maw_rp_obs(this) integer(I4B) :: jj character(len=LENBOUNDNAME) :: bname logical :: jfound - class(ObserveType), pointer :: obsrv => null() + class(ObserveType), pointer :: obsrv => null() ! -------------------------------------------------------------------------- ! -- formats -10 format('Boundary "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') +10 format('Boundary "', a, '" for observation "', a, & + '" is invalid in package "', a, '"') ! ! -- process each package observation ! only done the first stress period since boundaries are fixed @@ -3383,10 +3398,10 @@ subroutine maw_rp_obs(this) ! Iterate through all multi-aquifer wells to identify and store ! corresponding index in bound array. jfound = .false. - if (obsrv%ObsTypeId=='MAW' .or. & - obsrv%ObsTypeId=='CONDUCTANCE') then + if (obsrv%ObsTypeId == 'MAW' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE') then do j = 1, this%nmawwells - do jj = this%iaconn(j), this%iaconn(j+1) - 1 + do jj = this%iaconn(j), this%iaconn(j + 1) - 1 if (this%boundname(jj) == bname) then jfound = .true. call obsrv%AddObsIndex(jj) @@ -3402,14 +3417,15 @@ subroutine maw_rp_obs(this) end do end if if (.not. jfound) then - write(errmsg,10) trim(bname), trim(obsrv%Name), trim(this%packName) + write (errmsg, 10) & + trim(bname), trim(obsrv%Name), trim(this%packName) call store_error(errmsg) end if end if else if (obsrv%indxbnds_count == 0) then - if (obsrv%ObsTypeId=='MAW' .or. & - obsrv%ObsTypeId=='CONDUCTANCE') then + if (obsrv%ObsTypeId == 'MAW' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE') then nn2 = obsrv%NodeNumber2 j = this%iaconn(nn1) + nn2 - 1 call obsrv%AddObsIndex(j) @@ -3426,38 +3442,38 @@ subroutine maw_rp_obs(this) ! by a boundname that is assigned to more than one element if (obsrv%ObsTypeId == 'HEAD') then if (obsrv%indxbnds_count > 1) then - write (errmsg, '(a,3(1x,a))') & - trim(adjustl(obsrv%ObsTypeId)), & - 'for observation', trim(adjustl(obsrv%Name)), & + write (errmsg, '(a,3(1x,a))') & + trim(adjustl(obsrv%ObsTypeId)), & + 'for observation', trim(adjustl(obsrv%Name)), & 'must be assigned to a multi-aquifer well with a unique boundname.' call store_error(errmsg) end if end if ! ! -- check that index values are valid - if (obsrv%ObsTypeId=='MAW' .or. & - obsrv%ObsTypeId=='CONDUCTANCE') then + if (obsrv%ObsTypeId == 'MAW' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE') then do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) + nn1 = obsrv%indxbnds(j) n = this%imap(nn1) nn2 = nn1 - this%iaconn(n) + 1 - jj = this%iaconn(n+1) - this%iaconn(n) + jj = this%iaconn(n + 1) - this%iaconn(n) if (nn1 < 1 .or. nn1 > this%maxbound) then - write (errmsg, '(3(a,1x),i0,1x,a,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - 'multi-aquifer well connection number must be greater than 0', & + write (errmsg, '(3(a,1x),i0,1x,a,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + 'multi-aquifer well connection number must be greater than 0', & 'and less than', jj, '(specified value is ', nn2, ').' call store_error(errmsg) end if end do else do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) + nn1 = obsrv%indxbnds(j) if (nn1 < 1 .or. nn1 > this%nmawwells) then - write (errmsg, '(3(a,1x),i0,1x,a,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - 'multi-aquifer well must be greater than 0 ', & - 'and less than or equal to', this%nmawwells, & + write (errmsg, '(3(a,1x),i0,1x,a,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + 'multi-aquifer well must be greater than 0 ', & + 'and less than or equal to', this%nmawwells, & '(specified value is ', nn1, ').' call store_error(errmsg) end if @@ -3475,17 +3491,16 @@ subroutine maw_rp_obs(this) return end subroutine maw_rp_obs - ! ! -- Procedures related to observations (NOT type-bound) subroutine maw_process_obsID(obsrv, dis, inunitobs, iout) ! -- This procedure is pointed to by ObsDataType%ProcesssIdPtr. It processes ! the ID string of an observation definition for MAW package observations. ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1, nn2 integer(I4B) :: icol, istart, istop @@ -3503,15 +3518,15 @@ subroutine maw_process_obsID(obsrv, dis, inunitobs, iout) if (nn1 == NAMEDBOUNDFLAG) then obsrv%FeatureName = bndname else - if (obsrv%ObsTypeId=='MAW' .or. & - obsrv%ObsTypeId=='CONDUCTANCE') then + if (obsrv%ObsTypeId == 'MAW' .or. & + obsrv%ObsTypeId == 'CONDUCTANCE') then call extract_idnum_or_bndname(strng, icol, istart, istop, nn2, bndname) if (len_trim(bndName) < 1 .and. nn2 < 0) then - write(errmsg, '(a,1x,a,a,1x,a,1x,a)') & - 'For observation type', trim(adjustl(obsrv%ObsTypeId)), & - ', ID given as an integer and not as boundname,', & - 'but ID2 (icon) is missing. Either change ID to valid', & - 'boundname or supply valid entry for ID2.' + write (errmsg, '(a,1x,a,a,1x,a,1x,a)') & + 'For observation type', trim(adjustl(obsrv%ObsTypeId)), & + ', ID given as an integer and not as boundname,', & + 'but ID2 (icon) is missing. Either change ID to valid', & + 'boundname or supply valid entry for ID2.' call store_error(errmsg) end if if (nn2 == NAMEDBOUNDFLAG) then @@ -3533,9 +3548,55 @@ end subroutine maw_process_obsID ! ! -- private MAW methods ! + !> @brief Initialize the auto flow reduce csv output file + subroutine maw_redflow_csv_init(this, fname) + ! -- dummy variables + class(MawType), intent(inout) :: this !< MawType object + character(len=*), intent(in) :: fname + ! -- format + character(len=*), parameter :: fmtredflowcsv = & + "(4x, 'MAW REDUCED FLOW INFORMATION WILL BE SAVED TO FILE: ', a, /4x, & + &'OPENED ON UNIT: ', I0)" + + this%ioutredflowcsv = getunit() + call openfile(this%ioutredflowcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtredflowcsv) trim(adjustl(fname)), & + this%ioutredflowcsv + write (this%ioutredflowcsv, '(a)') & + 'time,period,step,MAWnumber,rate-requested,rate-actual,maw-reduction' + return + end subroutine maw_redflow_csv_init + + !> @brief MAW reduced flows only when & where they occur + subroutine maw_redflow_csv_write(this) + ! -- modules + use TdisModule, only: totim, kstp, kper + ! -- dummy variables + class(MawType), intent(inout) :: this !< MawType object + ! -- local + integer(I4B) :: n + !integer(I4B) :: nodereduced + !integer(I4B) :: nodeuser + real(DP) :: v + ! -- format + do n = 1, this%nmawwells + ! + ! -- test if node is constant or inactive + if (this%status(n) .ne. 'ACTIVE') then + cycle + end if + v = this%rate(n) - this%ratesim(n) !reductions in extraction will be negative and reductions in injection will be positive; follows convention of WEL AUTO_FLOW_REDUCE_CSV + if (abs(v) > DEM9) then !need to check absolute value of difference for both extraction and injection; using 1e-9 as epsilon value but could be tweaked + write (this%ioutredflowcsv, '(*(G0,:,","))') & + totim, kper, kstp, n, this%rate(n), this%ratesim(n), v + end if + end do + end subroutine maw_redflow_csv_write + subroutine maw_calculate_satcond(this, i, j, node) ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: i integer(I4B), intent(in) :: j integer(I4B), intent(in) :: node @@ -3593,7 +3654,7 @@ subroutine maw_calculate_satcond(this, i, j, node) ! -- set gwftop, gwfbot, and gwfsat gwftop = this%dis%top(node) gwfbot = this%dis%bot(node) - tthka = gwftop - gwfbot + tthka = gwftop - gwfbot gwfsat = this%gwfsat(node) ! ! -- set top and bottom of well screen @@ -3619,9 +3680,10 @@ subroutine maw_calculate_satcond(this, i, j, node) Tyy = k22 * tthka dx = sqrt(this%dis%area(node)) dy = dx - yx4 = (Tyy/Txx)**DQUARTER - xy4 = (Txx/Tyy)**DQUARTER - eradius = 0.28_DP * ((yx4*dx)**DTWO + (xy4*dy)**DTWO)**DHALF / (yx4+xy4) + yx4 = (Tyy / Txx)**DQUARTER + xy4 = (Txx / Tyy)**DQUARTER + eradius = 0.28_DP * ((yx4 * dx)**DTWO + & + (xy4 * dy)**DTWO)**DHALF / (yx4 + xy4) else area = this%dis%area(node) eradius = sqrt(area / (DEIGHT * DPI)) @@ -3641,17 +3703,17 @@ subroutine maw_calculate_satcond(this, i, j, node) skin = (Tcontrast - DONE) * log(this%sradius(jpos) / this%radius(i)) ! ! -- trap invalid transmissvity contrast if using skin equation (2). - ! Not trapped for cumulative Thiem and skin equations (3) - ! because the MNW2 package allowed this condition (for - ! backward compatibility with the MNW2 package for + ! Not trapped for cumulative Thiem and skin equations (3) + ! because the MNW2 package allowed this condition (for + ! backward compatibility with the MNW2 package for ! MODFLOW-2005, MODFLOW-NWT, and MODFLOW-USG). if (Tcontrast <= 1 .and. this%ieqn(i) == 2) then iTcontrastErr = 1 - write(errmsg, '(a,g0,a,1x,i0,1x,a,1x,i0,a,4(1x,a))') & - 'Invalid calculated transmissivity contrast (', Tcontrast, & - ') for maw well', i, 'connection', j, '.', 'This happens when the', & + write (errmsg, '(a,g0,a,1x,i0,1x,a,1x,i0,a,4(1x,a))') & + 'Invalid calculated transmissivity contrast (', Tcontrast, & + ') for maw well', i, 'connection', j, '.', 'This happens when the', & 'skin transmissivity equals or exceeds the aquifer transmissivity.', & - 'Consider decreasing HK_SKIN for the connection or using the', & + 'Consider decreasing HK_SKIN for the connection or using the', & 'CUMULATIVE or MEAN conductance equations.' call store_error(errmsg) else @@ -3659,7 +3721,7 @@ subroutine maw_calculate_satcond(this, i, j, node) end if end if end if - ! -- conductance using screen elevations, hk, well radius, + ! -- conductance using screen elevations, hk, well radius, ! and screen radius if (this%ieqn(i) == 4) then hks = this%hk(jpos) @@ -3669,7 +3731,7 @@ subroutine maw_calculate_satcond(this, i, j, node) c = hks * pavg * tthkw / slen end if ! - ! -- calculate final conductance for Theim (1), Skin (2), and + ! -- calculate final conductance for Theim (1), Skin (2), and ! and cumulative Thiem and skin equations (3) if (this%ieqn(i) < 4) then if (lc1 + lc2 /= DZERO) then @@ -3682,11 +3744,11 @@ subroutine maw_calculate_satcond(this, i, j, node) ! -- ensure that the conductance is not negative. Only write error message ! if error condition has not occured for skin calculations (LC2) if (c < DZERO .and. iTcontrastErr == 0) then - write(errmsg, '(a,g0,a,1x,i0,1x,a,1x,i0,a,4(1x,a))') & - 'Invalid calculated negative conductance (', c, & - ') for maw well', i, 'connection', j, '.', 'this happens when the', & - 'skin transmissivity equals or exceeds the aquifer transmissivity.', & - 'consider decreasing hk_skin for the connection or using the', & + write (errmsg, '(a,g0,a,1x,i0,1x,a,1x,i0,a,4(1x,a))') & + 'Invalid calculated negative conductance (', c, & + ') for maw well', i, 'connection', j, '.', 'this happens when the', & + 'skin transmissivity equals or exceeds the aquifer transmissivity.', & + 'consider decreasing hk_skin for the connection or using the', & 'mean conductance equation.' call store_error(errmsg) end if @@ -3698,10 +3760,9 @@ subroutine maw_calculate_satcond(this, i, j, node) return end subroutine maw_calculate_satcond - subroutine maw_calculate_saturation(this, n, j, node, sat) ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: n integer(I4B), intent(in) :: j integer(I4B), intent(in) :: node @@ -3759,12 +3820,12 @@ subroutine maw_calculate_saturation(this, n, j, node, sat) ! -- return return end subroutine maw_calculate_saturation - - subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & + + subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & flow, term2) ! ****************************************************************************** ! maw_calculate_conn_terms-- Calculate matrix terms for a multi-aquifer well -! connection. Terms for fc and fn methods are +! connection. Terms for fc and fn methods are ! calculated based on whether term2 is passed ! ! -- Arguments are as follows: @@ -3807,10 +3868,12 @@ subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & real(DP) :: hbar real(DP) :: drterm real(DP) :: dhbarterm + real(DP) :: vscratio ! ------------------------------------------------------------------------------ ! ! -- initialize terms cterm = DZERO + vscratio = DONE icflow = 0 if (present(term2)) then inewton = 1 @@ -3826,9 +3889,19 @@ subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & tmaw = this%topscrn(jpos) bmaw = this%botscrn(jpos) ! + ! -- if vsc active, select appropriate viscosity ratio + if (this%ivsc == 1) then + ! flow out of well (flow is negative) + if (flow < 0) then + vscratio = this%viscratios(1, igwfnode) + else + vscratio = this%viscratios(2, igwfnode) + end if + end if + ! ! -- calculate saturation call this%maw_calculate_saturation(n, j, igwfnode, sat) - cmaw = this%satcond(jpos) * sat + cmaw = this%satcond(jpos) * vscratio * sat ! ! -- set upstream head, term, and term2 if returning newton terms if (inewton == 1) then @@ -3877,14 +3950,14 @@ subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & ! -- maw is upstream if (hmaw > hgwf) then hbar = sQuadratic0sp(hgwf, en, this%satomega) - term = drterm * this%satcond(jpos) * (hbar - hmaw) + term = drterm * this%satcond(jpos) * vscratio * (hbar - hmaw) dhbarterm = sQuadratic0spDerivative(hgwf, en, this%satomega) term2 = cmaw * (dhbarterm - DONE) - ! - ! -- gwf is upstream + ! + ! -- gwf is upstream else hbar = sQuadratic0sp(hmaw, en, this%satomega) - term = -drterm * this%satcond(jpos) * (hgwf - hbar) + term = -drterm * this%satcond(jpos) * vscratio * (hgwf - hbar) dhbarterm = sQuadratic0spDerivative(hmaw, en, this%satomega) term2 = cmaw * (DONE - dhbarterm) end if @@ -3893,7 +3966,7 @@ subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & ! ! -- flow is not corrected, so calculate term for newton formulation if (inewton /= 0) then - term = drterm * this%satcond(jpos) * (hgwf - hmaw) + term = drterm * this%satcond(jpos) * vscratio * (hgwf - hmaw) end if end if ! @@ -3905,10 +3978,10 @@ subroutine maw_calculate_conn_terms(this, n, j, icflow, cmaw, cterm, term, & ! ! -- add density part here if (this%idense /= 0 .and. inewton == 0) then - call this%maw_calculate_density_exchange(jpos, hmaw, hgwf, cmaw, & - bmaw, flow, term, cterm) - end if - + call this%maw_calculate_density_exchange(jpos, hmaw, hgwf, cmaw, & + bmaw, flow, term, cterm) + end if + ! ! -- return return @@ -3946,7 +4019,7 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) if (rate < DZERO) then ! ! -- If well shut off is activated, then turn off well if necessary, - ! or if shut off is not activated then check to see if rate scaling + ! or if shut off is not activated then check to see if rate scaling ! is on. if (this%shutofflevel(n) /= DEP20) then call this%maw_calculate_qpot(n, q) @@ -3963,14 +4036,14 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) weight = this%shutoffweight(n) ! ! -- for flip-flop condition, decrease factor - if ( this%shutoffdq(n) * dq < DZERO ) then + if (this%shutoffdq(n) * dq < DZERO) then weight = this%theta * this%shutoffweight(n) - ! - ! -- when change is of same sign, increase factor + ! + ! -- when change is of same sign, increase factor else weight = this%shutoffweight(n) + this%kappa end if - if ( weight > DONE ) weight = DONE + if (weight > DONE) weight = DONE q = this%shutoffqold(n) + weight * dq @@ -3978,7 +4051,7 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) this%shutoffdq(n) = dq this%shutoffweight(n) = weight ! - ! -- If shutoffmin and shutoffmax are specified then apply + ! -- If shutoffmin and shutoffmax are specified then apply ! additional checks for when to shut off the well. if (this%shutoffmin(n) > DZERO) then if (hmaw < this%shutofflevel(n)) then @@ -3987,8 +4060,8 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) ! -- well is shutoff if (this%ishutoff(n) /= 0) then q = DZERO - ! - ! --- well is not shut off + ! + ! --- well is not shut off else ! -- turn off well if q is less than the minimum rate and ! reset the ishutoff flag if at least on iteration 3 @@ -3997,13 +4070,13 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) this%ishutoff(n) = 1 end if q = DZERO - ! - ! -- leave well on and use the specified rate - ! or the potential rate + ! + ! -- leave well on and use the specified rate + ! or the potential rate end if end if - ! - ! -- try to use the specified rate or the potential rate + ! + ! -- try to use the specified rate or the potential rate else if (q > this%shutoffmax(n)) then if (this%ishutoffcnt <= 2) then @@ -4021,8 +4094,8 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) else scale = DONE ! - ! -- Apply rate scaling by reducing pumpage when hmaw is less than the - ! sum of maw pump elevation (pumpelev) and the specified reduction + ! -- Apply rate scaling by reducing pumpage when hmaw is less than the + ! sum of maw pump elevation (pumpelev) and the specified reduction ! length. The rate will go to zero as hmaw drops to the pump ! elevation. if (this%reduction_length(n) /= DEP20) then @@ -4032,7 +4105,7 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) end if q = scale * rate end if - ! + ! else ! ! -- Handle the injection case (rate > 0) differently than extraction. @@ -4053,25 +4126,25 @@ subroutine maw_calculate_wellq(this, n, hmaw, q) weight = this%shutoffweight(n) ! ! -- for flip-flop condition, decrease factor - if ( this%shutoffdq(n) * dq < DZERO ) then + if (this%shutoffdq(n) * dq < DZERO) then weight = this%theta * this%shutoffweight(n) - ! - ! -- when change is of same sign, increase factor + ! + ! -- when change is of same sign, increase factor else weight = this%shutoffweight(n) + this%kappa end if - if ( weight > DONE ) weight = DONE - + if (weight > DONE) weight = DONE + q = this%shutoffqold(n) + weight * dq - + this%shutoffqold(n) = q this%shutoffdq(n) = dq this%shutoffweight(n) = weight - + else scale = DONE ! - ! -- Apply rate scaling for an injection well by reducting the + ! -- Apply rate scaling for an injection well by reducting the ! injection rate as hmaw rises above the pump elevation. The rate ! will approach zero as hmaw approaches pumpelev + reduction_length. if (this%reduction_length(n) /= DEP20) then @@ -4094,9 +4167,9 @@ subroutine maw_calculate_qpot(this, n, qnet) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use TdisModule,only:delt + use TdisModule, only: delt ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: n real(DP), intent(inout) :: qnet ! -- local @@ -4114,20 +4187,32 @@ subroutine maw_calculate_qpot(this, n, qnet) real(DP) :: bmaw real(DP) :: htmp real(DP) :: hv + real(DP) :: vscratio ! -- format ! ------------------------------------------------------------------------------ ! ! -- initialize qnet and htmp qnet = DZERO + vscratio = DONE htmp = this%shutofflevel(n) ! + ! -- if vsc active, select appropriate viscosity ratio + if (this%ivsc == 1) then + ! flow out of well (flow is negative) + if (qnet < 0) then + vscratio = this%viscratios(1, igwfnode) + else + vscratio = this%viscratios(2, igwfnode) + end if + end if + ! ! -- calculate discharge to flowing wells if (this%iflowingwells > 0) then if (this%fwcond(n) > DZERO) then bt = this%fwelev(n) tp = bt + this%fwrlen(n) scale = sQSaturation(tp, bt, htmp) - cfw = scale * this%fwcond(n) + cfw = scale * this%fwcond(n) * this%viscratios(2, n) this%ifwdischarge(n) = 0 if (cfw > DZERO) then this%ifwdischarge(n) = 1 @@ -4152,7 +4237,7 @@ subroutine maw_calculate_qpot(this, n, qnet) jpos = this%get_jpos(n, j) igwfnode = this%get_gwfnode(n, j) call this%maw_calculate_saturation(n, j, igwfnode, sat) - cmaw = this%satcond(jpos) * sat + cmaw = this%satcond(jpos) * vscratio * sat hgwf = this%xnew(igwfnode) bmaw = this%botscrn(jpos) hv = htmp @@ -4170,72 +4255,72 @@ subroutine maw_calculate_qpot(this, n, qnet) end subroutine maw_calculate_qpot subroutine maw_cfupdate(this) - ! ****************************************************************************** - ! maw_cfupdate -- Update MAW satcond and package rhs and hcof - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - class(MawType) :: this - ! -- dummy - ! -- local - integer(I4B) :: j - integer(I4B) :: n - integer(I4B) :: jpos - integer(I4B) :: icflow - integer(I4B) :: ibnd - real(DP) :: flow - real(DP) :: cmaw - real(DP) :: hmaw - real(DP) :: cterm - real(DP) :: term + ! ****************************************************************************** + ! maw_cfupdate -- Update MAW satcond and package rhs and hcof + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + class(MawType) :: this + ! -- dummy + ! -- local + integer(I4B) :: j + integer(I4B) :: n + integer(I4B) :: jpos + integer(I4B) :: icflow + integer(I4B) :: ibnd + real(DP) :: flow + real(DP) :: cmaw + real(DP) :: hmaw + real(DP) :: cterm + real(DP) :: term ! ------------------------------------------------------------------------------ - ! - ! -- Return if no maw wells - if(this%nbound.eq.0) return - ! - ! -- Update shutoff count - this%ishutoffcnt = this%ishutoffcnt + 1 - ! - ! -- Calculate hcof and rhs for each maw entry - ibnd = 1 - do n = 1, this%nmawwells - hmaw = this%xnewpak(n) - do j = 1, this%ngwfnodes(n) - jpos = this%get_jpos(n, j) - this%hcof(ibnd) = DZERO - this%rhs(ibnd) = DZERO - ! - ! -- set bound, hcof, and rhs components - ! - ! -- use connection method so the gwf-maw budget flows - ! are consistent with the maw-gwf budget flows - if (this%iboundpak(n) == 0) then - cmaw = DZERO - term = DZERO - cterm = DZERO - else - call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, & - term, flow) - end if - this%simcond(jpos) = cmaw - this%bound(2,ibnd) = cmaw - this%hcof(ibnd) = -term - this%rhs(ibnd) = -term * hmaw + cterm - ! - ! -- increment boundary number - ibnd = ibnd + 1 - end do + ! + ! -- Return if no maw wells + if (this%nbound .eq. 0) return + ! + ! -- Update shutoff count + this%ishutoffcnt = this%ishutoffcnt + 1 + ! + ! -- Calculate hcof and rhs for each maw entry + ibnd = 1 + do n = 1, this%nmawwells + hmaw = this%xnewpak(n) + do j = 1, this%ngwfnodes(n) + jpos = this%get_jpos(n, j) + this%hcof(ibnd) = DZERO + this%rhs(ibnd) = DZERO + ! + ! -- set bound, hcof, and rhs components + ! + ! -- use connection method so the gwf-maw budget flows + ! are consistent with the maw-gwf budget flows + if (this%iboundpak(n) == 0) then + cmaw = DZERO + term = DZERO + cterm = DZERO + else + call this%maw_calculate_conn_terms(n, j, icflow, cmaw, cterm, & + term, flow) + end if + this%simcond(jpos) = cmaw + this%bound(2, ibnd) = cmaw + this%hcof(ibnd) = -term + this%rhs(ibnd) = -term * hmaw + cterm + ! + ! -- increment boundary number + ibnd = ibnd + 1 end do - ! - ! -- Return - return + end do + ! + ! -- Return + return end subroutine maw_cfupdate subroutine maw_setup_budobj(this) ! ****************************************************************************** ! maw_setup_budobj -- Set up the budget object that stores all the maw flows -! The terms listed here must correspond in number and order to the ones +! The terms listed here must correspond in number and order to the ones ! listed in the maw_fill_budobj routine. ! ****************************************************************************** ! @@ -4255,8 +4340,8 @@ subroutine maw_setup_budobj(this) character(len=LENBUDTXT), dimension(1) :: auxtxt ! ------------------------------------------------------------------------------ ! - ! -- Determine the number of maw budget terms. These are fixed for - ! the simulation and cannot change. + ! -- Determine the number of maw budget terms. These are fixed for + ! the simulation and cannot change. ! gwf rate [flowing_well] storage constant_flow [frommvr tomvr tomvrcf [tomvrfw]] [aux] nbudterm = 4 if (this%iflowingwells > 0) then @@ -4278,10 +4363,10 @@ subroutine maw_setup_budobj(this) ! ! -- Go through and set up each budget term ! - ! -- + ! -- text = ' GWF' idx = idx + 1 - maxlist = this%maxbound + maxlist = this%maxbound naux = 1 auxtxt(1) = ' FLOW-AREA' call this%budobj%budterm(idx)%initialize(text, & @@ -4300,20 +4385,20 @@ subroutine maw_setup_budobj(this) end do end do ! - ! -- + ! -- text = ' RATE' idx = idx + 1 maxlist = this%nmawwells naux = 0 call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- if (this%iflowingwells > 0) then text = ' FW-RATE' idx = idx + 1 @@ -4328,10 +4413,10 @@ subroutine maw_setup_budobj(this) naux) end if ! - ! -- + ! -- text = ' STORAGE' idx = idx + 1 - maxlist = this%nmawwells + maxlist = this%nmawwells naux = 1 auxtxt(1) = ' VOLUME' call this%budobj%budterm(idx)%initialize(text, & @@ -4342,7 +4427,7 @@ subroutine maw_setup_budobj(this) maxlist, .false., .true., & naux, auxtxt) ! - ! -- + ! -- text = ' CONSTANT' idx = idx + 1 maxlist = this%nmawwells @@ -4355,10 +4440,10 @@ subroutine maw_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- if (this%imover == 1) then ! - ! -- + ! -- text = ' FROM-MVR' idx = idx + 1 maxlist = this%nmawwells @@ -4371,7 +4456,7 @@ subroutine maw_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' RATE-TO-MVR' idx = idx + 1 maxlist = this%nmawwells @@ -4397,10 +4482,10 @@ subroutine maw_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- if (this%iflowingwells > 0) then ! - ! -- + ! -- text = ' FW-RATE-TO-MVR' idx = idx + 1 maxlist = this%nmawwells @@ -4415,11 +4500,11 @@ subroutine maw_setup_budobj(this) end if end if ! - ! -- + ! -- naux = this%naux if (naux > 0) then ! - ! -- + ! -- text = ' AUXILIARY' idx = idx + 1 maxlist = this%maxbound @@ -4638,7 +4723,7 @@ subroutine maw_fill_budobj(this) call this%budobj%budterm(idx)%update_term(n, n, q) end do end if - + end if ! ! -- AUXILIARY VARIABLES @@ -4661,9 +4746,9 @@ end subroutine maw_fill_budobj subroutine maw_setup_tableobj(this) ! ****************************************************************************** -! maw_setup_tableobj -- Set up the table object that is used to write the maw -! head data. The terms listed here must correspond in -! number and order to the ones written to the head table +! maw_setup_tableobj -- Set up the table object that is used to write the maw +! head data. The terms listed here must correspond in +! number and order to the ones written to the head table ! in the maw_ot method. ! ****************************************************************************** ! @@ -4687,12 +4772,12 @@ subroutine maw_setup_tableobj(this) if (this%inamedbound == 1) nterms = nterms + 1 ! ! -- set up table title - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') HEADS FOR EACH CONTROL VOLUME' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') HEADS FOR EACH CONTROL VOLUME' ! ! -- set up head tableobj call table_cr(this%headtab, this%packName, title) - call this%headtab%table_df(this%nmawwells, nterms, this%iout, & + call this%headtab%table_df(this%nmawwells, nterms, this%iout, & transient=.TRUE.) ! ! -- Go through and set up table budget term @@ -4770,7 +4855,7 @@ subroutine maw_activate_density(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this ! -- local integer(I4B) :: i, j ! -- formats @@ -4785,17 +4870,47 @@ subroutine maw_activate_density(this) this%denseterms(j, i) = DZERO end do end do - write(this%iout,'(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR MAW & - &PACKAGE: ' // trim(adjustl(this%packName)) + write (this%iout, '(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR MAW & + &PACKAGE: '//trim(adjustl(this%packName)) ! ! -- return return end subroutine maw_activate_density - subroutine maw_calculate_density_exchange(this, iconn, hmaw, hgwf, cond, & + !> @brief Activate viscosity terms + !! + !! Method to activate addition of viscosity terms for a MAW package reach. + !! + !< + subroutine maw_activate_viscosity(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(MawType), intent(inout) :: this !< MawType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND + this%ivsc = 1 + call mem_reallocate(this%viscratios, 2, this%MAXBOUND, 'VISCRATIOS', & + this%memoryPath) + do i = 1, this%maxbound + do j = 1, 2 + this%viscratios(j, i) = DONE + end do + end do + write (this%iout, '(/1x,a)') 'VISCOSITY HAS BEEN ACTIVATED FOR MAW & + &PACKAGE: '//trim(adjustl(this%packName)) + ! + ! -- return + return + end subroutine maw_activate_viscosity + + subroutine maw_calculate_density_exchange(this, iconn, hmaw, hgwf, cond, & bmaw, flow, hcofterm, rhsterm) ! ****************************************************************************** -! maw_calculate_density_exchange -- Calculate the groundwater-maw density +! maw_calculate_density_exchange -- Calculate the groundwater-maw density ! exchange terms. ! ! -- Arguments are as follows: @@ -4813,7 +4928,7 @@ subroutine maw_calculate_density_exchange(this, iconn, hmaw, hgwf, cond, & ! col 1 is relative density of maw (densemaw / denseref) ! col 2 is relative density of gwf cell (densegwf / denseref) ! col 3 is elevation of gwf cell -! +! ! -- Upon return, amat and rhs for maw row should be updated as: ! amat(idiag) = amat(idiag) - hcofterm ! rhs(n) = rhs(n) + rhsterm @@ -4823,7 +4938,7 @@ subroutine maw_calculate_density_exchange(this, iconn, hmaw, hgwf, cond, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(MawType),intent(inout) :: this + class(MawType), intent(inout) :: this integer(I4B), intent(in) :: iconn real(DP), intent(in) :: hmaw real(DP), intent(in) :: hgwf diff --git a/src/Model/GroundWaterFlow/gwf3mvr8.f90 b/src/Model/GroundWaterFlow/gwf3mvr8.f90 index 72d71a19e83..aca20a35f9a 100644 --- a/src/Model/GroundWaterFlow/gwf3mvr8.f90 +++ b/src/Model/GroundWaterFlow/gwf3mvr8.f90 @@ -2,7 +2,7 @@ !This module contains a derived type, called GwfMvrType, that !is attached to the GWF model. The water mover can be used to move water !between packages. The mover requires that mover-aware packages have access -!to four arrays: qtformvr, qformvr, qtomvr, and qfrommvr. These arrays are +!to four arrays: qtformvr, qformvr, qtomvr, and qfrommvr. These arrays are !stored and managed by a separate PackageMoverType object. qformvr is a !vector of volumetric flow rates available for the mover. The package !must fill the vector (dimensioned by number of reaches) with the available @@ -49,11 +49,11 @@ ! ! if(this%inmvr > 0) call this%mvr%mvr_ar() ! -! Mover aware packages allocate the four vectors. The first three +! Mover aware packages allocate the four vectors. The first three ! (qtformvr, qformvr, qtomvr) are allocated to the number of providers ! and the last one (qfrommvr) is allocated to the number of receivers. ! -! 4. In gwf_rp call the RP method for the mover. This reads the +! 4. In gwf_rp call the RP method for the mover. This reads the ! movers active for the current period. ! ! if(this%inmvr > 0) call this%mvr%mvr_rp() @@ -81,8 +81,8 @@ ! if(this%inmvr > 0) call this%mvr%mvr_fc() ! called from gwf%gwf_fc() ! ! a. Mover aware packages first set qformvr(:) = 0. -! b. Mover aware packages that are receivers (MAW, SFR, LAK, UZF) add -! qfrommvr terms to their individual control volume equations as a +! b. Mover aware packages that are receivers (MAW, SFR, LAK, UZF) add +! qfrommvr terms to their individual control volume equations as a ! source of water. ! c. Mover aware packages calculate qformvr as amount of water available ! to be moved (these qformvr terms are used in the next iteration @@ -102,44 +102,46 @@ ! if(this%inmvr > 0) call this%mvr%mvr_ot() ! module GwfMvrModule - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMEMPATH, LENPACKAGENAME, LENMODELNAME, & - LENBUDTXT, LENAUXNAME, LENPAKLOC, & - DZERO, DNODATA, MAXCHARLEN, TABCENTER, & - LINELENGTH - use MvrModule, only: MvrType - use BudgetModule, only: BudgetType, budget_cr - use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMEMPATH, LENPACKAGENAME, LENMODELNAME, & + LENBUDTXT, LENAUXNAME, LENPAKLOC, & + DZERO, DNODATA, MAXCHARLEN, TABCENTER, & + LINELENGTH + use MvrModule, only: MvrType + use BudgetModule, only: BudgetType, budget_cr + use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr use NumericalPackageModule, only: NumericalPackageType - use BlockParserModule, only: BlockParserType - use PackageMoverModule, only: PackageMoverType - use BaseDisModule, only: DisBaseType - use InputOutputModule, only: urword - use TableModule, only: TableType, table_cr + use BlockParserModule, only: BlockParserType + use GwfMvrPeriodDataModule, only: GwfMvrPeriodDataType + use PackageMoverModule, only: PackageMoverType + use BaseDisModule, only: DisBaseType + use InputOutputModule, only: urword + use TableModule, only: TableType, table_cr implicit none private public :: GwfMvrType, mvr_cr type, extends(NumericalPackageType) :: GwfMvrType - integer(I4B), pointer :: ibudgetout => null() !< binary budget output file - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file - integer(I4B), pointer :: maxmvr => null() !< max number of movers to be specified - integer(I4B), pointer :: maxpackages => null() !< max number of packages to be specified - integer(I4B), pointer :: maxcomb => null() !< max number of combination of packages - integer(I4B), pointer :: nmvr => null() !< number of movers for current stress period - integer(I4B), pointer :: iexgmvr => null() !< indicate mover is for an exchange (not for a single model) - integer(I4B), pointer :: imodelnames => null() !< indicate package input file has model names in it - integer(I4B), dimension(:), pointer, contiguous :: ientries => null() !< number of entries for each combination - character(len=LENMEMPATH), & - dimension(:), pointer, contiguous :: pckMemPaths !< memory paths of all packages used in this mover - character(len=LENPACKAGENAME), & - dimension(:), pointer, contiguous :: paknames => null() !< array of package names - type(MvrType), dimension(:), pointer, contiguous :: mvr => null() !< array of movers - type(BudgetType), pointer :: budget => null() !< mover budget object (used to write table) - type(BudgetObjectType), pointer :: budobj => null() !< new budget container (used to write binary file) - type(PackageMoverType), & - dimension(:), pointer, contiguous :: pakmovers => null() !< pointer to package mover objects + integer(I4B), pointer :: ibudgetout => null() !< binary budget output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + integer(I4B), pointer :: maxmvr => null() !< max number of movers to be specified + integer(I4B), pointer :: maxpackages => null() !< max number of packages to be specified + integer(I4B), pointer :: maxcomb => null() !< max number of combination of packages + integer(I4B), pointer :: nmvr => null() !< number of movers for current stress period + integer(I4B), pointer :: iexgmvr => null() !< indicate mover is for an exchange (not for a single model) + integer(I4B), pointer :: imodelnames => null() !< indicate package input file has model names in it + integer(I4B), dimension(:), pointer, contiguous :: ientries => null() !< number of entries for each combination + character(len=LENMEMPATH), & + dimension(:), pointer, contiguous :: pckMemPaths !< memory paths of all packages used in this mover + character(len=LENPACKAGENAME), & + dimension(:), pointer, contiguous :: paknames => null() !< array of package names + type(MvrType), dimension(:), pointer, contiguous :: mvr => null() !< array of movers + type(GwfMvrPeriodDataType), pointer :: gwfmvrperioddata => null() !< input data object + type(BudgetType), pointer :: budget => null() !< mover budget object (used to write table) + type(BudgetObjectType), pointer :: budobj => null() !< new budget container (used to write binary file) + type(PackageMoverType), & + dimension(:), pointer, contiguous :: pakmovers => null() !< pointer to package mover objects ! ! -- table objects type(TableType), pointer :: outputtab => null() @@ -169,7 +171,7 @@ module GwfMvrModule procedure, private :: mvr_print_outputtab end type GwfMvrType - contains +contains subroutine mvr_cr(mvrobj, name_parent, inunit, iout, dis, iexgmvr) ! ****************************************************************************** @@ -188,7 +190,7 @@ subroutine mvr_cr(mvrobj, name_parent, inunit, iout, dis, iexgmvr) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(mvrobj) + allocate (mvrobj) ! ! -- create name and memory paths. name_parent will either be model name or the ! exchange name. @@ -205,7 +207,7 @@ subroutine mvr_cr(mvrobj, name_parent, inunit, iout, dis, iexgmvr) mvrobj%iout = iout ! ! -- Set iexgmvr - if(present(iexgmvr)) mvrobj%iexgmvr = iexgmvr + if (present(iexgmvr)) mvrobj%iexgmvr = iexgmvr ! ! -- Create the budget object if (inunit > 0) then @@ -213,7 +215,7 @@ subroutine mvr_cr(mvrobj, name_parent, inunit, iout, dis, iexgmvr) ! ! -- Initialize block parser call mvrobj%parser%Initialize(mvrobj%inunit, mvrobj%iout) - endif + end if ! ! -- instantiate the budget object call budgetobject_cr(mvrobj%budobj, 'WATER MOVER') @@ -236,9 +238,9 @@ subroutine mvr_ar(this) ! ------------------------------------------------------------------------------ ! ! -- Print a message identifying the water mover package. - write(this%iout, 1) this%inunit - 1 format(1x,/1x,'MVR -- WATER MOVER PACKAGE, VERSION 8, 1/29/2016', & - ' INPUT READ FROM UNIT ', i0) + write (this%iout, 1) this%inunit +1 format(1x, /1x, 'MVR -- WATER MOVER PACKAGE, VERSION 8, 1/29/2016', & + ' INPUT READ FROM UNIT ', i0) ! ! -- Read and check options call this%read_options() @@ -280,18 +282,18 @@ subroutine mvr_rp(this) use SimModule, only: store_error, store_error_unit, count_errors use ArrayHandlersModule, only: ifind ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local integer(I4B) :: i, ierr, nlist, ipos integer(I4B) :: ii, jj - logical :: isfound, endOfBlock + logical :: isfound character(len=LINELENGTH) :: line, errmsg character(len=LENMODELNAME) :: mname ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" character(len=*), parameter :: fmtnbd = & "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6, & &') IS GREATER THAN MAXIMUM(',I6,')')" @@ -299,15 +301,16 @@ subroutine mvr_rp(this) ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -320,80 +323,73 @@ subroutine mvr_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- read data if ionper == kper - if(this%ionper == kper) then - write(this%iout, '(/,2x,a,i0)') 'READING WATER MOVERS FOR PERIOD ', kper + if (this%ionper == kper) then + write (this%iout, '(/,2x,a,i0)') 'READING WATER MOVERS FOR PERIOD ', kper nlist = -1 i = 1 ! ! -- set mname to '' if this is an exchange mover, or to the model name - if(this%iexgmvr == 0) then + if (this%iexgmvr == 0) then mname = this%name_model else mname = '' - endif + end if ! ! -- Assign a pointer to the package mover object. The pointer assignment ! will happen only the first time call this%assign_packagemovers() ! - ! -- Read each mover entry - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetCurrentLine(line) - ! - ! -- Raise error if movers exceeds maxmvr - if (i > this%maxmvr) then - write(errmsg,'(4x,a,a)') 'MOVERS EXCEED MAXMVR ON LINE: ', & - trim(adjustl(line)) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - ! - ! -- Process the water mover line (mname = '' if this is an exchange) - call this%mvr(i)%set(line, this%parser%iuactive, this%iout, mname, & - this%pckMemPaths, this%pakmovers) - ! - ! -- Echo input - if(this%iprpak == 1) call this%mvr(i)%echo(this%iout) - ! - ! -- increment counter - i = i + 1 + ! -- Call the period data input reader + call this%gwfmvrperioddata%read_from_parser(this%parser, nlist, mname) + ! + ! -- Process the input data into the individual mover objects + do i = 1, nlist + call this%mvr(i)%set_values(this%gwfmvrperioddata%mname1(i), & + this%gwfmvrperioddata%pname1(i), & + this%gwfmvrperioddata%id1(i), & + this%gwfmvrperioddata%mname2(i), & + this%gwfmvrperioddata%pname2(i), & + this%gwfmvrperioddata%id2(i), & + this%gwfmvrperioddata%imvrtype(i), & + this%gwfmvrperioddata%value(i)) + call this%mvr(i)%prepare(this%parser%iuactive, & + this%pckMemPaths, & + this%pakmovers) + if (this%iprpak == 1) call this%mvr(i)%echo(this%iout) end do - write(this%iout,'(/,1x,a,1x,i6,/)') 'END OF DATA FOR PERIOD', kper - nlist = i - 1 + write (this%iout, '(/,1x,a,1x,i6,/)') 'END OF DATA FOR PERIOD', kper ! ! -- Set the number of movers for this period to nlist this%nmvr = nlist - write(this%iout, '(4x, i0, a, i0)') this%nmvr, & + write (this%iout, '(4x, i0, a, i0)') this%nmvr, & ' MOVERS READ FOR PERIOD ', kper ! ! -- Check to make sure all providers and receivers are properly stored do i = 1, this%nmvr ipos = ifind(this%pckMemPaths, this%mvr(i)%pckNameSrc) - if(ipos < 1) then - write(errmsg,'(4x,a,a,a)') 'PROVIDER ', & + if (ipos < 1) then + write (errmsg, '(4x,a,a,a)') 'PROVIDER ', & trim(this%mvr(i)%pckNameSrc), ' NOT LISTED IN PACKAGES BLOCK.' call store_error(errmsg) - endif + end if ipos = ifind(this%pckMemPaths, this%mvr(i)%pckNameTgt) - if(ipos < 1) then - write(errmsg,'(4x,a,a,a)') 'RECEIVER ', & + if (ipos < 1) then + write (errmsg, '(4x,a,a,a)') 'RECEIVER ', & trim(this%mvr(i)%pckNameTgt), ' NOT LISTED IN PACKAGES BLOCK.' call store_error(errmsg) - endif - enddo - if(count_errors() > 0) then + end if + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- reset ientries do i = 1, this%maxcomb @@ -408,9 +404,9 @@ subroutine mvr_rp(this) this%ientries(ipos) = this%ientries(ipos) + 1 end do else - write(this%iout, fmtlsp) 'MVR' + write (this%iout, fmtlsp) 'MVR' ! - endif + end if ! ! -- return return @@ -432,7 +428,7 @@ subroutine mvr_ad(this) ! do i = 1, this%nmvr call this%mvr(i)%advance() - enddo + end do ! ! -- Return return @@ -454,7 +450,7 @@ subroutine mvr_fc(this) ! do i = 1, this%nmvr call this%mvr(i)%fc() - enddo + end do ! ! -- Return return @@ -469,16 +465,16 @@ subroutine mvr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfMvrType) :: this - integer(I4B),intent(in) :: innertot - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: iend - integer(I4B),intent(in) :: icnvgmod + integer(I4B), intent(in) :: innertot + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: iend + integer(I4B), intent(in) :: icnvgmod character(len=LENPAKLOC), intent(inout) :: cpak integer(I4B), intent(inout) :: ipak real(DP), intent(inout) :: dpak ! -- local ! -- formats - character(len=*),parameter :: fmtmvrcnvg = & + character(len=*), parameter :: fmtmvrcnvg = & "(/,1x,'MOVER PACKAGE REQUIRES AT LEAST TWO OUTER ITERATIONS. CONVERGE & &FLAG HAS BEEN RESET TO FALSE.')" ! ------------------------------------------------------------------------------ @@ -488,14 +484,14 @@ subroutine mvr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) if (icnvgmod == 1 .and. kiter == 1) then dpak = DNODATA cpak = trim(this%packName) - write(this%iout, fmtmvrcnvg) - endif - endif + write (this%iout, fmtmvrcnvg) + end if + end if ! ! -- return return end subroutine mvr_cc - + subroutine mvr_bd(this) ! ****************************************************************************** ! mvr_bd -- fill the mover budget object @@ -504,7 +500,6 @@ subroutine mvr_bd(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use InputOutputModule, only: ubdsv06, ubdsvd ! -- dummy class(GwfMvrType) :: this ! -- locals @@ -526,8 +521,7 @@ subroutine mvr_bdsav(this, icbcfl, ibudfl, isuppress_output) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use TdisModule, only : kstp, kper, delt, pertim, totim - use InputOutputModule, only: ubdsv06, ubdsvd + use TdisModule, only: kstp, kper, delt, pertim, totim ! -- dummy class(GwfMvrType) :: this integer(I4B), intent(in) :: icbcfl @@ -537,7 +531,7 @@ subroutine mvr_bdsav(this, icbcfl, ibudfl, isuppress_output) integer(I4B) :: ibinun ! -- formats character(len=*), parameter :: fmttkk = & - "(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" + "(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" ! ------------------------------------------------------------------------------ ! ! -- Print the mover flow table @@ -547,14 +541,14 @@ subroutine mvr_bdsav(this, icbcfl, ibudfl, isuppress_output) ! ! -- Save the mover flows from the budobj to a mover binary file ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (isuppress_output /= 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & - pertim, totim, this%iout) + pertim, totim, this%iout) end if ! ! -- Return @@ -569,7 +563,7 @@ subroutine mvr_ot_saveflow(this, icbcfl, ibudfl) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use TdisModule, only : kstp, kper, delt, pertim, totim + use TdisModule, only: kstp, kper, delt, pertim, totim ! -- dummy class(GwfMvrType) :: this integer(I4B), intent(in) :: icbcfl @@ -580,13 +574,13 @@ subroutine mvr_ot_saveflow(this, icbcfl, ibudfl) ! ! -- Save the mover flows from the budobj to a mover binary file ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & - pertim, totim, this%iout) + pertim, totim, this%iout) end if ! ! -- Return @@ -637,34 +631,34 @@ subroutine mvr_ot_bdsummary(this, ibudfl) ! ------------------------------------------------------------------------------ ! ! -- Allocate and initialize ratin/ratout - allocate(ratin(this%maxpackages), ratout(this%maxpackages)) + allocate (ratin(this%maxpackages), ratout(this%maxpackages)) do j = 1, this%maxpackages ratin(j) = DZERO ratout(j) = DZERO - enddo + end do ! ! -- Accumulate the rates do i = 1, this%nmvr do j = 1, this%maxpackages - if(this%pckMemPaths(j) == this%mvr(i)%pckNameSrc) then + if (this%pckMemPaths(j) == this%mvr(i)%pckNameSrc) then ratin(j) = ratin(j) + this%mvr(i)%qpactual - endif - if(this%pckMemPaths(j) == this%mvr(i)%pckNameTgt) then + end if + if (this%pckMemPaths(j) == this%mvr(i)%pckNameTgt) then ratout(j) = ratout(j) + this%mvr(i)%qpactual - endif - enddo - enddo + end if + end do + end do ! ! -- Send rates to budget object call this%budget%reset() do j = 1, this%maxpackages - if((this%iexgmvr) == 1) then + if ((this%iexgmvr) == 1) then pckMemPath = this%pckMemPaths(j) else pckMemPath = this%paknames(j) - endif + end if call this%budget%addentry(ratin(j), ratout(j), delt, pckMemPath) - enddo + end do ! ! -- Write the budget if (ibudfl /= 0) then @@ -675,7 +669,7 @@ subroutine mvr_ot_bdsummary(this, ibudfl) call this%budget%writecsv(totim) ! ! -- Deallocate - deallocate(ratin, ratout) + deallocate (ratin, ratout) ! ! -- Output mvr budget ! Not using budobj write_table here because it would result @@ -705,27 +699,32 @@ subroutine mvr_da(this) ! -- Arrays if (this%inunit > 0) then call mem_deallocate(this%ientries) - deallocate(this%mvr) - deallocate(this%pckMemPaths) - deallocate(this%paknames) - deallocate(this%pakmovers) + deallocate (this%mvr) + deallocate (this%pckMemPaths) + deallocate (this%paknames) + deallocate (this%pakmovers) + ! + ! -- allocate the perioddata object + call this%gwfmvrperioddata%destroy() + deallocate (this%gwfmvrperioddata) + nullify (this%gwfmvrperioddata) ! ! -- budget object call this%budget%budget_da() - deallocate(this%budget) + deallocate (this%budget) ! ! -- budobj call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- output table object if (associated(this%outputtab)) then call this%outputtab%table_da() - deallocate(this%outputtab) - nullify(this%outputtab) + deallocate (this%outputtab) + nullify (this%outputtab) end if - endif + end if ! ! -- Scalars call mem_deallocate(this%ibudgetout) @@ -764,77 +763,78 @@ subroutine read_options(this) integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*),parameter :: fmtmvrbin = & + character(len=*), parameter :: fmtmvrbin = & "(4x, 'MVR ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON & &UNIT: ', I0)" ! ------------------------------------------------------------------------------ ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING MVR OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING MVR OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE') - write(this%iout,fmtmvrbin) 'BUDGET', fname, this%ibudgetout - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtmvrbin) 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'WATER MOVER INPUT '// & - 'WILL BE PRINTED TO LIST FILE.' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') 'LISTS OF WATER MOVER FLOWS '// & - 'WILL BE PRINTED TO LIST FILE.' - case ('MODELNAMES') - this%imodelnames = 1 - write(this%iout,'(4x,a)') 'ALL PACKAGE NAMES ARE PRECEDED '// & - 'BY THE NAME OF THE MODEL CONTAINING THE PACKAGE.' - if (this%iexgmvr == 0) then - write(errmsg,'(4x,a,a)') & - 'MODELNAMES CANNOT BE SPECIFIED UNLESS THE ' // & - 'MOVER PACKAGE IS FOR AN EXCHANGE.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - case default - write(errmsg,'(4x,a,a)') 'Unknown MVR option: ', trim(keyword) + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtmvrbin) 'BUDGET', fname, this%ibudgetout + else + call store_error('OPTIONAL BUDGET KEYWORD MUST & + &BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtmvrbin) 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') 'WATER MOVER INPUT '// & + 'WILL BE PRINTED TO LIST FILE.' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') 'LISTS OF WATER MOVER FLOWS '// & + 'WILL BE PRINTED TO LIST FILE.' + case ('MODELNAMES') + this%imodelnames = 1 + write (this%iout, '(4x,a)') 'ALL PACKAGE NAMES ARE PRECEDED '// & + 'BY THE NAME OF THE MODEL CONTAINING THE PACKAGE.' + if (this%iexgmvr == 0) then + write (errmsg, '(4x,a,a)') & + 'MODELNAMES CANNOT BE SPECIFIED UNLESS THE '// & + 'MOVER PACKAGE IS FOR AN EXCHANGE.' call store_error(errmsg) call this%parser%StoreErrorUnit() + end if + case default + write (errmsg, '(4x,a,a)') 'Unknown MVR option: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF MVR OPTIONS' + write (this%iout, '(1x,a)') 'END OF MVR OPTIONS' end if ! ! -- Return return - end subroutine read_options + end subroutine read_options subroutine check_options(this) ! ****************************************************************************** @@ -855,21 +855,21 @@ subroutine check_options(this) ! ! -- Check if not exchange mover but model names are specified if (this%iexgmvr == 0 .and. this%imodelnames == 1) then - write(errmsg,'(4x,a,a)') & - '****ERROR. MODELNAMES CANNOT BE SPECIFIED UNLESS THE ' // & + write (errmsg, '(4x,a,a)') & + '****ERROR. MODELNAMES CANNOT BE SPECIFIED UNLESS THE '// & 'MOVER PACKAGE IS FOR AN EXCHANGE.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Check if exchange mover but model names not specified if (this%iexgmvr /= 0 .and. this%imodelnames == 0) then - write(errmsg,'(4x,a,a)') & - '****ERROR. MODELNAMES OPTION MUST BE SPECIFIED BECAUSE ' // & + write (errmsg, '(4x,a,a)') & + '****ERROR. MODELNAMES OPTION MUST BE SPECIFIED BECAUSE '// & 'MOVER PACKAGE IS FOR AN EXCHANGE.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return @@ -886,9 +886,9 @@ subroutine read_dimensions(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: errmsg, keyword + character(len=LINELENGTH) :: errmsg, keyword integer(I4B) :: ierr logical :: isfound, endOfBlock integer(I4B) :: i @@ -902,26 +902,26 @@ subroutine read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING MVR DIMENSIONS' + write (this%iout, '(/1x,a)') 'PROCESSING MVR DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('MAXMVR') - this%maxmvr = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)')'MAXMVR = ', this%maxmvr - case ('MAXPACKAGES') - this%maxpackages = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)')'MAXPACKAGES = ', this%maxpackages - case default - write(errmsg,'(4x,a,a)') & - 'Unknown MVR dimension: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('MAXMVR') + this%maxmvr = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'MAXMVR = ', this%maxmvr + case ('MAXPACKAGES') + this%maxpackages = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'MAXPACKAGES = ', this%maxpackages + case default + write (errmsg, '(4x,a,a)') & + 'Unknown MVR dimension: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF MVR DIMENSIONS' + write (this%iout, '(1x,a)') 'END OF MVR DIMENSIONS' else call store_error('Required DIMENSIONS block not found.') call this%parser%StoreErrorUnit() @@ -936,18 +936,18 @@ subroutine read_dimensions(this) end do ! ! -- verify dimensions were set - if(this%maxmvr < 0) then - write(errmsg, '(1x,a)') & + if (this%maxmvr < 0) then + write (errmsg, '(1x,a)') & 'MAXMVR was not specified or was specified incorrectly.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif - if(this%maxpackages < 0) then - write(errmsg, '(1x,a)') & + end if + if (this%maxpackages < 0) then + write (errmsg, '(1x,a)') & 'MAXPACKAGES was not specified or was specified incorrectly.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -965,9 +965,9 @@ subroutine read_packages(this) use MemoryHelperModule, only: create_mem_path use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: errmsg, word, word1, word2 + character(len=LINELENGTH) :: errmsg, word, word1, word2 integer(I4B) :: lloc, ierr integer(I4B) :: npak logical :: isfound, endOfBlock @@ -980,7 +980,7 @@ subroutine read_packages(this) ! ! -- parse packages block if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING MVR PACKAGES' + write (this%iout, '(/1x,a)') 'PROCESSING MVR PACKAGES' npak = 0 do call this%parser%GetNextLine(endOfBlock) @@ -991,8 +991,8 @@ subroutine read_packages(this) if (npak > this%maxpackages) then call store_error('ERROR. MAXPACKAGES NOT SET LARGE ENOUGH.') call this%parser%StoreErrorUnit() - endif - if(this%iexgmvr == 0) then + end if + if (this%iexgmvr == 0) then this%pckMemPaths(npak) = create_mem_path(this%name_model, word1) word = word1 else @@ -1000,25 +1000,25 @@ subroutine read_packages(this) call this%parser%GetStringCaps(word2) this%pckMemPaths(npak) = create_mem_path(this%pckMemPaths(npak), word2) word = word2 - endif + end if this%paknames(npak) = trim(word) - write(this%iout,'(3x,a,a)')'INCLUDING PACKAGE: ', & + write (this%iout, '(3x,a,a)') 'INCLUDING PACKAGE: ', & trim(this%pckMemPaths(npak)) end do - write(this%iout,'(1x,a)')'END OF MVR PACKAGES' + write (this%iout, '(1x,a)') 'END OF MVR PACKAGES' else call store_error('ERROR. REQUIRED PACKAGES BLOCK NOT FOUND.') call this%parser%StoreErrorUnit() end if ! ! -- Check to make sure npak = this%maxpackages - if(npak /= this%maxpackages) then - write(errmsg, '(a, i0, a, i0, a)') & - 'ERROR. NUMBER OF PACKAGES (', npak, ') DOES NOT EQUAL ' // & + if (npak /= this%maxpackages) then + write (errmsg, '(a, i0, a, i0, a)') & + 'ERROR. NUMBER OF PACKAGES (', npak, ') DOES NOT EQUAL '// & 'MAXPACKAGES (', this%maxpackages, ').' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -1036,9 +1036,9 @@ subroutine check_packages(this) use MemoryManagerModule, only: mem_setptr use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: errmsg + character(len=LINELENGTH) :: errmsg integer(I4B) :: i integer(I4B), pointer :: imover_ptr ! -- format @@ -1049,10 +1049,10 @@ subroutine check_packages(this) imover_ptr => null() call mem_setptr(imover_ptr, 'IMOVER', trim(this%pckMemPaths(i))) if (imover_ptr == 0) then - write(errmsg, '(a, a, a)') & - 'ERROR. MODEL AND PACKAGE "', & - trim(this%pckMemPaths(i)), & - '" DOES NOT HAVE MOVER SPECIFIED IN OPTIONS BLOCK.' + write (errmsg, '(a, a, a)') & + 'ERROR. MODEL AND PACKAGE "', & + trim(this%pckMemPaths(i)), & + '" DOES NOT HAVE MOVER SPECIFIED IN OPTIONS BLOCK.' call store_error(errmsg) end if end do @@ -1060,7 +1060,7 @@ subroutine check_packages(this) ! -- Terminate if errors detected. if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -1076,7 +1076,7 @@ subroutine assign_packagemovers(this) ! -- modules use PackageMoverModule, only: set_packagemover_pointer ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local integer(I4B) :: i ! -- format @@ -1132,6 +1132,9 @@ subroutine allocate_scalars(this) this%iexgmvr = 0 this%imodelnames = 0 ! + ! -- allocate the period data input object + allocate (this%gwfmvrperioddata) + ! ! -- Return return end subroutine allocate_scalars @@ -1154,16 +1157,20 @@ subroutine allocate_arrays(this) ! ------------------------------------------------------------------------------ ! ! -- Allocate - allocate(this%mvr(this%maxmvr)) - allocate(this%pckMemPaths(this%maxpackages)) - allocate(this%paknames(this%maxpackages)) - allocate(this%pakmovers(this%maxpackages)) + allocate (this%mvr(this%maxmvr)) + allocate (this%pckMemPaths(this%maxpackages)) + allocate (this%paknames(this%maxpackages)) + allocate (this%pakmovers(this%maxpackages)) ! ! -- nullify the pakmovers do i = 1, this%maxpackages call nulllify_packagemover_pointer(this%pakmovers(i)) end do ! + ! -- allocate the perioddata object + call this%gwfmvrperioddata%construct(this%maxmvr, this%memoryPath) + ! + ! ! -- allocate the object and assign values to object variables call mem_allocate(this%ientries, this%maxcomb, 'IENTRIES', this%memoryPath) ! @@ -1197,14 +1204,14 @@ subroutine mvr_setup_budobj(this) integer(I4B) :: i integer(I4B) :: j integer(I4B) :: naux - character (len=LENMODELNAME) :: modelname1, modelname2 - character (len=LENPACKAGENAME) :: packagename1, packagename2 + character(len=LENMODELNAME) :: modelname1, modelname2 + character(len=LENPACKAGENAME) :: packagename1, packagename2 integer(I4B) :: maxlist integer(I4B) :: idx character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! - ! -- Determine the number of mover budget terms. These are fixed for + ! -- Determine the number of mover budget terms. These are fixed for ! the simulation and cannot change. A separate term is required ! for each possible provider/receiver combination. nbudterm = 0 @@ -1227,11 +1234,11 @@ subroutine mvr_setup_budobj(this) maxlist = this%maxmvr naux = 0 do i = 1, this%maxpackages - + call split_mem_path(this%pckMemPaths(i), modelname1, packagename1) - - do j = 1, this%maxpackages - + + do j = 1, this%maxpackages + idx = idx + 1 call split_mem_path(this%pckMemPaths(j), modelname2, packagename2) call this%budobj%budterm(idx)%initialize(text, & @@ -1270,9 +1277,9 @@ subroutine mvr_fill_budobj(this) integer(I4B) :: istart integer(I4B) :: istop real(DP) :: rval - character (len=LENMODELNAME) :: modelname1, modelname2 - character (len=LENPACKAGENAME) :: packagename1, packagename2 - character (len=LENMEMPATH) :: pckMemPathsDummy + character(len=LENMODELNAME) :: modelname1, modelname2 + character(len=LENPACKAGENAME) :: packagename1, packagename2 + character(len=LENMEMPATH) :: pckMemPathsDummy real(DP) :: q ! -- formats ! ----------------------------------------------------------------------------- @@ -1280,7 +1287,6 @@ subroutine mvr_fill_budobj(this) ! -- initialize counter idx = 0 - do i = 1, this%maxpackages ! -- Retrieve modelname1 and packagename1 lloc = 1 @@ -1293,10 +1299,12 @@ subroutine mvr_fill_budobj(this) do j = 1, this%maxpackages ! -- Retrieve modelname2 and packagename2 lloc = 1 - call urword(this%pckMemPaths(j), lloc, istart, istop, 1, ival, rval, -1, -1) + call urword(this%pckMemPaths(j), lloc, istart, istop, 1, ival, rval, & + -1, -1) pckMemPathsDummy = this%pckMemPaths(j) modelname2 = pckMemPathsDummy(istart:istop) - call urword(this%pckMemPaths(j), lloc, istart, istop, 1, ival, rval, -1, -1) + call urword(this%pckMemPaths(j), lloc, istart, istop, 1, ival, rval, & + -1, -1) pckMemPathsDummy = this%pckMemPaths(j) packagename2 = pckMemPathsDummy(istart:istop) ipos = (i - 1) * this%maxpackages + j @@ -1311,8 +1319,8 @@ subroutine mvr_fill_budobj(this) ! ! -- pname1 is provider, pname2 is receiver ! flow is always negative because it is coming from provider - if(this%pckMemPaths(i) == this%mvr(n)%pckNameSrc) then - if(this%pckMemPaths(j) == this%mvr(n)%pckNameTgt) then + if (this%pckMemPaths(i) == this%mvr(n)%pckNameSrc) then + if (this%pckMemPaths(j) == this%mvr(n)%pckNameTgt) then ! ! -- set q to qpactual q = -this%mvr(n)%qpactual @@ -1347,7 +1355,7 @@ subroutine mvr_setup_outputtab(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -1362,15 +1370,15 @@ subroutine mvr_setup_outputtab(this) ntabcol = 7 ! ! -- initialize the output table object - title = 'WATER MOVER PACKAGE (' // trim(this%packName) // & + title = 'WATER MOVER PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call table_cr(this%outputtab, this%packName, title) - call this%outputtab%table_df(this%maxmvr, ntabcol, this%iout, & - transient=.TRUE.) + call this%outputtab%table_df(this%maxmvr, ntabcol, this%iout, & + transient=.TRUE.) text = 'NUMBER' call this%outputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'PROVIDER LOCATION' - ilen = LENMODELNAME+LENPACKAGENAME+1 + ilen = LENMODELNAME + LENPACKAGENAME + 1 call this%outputtab%initialize_column(text, ilen) text = 'PROVIDER ID' call this%outputtab%initialize_column(text, 10) @@ -1379,11 +1387,11 @@ subroutine mvr_setup_outputtab(this) text = 'PROVIDED RATE' call this%outputtab%initialize_column(text, 10) text = 'RECEIVER LOCATION' - ilen = LENMODELNAME+LENPACKAGENAME+1 + ilen = LENMODELNAME + LENPACKAGENAME + 1 call this%outputtab%initialize_column(text, ilen) text = 'RECEIVER ID' call this%outputtab%initialize_column(text, 10) - + end if ! ! -- return @@ -1400,9 +1408,9 @@ subroutine mvr_print_outputtab(this) ! -- module use TdisModule, only: kstp, kper ! -- dummy - class(GwfMvrType),intent(inout) :: this + class(GwfMvrType), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: title + character(len=LINELENGTH) :: title integer(I4B) :: i ! ------------------------------------------------------------------------------ ! @@ -1410,7 +1418,7 @@ subroutine mvr_print_outputtab(this) call this%outputtab%set_kstpkper(kstp, kper) ! ! -- Add terms and print the table - title = 'WATER MOVER PACKAGE (' // trim(this%packName) // & + title = 'WATER MOVER PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call this%outputtab%set_title(title) call this%outputtab%set_maxbound(this%nmvr) diff --git a/src/Model/GroundWaterFlow/gwf3npf8.f90 b/src/Model/GroundWaterFlow/gwf3npf8.f90 index c9756115bbd..7d38192c9ec 100644 --- a/src/Model/GroundWaterFlow/gwf3npf8.f90 +++ b/src/Model/GroundWaterFlow/gwf3npf8.f90 @@ -1,20 +1,24 @@ module GwfNpfModule - use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DEM9, DEM8, DEM7, DEM6, DEM2, & - DHALF, DP9, DONE, DTWO, & - DLNLOW, DLNHIGH, & - DHNOFLO, DHDRY, DEM10 - use SmoothingModule, only: sQuadraticSaturation, & - sQuadraticSaturationDerivative - use NumericalPackageModule, only: NumericalPackageType - use GwfNpfGridDataModule, only: GwfNpfGridDataType - use GwfNpfOptionsModule, only: GwfNpfOptionsType - use BaseDisModule, only: DisBaseType - use GwfIcModule, only: GwfIcType - use Xt3dModule, only: Xt3dType - use BlockParserModule, only: BlockParserType - use InputOutputModule, only: GetUnit, openfile - use TvkModule, only: TvkType, tvk_cr + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, DEM9, DEM8, DEM7, DEM6, DEM2, & + DHALF, DP9, DONE, DTWO, & + DLNLOW, DLNHIGH, & + DHNOFLO, DHDRY, DEM10, & + LENMEMPATH, LENVARNAME, LINELENGTH + use SmoothingModule, only: sQuadraticSaturation, & + sQuadraticSaturationDerivative + use NumericalPackageModule, only: NumericalPackageType + use GwfNpfOptionsModule, only: GwfNpfOptionsType + use BaseDisModule, only: DisBaseType + use GwfIcModule, only: GwfIcType + use GwfVscModule, only: GwfVscType + use Xt3dModule, only: Xt3dType + use BlockParserModule, only: BlockParserType + use InputOutputModule, only: GetUnit, openfile + use TvkModule, only: TvkType, tvk_cr + use MemoryManagerModule, only: mem_allocate, mem_reallocate, & + mem_deallocate, mem_setptr, & + mem_reassignptr implicit none @@ -29,131 +33,144 @@ module GwfNpfModule type, extends(NumericalPackageType) :: GwfNpfType - type(GwfIcType), pointer :: ic => null() !< initial conditions object - type(Xt3dType), pointer :: xt3d => null() !< xt3d pointer - integer(I4B), pointer :: iname => null() !< length of variable names - character(len=24), dimension(:), pointer :: aname => null() !< variable names - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - real(DP), dimension(:), pointer, contiguous :: hnew => null() !< pointer to model xnew - integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs) - integer(I4B), pointer :: iperched => null() !< vertical flow corrections if 1 - integer(I4B), pointer :: ivarcv => null() !< CV is function of water table - integer(I4B), pointer :: idewatcv => null() !< CV may be a discontinuous function of water table - integer(I4B), pointer :: ithickstrt => null() !< thickstrt option flag - integer(I4B), pointer :: igwfnewtonur => null() !< newton head dampening using node bottom option flag - integer(I4B), pointer :: iusgnrhc => null() !< MODFLOW-USG saturation calculation option flag - integer(I4B), pointer :: inwtupw => null() !< MODFLOW-NWT upstream weighting option flag - integer(I4B), pointer :: icalcspdis => null() !< Calculate specific discharge at cell centers - integer(I4B), pointer :: isavspdis => null() !< Save specific discharge at cell centers - integer(I4B), pointer :: isavsat => null() !< Save sat to budget file - real(DP), pointer :: hnoflo => null() !< default is 1.e30 - real(DP), pointer :: satomega => null() !< newton-raphson saturation omega - integer(I4B),pointer :: irewet => null() !< rewetting (0:off, 1:on) - integer(I4B),pointer :: iwetit => null() !< wetting interval (default is 1) - integer(I4B),pointer :: ihdwet => null() !< (0 or not 0) - integer(I4B), pointer :: icellavg => null() !< harmonic(0), logarithmic(1), or arithmetic thick-log K (2) - real(DP), pointer :: wetfct => null() !< wetting factor - real(DP), pointer :: hdry => null() !< default is -1.d30 - integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< confined (0) or convertible (1) - integer(I4B), dimension(:), pointer, contiguous:: ithickstartflag => null() !< array of flags for handling the thickstrt option + type(GwfIcType), pointer :: ic => null() !< initial conditions object + type(GwfVscType), pointer :: vsc => null() !< viscosity object + type(Xt3dType), pointer :: xt3d => null() !< xt3d pointer + integer(I4B), pointer :: iname => null() !< length of variable names + character(len=24), dimension(:), pointer :: aname => null() !< variable names + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + real(DP), dimension(:), pointer, contiguous :: hnew => null() !< pointer to model xnew + integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs) + integer(I4B), pointer :: ixt3drhs => null() !< xt3d rhs flag, xt3d rhs is set active if 1 + integer(I4B), pointer :: iperched => null() !< vertical flow corrections if 1 + integer(I4B), pointer :: ivarcv => null() !< CV is function of water table + integer(I4B), pointer :: idewatcv => null() !< CV may be a discontinuous function of water table + integer(I4B), pointer :: ithickstrt => null() !< thickstrt option flag + integer(I4B), pointer :: igwfnewtonur => null() !< newton head dampening using node bottom option flag + integer(I4B), pointer :: iusgnrhc => null() !< MODFLOW-USG saturation calculation option flag + integer(I4B), pointer :: inwtupw => null() !< MODFLOW-NWT upstream weighting option flag + integer(I4B), pointer :: icalcspdis => null() !< Calculate specific discharge at cell centers + integer(I4B), pointer :: isavspdis => null() !< Save specific discharge at cell centers + integer(I4B), pointer :: isavsat => null() !< Save sat to budget file + real(DP), pointer :: hnoflo => null() !< default is 1.e30 + real(DP), pointer :: satomega => null() !< newton-raphson saturation omega + integer(I4B), pointer :: irewet => null() !< rewetting (0:off, 1:on) + integer(I4B), pointer :: iwetit => null() !< wetting interval (default is 1) + integer(I4B), pointer :: ihdwet => null() !< (0 or not 0) + integer(I4B), pointer :: icellavg => null() !< harmonic(0), logarithmic(1), or arithmetic thick-log K (2) + real(DP), pointer :: wetfct => null() !< wetting factor + real(DP), pointer :: hdry => null() !< default is -1.d30 + integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< confined (0) or convertible (1) + integer(I4B), dimension(:), pointer, contiguous :: ithickstartflag => null() !< array of flags for handling the thickstrt option ! ! K properties - real(DP), dimension(:), pointer, contiguous :: k11 => null() !< hydraulic conductivity; if anisotropic, then this is Kx prior to rotation - real(DP), dimension(:), pointer, contiguous :: k22 => null() !< hydraulic conductivity; if specified then this is Ky prior to rotation - real(DP), dimension(:), pointer, contiguous :: k33 => null() !< hydraulic conductivity; if specified then this is Kz prior to rotation - integer(I4B), pointer :: iavgkeff => null() !< effective conductivity averaging (0: harmonic, 1: arithmetic) - integer(I4B), pointer :: ik22 => null() !< flag that k22 is specified - integer(I4B), pointer :: ik33 => null() !< flag that k33 is specified - integer(I4B), pointer :: ik22overk => null() !< flag that k22 is specified as anisotropy ratio - integer(I4B), pointer :: ik33overk => null() !< flag that k33 is specified as anisotropy ratio - integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read - integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read - integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read - real(DP), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw) - real(DP), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch) - real(DP), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll) - ! - integer(I4B), pointer :: iwetdry => null() !< flag to indicate angle1 was read - real(DP), dimension(:), pointer, contiguous :: wetdry => null() !< wetdry array - real(DP), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell - real(DP), dimension(:), pointer, contiguous :: condsat => null() !< saturated conductance (symmetric array) - real(DP), pointer :: satmin => null() !< minimum saturated thickness - integer(I4B), dimension(:), pointer, contiguous :: ibotnode => null() !< bottom node used if igwfnewtonur /= 0 - ! - real(DP), dimension(:, :), pointer, contiguous :: spdis => null() !< specific discharge : qx, qy, qz (nodes, 3) - integer(I4B), pointer :: nedges => null() !< number of cell edges - integer(I4B), pointer :: lastedge => null() !< last edge number - integer(I4B), dimension(:), pointer, contiguous :: nodedge => null() !< array of node numbers that have edges - integer(I4B), dimension(:), pointer, contiguous :: ihcedge => null() !< edge type (horizontal or vertical) - real(DP), dimension(:, :), pointer, contiguous :: propsedge => null() !< edge properties (Q, area, nx, ny, distance) - ! - integer(I4B), pointer :: intvk => null() ! TVK (time-varying K) unit number (0 if unused) - type(TvkType), pointer :: tvk => null() ! TVK object - integer(I4B), pointer :: kchangeper => null() ! last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) - integer(I4B), pointer :: kchangestp => null() ! last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) - integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() ! grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0) + real(DP), dimension(:), pointer, contiguous :: k11 => null() !< hydraulic conductivity; if anisotropic, then this is Kx prior to rotation + real(DP), dimension(:), pointer, contiguous :: k22 => null() !< hydraulic conductivity; if specified then this is Ky prior to rotation + real(DP), dimension(:), pointer, contiguous :: k33 => null() !< hydraulic conductivity; if specified then this is Kz prior to rotation + real(DP), dimension(:), pointer, contiguous :: k11input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification + real(DP), dimension(:), pointer, contiguous :: k22input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification + real(DP), dimension(:), pointer, contiguous :: k33input => null() !< hydraulic conductivity originally specified by user prior to TVK or VSC modification + integer(I4B), pointer :: iavgkeff => null() !< effective conductivity averaging (0: harmonic, 1: arithmetic) + integer(I4B), pointer :: ik22 => null() !< flag that k22 is specified + integer(I4B), pointer :: ik33 => null() !< flag that k33 is specified + integer(I4B), pointer :: ik22overk => null() !< flag that k22 is specified as anisotropy ratio + integer(I4B), pointer :: ik33overk => null() !< flag that k33 is specified as anisotropy ratio + integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read + integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read + integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read + real(DP), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw) + real(DP), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch) + real(DP), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll) + ! + integer(I4B), pointer :: iwetdry => null() !< flag to indicate angle1 was read + real(DP), dimension(:), pointer, contiguous :: wetdry => null() !< wetdry array + real(DP), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell + real(DP), dimension(:), pointer, contiguous :: condsat => null() !< saturated conductance (symmetric array) + real(DP), pointer :: satmin => null() !< minimum saturated thickness + integer(I4B), dimension(:), pointer, contiguous :: ibotnode => null() !< bottom node used if igwfnewtonur /= 0 + ! + real(DP), dimension(:, :), pointer, contiguous :: spdis => null() !< specific discharge : qx, qy, qz (nodes, 3) + integer(I4B), pointer :: nedges => null() !< number of cell edges + integer(I4B), pointer :: lastedge => null() !< last edge number + integer(I4B), dimension(:), pointer, contiguous :: nodedge => null() !< array of node numbers that have edges + integer(I4B), dimension(:), pointer, contiguous :: ihcedge => null() !< edge type (horizontal or vertical) + real(DP), dimension(:, :), pointer, contiguous :: propsedge => null() !< edge properties (Q, area, nx, ny, distance) + ! + integer(I4B), pointer :: intvk => null() ! TVK (time-varying K) unit number (0 if unused) + integer(I4B), pointer :: invsc => null() ! VSC (viscosity) unit number (0 if unused); viscosity leads to time-varying K's + type(TvkType), pointer :: tvk => null() ! TVK object + integer(I4B), pointer :: kchangeper => null() ! last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), pointer :: kchangestp => null() ! last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() ! grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0) ! contains - procedure :: npf_df - procedure :: npf_ac - procedure :: npf_mc - procedure :: npf_ar - procedure :: npf_rp - procedure :: npf_ad - procedure :: npf_cf - procedure :: npf_fc - procedure :: npf_fn - procedure :: npf_cq - procedure :: npf_save_model_flows - procedure :: npf_nur - procedure :: npf_print_model_flows - procedure :: npf_da - procedure, private :: thksat => sgwf_npf_thksat - procedure, private :: qcalc => sgwf_npf_qcalc - procedure, private :: wd => sgwf_npf_wetdry - procedure, private :: wdmsg => sgwf_npf_wdmsg - procedure :: allocate_scalars - procedure, private :: allocate_arrays - procedure, private :: read_options - procedure, private :: set_options - procedure, private :: rewet_options - procedure, private :: check_options - procedure, private :: read_grid_data - procedure, private :: set_grid_data - procedure, private :: prepcheck - procedure, private :: preprocess_input - procedure, private :: calc_condsat - procedure, private :: calc_initial_sat - procedure, public :: rewet_check - procedure, public :: hy_eff - procedure, public :: calc_spdis - procedure, public :: sav_spdis - procedure, public :: sav_sat - procedure, public :: increase_edge_count - procedure, public :: set_edge_properties - procedure, public :: calcSatThickness - endtype - - contains + procedure :: npf_df + procedure :: npf_ac + procedure :: npf_mc + procedure :: npf_ar + procedure :: npf_rp + procedure :: npf_ad + procedure :: npf_cf + procedure :: npf_fc + procedure :: npf_fn + procedure :: npf_cq + procedure :: npf_save_model_flows + procedure :: npf_nur + procedure :: npf_print_model_flows + procedure :: npf_da + procedure, private :: thksat => sgwf_npf_thksat + procedure, private :: qcalc => sgwf_npf_qcalc + procedure, private :: wd => sgwf_npf_wetdry + procedure, private :: wdmsg => sgwf_npf_wdmsg + procedure :: allocate_scalars + procedure, private :: store_original_k_arrays + procedure, private :: allocate_arrays + procedure, private :: source_options + procedure, private :: source_griddata + procedure, private :: log_options + procedure, private :: log_griddata + procedure, private :: set_options + procedure, private :: check_options + procedure, private :: prepcheck + procedure, private :: preprocess_input + procedure, private :: calc_condsat + procedure, private :: calc_initial_sat + procedure, public :: rewet_check + procedure, public :: hy_eff + procedure, public :: calc_spdis + procedure, public :: sav_spdis + procedure, public :: sav_sat + procedure, public :: increase_edge_count + procedure, public :: set_edge_properties + procedure, public :: calcSatThickness + end type + +contains subroutine npf_cr(npfobj, name_model, inunit, iout) ! ****************************************************************************** ! npf_cr -- Create a new NPF object. Pass a inunit value of 0 if npf data will -! initialized from memory +! initialized from memory ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules + use IdmMf6FileLoaderModule, only: input_load + use ConstantsModule, only: LENPACKAGETYPE ! -- dummy - type(GwfNpftype), pointer :: npfobj + type(GwfNpfType), pointer :: npfobj character(len=*), intent(in) :: name_model - integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout + ! -- formats + character(len=*), parameter :: fmtheader = & + "(1x, /1x, 'NPF -- NODE PROPERTY FLOW PACKAGE, VERSION 1, 3/30/2015', & + &' INPUT READ FROM UNIT ', i0, /)" ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(npfobj) + allocate (npfobj) ! ! -- create name and memory path call npfobj%set_names(1, name_model, 'NPF', 'NPF') @@ -163,20 +180,35 @@ subroutine npf_cr(npfobj, name_model, inunit, iout) ! ! -- Set variables npfobj%inunit = inunit - npfobj%iout = iout + npfobj%iout = iout + ! + ! -- Check if input file is open + if (inunit > 0) then + ! + ! -- Print a message identifying the node property flow package. + write (iout, fmtheader) inunit + ! + ! -- Initialize block parser and read options + call npfobj%parser%Initialize(inunit, iout) + ! + ! -- Use the input data model routines to load the input data + ! into memory + call input_load(npfobj%parser, 'NPF6', 'GWF', 'NPF', npfobj%name_model, & + 'NPF', [character(len=LENPACKAGETYPE) :: 'TVK6'], iout) + end if ! ! -- Return return end subroutine npf_cr !> @brief define the NPF package instance - !! + !! !! This is a hybrid routine: it either reads the options for this package !! from the input file, or the optional argument @param npf_options - !! should be passed. A consistency check is performed, and finally + !! should be passed. A consistency check is performed, and finally !! xt3d_df is called, when enabled. !< - subroutine npf_df(this, dis, xt3d, ingnc, npf_options) + subroutine npf_df(this, dis, xt3d, ingnc, invsc, npf_options) ! ****************************************************************************** ! npf_df -- Define ! ****************************************************************************** @@ -187,33 +219,40 @@ subroutine npf_df(this, dis, xt3d, ingnc, npf_options) use SimModule, only: store_error use Xt3dModule, only: xt3d_cr ! -- dummy - class(GwfNpftype) :: this !< instance of the NPF package - class(DisBaseType), pointer, intent(inout) :: dis !< the pointer to the discretization - type(Xt3dType), pointer :: xt3d !< the pointer to the XT3D 'package' - integer(I4B), intent(in) :: ingnc !< ghostnodes enabled? (>0 means yes) - type(GwfNpfOptionsType), optional, intent(in) :: npf_options !< the optional options, for when not constructing from file + class(GwfNpftype) :: this !< instance of the NPF package + class(DisBaseType), pointer, intent(inout) :: dis !< the pointer to the discretization + type(Xt3dType), pointer :: xt3d !< the pointer to the XT3D 'package' + integer(I4B), intent(in) :: ingnc !< ghostnodes enabled? (>0 means yes) + integer(I4B), intent(in) :: invsc !< viscosity enabled? (>0 means yes) + type(GwfNpfOptionsType), optional, intent(in) :: npf_options !< the optional options, for when not constructing from file ! -- local - ! -- formats - character(len=*), parameter :: fmtheader = & - "(1x, /1x, 'NPF -- NODE PROPERTY FLOW PACKAGE, VERSION 1, 3/30/2015', & - &' INPUT READ FROM UNIT ', i0, //)" ! -- data ! ------------------------------------------------------------------------------ ! ! -- Set a pointer to dis this%dis => dis ! + ! -- Set flag signifying whether vsc is active + if (invsc > 0) this%invsc = invsc + ! if (.not. present(npf_options)) then - ! -- Print a message identifying the node property flow package. - write(this%iout, fmtheader) this%inunit ! - ! -- Initialize block parser and read options - call this%parser%Initialize(this%inunit, this%iout) - call this%read_options() + ! -- source options + call this%source_options() + ! + ! -- allocate arrays + call this%allocate_arrays(this%dis%nodes, this%dis%njas) + ! + ! -- source griddata, set, and convert/check the input + call this%source_griddata() + call this%prepcheck() else call this%set_options(npf_options) + ! + ! -- allocate arrays + call this%allocate_arrays(this%dis%nodes, this%dis%njas) end if - + call this%check_options() ! ! -- Save pointer to xt3d object @@ -223,10 +262,10 @@ subroutine npf_df(this, dis, xt3d, ingnc, npf_options) ! ! -- Ensure GNC and XT3D are not both on at the same time if (this%ixt3d /= 0 .and. ingnc > 0) then - call store_error('Error in model ' // trim(this%name_model) // & - '. The XT3D option cannot be used with the GNC Package.', & - terminate=.TRUE.) - endif + call store_error('Error in model '//trim(this%name_model)// & + '. The XT3D option cannot be used with the GNC & + &Package.', terminate=.TRUE.) + end if ! ! -- Return return @@ -241,7 +280,6 @@ subroutine npf_ac(this, moffset, sparse) ! ------------------------------------------------------------------------------ ! -- modules use SparseModule, only: sparsematrix - use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwfNpftype) :: this integer(I4B), intent(in) :: moffset @@ -250,7 +288,7 @@ subroutine npf_ac(this, moffset, sparse) ! ------------------------------------------------------------------------------ ! ! -- Add extended neighbors (neighbors of neighbors) - if(this%ixt3d /= 0) call this%xt3d%xt3d_ac(moffset, sparse) + if (this%ixt3d /= 0) call this%xt3d%xt3d_ac(moffset, sparse) ! ! -- Return return @@ -264,7 +302,6 @@ subroutine npf_mc(this, moffset, iasln, jasln) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwfNpftype) :: this integer(I4B), intent(in) :: moffset @@ -278,57 +315,80 @@ subroutine npf_mc(this, moffset, iasln, jasln) ! -- Return return end subroutine npf_mc - + !> @brief allocate and read this NPF instance !! - !! Allocate package arrays, read the grid data either from file or - !! from the input argument (when the optional @param grid_data is passed), - !! preprocess the input data and call *_ar on xt3d, when active. + !! Allocate remaining package arrays, preprocess the input data and + !! call *_ar on xt3d, when active. !< - subroutine npf_ar(this, ic, ibound, hnew, grid_data) + subroutine npf_ar(this, ic, vsc, ibound, hnew) ! ****************************************************************************** ! npf_ar -- Allocate and Read ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules + use MemoryManagerModule, only: mem_reallocate ! -- dummy - class(GwfNpftype) :: this !< instance of the NPF package - type(GwfIcType), pointer, intent(in) :: ic !< initial conditions - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: ibound !< model ibound array - real(DP), dimension(:), pointer, contiguous, intent(inout) :: hnew !< pointer to model head array - type(GwfNpfGridDataType), optional, intent(in) :: grid_data !< (optional) data structure with NPF grid data + class(GwfNpftype) :: this !< instance of the NPF package + type(GwfIcType), pointer, intent(in) :: ic !< initial conditions + type(GwfVscType), pointer, intent(in) :: vsc !< viscosity package + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: ibound !< model ibound array + real(DP), dimension(:), pointer, contiguous, intent(inout) :: hnew !< pointer to model head array ! -- local + integer(I4B) :: n ! -- formats ! -- data ! ------------------------------------------------------------------------------ ! ! -- Store pointers to arguments that were passed in - this%ic => ic - this%ibound => ibound - this%hnew => hnew + this%ic => ic + this%ibound => ibound + this%hnew => hnew + ! + if (this%icalcspdis == 1) then + call mem_reallocate(this%spdis, 3, this%dis%nodes, 'SPDIS', this%memoryPath) + call mem_reallocate(this%nodedge, this%nedges, 'NODEDGE', this%memoryPath) + call mem_reallocate(this%ihcedge, this%nedges, 'IHCEDGE', this%memoryPath) + call mem_reallocate(this%propsedge, 5, this%nedges, 'PROPSEDGE', & + this%memoryPath) + do n = 1, this%dis%nodes + this%spdis(:, n) = DZERO + end do + end if ! - ! -- allocate arrays - call this%allocate_arrays(this%dis%nodes, this%dis%njas) + ! -- Store pointer to VSC if active + if (this%invsc /= 0) then + this%vsc => vsc + end if + ! - if (.not. present(grid_data)) then - ! -- read from file, set, and convert/check the input - call this%read_grid_data() - call this%prepcheck() - else - ! -- set the data block - call this%set_grid_data(grid_data) + ! -- allocate arrays to store original user input in case TVK/VSC modify them + if (this%invsc > 0) then + ! + ! -- Reallocate arrays that store user-input values. + call mem_reallocate(this%k11input, this%dis%nodes, 'K11INPUT', & + this%memoryPath) + call mem_reallocate(this%k22input, this%dis%nodes, 'K22INPUT', & + this%memoryPath) + call mem_reallocate(this%k33input, this%dis%nodes, 'K33INPUT', & + this%memoryPath) + ! Allocate arrays that will store the original K values. When VSC active, + ! the current Kxx arrays carry the viscosity-adjusted K values. + ! This approach leverages existing functionality that makes use of K. + call this%store_original_k_arrays(this%dis%nodes, this%dis%njas) end if ! ! -- preprocess data - call this%preprocess_input() + call this%preprocess_input() ! ! -- xt3d if (this%ixt3d /= 0) then - call this%xt3d%xt3d_ar(ibound, this%k11, this%ik33, this%k33, & - this%sat, this%ik22, this%k22, & - this%iangle1, this%iangle2, this%iangle3, & - this%angle1, this%angle2, this%angle3, & + call this%xt3d%xt3d_ar(ibound, this%k11, this%ik33, this%k33, & + this%sat, this%ik22, this%k22, & + this%iangle1, this%iangle2, this%iangle3, & + this%angle1, this%angle2, this%angle3, & this%inewton, this%icelltype) end if ! @@ -349,7 +409,6 @@ end subroutine npf_ar subroutine npf_rp(this) implicit none class(GwfNpfType) :: this -! ------------------------------------------------------------------------------ ! ! -- TVK if (this%intvk /= 0) then @@ -379,45 +438,51 @@ subroutine npf_ad(this, nodes, hold, hnew, irestore) ! ------------------------------------------------------------------------------ ! ! -- loop through all cells and set hold=bot if wettable cell is dry - if(this%irewet > 0) then + if (this%irewet > 0) then do n = 1, this%dis%nodes - if(this%wetdry(n) == DZERO) cycle - if(this%ibound(n) /= 0) cycle + if (this%wetdry(n) == DZERO) cycle + if (this%ibound(n) /= 0) cycle hold(n) = this%dis%bot(n) - enddo + end do ! ! -- if restore state, then set hnew to DRY if it is a dry wettable cell do n = 1, this%dis%nodes - if(this%wetdry(n) == DZERO) cycle - if(this%ibound(n) /= 0) cycle + if (this%wetdry(n) == DZERO) cycle + if (this%ibound(n) /= 0) cycle hnew(n) = DHDRY - enddo - endif + end do + end if ! ! -- TVK - if(this%intvk /= 0) then + if (this%intvk /= 0) then call this%tvk%ad() - endif + end if + ! + ! -- VSC + ! -- Hit the TVK-updated K's with VSC correction before calling/updating condsat + if (this%invsc /= 0) then + call this%vsc%update_k_with_vsc() + end if ! ! -- If any K values have changed, we need to update CONDSAT or XT3D arrays - if(this%kchangeper == kper .and. this%kchangestp == kstp) then - if(this%ixt3d == 0) then + if (this%kchangeper == kper .and. this%kchangestp == kstp) then + if (this%ixt3d == 0) then ! ! -- Update the saturated conductance for all connections ! -- of the affected nodes do n = 1, this%dis%nodes - if(this%nodekchange(n) == 1) then + if (this%nodekchange(n) == 1) then call this%calc_condsat(n, .false.) - endif - enddo + end if + end do else ! ! -- Recompute XT3D coefficients for permanently confined connections - if(this%xt3d%lamatsaved .and. .not. this%xt3d%ldispersion) then + if (this%xt3d%lamatsaved .and. .not. this%xt3d%ldispersion) then call this%xt3d%xt3d_fcpc(this%dis%nodes, .true.) - endif - endif - endif + end if + end if + end if ! ! -- Return return @@ -433,8 +498,8 @@ subroutine npf_cf(this, kiter, nodes, hnew) ! -- dummy class(GwfNpfType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: nodes - real(DP),intent(inout),dimension(nodes) :: hnew + integer(I4B), intent(in) :: nodes + real(DP), intent(inout), dimension(nodes) :: hnew ! -- local integer(I4B) :: n real(DP) :: satn @@ -447,15 +512,15 @@ subroutine npf_cf(this, kiter, nodes, hnew) ! ! -- Calculate saturation for convertible cells do n = 1, this%dis%nodes - if(this%icelltype(n) /= 0) then - if(this%ibound(n) == 0) then + if (this%icelltype(n) /= 0) then + if (this%ibound(n) == 0) then satn = DZERO else call this%thksat(n, hnew(n), satn) - endif + end if this%sat(n) = satn - endif - enddo + end if + end do ! ! -- Return return @@ -473,11 +538,11 @@ subroutine npf_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! -- dummy class(GwfNpfType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(:) :: idxglo - real(DP),intent(inout),dimension(:) :: rhs - real(DP),intent(inout),dimension(:) :: hnew + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(:) :: idxglo + real(DP), intent(inout), dimension(:) :: rhs + real(DP), intent(inout), dimension(:) :: hnew ! -- local integer(I4B) :: n, m, ii, idiag, ihc integer(I4B) :: isymcon, idiagm @@ -487,96 +552,95 @@ subroutine npf_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! ! -- Calculate conductance and put into amat ! - if(this%ixt3d /= 0) then + if (this%ixt3d /= 0) then call this%xt3d%xt3d_fc(kiter, njasln, amat, idxglo, rhs, hnew) else - ! - do n = 1, this%dis%nodes - do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 - if (this%dis%con%mask(ii) == 0) cycle - - m = this%dis%con%ja(ii) - ! - ! -- Calculate conductance only for upper triangle but insert into - ! upper and lower parts of amat. - if (m < n) cycle - ihc = this%dis%con%ihc(this%dis%con%jas(ii)) - hyn = this%hy_eff(n, m, ihc, ipos=ii) - hym = this%hy_eff(m, n, ihc, ipos=ii) - ! - ! -- Vertical connection - if (ihc == 0) then + ! + do n = 1, this%dis%nodes + do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 + if (this%dis%con%mask(ii) == 0) cycle + + m = this%dis%con%ja(ii) ! - ! -- Calculate vertical conductance - cond = vcond(this%ibound(n), this%ibound(m), & - this%icelltype(n), this%icelltype(m), this%inewton, & - this%ivarcv, this%idewatcv, & - this%condsat(this%dis%con%jas(ii)), hnew(n), hnew(m), & - hyn, hym, & - this%sat(n), this%sat(m), & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%hwva(this%dis%con%jas(ii))) + ! -- Calculate conductance only for upper triangle but insert into + ! upper and lower parts of amat. + if (m < n) cycle + ihc = this%dis%con%ihc(this%dis%con%jas(ii)) + hyn = this%hy_eff(n, m, ihc, ipos=ii) + hym = this%hy_eff(m, n, ihc, ipos=ii) ! - ! -- Vertical flow for perched conditions - if (this%iperched /= 0) then - if (this%icelltype(m) /= 0) then - if (hnew(m) < this%dis%top(m)) then - ! - ! -- Fill row n - idiag = this%dis%con%ia(n) - rhs(n) = rhs(n) - cond * this%dis%bot(n) - amat(idxglo(idiag)) = amat(idxglo(idiag)) - cond - ! - ! -- Fill row m - isymcon = this%dis%con%isym(ii) - amat(idxglo(isymcon)) = amat(idxglo(isymcon)) + cond - rhs(m) = rhs(m) + cond * this%dis%bot(n) - ! - ! -- cycle the connection loop - cycle - endif - endif - endif + ! -- Vertical connection + if (ihc == 0) then + ! + ! -- Calculate vertical conductance + cond = vcond(this%ibound(n), this%ibound(m), & + this%icelltype(n), this%icelltype(m), this%inewton, & + this%ivarcv, this%idewatcv, & + this%condsat(this%dis%con%jas(ii)), hnew(n), hnew(m), & + hyn, hym, & + this%sat(n), this%sat(m), & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%hwva(this%dis%con%jas(ii))) + ! + ! -- Vertical flow for perched conditions + if (this%iperched /= 0) then + if (this%icelltype(m) /= 0) then + if (hnew(m) < this%dis%top(m)) then + ! + ! -- Fill row n + idiag = this%dis%con%ia(n) + rhs(n) = rhs(n) - cond * this%dis%bot(n) + amat(idxglo(idiag)) = amat(idxglo(idiag)) - cond + ! + ! -- Fill row m + isymcon = this%dis%con%isym(ii) + amat(idxglo(isymcon)) = amat(idxglo(isymcon)) + cond + rhs(m) = rhs(m) + cond * this%dis%bot(n) + ! + ! -- cycle the connection loop + cycle + end if + end if + end if + ! + else + ! + ! -- Horizontal conductance + cond = hcond(this%ibound(n), this%ibound(m), & + this%icelltype(n), this%icelltype(m), & + this%inewton, this%inewton, & + this%dis%con%ihc(this%dis%con%jas(ii)), & + this%icellavg, this%iusgnrhc, this%inwtupw, & + this%condsat(this%dis%con%jas(ii)), & + hnew(n), hnew(m), this%sat(n), this%sat(m), hyn, hym, & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%cl1(this%dis%con%jas(ii)), & + this%dis%con%cl2(this%dis%con%jas(ii)), & + this%dis%con%hwva(this%dis%con%jas(ii)), & + this%satomega, this%satmin) + end if ! - else + ! -- Fill row n + idiag = this%dis%con%ia(n) + amat(idxglo(ii)) = amat(idxglo(ii)) + cond + amat(idxglo(idiag)) = amat(idxglo(idiag)) - cond ! - ! -- Horizontal conductance - cond = hcond(this%ibound(n), this%ibound(m), & - this%icelltype(n), this%icelltype(m), & - this%inewton, this%inewton, & - this%dis%con%ihc(this%dis%con%jas(ii)), & - this%icellavg, this%iusgnrhc, this%inwtupw, & - this%condsat(this%dis%con%jas(ii)), & - hnew(n), hnew(m), this%sat(n), this%sat(m), hyn, hym, & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%cl1(this%dis%con%jas(ii)), & - this%dis%con%cl2(this%dis%con%jas(ii)), & - this%dis%con%hwva(this%dis%con%jas(ii)), & - this%satomega, this%satmin) - endif - ! - ! -- Fill row n - idiag = this%dis%con%ia(n) - amat(idxglo(ii)) = amat(idxglo(ii)) + cond - amat(idxglo(idiag)) = amat(idxglo(idiag)) - cond - ! - ! -- Fill row m - isymcon = this%dis%con%isym(ii) - idiagm = this%dis%con%ia(m) - amat(idxglo(isymcon)) = amat(idxglo(isymcon)) + cond - amat(idxglo(idiagm)) = amat(idxglo(idiagm)) - cond - enddo - enddo - ! - endif + ! -- Fill row m + isymcon = this%dis%con%isym(ii) + idiagm = this%dis%con%ia(m) + amat(idxglo(isymcon)) = amat(idxglo(isymcon)) + cond + amat(idxglo(idiagm)) = amat(idxglo(idiagm)) - cond + end do + end do + ! + end if ! ! -- Return return end subroutine npf_fc - subroutine npf_fn(this, kiter, njasln, amat, idxglo, rhs, hnew) ! ****************************************************************************** ! npf_fn -- Fill newton terms @@ -587,14 +651,14 @@ subroutine npf_fn(this, kiter, njasln, amat, idxglo, rhs, hnew) ! -- dummy class(GwfNpfType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(:) :: idxglo - real(DP),intent(inout),dimension(:) :: rhs - real(DP),intent(inout),dimension(:) :: hnew + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(:) :: idxglo + real(DP), intent(inout), dimension(:) :: rhs + real(DP), intent(inout), dimension(:) :: hnew ! -- local integer(I4B) :: nodes, nja - integer(I4B) :: n,m,ii,idiag + integer(I4B) :: n, m, ii, idiag integer(I4B) :: isymcon, idiagm integer(I4B) :: iups integer(I4B) :: idn @@ -615,104 +679,104 @@ subroutine npf_fn(this, kiter, njasln, amat, idxglo, rhs, hnew) ! nodes = this%dis%nodes nja = this%dis%con%nja - if(this%ixt3d /= 0) then + if (this%ixt3d /= 0) then call this%xt3d%xt3d_fn(kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) else - ! - do n=1, nodes - idiag=this%dis%con%ia(n) - do ii=this%dis%con%ia(n)+1,this%dis%con%ia(n+1)-1 - if (this%dis%con%mask(ii) == 0) cycle - - m=this%dis%con%ja(ii) - isymcon = this%dis%con%isym(ii) - ! work on upper triangle - if(m < n) cycle - if(this%dis%con%ihc(this%dis%con%jas(ii))==0 .and. & - this%ivarcv == 0) then - !call this%vcond(n,m,hnew(n),hnew(m),ii,cond) - ! do nothing - else - ! determine upstream node - iups = m - if (hnew(m) < hnew(n)) iups = n - idn = n - if (iups == n) idn = m - ! - ! -- no newton terms if upstream cell is confined - if (this%icelltype(iups) == 0) cycle - ! - ! -- Set the upstream top and bot, and then recalculate for a - ! vertically staggered horizontal connection - topup = this%dis%top(iups) - botup = this%dis%bot(iups) - if(this%dis%con%ihc(this%dis%con%jas(ii)) == 2) then - topup = min(this%dis%top(n), this%dis%top(m)) - botup = max(this%dis%bot(n), this%dis%bot(m)) - endif - ! - ! get saturated conductivity for derivative - cond = this%condsat(this%dis%con%jas(ii)) - ! - ! -- if using MODFLOW-NWT upstream weighting option apply - ! factor to remove average thickness - if (this%inwtupw /= 0) then - topdn = this%dis%top(idn) - botdn = this%dis%bot(idn) - afac = DTWO / (DONE + (topdn - botdn) / (topup - botup)) - cond = cond * afac - end if - ! - ! compute additional term - consterm = -cond * (hnew(iups) - hnew(idn)) !needs to use hwadi instead of hnew(idn) - !filledterm = cond - filledterm = amat(idxglo(ii)) - derv = sQuadraticSaturationDerivative(topup, botup, hnew(iups), & - this%satomega, this%satmin) - idiagm = this%dis%con%ia(m) - ! fill jacobian for n being the upstream node - if (iups == n) then - hds = hnew(m) - !isymcon = this%dis%con%isym(ii) - term = consterm * derv - rhs(n) = rhs(n) + term * hnew(n) !+ amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi - rhs(m) = rhs(m) - term * hnew(n) !- amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi - ! fill in row of n - amat(idxglo(idiag)) = amat(idxglo(idiag)) + term - ! fill newton term in off diagonal if active cell - if (this%ibound(n) > 0) then - amat(idxglo(ii)) = amat(idxglo(ii)) !* dwadi !need to add dwadi - end if - !fill row of m - amat(idxglo(idiagm)) = amat(idxglo(idiagm)) !- filledterm * (dwadi - DONE) !need to add dwadi - ! fill newton term in off diagonal if active cell - if (this%ibound(m) > 0) then - amat(idxglo(isymcon)) = amat(idxglo(isymcon)) - term - end if - ! fill jacobian for m being the upstream node + ! + do n = 1, nodes + idiag = this%dis%con%ia(n) + do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 + if (this%dis%con%mask(ii) == 0) cycle + + m = this%dis%con%ja(ii) + isymcon = this%dis%con%isym(ii) + ! work on upper triangle + if (m < n) cycle + if (this%dis%con%ihc(this%dis%con%jas(ii)) == 0 .and. & + this%ivarcv == 0) then + !call this%vcond(n,m,hnew(n),hnew(m),ii,cond) + ! do nothing else - hds = hnew(n) - term = -consterm * derv - rhs(n) = rhs(n) + term * hnew(m) !+ amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi - rhs(m) = rhs(m) - term * hnew(m) !- amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi - ! fill in row of n - amat(idxglo(idiag)) = amat(idxglo(idiag)) !- filledterm * (dwadi - DONE) !need to add dwadi - ! fill newton term in off diagonal if active cell - if (this%ibound(n) > 0) then - amat(idxglo(ii)) = amat(idxglo(ii)) + term + ! determine upstream node + iups = m + if (hnew(m) < hnew(n)) iups = n + idn = n + if (iups == n) idn = m + ! + ! -- no newton terms if upstream cell is confined + if (this%icelltype(iups) == 0) cycle + ! + ! -- Set the upstream top and bot, and then recalculate for a + ! vertically staggered horizontal connection + topup = this%dis%top(iups) + botup = this%dis%bot(iups) + if (this%dis%con%ihc(this%dis%con%jas(ii)) == 2) then + topup = min(this%dis%top(n), this%dis%top(m)) + botup = max(this%dis%bot(n), this%dis%bot(m)) end if - !fill row of m - amat(idxglo(idiagm)) = amat(idxglo(idiagm)) - term - ! fill newton term in off diagonal if active cell - if (this%ibound(m) > 0) then - amat(idxglo(isymcon)) = amat(idxglo(isymcon)) !* dwadi !need to add dwadi + ! + ! get saturated conductivity for derivative + cond = this%condsat(this%dis%con%jas(ii)) + ! + ! -- if using MODFLOW-NWT upstream weighting option apply + ! factor to remove average thickness + if (this%inwtupw /= 0) then + topdn = this%dis%top(idn) + botdn = this%dis%bot(idn) + afac = DTWO / (DONE + (topdn - botdn) / (topup - botup)) + cond = cond * afac + end if + ! + ! compute additional term + consterm = -cond * (hnew(iups) - hnew(idn)) !needs to use hwadi instead of hnew(idn) + !filledterm = cond + filledterm = amat(idxglo(ii)) + derv = sQuadraticSaturationDerivative(topup, botup, hnew(iups), & + this%satomega, this%satmin) + idiagm = this%dis%con%ia(m) + ! fill jacobian for n being the upstream node + if (iups == n) then + hds = hnew(m) + !isymcon = this%dis%con%isym(ii) + term = consterm * derv + rhs(n) = rhs(n) + term * hnew(n) !+ amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi + rhs(m) = rhs(m) - term * hnew(n) !- amat(idxglo(isymcon)) * (dwadi * hds - hds) !need to add dwadi + ! fill in row of n + amat(idxglo(idiag)) = amat(idxglo(idiag)) + term + ! fill newton term in off diagonal if active cell + if (this%ibound(n) > 0) then + amat(idxglo(ii)) = amat(idxglo(ii)) !* dwadi !need to add dwadi + end if + !fill row of m + amat(idxglo(idiagm)) = amat(idxglo(idiagm)) !- filledterm * (dwadi - DONE) !need to add dwadi + ! fill newton term in off diagonal if active cell + if (this%ibound(m) > 0) then + amat(idxglo(isymcon)) = amat(idxglo(isymcon)) - term + end if + ! fill jacobian for m being the upstream node + else + hds = hnew(n) + term = -consterm * derv + rhs(n) = rhs(n) + term * hnew(m) !+ amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi + rhs(m) = rhs(m) - term * hnew(m) !- amat(idxglo(ii)) * (dwadi * hds - hds) !need to add dwadi + ! fill in row of n + amat(idxglo(idiag)) = amat(idxglo(idiag)) !- filledterm * (dwadi - DONE) !need to add dwadi + ! fill newton term in off diagonal if active cell + if (this%ibound(n) > 0) then + amat(idxglo(ii)) = amat(idxglo(ii)) + term + end if + !fill row of m + amat(idxglo(idiagm)) = amat(idxglo(idiagm)) - term + ! fill newton term in off diagonal if active cell + if (this%ibound(m) > 0) then + amat(idxglo(isymcon)) = amat(idxglo(isymcon)) !* dwadi !need to add dwadi + end if end if end if - endif - enddo - end do - ! + end do + end do + ! end if ! ! -- Return @@ -755,7 +819,7 @@ subroutine npf_nur(this, neqmod, x, xtemp, dx, inewtonur, dxmax, locmax) ! solution head is below the bottom of the model if (x(n) < botm) then inewtonur = 1 - xx = xtemp(n)*(DONE-DP9) + botm*DP9 + xx = xtemp(n) * (DONE - DP9) + botm * DP9 dxx = x(n) - xx if (abs(dxx) > abs(dxmax)) then locmax = n @@ -765,7 +829,7 @@ subroutine npf_nur(this, neqmod, x, xtemp, dx, inewtonur, dxmax, locmax) dx(n) = DZERO end if end if - enddo + end do ! ! -- return return @@ -780,8 +844,8 @@ subroutine npf_cq(this, hnew, flowja) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfNpfType) :: this - real(DP),intent(inout),dimension(:) :: hnew - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(inout), dimension(:) :: hnew + real(DP), intent(inout), dimension(:) :: flowja ! -- local integer(I4B) :: n, ipos, m real(DP) :: qnm @@ -789,21 +853,21 @@ subroutine npf_cq(this, hnew, flowja) ! ! -- Calculate the flow across each cell face and store in flowja ! - if(this%ixt3d /= 0) then + if (this%ixt3d /= 0) then call this%xt3d%xt3d_flowja(hnew, flowja) else - ! - do n = 1, this%dis%nodes - do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 - m = this%dis%con%ja(ipos) - if(m < n) cycle - call this%qcalc(n, m, hnew(n), hnew(m), ipos, qnm) - flowja(ipos) = qnm - flowja(this%dis%con%isym(ipos)) = -qnm - enddo - enddo - ! - endif + ! + do n = 1, this%dis%nodes + do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 + m = this%dis%con%ja(ipos) + if (m < n) cycle + call this%qcalc(n, m, hnew(n), hnew(m), ipos, qnm) + flowja(ipos) = qnm + flowja(this%dis%con%isym(ipos)) = -qnm + end do + end do + ! + end if ! ! -- Return return @@ -818,30 +882,30 @@ subroutine sgwf_npf_thksat(this, n, hn, thksat) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfNpfType) :: this - integer(I4B),intent(in) :: n - real(DP),intent(in) :: hn - real(DP),intent(inout) :: thksat + integer(I4B), intent(in) :: n + real(DP), intent(in) :: hn + real(DP), intent(inout) :: thksat ! ------------------------------------------------------------------------------ ! ! -- Standard Formulation - if(hn >= this%dis%top(n)) then + if (hn >= this%dis%top(n)) then thksat = DONE else thksat = (hn - this%dis%bot(n)) / (this%dis%top(n) - this%dis%bot(n)) - endif + end if ! ! -- Newton-Raphson Formulation - if(this%inewton /= 0) then - thksat = sQuadraticSaturation(this%dis%top(n), this%dis%bot(n), hn, & + if (this%inewton /= 0) then + thksat = sQuadraticSaturation(this%dis%top(n), this%dis%bot(n), hn, & this%satomega, this%satmin) !if (thksat < this%satmin) thksat = this%satmin - endif + end if ! ! -- Return return end subroutine sgwf_npf_thksat - subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm) + subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm) ! ****************************************************************************** ! sgwf_npf_qcalc -- Flow between two cells ! ****************************************************************************** @@ -850,12 +914,12 @@ subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfNpfType) :: this - integer(I4B),intent(in) :: n - integer(I4B),intent(in) :: m - real(DP),intent(in) :: hn - real(DP),intent(in) :: hm - integer(I4B),intent(in) :: icon - real(DP),intent(inout) :: qnm + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: m + real(DP), intent(in) :: hn + real(DP), intent(in) :: hm + integer(I4B), intent(in) :: icon + real(DP), intent(inout) :: qnm ! -- local real(DP) :: hyn, hym real(DP) :: condnm @@ -869,50 +933,50 @@ subroutine sgwf_npf_qcalc(this, n, m, hn, hm, icon, qnm) hym = this%hy_eff(m, n, ihc, ipos=icon) ! ! -- Calculate conductance - if(ihc == 0) then - condnm = vcond(this%ibound(n), this%ibound(m), & - this%icelltype(n), this%icelltype(m), this%inewton, & - this%ivarcv, this%idewatcv, & - this%condsat(this%dis%con%jas(icon)), hn, hm, & - hyn, hym, & - this%sat(n), this%sat(m), & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%hwva(this%dis%con%jas(icon))) + if (ihc == 0) then + condnm = vcond(this%ibound(n), this%ibound(m), & + this%icelltype(n), this%icelltype(m), this%inewton, & + this%ivarcv, this%idewatcv, & + this%condsat(this%dis%con%jas(icon)), hn, hm, & + hyn, hym, & + this%sat(n), this%sat(m), & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%hwva(this%dis%con%jas(icon))) else - condnm = hcond(this%ibound(n), this%ibound(m), & - this%icelltype(n), this%icelltype(m), & - this%inewton, this%inewton, & - this%dis%con%ihc(this%dis%con%jas(icon)), & - this%icellavg, this%iusgnrhc, this%inwtupw, & - this%condsat(this%dis%con%jas(icon)), & - hn, hm, this%sat(n), this%sat(m), hyn, hym, & - this%dis%top(n), this%dis%top(m), & - this%dis%bot(n), this%dis%bot(m), & - this%dis%con%cl1(this%dis%con%jas(icon)), & - this%dis%con%cl2(this%dis%con%jas(icon)), & - this%dis%con%hwva(this%dis%con%jas(icon)), & + condnm = hcond(this%ibound(n), this%ibound(m), & + this%icelltype(n), this%icelltype(m), & + this%inewton, this%inewton, & + this%dis%con%ihc(this%dis%con%jas(icon)), & + this%icellavg, this%iusgnrhc, this%inwtupw, & + this%condsat(this%dis%con%jas(icon)), & + hn, hm, this%sat(n), this%sat(m), hyn, hym, & + this%dis%top(n), this%dis%top(m), & + this%dis%bot(n), this%dis%bot(m), & + this%dis%con%cl1(this%dis%con%jas(icon)), & + this%dis%con%cl2(this%dis%con%jas(icon)), & + this%dis%con%hwva(this%dis%con%jas(icon)), & this%satomega, this%satmin) - endif + end if ! ! -- Initialize hntemp and hmtemp hntemp = hn hmtemp = hm ! ! -- Check and adjust for dewatered conditions - if(this%iperched /= 0) then - if(this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then - if(n > m) then - if(this%icelltype(n) /= 0) then - if(hn < this%dis%top(n)) hntemp = this%dis%bot(m) - endif + if (this%iperched /= 0) then + if (this%dis%con%ihc(this%dis%con%jas(icon)) == 0) then + if (n > m) then + if (this%icelltype(n) /= 0) then + if (hn < this%dis%top(n)) hntemp = this%dis%bot(m) + end if else - if(this%icelltype(m) /= 0) then - if(hm < this%dis%top(m)) hmtemp = this%dis%bot(n) - endif - endif - endif - endif + if (this%icelltype(m) /= 0) then + if (hm < this%dis%top(m)) hmtemp = this%dis%bot(n) + end if + end if + end if + end if ! ! -- Calculate flow positive into cell n qnm = condnm * (hmtemp - hntemp) @@ -930,7 +994,7 @@ subroutine npf_save_model_flows(this, flowja, icbcfl, icbcun) ! ------------------------------------------------------------------------------ ! -- dummy class(GwfNpfType) :: this - real(DP),dimension(:),intent(in) :: flowja + real(DP), dimension(:), intent(in) :: flowja integer(I4B), intent(in) :: icbcfl integer(I4B), intent(in) :: icbcun ! -- local @@ -940,29 +1004,29 @@ subroutine npf_save_model_flows(this, flowja, icbcfl, icbcun) ! ------------------------------------------------------------------------------ ! ! -- Set unit number for binary output - if(this%ipakcb < 0) then + if (this%ipakcb < 0) then ibinun = icbcun - elseif(this%ipakcb == 0) then + elseif (this%ipakcb == 0) then ibinun = 0 else ibinun = this%ipakcb - endif - if(icbcfl == 0) ibinun = 0 + end if + if (icbcfl == 0) ibinun = 0 ! ! -- Write the face flows if requested - if(ibinun /= 0) then + if (ibinun /= 0) then call this%dis%record_connection_array(flowja, ibinun, this%iout) - endif + end if ! ! -- Calculate specific discharge at cell centers and write, if requested - if (this%icalcspdis /= 0) then - if(ibinun /= 0) call this%sav_spdis(ibinun) - endif + if (this%isavspdis /= 0) then + if (ibinun /= 0) call this%sav_spdis(ibinun) + end if ! ! -- Save saturation, if requested if (this%isavsat /= 0) then - if(ibinun /= 0) call this%sav_sat(ibinun) - endif + if (ibinun /= 0) call this%sav_sat(ibinun) + end if ! ! -- Return return @@ -981,35 +1045,35 @@ subroutine npf_print_model_flows(this, ibudfl, flowja) ! -- dummy class(GwfNpfType) :: this integer(I4B), intent(in) :: ibudfl - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(inout), dimension(:) :: flowja ! -- local character(len=LENBIGLINE) :: line character(len=30) :: tempstr integer(I4B) :: n, ipos, m real(DP) :: qnm ! -- formats - character(len=*), parameter :: fmtiprflow = & - "(/,4x,'CALCULATED INTERCELL FLOW FOR PERIOD ', i0, ' STEP ', i0)" + character(len=*), parameter :: fmtiprflow = & + &"(/,4x,'CALCULATED INTERCELL FLOW FOR PERIOD ', i0, ' STEP ', i0)" ! ------------------------------------------------------------------------------ ! ! -- Write flowja to list file if requested if (ibudfl /= 0 .and. this%iprflow > 0) then - write(this%iout, fmtiprflow) kper, kstp + write (this%iout, fmtiprflow) kper, kstp do n = 1, this%dis%nodes line = '' call this%dis%noder_to_string(n, tempstr) - line = trim(tempstr) // ':' + line = trim(tempstr)//':' do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ipos) call this%dis%noder_to_string(m, tempstr) - line = trim(line) // ' ' // trim(tempstr) + line = trim(line)//' '//trim(tempstr) qnm = flowja(ipos) - write(tempstr, '(1pg15.6)') qnm - line = trim(line) // ' ' // trim(adjustl(tempstr)) - enddo - write(this%iout, '(a)') trim(line) - enddo - endif + write (tempstr, '(1pg15.6)') qnm + line = trim(line)//' '//trim(adjustl(tempstr)) + end do + write (this%iout, '(a)') trim(line) + end do + end if ! ! -- Return return @@ -1023,15 +1087,24 @@ subroutine npf_da(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use MemoryManagerModule, only: mem_deallocate + use MemoryManagerExtModule, only: memorylist_remove + use SimVariablesModule, only: idm_context ! -- dummy class(GwfNpftype) :: this ! ------------------------------------------------------------------------------ + ! + ! -- Deallocate input memory + call memorylist_remove(this%name_model, 'NPF', idm_context) ! ! -- TVK if (this%intvk /= 0) then call this%tvk%da() - deallocate(this%tvk) + deallocate (this%tvk) + end if + ! + ! -- VSC + if (this%invsc /= 0) then + nullify (this%vsc) end if ! ! -- Strings @@ -1039,6 +1112,7 @@ subroutine npf_da(this) ! -- Scalars call mem_deallocate(this%iname) call mem_deallocate(this%ixt3d) + call mem_deallocate(this%ixt3drhs) call mem_deallocate(this%satomega) call mem_deallocate(this%hnoflo) call mem_deallocate(this%hdry) @@ -1070,16 +1144,20 @@ subroutine npf_da(this) call mem_deallocate(this%ik22overk) call mem_deallocate(this%ik33overk) call mem_deallocate(this%intvk) + call mem_deallocate(this%invsc) call mem_deallocate(this%kchangeper) call mem_deallocate(this%kchangestp) ! ! -- Deallocate arrays - deallocate(this%aname) + deallocate (this%aname) call mem_deallocate(this%ithickstartflag) call mem_deallocate(this%icelltype) call mem_deallocate(this%k11) - call mem_deallocate(this%k22, 'K22', trim(this%memoryPath)) - call mem_deallocate(this%k33, 'K33', trim(this%memoryPath)) + call mem_deallocate(this%k22) + call mem_deallocate(this%k33) + call mem_deallocate(this%k11input) + call mem_deallocate(this%k22input) + call mem_deallocate(this%k33input) call mem_deallocate(this%sat) call mem_deallocate(this%condsat) call mem_deallocate(this%wetdry) @@ -1099,15 +1177,14 @@ subroutine npf_da(this) return end subroutine npf_da + !> @ brief Allocate scalars + !! + !! Allocate and initialize scalars for the VSC package. The base model + !! allocate scalars method is also called. + !! + !< subroutine allocate_scalars(this) -! ****************************************************************************** -! allocate_scalars -- Allocate scalar pointer variables -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules - use MemoryManagerModule, only: mem_allocate, mem_setptr use MemoryHelperModule, only: create_mem_path ! -- dummy class(GwfNpftype) :: this @@ -1119,6 +1196,7 @@ subroutine allocate_scalars(this) ! -- Allocate scalars call mem_allocate(this%iname, 'INAME', this%memoryPath) call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) + call mem_allocate(this%ixt3drhs, 'IXT3DRHS', this%memoryPath) call mem_allocate(this%satomega, 'SATOMEGA', this%memoryPath) call mem_allocate(this%hnoflo, 'HNOFLO', this%memoryPath) call mem_allocate(this%hdry, 'HDRY', this%memoryPath) @@ -1149,15 +1227,18 @@ subroutine allocate_scalars(this) call mem_allocate(this%nedges, 'NEDGES', this%memoryPath) call mem_allocate(this%lastedge, 'LASTEDGE', this%memoryPath) call mem_allocate(this%intvk, 'INTVK', this%memoryPath) + call mem_allocate(this%invsc, 'INVSC', this%memoryPath) call mem_allocate(this%kchangeper, 'KCHANGEPER', this%memoryPath) call mem_allocate(this%kchangestp, 'KCHANGESTP', this%memoryPath) ! ! -- set pointer to inewtonur - call mem_setptr(this%igwfnewtonur, 'INEWTONUR', create_mem_path(this%name_model)) + call mem_setptr(this%igwfnewtonur, 'INEWTONUR', & + create_mem_path(this%name_model)) ! ! -- Initialize value this%iname = 8 this%ixt3d = 0 + this%ixt3drhs = 0 this%satomega = DZERO this%hnoflo = DHNOFLO !1.d30 this%hdry = DHDRY !-1.d30 @@ -1188,6 +1269,7 @@ subroutine allocate_scalars(this) this%nedges = 0 this%lastedge = 0 this%intvk = 0 + this%invsc = 0 this%kchangeper = 0 this%kchangestp = 0 ! @@ -1198,6 +1280,40 @@ subroutine allocate_scalars(this) return end subroutine allocate_scalars + !> @ brief Store backup copy of hydraulic conductivity when the VSC + !! package is activate + !! + !! The K arrays (K11, etc.) get multiplied by the viscosity ratio + !! so that subsequent uses of K already take into account the effect + !! of viscosity. Thus the original user-specified K array values are + !! lost unless they are backed up in k11input, for example. In a new + !! stress period/time step, the values in k11input are multiplied by + !! the viscosity ratio, not k11 since it contains viscosity-adjusted + !! hydraulic conductivity values. + !! + !< + subroutine store_original_k_arrays(this, ncells, njas) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy + class(GwfNpftype) :: this + integer(I4B), intent(in) :: ncells + integer(I4B), intent(in) :: njas + ! -- local + integer(I4B) :: n +! ------------------------------------------------------------------------------ + ! + ! -- Retain copy of user-specified K arrays + do n = 1, ncells + this%k11input(n) = this%k11(n) + this%k22input(n) = this%k22(n) + this%k33input(n) = this%k33(n) + end do + ! + ! -- Return + return + end subroutine store_original_k_arrays + subroutine allocate_arrays(this, ncells, njas) ! ****************************************************************************** ! allocate_arrays -- Allocate npf arrays @@ -1206,7 +1322,6 @@ subroutine allocate_arrays(this, ncells, njas) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwfNpftype) :: this integer(I4B), intent(in) :: ncells @@ -1215,7 +1330,8 @@ subroutine allocate_arrays(this, ncells, njas) integer(I4B) :: n ! ------------------------------------------------------------------------------ ! - call mem_allocate(this%ithickstartflag, ncells, 'ITHICKSTARTFLAG', this%memoryPath) + call mem_allocate(this%ithickstartflag, ncells, 'ITHICKSTARTFLAG', & + this%memoryPath) call mem_allocate(this%icelltype, ncells, 'ICELLTYPE', this%memoryPath) call mem_allocate(this%k11, ncells, 'K11', this%memoryPath) call mem_allocate(this%sat, ncells, 'SAT', this%memoryPath) @@ -1231,23 +1347,17 @@ subroutine allocate_arrays(this, ncells, njas) ! ! -- Optional arrays call mem_allocate(this%ibotnode, 0, 'IBOTNODE', this%memoryPath) + call mem_allocate(this%nodedge, 0, 'NODEDGE', this%memoryPath) + call mem_allocate(this%ihcedge, 0, 'IHCEDGE', this%memoryPath) + call mem_allocate(this%propsedge, 0, 0, 'PROPSEDGE', this%memoryPath) ! - ! -- Specific discharge - if (this%icalcspdis == 1) then - call mem_allocate(this%spdis, 3, ncells, 'SPDIS',this%memoryPath) - call mem_allocate(this%nodedge, this%nedges, 'NODEDGE', this%memoryPath) - call mem_allocate(this%ihcedge, this%nedges, 'IHCEDGE', this%memoryPath) - call mem_allocate(this%propsedge, 5, this%nedges, 'PROPSEDGE', & - this%memoryPath) - do n = 1, ncells - this%spdis(:, n) = DZERO - end do - else - call mem_allocate(this%spdis, 3, 0, 'SPDIS', this%memoryPath) - call mem_allocate(this%nodedge, 0, 'NODEDGE', this%memoryPath) - call mem_allocate(this%ihcedge, 0, 'IHCEDGE', this%memoryPath) - call mem_allocate(this%propsedge, 0, 0, 'PROPSEDGE', this%memoryPath) - endif + ! -- Optional arrays only needed when vsc package is active + call mem_allocate(this%k11input, 0, 'K11INPUT', this%memoryPath) + call mem_allocate(this%k22input, 0, 'K22INPUT', this%memoryPath) + call mem_allocate(this%k33input, 0, 'K33INPUT', this%memoryPath) + ! + ! -- Specific discharge is (re-)allocated when nedges is known + call mem_allocate(this%spdis, 3, 0, 'SPDIS', this%memoryPath) ! ! -- Time-varying property flag arrays call mem_allocate(this%nodekchange, ncells, 'NODEKCHANGE', this%memoryPath) @@ -1262,352 +1372,205 @@ subroutine allocate_arrays(this, ncells, njas) end do ! ! -- allocate variable names - allocate(this%aname(this%iname)) - this%aname = [' ICELLTYPE', ' K', & - ' K33', ' K22', & - ' WETDRY', ' ANGLE1', & + allocate (this%aname(this%iname)) + this%aname = [' ICELLTYPE', ' K', & + ' K33', ' K22', & + ' WETDRY', ' ANGLE1', & ' ANGLE2', ' ANGLE3'] ! ! -- return return end subroutine allocate_arrays - subroutine read_options(this) + subroutine log_options(this, found) ! ****************************************************************************** -! read_options -- Read the options +! log_options -- log npf options sourced from the input mempath ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, count_errors - implicit none + use KindModule, only: LGP + use GwfNpfInputModule, only: GwfNpfParamFoundType ! -- dummy class(GwfNpftype) :: this - ! -- local - character(len=LINELENGTH) :: errmsg, keyword, fname - integer(I4B) :: ierr - logical :: isfound, endOfBlock - ! -- formats - character(len=*), parameter :: fmtiprflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE PRINTED TO LISTING FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtcellavg = & - "(4x,'ALTERNATIVE CELL AVERAGING HAS BEEN SET TO ', a)" - character(len=*), parameter :: fmtnct = & - "(1x, 'Negative cell thickness at cell: ', a)" - ! -- data + ! -- locals + type(GwfNpfParamFoundType), intent(in) :: found +! ------------------------------------------------------------------------------ + ! + write (this%iout, '(1x,a)') 'Setting NPF Options' + if (found%iprflow) & + write (this%iout, '(4x,a)') 'Cell-by-cell flow information will be printed & + &to listing file whenever ICBCFL is not zero.' + if (found%ipakcb) & + write (this%iout, '(4x,a)') 'Cell-by-cell flow information will be saved & + &to binary file whenever ICBCFL is not zero.' + if (found%cellavg) & + write (this%iout, '(4x,a,i0)') 'Alternative cell averaging [1=logarithmic, & + &2=AMT-LMK, 3=AMT-HMK] set to: ', & + this%icellavg + if (found%ithickstrt) & + write (this%iout, '(4x,a)') 'THICKSTRT option has been activated.' + if (found%iperched) & + write (this%iout, '(4x,a)') 'Vertical flow will be adjusted for perched & + &conditions.' + if (found%ivarcv) & + write (this%iout, '(4x,a)') 'Vertical conductance varies with water table.' + if (found%idewatcv) & + write (this%iout, '(4x,a)') 'Vertical conductance accounts for dewatered & + &portion of an underlying cell.' + if (found%ixt3d) write (this%iout, '(4x,a)') 'XT3D formulation is selected.' + if (found%ixt3drhs) & + write (this%iout, '(4x,a)') 'XT3D RHS formulation is selected.' + if (found%isavspdis) & + write (this%iout, '(4x,a)') 'Specific discharge will be calculated at cell & + ¢ers and written to DATA-SPDIS in budget & + &file when requested.' + if (found%isavsat) & + write (this%iout, '(4x,a)') 'Saturation will be written to DATA-SAT in & + &budget file when requested.' + if (found%ik22overk) & + write (this%iout, '(4x,a)') 'Values specified for K22 are anisotropy & + &ratios and will be multiplied by K before & + &being used in calculations.' + if (found%ik33overk) & + write (this%iout, '(4x,a)') 'Values specified for K33 are anisotropy & + &ratios and will be multiplied by K before & + &being used in calculations.' + if (found%inewton) & + write (this%iout, '(4x,a)') 'NEWTON-RAPHSON method disabled for unconfined & + &cells' + if (found%iusgnrhc) & + write (this%iout, '(4x,a)') 'MODFLOW-USG saturation calculation method & + &will be used' + if (found%inwtupw) & + write (this%iout, '(4x,a)') 'MODFLOW-NWT upstream weighting method will be & + &used' + if (found%satmin) & + write (this%iout, '(4x,a,1pg15.6)') 'Minimum saturated thickness has been & + &set to: ', this%satmin + if (found%satomega) & + write (this%iout, '(4x,a,1pg15.6)') 'Saturation omega: ', this%satomega + if (found%irewet) & + write (this%iout, '(4x,a)') 'Rewetting is active.' + if (found%wetfct) & + write (this%iout, '(4x,a,1pg15.6)') & + 'Wetting factor (WETFCT) has been set to: ', this%wetfct + if (found%iwetit) & + write (this%iout, '(4x,a,i5)') & + 'Wetting iteration interval (IWETIT) has been set to: ', this%iwetit + if (found%ihdwet) & + write (this%iout, '(4x,a,i5)') & + 'Head rewet equation (IHDWET) has been set to: ', this%ihdwet + write (this%iout, '(1x,a,/)') 'End Setting NPF Options' + + end subroutine log_options + + subroutine source_options(this) +! ****************************************************************************** +! source_options -- update simulation options from input mempath +! ****************************************************************************** +! +! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING NPF OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout, fmtiprflow) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtisvflow) - case ('ALTERNATIVE_CELL_AVERAGING') - call this%parser%GetStringCaps(keyword) - select case(keyword) - case('LOGARITHMIC') - this%icellavg = 1 - write(this%iout, fmtcellavg) 'LOGARITHMIC' - case('AMT-LMK') - this%icellavg = 2 - write(this%iout, fmtcellavg) 'AMT-LMK' - case('AMT-HMK') - this%icellavg = 3 - write(this%iout, fmtcellavg) 'AMT-HMK' - case default - write(errmsg,'(4x,a,a)')'UNKNOWN CELL AVERAGING METHOD: ', & - keyword - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - write(this%iout,'(4x,a,a)') & - 'CELL AVERAGING METHOD HAS BEEN SET TO: ', keyword - case ('THICKSTRT') - this%ithickstrt = 1 - write(this%iout, '(4x,a)') 'THICKSTRT OPTION HAS BEEN ACTIVATED.' - case ('PERCHED') - this%iperched = 1 - write(this%iout,'(4x,a)') & - 'VERTICAL FLOW WILL BE ADJUSTED FOR PERCHED CONDITIONS.' - case ('VARIABLECV') - this%ivarcv = 1 - write(this%iout,'(4x,a)') & - 'VERTICAL CONDUCTANCE VARIES WITH WATER TABLE.' - call this%parser%GetStringCaps(keyword) - if(keyword == 'DEWATERED') then - this%idewatcv = 1 - write(this%iout,'(4x,a)') & - 'VERTICAL CONDUCTANCE ACCOUNTS FOR DEWATERED PORTION OF ' // & - 'AN UNDERLYING CELL.' - endif - case ('REWET') - call this%rewet_options() - case ('XT3D') - this%ixt3d = 1 - write(this%iout, '(4x,a)') & - 'XT3D FORMULATION IS SELECTED.' - call this%parser%GetStringCaps(keyword) - if(keyword == 'RHS') then - this%ixt3d = 2 - endif - case ('SAVE_SPECIFIC_DISCHARGE') - this%icalcspdis = 1 - this%isavspdis = 1 - write(this%iout,'(4x,a)') & - 'SPECIFIC DISCHARGE WILL BE CALCULATED AT CELL CENTERS ' // & - 'AND WRITTEN TO DATA-SPDIS IN BUDGET FILE WHEN REQUESTED.' - case ('SAVE_SATURATION') - this%isavsat = 1 - write(this%iout,'(4x,a)') & - 'SATURATION WILL BE WRITTEN TO DATA-SAT IN BUDGET FILE ' // & - 'WHEN REQUESTED.' - case ('K22OVERK') - this%ik22overk = 1 - write(this%iout,'(4x,a)') & - 'VALUES SPECIFIED FOR K22 ARE ANISOTROPY RATIOS AND ' // & - 'WILL BE MULTIPLIED BY K BEFORE BEING USED IN CALCULATIONS.' - case ('K33OVERK') - this%ik33overk = 1 - write(this%iout,'(4x,a)') & - 'VALUES SPECIFIED FOR K33 ARE ANISOTROPY RATIOS AND ' // & - 'WILL BE MULTIPLIED BY K BEFORE BEING USED IN CALCULATIONS.' - case ('TVK6') - if (this%intvk /= 0) then - errmsg = 'Multiple TVK6 keywords detected in OPTIONS block.' // & - ' Only one TVK6 entry allowed.' - call store_error(errmsg, terminate=.TRUE.) - end if - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TVK6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg, terminate=.TRUE.) - endif - call this%parser%GetString(fname) - this%intvk = GetUnit() - call openfile(this%intvk, this%iout, fname, 'TVK') - call tvk_cr(this%tvk, this%name_model, this%intvk, this%iout) - ! - ! -- The following are options that are only available in the - ! development version and are not included in the documentation. - ! These options are only available when IDEVELOPMODE in - ! constants module is set to 1 - case ('DEV_NO_NEWTON') - call this%parser%DevOpt() - this%inewton = 0 - write(this%iout, '(4x,a)') & - 'NEWTON-RAPHSON method disabled for unconfined cells' - this%iasym = 0 - case ('DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION') - call this%parser%DevOpt() - this%iusgnrhc = 1 - write(this%iout, '(4x,a)') & - 'MODFLOW-USG saturation calculation method will be used ' - case ('DEV_MODFLOWNWT_UPSTREAM_WEIGHTING') - call this%parser%DevOpt() - this%inwtupw = 1 - write(this%iout, '(4x,a)') & - 'MODFLOW-NWT upstream weighting method will be used ' - case ('DEV_MINIMUM_SATURATED_THICKNESS') - call this%parser%DevOpt() - this%satmin = this%parser%GetDouble() - write(this%iout, '(4x,a,1pg15.6)') & - 'MINIMUM SATURATED THICKNESS HAS BEEN SET TO: ', & - this%satmin - case ('DEV_OMEGA') - call this%parser%DevOpt() - this%satomega = this%parser%GetDouble() - write(this%iout, '(4x,a,1pg15.6)') & - 'SATURATION OMEGA: ', this%satomega - - case default - write(errmsg,'(4x,a,a)') 'Unknown NPF option: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)') 'END OF NPF OPTIONS' - end if - ! -- check if this%iusgnrhc has been enabled for a model that is not using - ! the Newton-Raphson formulation - if (this%iusgnrhc > 0 .and. this%inewton == 0) then - this%iusgnrhc = 0 - write(this%iout, '(4x,a,3(1x,a))') & - '****WARNING. MODFLOW-USG saturation calculation not needed', & - 'for a model that is using the standard conductance formulation.', & - 'Resetting DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION OPTION from', & - '1 to 0.' - end if - ! - ! -- check that the this%inwtupw option is not specified for non-newton - ! models - if (this%inwtupw /= 0 .and. this%inewton == 0) then - this%inwtupw = 0 - write(this%iout,'(4x,a,3(1x,a))') & - '****WARNING. The DEV_MODFLOWNWT_UPSTREAM_WEIGHTING option has', & - 'been specified for a model that is using the standard conductance', & - 'formulation. Resetting DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTION from', & - '1 to 0.' - end if - ! - ! -- check that the transmissivity weighting functions are not specified with - ! with the this%inwtupw option - if (this%inwtupw /= 0 .and. this%icellavg < 2) then - write(errmsg,'(4x,a,2(1x,a))') & - '****ERROR. THE DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTION CAN', & - 'ONLY BE SPECIFIED WITH THE AMT-LMK AND AMT-HMK', & - 'ALTERNATIVE_CELL_AVERAGING OPTIONS IN THE NPF PACKAGE.' - call store_error(errmsg) - end if - ! - ! -- check that this%iusgnrhc and this%inwtupw have not both been enabled - if (this%iusgnrhc /= 0 .and. this%inwtupw /= 0) then - write(errmsg,'(4x,a,2(1x,a))') & - '****ERROR. THE DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION', & - 'AND DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTIONS CANNOT BE', & - 'SPECIFIED IN THE SAME NPF PACKAGE.' - call store_error(errmsg) + ! -- modules + use KindModule, only: LGP + use MemoryHelperModule, only: create_mem_path + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfNpfInputModule, only: GwfNpfParamFoundType + ! -- dummy + class(GwfNpftype) :: this + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + character(len=LENVARNAME), dimension(3) :: cellavg_method = & + &[character(len=LENVARNAME) :: 'LOGARITHMIC', 'AMT-LMK', 'AMT-HMK'] + type(GwfNpfParamFoundType) :: found + character(len=LINELENGTH) :: tvk6_filename +! ------------------------------------------------------------------------------ + ! + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'NPF', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%iprflow, 'IPRFLOW', idmMemoryPath, found%iprflow) + call mem_set_value(this%ipakcb, 'IPAKCB', idmMemoryPath, found%ipakcb) + call mem_set_value(this%icellavg, 'CELLAVG', idmMemoryPath, cellavg_method, & + found%cellavg) + call mem_set_value(this%ithickstrt, 'ITHICKSTRT', idmMemoryPath, & + found%ithickstrt) + call mem_set_value(this%iperched, 'IPERCHED', idmMemoryPath, found%iperched) + call mem_set_value(this%ivarcv, 'IVARCV', idmMemoryPath, found%ivarcv) + call mem_set_value(this%idewatcv, 'IDEWATCV', idmMemoryPath, found%idewatcv) + call mem_set_value(this%ixt3d, 'IXT3D', idmMemoryPath, found%ixt3d) + call mem_set_value(this%ixt3drhs, 'IXT3DRHS', idmMemoryPath, found%ixt3drhs) + call mem_set_value(this%isavspdis, 'ISAVSPDIS', idmMemoryPath, & + found%isavspdis) + call mem_set_value(this%isavsat, 'ISAVSAT', idmMemoryPath, found%isavsat) + call mem_set_value(this%ik22overk, 'IK22OVERK', idmMemoryPath, & + found%ik22overk) + call mem_set_value(this%ik33overk, 'IK33OVERK', idmMemoryPath, & + found%ik33overk) + call mem_set_value(tvk6_filename, 'TVK6_FILENAME', idmMemoryPath, & + found%tvk6_filename) + call mem_set_value(this%inewton, 'INEWTON', idmMemoryPath, found%inewton) + call mem_set_value(this%iusgnrhc, 'IUSGNRHC', idmMemoryPath, & + found%iusgnrhc) + call mem_set_value(this%inwtupw, 'INWTUPW', idmMemoryPath, found%inwtupw) + call mem_set_value(this%satmin, 'SATMIN', idmMemoryPath, found%satmin) + call mem_set_value(this%satomega, 'SATOMEGA', idmMemoryPath, found%satomega) + call mem_set_value(this%irewet, 'IREWET', idmMemoryPath, found%irewet) + call mem_set_value(this%wetfct, 'WETFCT', idmMemoryPath, found%wetfct) + call mem_set_value(this%iwetit, 'IWETIT', idmMemoryPath, found%iwetit) + call mem_set_value(this%ihdwet, 'IHDWET', idmMemoryPath, found%ihdwet) + ! + ! -- save flows option active + if (found%ipakcb) this%ipakcb = -1 + ! + ! -- xt3d active with rhs + if (found%ixt3d .and. found%ixt3drhs) this%ixt3d = 2 + ! + ! -- save specific discharge active + if (found%isavspdis) this%icalcspdis = this%isavspdis + ! + ! -- TVK6 subpackage file spec provided + if (found%tvk6_filename) then + this%intvk = GetUnit() + call openfile(this%intvk, this%iout, tvk6_filename, 'TVK') + call tvk_cr(this%tvk, this%name_model, this%intvk, this%iout) end if ! - ! -- set omega value used for saturation calculations - if (this%inewton > 0) then - this%satomega = DEM6 + ! -- no newton specified + if (found%inewton) then + this%inewton = 0 + this%iasym = 0 end if ! - ! -- terminate if errors encountered in options block - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + ! -- log options + if (this%iout > 0) then + call this%log_options(found) end if ! ! -- Return return - end subroutine read_options + end subroutine source_options subroutine set_options(this, options) class(GwfNpftype) :: this type(GwfNpfOptionsType), intent(in) :: options - this%icellavg = options%icellavg - this%ithickstrt = options%ithickstrt - this%iperched = options%iperched - this%ivarcv = options%ivarcv - this%idewatcv = options%idewatcv - this%irewet = options%irewet - this%wetfct = options%wetfct - this%iwetit = options%iwetit - this%ihdwet = options%ihdwet + this%icellavg = options%icellavg + this%ithickstrt = options%ithickstrt + this%iperched = options%iperched + this%ivarcv = options%ivarcv + this%idewatcv = options%idewatcv + this%irewet = options%irewet + this%wetfct = options%wetfct + this%iwetit = options%iwetit + this%ihdwet = options%ihdwet end subroutine set_options - subroutine rewet_options(this) -! ****************************************************************************** -! rewet_options -- Set rewet options -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - ! -- modules - use SimModule, only: store_error - use ConstantsModule, only: LINELENGTH - ! -- dummy - class(GwfNpftype) :: this - ! -- local - integer(I4B) :: ival - character(len=LINELENGTH) :: keyword, errmsg - logical, dimension(3) :: lfound = .false. -! ------------------------------------------------------------------------------ - ! - ! -- If rewet already set, then terminate with error - if (this%irewet == 1) then - write(errmsg, '(a)') 'ERROR WITH NPF REWET OPTION. REWET WAS ' // & - 'ALREADY SET. REMOVE DUPLICATE REWET ENTRIES ' // & - 'FROM NPF OPTIONS BLOCK.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - this%irewet = 1 - write(this%iout,'(4x,a)')'REWETTING IS ACTIVE.' - ! - ! -- Parse rewet options - do - call this%parser%GetStringCaps(keyword) - if (keyword == '') exit - select case (keyword) - case ('WETFCT') - this%wetfct = this%parser%GetDouble() - write(this%iout,'(4x,a,1pg15.6)') & - 'WETTING FACTOR HAS BEEN SET TO: ', this%wetfct - lfound(1) = .true. - case ('IWETIT') - if (.not. lfound(1)) then - write(errmsg,'(4x,a)') & - 'NPF rewetting flags must be specified in order. ' // & - 'Found iwetit but wetfct not specified.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - ival = this%parser%GetInteger() - if(ival <= 0) ival = 1 - this%iwetit = ival - write(this%iout,'(4x,a,i5)') 'IWETIT HAS BEEN SET TO: ', & - this%iwetit - lfound(2) = .true. - case ('IHDWET') - if (.not. lfound(2)) then - write(errmsg,'(4x,a)') & - 'NPF rewetting flags must be specified in order. ' // & - 'Found ihdwet but iwetit not specified.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - this%ihdwet = this%parser%GetInteger() - write(this%iout,'(4x,a,i5)') 'IHDWET HAS BEEN SET TO: ', & - this%ihdwet - lfound(3) = .true. - case default - write(errmsg,'(4x,a,a)') 'Unknown NPF rewet option: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - enddo - ! - if (.not. lfound(3)) then - write(errmsg,'(4x,a)') & - '****ERROR. NPF REWETTING FLAGS MUST BE SPECIFIED IN ORDER. ' // & - 'DID NOT FIND IHDWET AS LAST REWET SETTING.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - ! - ! -- Write rewet settings - write(this%iout, '(4x, a)') 'THE FOLLOWING REWET SETTINGS WILL BE USED.' - write(this%iout, '(6x, a,1pg15.6)') ' WETFCT = ', this%wetfct - write(this%iout, '(6x, a,i0)') ' IWETIT = ', this%iwetit - write(this%iout, '(6x, a,i0)') ' IHDWET = ', this%ihdwet - ! - ! -- Return - return - end subroutine rewet_options - subroutine check_options(this) ! ****************************************************************************** ! check_options -- Check for conflicting NPF options @@ -1623,266 +1586,251 @@ subroutine check_options(this) ! -- local character(len=LINELENGTH) :: errmsg ! ------------------------------------------------------------------------------ + ! -- check if this%iusgnrhc has been enabled for a model that is not using + ! the Newton-Raphson formulation + if (this%iusgnrhc > 0 .and. this%inewton == 0) then + this%iusgnrhc = 0 + write (this%iout, '(4x,a,3(1x,a))') & + '****WARNING. MODFLOW-USG saturation calculation not needed', & + 'for a model that is using the standard conductance formulation.', & + 'Resetting DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION OPTION from', & + '1 to 0.' + end if + ! + ! -- check that the this%inwtupw option is not specified for non-newton + ! models + if (this%inwtupw /= 0 .and. this%inewton == 0) then + this%inwtupw = 0 + write (this%iout, '(4x,a,3(1x,a))') & + '****WARNING. The DEV_MODFLOWNWT_UPSTREAM_WEIGHTING option has', & + 'been specified for a model that is using the standard conductance', & + 'formulation. Resetting DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTION from', & + '1 to 0.' + end if + ! + ! -- check that the transmissivity weighting functions are not specified with + ! with the this%inwtupw option + if (this%inwtupw /= 0 .and. this%icellavg < 2) then + write (errmsg, '(4x,a,2(1x,a))') & + '****ERROR. THE DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTION CAN', & + 'ONLY BE SPECIFIED WITH THE AMT-LMK AND AMT-HMK', & + 'ALTERNATIVE_CELL_AVERAGING OPTIONS IN THE NPF PACKAGE.' + call store_error(errmsg) + end if + ! + ! -- check that this%iusgnrhc and this%inwtupw have not both been enabled + if (this%iusgnrhc /= 0 .and. this%inwtupw /= 0) then + write (errmsg, '(4x,a,2(1x,a))') & + '****ERROR. THE DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION', & + 'AND DEV_MODFLOWNWT_UPSTREAM_WEIGHTING OPTIONS CANNOT BE', & + 'SPECIFIED IN THE SAME NPF PACKAGE.' + call store_error(errmsg) + end if + ! + ! -- set omega value used for saturation calculations + if (this%inewton > 0) then + this%satomega = DEM6 + end if ! - if(this%inewton > 0) then - if(this%iperched > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT ' // & - 'BE USED WITH PERCHED OPTION.' + if (this%inewton > 0) then + if (this%iperched > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// & + 'BE USED WITH PERCHED OPTION.' call store_error(errmsg) - endif - if(this%ivarcv > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT ' // & - 'BE USED WITH VARIABLECV OPTION.' + end if + if (this%ivarcv > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// & + 'BE USED WITH VARIABLECV OPTION.' call store_error(errmsg) - endif - if(this%irewet > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT ' // & - 'BE USED WITH REWET OPTION.' + end if + if (this%irewet > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. NEWTON OPTION CANNOT '// & + 'BE USED WITH REWET OPTION.' call store_error(errmsg) - endif - endif + end if + end if ! if (this%ixt3d /= 0) then - if(this%icellavg > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. ' // & - 'ALTERNATIVE_CELL_AVERAGING OPTION ' // & - 'CANNOT BE USED WITH XT3D OPTION.' + if (this%icellavg > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. '// & + 'ALTERNATIVE_CELL_AVERAGING OPTION '// & + 'CANNOT BE USED WITH XT3D OPTION.' call store_error(errmsg) - endif - if(this%ithickstrt > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. THICKSTRT OPTION ' // & - 'CANNOT BE USED WITH XT3D OPTION.' + end if + if (this%ithickstrt > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. THICKSTRT OPTION '// & + 'CANNOT BE USED WITH XT3D OPTION.' call store_error(errmsg) - endif - if(this%iperched > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. PERCHED OPTION ' // & - 'CANNOT BE USED WITH XT3D OPTION.' + end if + if (this%iperched > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. PERCHED OPTION '// & + 'CANNOT BE USED WITH XT3D OPTION.' call store_error(errmsg) - endif - if(this%ivarcv > 0) then - write(errmsg, '(a)') 'ERROR IN NPF OPTIONS. VARIABLECV OPTION ' // & - 'CANNOT BE USED WITH XT3D OPTION.' + end if + if (this%ivarcv > 0) then + write (errmsg, '(a)') 'ERROR IN NPF OPTIONS. VARIABLECV OPTION '// & + 'CANNOT BE USED WITH XT3D OPTION.' call store_error(errmsg) - endif + end if end if ! ! -- Terminate if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return end subroutine check_options - subroutine read_grid_data(this) + !> @brief Write dimensions to list file + !< + subroutine log_griddata(this, found) + use GwfNpfInputModule, only: GwfNpfParamFoundType + class(GwfNpfType) :: this + type(GwfNpfParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting NPF Griddata' + + if (found%icelltype) then + write (this%iout, '(4x,a)') 'ICELLTYPE set from input file' + end if + + if (found%k) then + write (this%iout, '(4x,a)') 'K set from input file' + end if + + if (found%k33) then + write (this%iout, '(4x,a)') 'K33 set from input file' + else + write (this%iout, '(4x,a)') 'K33 not provided. Setting K33 = K.' + end if + + if (found%k22) then + write (this%iout, '(4x,a)') 'K22 set from input file' + else + write (this%iout, '(4x,a)') 'K22 not provided. Setting K22 = K.' + end if + + if (found%wetdry) then + write (this%iout, '(4x,a)') 'WETDRY set from input file' + end if + + if (found%angle1) then + write (this%iout, '(4x,a)') 'ANGLE1 set from input file' + end if + + if (found%angle2) then + write (this%iout, '(4x,a)') 'ANGLE2 set from input file' + end if + + if (found%angle3) then + write (this%iout, '(4x,a)') 'ANGLE3 set from input file' + end if + + write (this%iout, '(1x,a,/)') 'End Setting NPF Griddata' + + end subroutine log_griddata + + subroutine source_griddata(this) ! ****************************************************************************** -! read_grid_data -- read the npf data block +! source_griddata -- update simulation griddata from input mempath ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH, DONE, DPIO180 - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_deallocate, & - mem_reassignptr - use SimModule, only: store_error, count_errors + use SimModule, only: count_errors, store_error + use MemoryHelperModule, only: create_mem_path + use MemoryManagerModule, only: mem_reallocate + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use GwfNpfInputModule, only: GwfNpfParamFoundType ! -- dummy class(GwfNpftype) :: this - ! -- local + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath character(len=LINELENGTH) :: errmsg - integer(I4B) :: n, ierr - logical :: isfound - logical, dimension(8) :: lname - character(len=24), dimension(:), pointer :: aname - character(len=24), dimension(8) :: varinames + type(GwfNpfParamFoundType) :: found + logical, dimension(2) :: afound + integer(I4B), dimension(:), pointer, contiguous :: map ! -- formats - character(len=*), parameter :: fmtiprflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE PRINTED TO LISTING FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtnct = & - "(1x, 'Negative cell thickness at cell: ', a)" - ! -- data - !data aname(1) /' ICELLTYPE'/ - !data aname(2) /' K'/ - !data aname(3) /' K33'/ - !data aname(4) /' K22'/ - !data aname(5) /' WETDRY'/ - !data aname(6) /' ANGLE1'/ - !data aname(7) /' ANGLE2'/ - !data aname(8) /' ANGLE3'/ ! ------------------------------------------------------------------------------ ! - ! -- Initialize - aname => this%aname - do n = 1, size(aname) - varinames(n) = adjustl(aname(n)) - lname(n) = .false. - end do - varinames(2) = 'K11 ' - ! - ! -- Read all of the arrays in the GRIDDATA block using the get_block_data - ! method, which is part of NumericalPackageType - call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' - call this%get_block_data(aname, lname, varinames) - else - write(errmsg,'(1x,a)') 'Required GRIDDATA block not found.' + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'NPF', idm_context) + ! + ! -- set map to convert user input data into reduced data + map => null() + if (this%dis%nodes < this%dis%nodesuser) map => this%dis%nodeuser + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%icelltype, 'ICELLTYPE', idmMemoryPath, map, & + found%icelltype) + call mem_set_value(this%k11, 'K', idmMemoryPath, map, found%k) + call mem_set_value(this%k33, 'K33', idmMemoryPath, map, found%k33) + call mem_set_value(this%k22, 'K22', idmMemoryPath, map, found%k22) + call mem_set_value(this%wetdry, 'WETDRY', idmMemoryPath, map, found%wetdry) + call mem_set_value(this%angle1, 'ANGLE1', idmMemoryPath, map, found%angle1) + call mem_set_value(this%angle2, 'ANGLE2', idmMemoryPath, map, found%angle2) + call mem_set_value(this%angle3, 'ANGLE3', idmMemoryPath, map, found%angle3) + ! + ! -- ensure ICELLTYPE was found + if (.not. found%icelltype) then + write (errmsg, '(a)') 'Error in GRIDDATA block: ICELLTYPE not found.' call store_error(errmsg) - call this%parser%StoreErrorUnit() end if ! - ! -- Check for ICELLTYPE - if(.not. lname(1)) then - write(errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', & - trim(adjustl(aname(1))), ' not found.' + ! -- ensure K was found + if (.not. found%k) then + write (errmsg, '(a)') 'Error in GRIDDATA block: K not found.' call store_error(errmsg) - endif + end if ! - ! -- Check for K - if(.not. lname(2)) then - write(errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', & - trim(adjustl(aname(2))), ' not found.' + ! -- set error if ik33overk set with no k33 + if (.not. found%k33 .and. this%ik33overk /= 0) then + write (errmsg, '(a)') 'K33OVERK option specified but K33 not specified.' call store_error(errmsg) - endif - ! - ! -- set ik33 flag - if(lname(3)) then - this%ik33 = 1 - else - if (this%ik33overk /= 0) then - write(errmsg, '(a)') 'K33OVERK option specified but K33 not specified.' - call store_error(errmsg) - endif - write(this%iout, '(1x, a)') 'K33 not provided. Assuming K33 = K.' - call mem_reassignptr(this%k33, 'K33', trim(this%memoryPath), & - 'K11', trim(this%memoryPath)) - endif - ! - ! -- set ik22 flag - if(lname(4)) then - this%ik22 = 1 - else - if (this%ik22overk /= 0) then - write(errmsg, '(a)') 'K22OVERK option specified but K22 not specified.' - call store_error(errmsg) - endif - write(this%iout, '(1x, a)') 'K22 not provided. Assuming K22 = K.' - call mem_reassignptr(this%k22, 'K22', trim(this%memoryPath), & - 'K11', trim(this%memoryPath)) - endif - ! - ! -- Set WETDRY - if (lname(5)) then - this%iwetdry = 1 - else - call mem_reallocate(this%wetdry, 1, 'WETDRY', trim(this%memoryPath)) end if ! - ! -- set angle flags - if (lname(6)) then - this%iangle1 = 1 - else - if (this%ixt3d == 0) then - call mem_reallocate(this%angle1, 1, 'ANGLE1', trim(this%memoryPath)) - end if - endif - if (lname(7)) then - this%iangle2 = 1 - else - if (this%ixt3d == 0) then - call mem_reallocate(this%angle2, 1, 'ANGLE2', trim(this%memoryPath)) - end if - endif - if (lname(8)) then - this%iangle3 = 1 - else - if (this%ixt3d == 0) then - call mem_reallocate(this%angle3, 1, 'ANGLE3', trim(this%memoryPath)) - end if - endif - ! - ! -- terminate if read errors encountered - if(count_errors() > 0) then - call this%parser%StoreErrorUnit() - endif - ! - ! -- Final NPFDATA message - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' - ! - ! -- Return - return - end subroutine read_grid_data - - subroutine set_grid_data(this, npf_data) - use MemoryManagerModule, only: mem_reallocate, mem_reassignptr - class(GwfNpfType), intent(inout) :: this - type(GwfNpfGridDataType), intent(in) :: npf_data - - ! fill grid arrays - call this%dis%fill_grid_array(npf_data%icelltype, this%icelltype) - call this%dis%fill_grid_array(npf_data%k11, this%k11) - - if (npf_data%ik22 == 1) then - this%ik22 = 1 - call this%dis%fill_grid_array(npf_data%k22, this%k22) - else - ! if not present, then K22 = K11 - this%ik22 = 0 - call mem_reassignptr(this%k22, 'K22', trim(this%memoryPath), & - 'K11', trim(this%memoryPath)) + ! -- set error if ik22overk set with no k22 + if (.not. found%k22 .and. this%ik22overk /= 0) then + write (errmsg, '(a)') 'K22OVERK option specified but K22 not specified.' + call store_error(errmsg) end if - - if (npf_data%ik33 == 1) then - this%ik33 = 1 - call this%dis%fill_grid_array(npf_data%k33, this%k33) - else - ! if not present, then K33 = K11 - this%ik33 = 0 - call mem_reassignptr(this%k33, 'K33', trim(this%memoryPath), & - 'K11', trim(this%memoryPath)) + ! + ! -- handle found side effects + if (found%k33) this%ik33 = 1 + if (found%k22) this%ik22 = 1 + if (found%wetdry) this%iwetdry = 1 + if (found%angle1) this%iangle1 = 1 + if (found%angle2) this%iangle2 = 1 + if (found%angle3) this%iangle3 = 1 + ! + ! -- handle not found side effects + if (.not. found%k33) then + call mem_set_value(this%k33, 'K', idmMemoryPath, map, afound(1)) end if - - if (npf_data%iwetdry == 1) then - call this%dis%fill_grid_array(npf_data%wetdry, this%wetdry) - else - ! if not present, then compress array - this%iwetdry = 0 - call mem_reallocate(this%wetdry, 1, 'WETDRY', trim(this%memoryPath)) + if (.not. found%k22) then + call mem_set_value(this%k22, 'K', idmMemoryPath, map, afound(2)) end if - - if (npf_data%iangle1 == 1) then - this%iangle1 = 1 - call this%dis%fill_grid_array(npf_data%angle1, this%angle1) - else - ! if not present, then compress array - this%iangle1 = 0 + if (.not. found%wetdry) call mem_reallocate(this%wetdry, 1, 'WETDRY', & + trim(this%memoryPath)) + if (.not. found%angle1 .and. this%ixt3d == 0) & call mem_reallocate(this%angle1, 1, 'ANGLE1', trim(this%memoryPath)) - end if - - if (npf_data%iangle2 == 1) then - this%iangle2 = 1 - call this%dis%fill_grid_array(npf_data%angle2, this%angle2) - else - ! if not present, then compress array - this%iangle2 = 0 + if (.not. found%angle2 .and. this%ixt3d == 0) & call mem_reallocate(this%angle2, 1, 'ANGLE2', trim(this%memoryPath)) - end if - - if (npf_data%iangle3 == 1) then - this%iangle3 = 1 - call this%dis%fill_grid_array(npf_data%angle3, this%angle3) - else - ! if not present, then compress array - this%iangle3 = 0 + if (.not. found%angle3 .and. this%ixt3d == 0) & call mem_reallocate(this%angle3, 1, 'ANGLE3', trim(this%memoryPath)) + ! + ! -- log griddata + if (this%iout > 0) then + call this%log_griddata(found) end if - - end subroutine set_grid_data + ! + ! -- Return + return + end subroutine source_griddata subroutine prepcheck(this) ! ****************************************************************************** @@ -1891,7 +1839,7 @@ subroutine prepcheck(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH, DPIO180 + use ConstantsModule, only: LINELENGTH, DPIO180 use SimModule, only: store_error, count_errors ! -- dummy class(GwfNpfType) :: this @@ -1900,10 +1848,10 @@ subroutine prepcheck(this) character(len=LINELENGTH) :: cellstr, errmsg integer(I4B) :: nerr, n ! -- format - character(len=*), parameter :: fmtkerr = & - "(1x, 'Hydraulic property ',a,' is <= 0 for cell ',a, ' ', 1pg15.6)" - character(len=*), parameter :: fmtkerr2 = & - "(1x, '... ', i0,' additional errors not shown for ',a)" + character(len=*), parameter :: fmtkerr = & + &"(1x, 'Hydraulic property ',a,' is <= 0 for cell ',a, ' ', 1pg15.6)" + character(len=*), parameter :: fmtkerr2 = & + &"(1x, '... ', i0,' additional errors not shown for ',a)" ! ------------------------------------------------------------------------------ ! ! -- initialize @@ -1912,20 +1860,20 @@ subroutine prepcheck(this) ! -- check k11 nerr = 0 do n = 1, size(this%k11) - if(this%k11(n) <= DZERO) then + if (this%k11(n) <= DZERO) then nerr = nerr + 1 - if(nerr <= 20) then + if (nerr <= 20) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(aname(2))), trim(cellstr), & - this%k11(n) + write (errmsg, fmtkerr) trim(adjustl(aname(2))), trim(cellstr), & + this%k11(n) call store_error(errmsg) - endif - endif - enddo - if(nerr > 20) then - write(errmsg, fmtkerr2) nerr, trim(adjustl(aname(2))) + end if + end if + end do + if (nerr > 20) then + write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(2))) call store_error(errmsg) - endif + end if ! ! -- check k33 because it was read if (this%ik33 /= 0) then @@ -1934,119 +1882,119 @@ subroutine prepcheck(this) nerr = 0 do n = 1, size(this%k33) if (this%ik33overk /= 0) this%k33(n) = this%k33(n) * this%k11(n) - if(this%k33(n) <= DZERO) then + if (this%k33(n) <= DZERO) then nerr = nerr + 1 - if(nerr <= 20) then + if (nerr <= 20) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(aname(3))), trim(cellstr), & - this%k33(n) + write (errmsg, fmtkerr) trim(adjustl(aname(3))), trim(cellstr), & + this%k33(n) call store_error(errmsg) - endif - endif - enddo - if(nerr > 20) then - write(errmsg, fmtkerr2) nerr, trim(adjustl(aname(3))) + end if + end if + end do + if (nerr > 20) then + write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(3))) call store_error(errmsg) - endif + end if end if ! ! -- check k22 because it was read if (this%ik22 /= 0) then ! ! -- Check to make sure that angles are available - if(this%dis%con%ianglex == 0) then - write(errmsg, '(a)') 'Error. ANGLDEGX not provided in ' // & - 'discretization file, but K22 was specified. ' + if (this%dis%con%ianglex == 0) then + write (errmsg, '(a)') 'Error. ANGLDEGX not provided in '// & + 'discretization file, but K22 was specified. ' call store_error(errmsg) - endif + end if ! ! -- Check to make sure values are greater than or equal to zero nerr = 0 do n = 1, size(this%k22) if (this%ik22overk /= 0) this%k22(n) = this%k22(n) * this%k11(n) - if(this%k22(n) <= DZERO) then + if (this%k22(n) <= DZERO) then nerr = nerr + 1 - if(nerr <= 20) then + if (nerr <= 20) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(aname(4))), trim(cellstr), & - this%k22(n) + write (errmsg, fmtkerr) trim(adjustl(aname(4))), trim(cellstr), & + this%k22(n) call store_error(errmsg) - endif - endif - enddo - if(nerr > 20) then - write(errmsg, fmtkerr2) nerr, trim(adjustl(aname(4))) + end if + end if + end do + if (nerr > 20) then + write (errmsg, fmtkerr2) nerr, trim(adjustl(aname(4))) call store_error(errmsg) - endif + end if end if ! ! -- check for wetdry conflicts - if(this%irewet == 1) then - if(this%iwetdry == 0) then - write(errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', & - trim(adjustl(aname(5))), ' not found.' + if (this%irewet == 1) then + if (this%iwetdry == 0) then + write (errmsg, '(a, a, a)') 'Error in GRIDDATA block: ', & + trim(adjustl(aname(5))), ' not found.' call store_error(errmsg) end if - endif + end if ! ! -- Check for angle conflicts if (this%iangle1 /= 0) then do n = 1, size(this%angle1) this%angle1(n) = this%angle1(n) * DPIO180 - enddo + end do else - if(this%ixt3d /= 0) then + if (this%ixt3d /= 0) then this%iangle1 = 1 - write(this%iout, '(a)') 'XT3D IN USE, BUT ANGLE1 NOT SPECIFIED. ' // & + write (this%iout, '(a)') 'XT3D IN USE, BUT ANGLE1 NOT SPECIFIED. '// & 'SETTING ANGLE1 TO ZERO.' do n = 1, size(this%angle1) this%angle1(n) = DZERO - enddo - endif - endif + end do + end if + end if if (this%iangle2 /= 0) then if (this%iangle1 == 0) then - write(errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE1. ' // & - 'ANGLE2 REQUIRES ANGLE1. ' + write (errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE1. '// & + 'ANGLE2 REQUIRES ANGLE1. ' call store_error(errmsg) - endif + end if if (this%iangle3 == 0) then - write(errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE3. ' // & - 'SPECIFY BOTH OR NEITHER ONE. ' + write (errmsg, '(a)') 'ANGLE2 SPECIFIED BUT NOT ANGLE3. '// & + 'SPECIFY BOTH OR NEITHER ONE. ' call store_error(errmsg) - endif + end if do n = 1, size(this%angle2) this%angle2(n) = this%angle2(n) * DPIO180 - enddo - endif + end do + end if if (this%iangle3 /= 0) then if (this%iangle1 == 0) then - write(errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE1. ' // & - 'ANGLE3 REQUIRES ANGLE1. ' + write (errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE1. '// & + 'ANGLE3 REQUIRES ANGLE1. ' call store_error(errmsg) - endif + end if if (this%iangle2 == 0) then - write(errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE2. ' // & - 'SPECIFY BOTH OR NEITHER ONE. ' + write (errmsg, '(a)') 'ANGLE3 SPECIFIED BUT NOT ANGLE2. '// & + 'SPECIFY BOTH OR NEITHER ONE. ' call store_error(errmsg) - endif + end if do n = 1, size(this%angle3) this%angle3(n) = this%angle3(n) * DPIO180 - enddo - endif + end do + end if ! ! -- terminate if data errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif - + end if + return end subroutine prepcheck !> @brief preprocess the NPF input data !! !! This routine consists of the following steps: - !! + !! !! 1. convert cells to noflow when all transmissive parameters equal zero !! 2. perform initial wetting and drying !! 3. initialize cell saturation @@ -2054,28 +2002,27 @@ end subroutine prepcheck !! 5. If NEWTON under-relaxation, determine lower most node !< subroutine preprocess_input(this) - use ConstantsModule, only: LINELENGTH - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_deallocate - use SimModule, only: store_error, count_errors + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error, count_errors class(GwfNpfType) :: this !< the instance of the NPF package - ! local + ! local integer(I4B) :: n, m, ii, nn real(DP) :: hyn, hym - real(DP) :: satn, topn, botn + real(DP) :: satn, topn, botn integer(I4B) :: nextn - real(DP) :: minbot, botm + real(DP) :: minbot, botm logical :: finished character(len=LINELENGTH) :: cellstr, errmsg ! format strings - character(len=*),parameter :: fmtcnv = & - "(1X,'CELL ', A, & - &' ELIMINATED BECAUSE ALL HYDRAULIC CONDUCTIVITIES TO NODE ARE 0.')" - character(len=*),parameter :: fmtnct = & - "(1X,'Negative cell thickness at cell ', A)" - character(len=*),parameter :: fmtihbe = & - "(1X,'Initial head, bottom elevation:',1P,2G13.5)" - character(len=*),parameter :: fmttebe = & - "(1X,'Top elevation, bottom elevation:',1P,2G13.5)" + character(len=*), parameter :: fmtcnv = & + "(1X,'CELL ', A, & + &' ELIMINATED BECAUSE ALL HYDRAULIC CONDUCTIVITIES TO NODE ARE 0.')" + character(len=*), parameter :: fmtnct = & + &"(1X,'Negative cell thickness at cell ', A)" + character(len=*), parameter :: fmtihbe = & + &"(1X,'Initial head, bottom elevation:',1P,2G13.5)" + character(len=*), parameter :: fmttebe = & + &"(1X,'Top elevation, bottom elevation:',1P,2G13.5)" ! do n = 1, this%dis%nodes this%ithickstartflag(n) = 0 @@ -2087,41 +2034,41 @@ subroutine preprocess_input(this) nodeloop: do n = 1, this%dis%nodes ! ! -- Skip if already inactive - if(this%ibound(n) == 0) then - if(this%irewet /= 0) then - if(this%wetdry(n) == DZERO) cycle nodeloop + if (this%ibound(n) == 0) then + if (this%irewet /= 0) then + if (this%wetdry(n) == DZERO) cycle nodeloop else cycle nodeloop - endif - endif + end if + end if ! ! -- Cycle if k11 is not zero - if(this%k11(n) /= DZERO) cycle nodeloop + if (this%k11(n) /= DZERO) cycle nodeloop ! ! -- Cycle if at least one vertical connection has non-zero k33 ! for n and m do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ii) - if(this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then + if (this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then hyn = this%k11(n) - if(this%ik33 /= 0) hyn = this%k33(n) - if(hyn /= DZERO) then + if (this%ik33 /= 0) hyn = this%k33(n) + if (hyn /= DZERO) then hym = this%k11(m) - if(this%ik33 /= 0) hym = this%k33(m) - if(hym /= DZERO) cycle - endif - endif - enddo + if (this%ik33 /= 0) hym = this%k33(m) + if (hym /= DZERO) cycle + end if + end if + end do ! ! -- If this part of the loop is reached, then all connections have ! zero transmissivity, so convert to noflow. this%ibound(n) = 0 this%hnew(n) = this%hnoflo - if(this%irewet /= 0) this%wetdry(n) = DZERO + if (this%irewet /= 0) this%wetdry(n) = DZERO call this%dis%noder_to_string(n, cellstr) - write(this%iout, fmtcnv) trim(adjustl(cellstr)) + write (this%iout, fmtcnv) trim(adjustl(cellstr)) ! - enddo nodeloop + end do nodeloop ! ! -- Preprocess cell status and heads based on initial conditions if (this%inewton == 0) then @@ -2148,66 +2095,66 @@ subroutine preprocess_input(this) ! Initialize sat to 1.0 for all other cells in order to calculate ! condsat in next section. do n = 1, this%dis%nodes - if(this%ibound(n) == 0) then + if (this%ibound(n) == 0) then this%sat(n) = DONE - if(this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then + if (this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then this%ithickstartflag(n) = 1 this%icelltype(n) = 0 - endif + end if else topn = this%dis%top(n) botn = this%dis%bot(n) - if(this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then + if (this%icelltype(n) < 0 .and. this%ithickstrt /= 0) then call this%thksat(n, this%ic%strt(n), satn) - if(botn > this%ic%strt(n)) then + if (botn > this%ic%strt(n)) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtnct) trim(adjustl(cellstr)) + write (errmsg, fmtnct) trim(adjustl(cellstr)) call store_error(errmsg) - write(errmsg, fmtihbe) this%ic%strt(n), botn + write (errmsg, fmtihbe) this%ic%strt(n), botn call store_error(errmsg) - endif + end if this%ithickstartflag(n) = 1 this%icelltype(n) = 0 else satn = DONE - if(botn > topn) then + if (botn > topn) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtnct) trim(adjustl(cellstr)) + write (errmsg, fmtnct) trim(adjustl(cellstr)) call store_error(errmsg) - write(errmsg, fmttebe) topn, botn + write (errmsg, fmttebe) topn, botn call store_error(errmsg) - endif - endif + end if + end if this%sat(n) = satn - endif - enddo - if(count_errors() > 0) then + end if + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Calculate condsat, but only if xt3d is not active. If xt3d is ! active, then condsat is allocated to size of zero. if (this%ixt3d == 0) then - ! - ! -- Calculate the saturated conductance for all connections assuming - ! that saturation is 1 (except for case where icelltype was entered - ! as a negative value and THCKSTRT option in effect) - do n = 1, this%dis%nodes - call this%calc_condsat(n, .true.) - enddo - ! - endif + ! + ! -- Calculate the saturated conductance for all connections assuming + ! that saturation is 1 (except for case where icelltype was entered + ! as a negative value and THCKSTRT option in effect) + do n = 1, this%dis%nodes + call this%calc_condsat(n, .true.) + end do + ! + end if ! ! -- Determine the lower most node if (this%igwfnewtonur /= 0) then - call mem_reallocate(this%ibotnode, this%dis%nodes, 'IBOTNODE', & + call mem_reallocate(this%ibotnode, this%dis%nodes, 'IBOTNODE', & trim(this%memoryPath)) do n = 1, this%dis%nodes ! minbot = this%dis%bot(n) nn = n finished = .false. - do while(.not. finished) + do while (.not. finished) nextn = 0 ! ! -- Go through the connecting cells @@ -2218,7 +2165,7 @@ subroutine preprocess_input(this) botm = this%dis%bot(m) ! ! -- select vertical connections: ihc == 0 - if(this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then + if (this%dis%con%ihc(this%dis%con%jas(ii)) == 0) then if (m > nn .and. botm < minbot) then nextn = m minbot = botm @@ -2271,8 +2218,8 @@ subroutine calc_condsat(this, node, upperOnly) ! -- we're not updating both upper and lower matrix parts for this node m = this%dis%con%ja(ii) jj = this%dis%con%jas(ii) - if(m < node) then - if(upperOnly) cycle + if (m < node) then + if (upperOnly) cycle ! m => node, n => neighbour n = m m = node @@ -2296,12 +2243,12 @@ subroutine calc_condsat(this, node, upperOnly) ihc = this%dis%con%ihc(jj) hyn = this%hy_eff(n, m, ihc, ipos=ii) hym = this%hy_eff(m, n, ihc, ipos=ii) - if(this%ithickstartflag(n) == 0) then + if (this%ithickstartflag(n) == 0) then hn = topn else hn = this%ic%strt(n) end if - if(this%ithickstartflag(m) == 0) then + if (this%ithickstartflag(m) == 0) then hm = topm else hm = this%ic%strt(m) @@ -2309,33 +2256,33 @@ subroutine calc_condsat(this, node, upperOnly) ! ! -- Calculate conductance depending on whether connection is ! vertical (0), horizontal (1), or staggered horizontal (2) - if(ihc == 0) then + if (ihc == 0) then ! ! -- Vertical conductance for fully saturated conditions - csat = vcond(1, 1, 1, 1, 0, 1, 1, DONE, & - botn, botm, & - hyn, hym, & - satn, satm, & - topn, topm, & - botn, botm, & + csat = vcond(1, 1, 1, 1, 0, 1, 1, DONE, & + botn, botm, & + hyn, hym, & + satn, satm, & + topn, topm, & + botn, botm, & this%dis%con%hwva(jj)) else ! ! -- Horizontal conductance for fully saturated conditions fawidth = this%dis%con%hwva(jj) - csat = hcond(1, 1, 1, 1, this%inewton, 0, & - ihc, & - this%icellavg, this%iusgnrhc, this%inwtupw, & - DONE, & - hn, hm, satn, satm, hyn, hym, & - topn, topm, & - botn, botm, & - this%dis%con%cl1(jj), & - this%dis%con%cl2(jj), & + csat = hcond(1, 1, 1, 1, this%inewton, 0, & + ihc, & + this%icellavg, this%iusgnrhc, this%inwtupw, & + DONE, & + hn, hm, satn, satm, hyn, hym, & + topn, topm, & + botn, botm, & + this%dis%con%cl1(jj), & + this%dis%con%cl2(jj), & fawidth, this%satomega, this%satmin) end if this%condsat(jj) = csat - enddo + end do ! return end subroutine calc_condsat @@ -2355,9 +2302,9 @@ function calc_initial_sat(this, n) result(satn) real(DP) :: satn ! satn = DONE - if(this%ibound(n) /= 0 .and. this%ithickstartflag(n) /= 0) then + if (this%ibound(n) /= 0 .and. this%ithickstartflag(n) /= 0) then call this%thksat(n, this%ic%strt(n), satn) - endif + end if ! return end function calc_initial_sat @@ -2370,34 +2317,34 @@ subroutine sgwf_npf_wetdry(this, kiter, hnew) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use TdisModule, only: kstp, kper - use SimModule, only: store_error + use TdisModule, only: kstp, kper + use SimModule, only: store_error use ConstantsModule, only: LINELENGTH ! -- dummy class(GwfNpfType) :: this - integer(I4B),intent(in) :: kiter - real(DP),intent(inout),dimension(:) :: hnew + integer(I4B), intent(in) :: kiter + real(DP), intent(inout), dimension(:) :: hnew ! -- local integer(I4B) :: n, m, ii, ihc real(DP) :: ttop, bbot, thck - integer(I4B) :: ncnvrt,ihdcnv + integer(I4B) :: ncnvrt, ihdcnv character(len=30), dimension(5) :: nodcnvrt character(len=30) :: nodestr - character(len=3),dimension(5) :: acnvrt + character(len=3), dimension(5) :: acnvrt character(len=LINELENGTH) :: errmsg integer(I4B) :: irewet ! -- formats - character(len=*),parameter :: fmtnct = & - "(1X,/1X,'Negative cell thickness at (layer,row,col)', & - &I4,',',I5,',',I5)" - character(len=*),parameter :: fmttopbot = & - "(1X,'Top elevation, bottom elevation:',1P,2G13.5)" - character(len=*),parameter :: fmttopbotthk = & - "(1X,'Top elevation, bottom elevation, thickness:',1P,3G13.5)" - character(len=*),parameter :: fmtdrychd = & - "(1X,/1X,'CONSTANT-HEAD CELL WENT DRY -- SIMULATION ABORTED')" - character(len=*),parameter :: fmtni = & - "(1X,'CELLID=',a,' ITERATION=',I0,' TIME STEP=',I0,' STRESS PERIOD=',I0)" + character(len=*), parameter :: fmtnct = & + "(1X,/1X,'Negative cell thickness at (layer,row,col)', & + &I4,',',I5,',',I5)" + character(len=*), parameter :: fmttopbot = & + &"(1X,'Top elevation, bottom elevation:',1P,2G13.5)" + character(len=*), parameter :: fmttopbotthk = & + &"(1X,'Top elevation, bottom elevation, thickness:',1P,3G13.5)" + character(len=*), parameter :: fmtdrychd = & + &"(1X,/1X,'CONSTANT-HEAD CELL WENT DRY -- SIMULATION ABORTED')" + character(len=*), parameter :: fmtni = & + &"(1X,'CELLID=',a,' ITERATION=',I0,' TIME STEP=',I0,' STRESS PERIOD=',I0)" ! ------------------------------------------------------------------------------ ! -- Initialize ncnvrt = 0 @@ -2405,67 +2352,67 @@ subroutine sgwf_npf_wetdry(this, kiter, hnew) ! ! -- Convert dry cells to wet do n = 1, this%dis%nodes - do ii = this%dis%con%ia(n)+1,this%dis%con%ia(n+1)-1 + do ii = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ii) ihc = this%dis%con%ihc(this%dis%con%jas(ii)) - call this%rewet_check(kiter, n, hnew(m), this%ibound(m), ihc, hnew, & - irewet) - if(irewet == 1) then - call this%wdmsg(2,ncnvrt,nodcnvrt,acnvrt,ihdcnv,kiter,n) - endif - enddo - enddo + call this%rewet_check(kiter, n, hnew(m), this%ibound(m), ihc, hnew, & + irewet) + if (irewet == 1) then + call this%wdmsg(2, ncnvrt, nodcnvrt, acnvrt, ihdcnv, kiter, n) + end if + end do + end do ! ! -- Perform drying - do n=1,this%dis%nodes + do n = 1, this%dis%nodes ! ! -- cycle if inactive or confined - if(this%ibound(n) == 0) cycle - if(this%icelltype(n) == 0) cycle + if (this%ibound(n) == 0) cycle + if (this%icelltype(n) == 0) cycle ! ! -- check for negative cell thickness - bbot=this%dis%bot(n) - ttop=this%dis%top(n) - if(bbot>ttop) then - write(errmsg, fmtnct) n + bbot = this%dis%bot(n) + ttop = this%dis%top(n) + if (bbot > ttop) then + write (errmsg, fmtnct) n call store_error(errmsg) - write(errmsg, fmttopbot) ttop,bbot + write (errmsg, fmttopbot) ttop, bbot call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Calculate saturated thickness - if(this%icelltype(n)/=0) then - if(hnew(n) 0) then - itflg=mod(kiter, this%iwetit) - if(itflg == 0) then - if(this%ibound(node) == 0 .and. this%wetdry(node) /= DZERO) then + if (this%irewet > 0) then + itflg = mod(kiter, this%iwetit) + if (itflg == 0) then + if (this%ibound(node) == 0 .and. this%wetdry(node) /= DZERO) then ! ! -- Calculate wetting elevation bbot = this%dis%bot(node) wd = this%wetdry(node) awd = wd - if(wd < 0) awd=-wd + if (wd < 0) awd = -wd turnon = bbot + awd ! ! -- Check head in adjacent cells to see if wetting elevation has ! been reached - if(ihc == 0) then + if (ihc == 0) then ! ! -- check cell below - if(ibdm > 0 .and. hm >= turnon) irewet = 1 + if (ibdm > 0 .and. hm >= turnon) irewet = 1 else - if(wd > DZERO) then + if (wd > DZERO) then ! ! -- check horizontally adjacent cells - if(ibdm > 0 .and. hm >= turnon) irewet = 1 + if (ibdm > 0 .and. hm >= turnon) irewet = 1 end if - endif + end if ! - if(irewet == 1) then + if (irewet == 1) then ! -- rewet cell; use equation 3a if ihdwet=0; use equation 3b if ! ihdwet is not 0. - if(this%ihdwet==0) then + if (this%ihdwet == 0) then hnew(node) = bbot + this%wetfct * (hm - bbot) else hnew(node) = bbot + this%wetfct * awd !(hm - bbot) - endif + end if this%ibound(node) = 30000 - endif - endif - endif - endif + end if + end if + end if + end if ! ! -- Return return end subroutine rewet_check - subroutine sgwf_npf_wdmsg(this,icode,ncnvrt,nodcnvrt,acnvrt,ihdcnv,kiter,n) + subroutine sgwf_npf_wdmsg(this, icode, ncnvrt, nodcnvrt, acnvrt, ihdcnv, & + kiter, n) ! ****************************************************************************** ! sgwf_npf_wdmsg -- Print wet/dry message ! ****************************************************************************** @@ -2556,40 +2504,41 @@ subroutine sgwf_npf_wdmsg(this,icode,ncnvrt,nodcnvrt,acnvrt,ihdcnv,kiter,n) use TdisModule, only: kstp, kper ! -- dummy class(GwfNpfType) :: this - integer(I4B),intent(in) :: icode - integer(I4B),intent(inout) :: ncnvrt + integer(I4B), intent(in) :: icode + integer(I4B), intent(inout) :: ncnvrt character(len=30), dimension(5), intent(inout) :: nodcnvrt - character(len=3),dimension(5),intent(inout) :: acnvrt - integer(I4B),intent(inout) :: ihdcnv - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: n + character(len=3), dimension(5), intent(inout) :: acnvrt + integer(I4B), intent(inout) :: ihdcnv + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: n ! -- local integer(I4B) :: l ! -- formats - character(len=*),parameter :: fmtcnvtn = & - "(1X,/1X,'CELL CONVERSIONS FOR ITER.=',I0, & + character(len=*), parameter :: fmtcnvtn = & + "(1X,/1X,'CELL CONVERSIONS FOR ITER.=',I0, & &' STEP=',I0,' PERIOD=',I0,' (NODE or LRC)')" - character(len=*),parameter :: fmtnode = "(1X,3X,5(A4, A20))" + character(len=*), parameter :: fmtnode = "(1X,3X,5(A4, A20))" ! ------------------------------------------------------------------------------ ! -- Keep track of cell conversions - if(icode>0) then - ncnvrt=ncnvrt+1 + if (icode > 0) then + ncnvrt = ncnvrt + 1 call this%dis%noder_to_string(n, nodcnvrt(ncnvrt)) - if(icode==1) then - acnvrt(ncnvrt)='DRY' + if (icode == 1) then + acnvrt(ncnvrt) = 'DRY' else - acnvrt(ncnvrt)='WET' + acnvrt(ncnvrt) = 'WET' end if end if ! ! -- Print a line if 5 conversions have occurred or if icode indicates that a ! partial line should be printed - if(ncnvrt==5 .or. (icode==0 .and. ncnvrt>0)) then - if(ihdcnv==0) write(this%iout,fmtcnvtn) kiter,kstp,kper - ihdcnv=1 - write(this%iout,fmtnode) (acnvrt(l), trim(adjustl(nodcnvrt(l))),l=1,ncnvrt) - ncnvrt=0 - endif + if (ncnvrt == 5 .or. (icode == 0 .and. ncnvrt > 0)) then + if (ihdcnv == 0) write (this%iout, fmtcnvtn) kiter, kstp, kper + ihdcnv = 1 + write (this%iout, fmtnode) & + (acnvrt(l), trim(adjustl(nodcnvrt(l))), l=1, ncnvrt) + ncnvrt = 0 + end if ! ! -- Return return @@ -2630,80 +2579,80 @@ function hy_eff(this, n, m, ihc, ipos, vg) result(hy) ! ! -- Initialize iipos = 0 - if(present(ipos)) iipos = ipos + if (present(ipos)) iipos = ipos hy11 = this%k11(n) hy22 = this%k11(n) hy33 = this%k11(n) - if(this%ik22 /= 0) hy22 = this%k22(n) - if(this%ik33 /= 0) hy33 = this%k33(n) + hy22 = this%k22(n) + hy33 = this%k33(n) ! ! -- Calculate effective K based on whether connection is vertical ! or horizontal - if(ihc == 0) then + if (ihc == 0) then ! ! -- Handle rotated anisotropy case that would affect the effective ! vertical hydraulic conductivity hy = hy33 - if(this%iangle2 > 0) then - if(present(vg)) then + if (this%iangle2 > 0) then + if (present(vg)) then vg1 = vg(1) vg2 = vg(2) vg3 = vg(3) else call this%dis%connection_normal(n, m, ihc, vg1, vg2, vg3, iipos) - endif + end if ang1 = this%angle1(n) ang2 = this%angle2(n) ang3 = DZERO - if(this%iangle3 > 0) ang3 = this%angle3(n) - hy = hyeff_calc(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, & + if (this%iangle3 > 0) ang3 = this%angle3(n) + hy = hyeff_calc(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, & this%iavgkeff) - endif + end if ! else ! ! -- Handle horizontal case hy = hy11 - if(this%ik22 > 0) then - if(present(vg)) then + if (this%ik22 > 0) then + if (present(vg)) then vg1 = vg(1) vg2 = vg(2) vg3 = vg(3) else call this%dis%connection_normal(n, m, ihc, vg1, vg2, vg3, iipos) - endif + end if ang1 = DZERO ang2 = DZERO ang3 = DZERO - if(this%iangle1 > 0) then + if (this%iangle1 > 0) then ang1 = this%angle1(n) - if(this%iangle2 > 0) then + if (this%iangle2 > 0) then ang2 = this%angle2(n) - if(this%iangle3 > 0) ang3 = this%angle3(n) - endif - endif - hy = hyeff_calc(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, & + if (this%iangle3 > 0) ang3 = this%angle3(n) + end if + end if + hy = hyeff_calc(hy11, hy22, hy33, ang1, ang2, ang3, vg1, vg2, vg3, & this%iavgkeff) - endif + end if ! - endif + end if ! ! -- Return return end function hy_eff function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & - iupw, condsat, hn, hm, satn, satm, hkn, hkm, topn, topm, & - botn, botm, cln, clm, fawidth, satomega, satminopt) & - result(condnm) + iupw, condsat, hn, hm, satn, satm, hkn, hkm, topn, topm, & + botn, botm, cln, clm, fawidth, satomega, satminopt) & + result(condnm) ! ****************************************************************************** ! hcond -- Horizontal conductance between two cells ! inwtup: if 1, then upstream-weight condsat, otherwise recalculate ! -! hcond function uses a weighted transmissivity in the harmonic mean -! conductance calculations. This differs from the MODFLOW-NWT and MODFLOW-USG -! conductance calculations for the Newton-Raphson formulation which use a -! weighted hydraulic conductivity. +! hcond function uses a weighted transmissivity in the harmonic mean +! conductance calculations. This differs from the MODFLOW-NWT and MODFLOW-USG +! conductance calculations for the Newton-Raphson formulation which use a +! weighted hydraulic conductivity. ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -2757,11 +2706,11 @@ function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & end if ! ! -- If either n or m is inactive then conductance is zero - if(ibdn == 0 .or. ibdm == 0) then + if (ibdn == 0 .or. ibdm == 0) then condnm = DZERO - ! - ! -- if both cells are non-convertible then use condsat - elseif(ictn == 0 .and. ictm == 0) then + ! + ! -- if both cells are non-convertible then use condsat + elseif (ictn == 0 .and. ictm == 0) then if (icellavg /= 4) then condnm = condsat else @@ -2772,15 +2721,15 @@ function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & end if condnm = condnm * condsat end if - ! - ! -- At least one of the cells is convertible, so calculate average saturated - ! thickness and multiply with saturated conductance + ! + ! -- At least one of the cells is convertible, so calculate average saturated + ! thickness and multiply with saturated conductance else if (inwtup == 1) then ! -- set flag use to determine if bottom of cells n and m are ! significantly different indk = 0 - if (abs(botm-botn) < DEM2) indk = 1 + if (abs(botm - botn) < DEM2) indk = 1 ! -- recalculate saturation if using MODFLOW-USG saturation ! calculation approach if (iusg == 1 .and. indk == 0) then @@ -2824,7 +2773,7 @@ function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & ! ! -- If staggered connection, subtract parts of cell that are above and ! below the sill top and bottom elevations - if(ihc == 2) then + if (ihc == 2) then ! ! -- Calculate sill_top and sill_bot sill_top = min(topn, topm) @@ -2837,8 +2786,8 @@ function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & ! -- Calculate saturated thickness for cells n and m thksatn = max(min(tpn, sill_top) - sill_bot, DZERO) thksatm = max(min(tpm, sill_top) - sill_bot, DZERO) - endif - + end if + athk = DONE if (iusg == 1) then if (ihc == 2) then @@ -2850,17 +2799,17 @@ function hcond(ibdn, ibdm, ictn, ictm, inewton, inwtup, ihc, icellavg, iusg, & thksatm = DONE end if ! - condnm = condmean(hkn, hkm, thksatn, thksatm, cln, clm, & + condnm = condmean(hkn, hkm, thksatn, thksatm, cln, clm, & fawidth, icellavg) * athk end if - endif + end if ! ! -- Return return end function hcond - function vcond(ibdn, ibdm, ictn, ictm, inewton, ivarcv, idewatcv, & - condsat, hn, hm, vkn, vkm, satn, satm, topn, topm, botn, & + function vcond(ibdn, ibdm, ictn, ictm, inewton, ivarcv, idewatcv, & + condsat, hn, hm, vkn, vkm, satn, satm, topn, topm, botn, & botm, flowarea) result(condnm) ! ****************************************************************************** ! vcond -- Vertical conductance between two cells @@ -2871,16 +2820,16 @@ function vcond(ibdn, ibdm, ictn, ictm, inewton, ivarcv, idewatcv, & ! -- return real(DP) :: condnm ! -- dummy - integer(I4B),intent(in) :: ibdn - integer(I4B),intent(in) :: ibdm + integer(I4B), intent(in) :: ibdn + integer(I4B), intent(in) :: ibdm integer(I4B), intent(in) :: ictn integer(I4B), intent(in) :: ictm integer(I4B), intent(in) :: inewton integer(I4B), intent(in) :: ivarcv integer(I4B), intent(in) :: idewatcv - real(DP),intent(in) :: condsat - real(DP),intent(in) :: hn - real(DP),intent(in) :: hm + real(DP), intent(in) :: condsat + real(DP), intent(in) :: hn + real(DP), intent(in) :: hm real(DP), intent(in) :: vkn real(DP), intent(in) :: vkm real(DP), intent(in) :: satn @@ -2896,50 +2845,50 @@ function vcond(ibdn, ibdm, ictn, ictm, inewton, ivarcv, idewatcv, & real(DP) :: bovk2 real(DP) :: denom ! ------------------------------------------------------------------------------ - ! - ! -- If either n or m is inactive then conductance is zero - if(ibdn == 0 .or. ibdm == 0) then - condnm = DZERO ! - ! -- if constantcv then use condsat - elseif(ivarcv == 0) then + ! -- If either n or m is inactive then conductance is zero + if (ibdn == 0 .or. ibdm == 0) then + condnm = DZERO + ! + ! -- if constantcv then use condsat + elseif (ivarcv == 0) then condnm = condsat - ! - ! -- if both cells are non-convertible then use condsat - elseif(ictn == 0 .and. ictm == 0) then + ! + ! -- if both cells are non-convertible then use condsat + elseif (ictn == 0 .and. ictm == 0) then condnm = condsat - ! - ! -- if both cells are fully saturated then use condsat - elseif(hn >= topn .and. hm >= topm) then + ! + ! -- if both cells are fully saturated then use condsat + elseif (hn >= topn .and. hm >= topm) then condnm = condsat - ! - ! -- At least one cell is partially saturated, so recalculate vertical - ! -- conductance for this connection - ! -- todo: upstream weighting? + ! + ! -- At least one cell is partially saturated, so recalculate vertical + ! -- conductance for this connection + ! -- todo: upstream weighting? else ! ! -- Default is for CV correction (dewatered option); use underlying ! saturation of 1. satntmp = satn satmtmp = satm - if(idewatcv == 0) then - if(botn > botm) then + if (idewatcv == 0) then + if (botn > botm) then ! -- n is above m satmtmp = DONE else ! -- m is above n satntmp = DONE - endif - endif + end if + end if bovk1 = satntmp * (topn - botn) * DHALF / vkn bovk2 = satmtmp * (topm - botm) * DHALF / vkm denom = (bovk1 + bovk2) - if(denom /= DZERO) then + if (denom /= DZERO) then condnm = flowarea / denom else condnm = DZERO - endif - endif + end if + end if ! ! -- Return return @@ -2992,36 +2941,36 @@ function condmean(k1, k2, thick1, thick2, cl1, cl2, width, iavgmeth) ! ! -- Averaging select case (iavgmeth) - ! - ! -- Harmonic-mean method - case(0) ! - if (t1*t2 > DZERO) then + ! -- Harmonic-mean method + case (0) + ! + if (t1 * t2 > DZERO) then condmean = width * t1 * t2 / (t1 * cl2 + t2 * cl1) else condmean = DZERO end if - ! - ! -- Logarithmic-mean method - case(1) - if (t1*t2 > DZERO) then + ! + ! -- Logarithmic-mean method + case (1) + if (t1 * t2 > DZERO) then tmean = logmean(t1, t2) else tmean = DZERO - endif + end if condmean = tmean * width / (cl1 + cl2) - ! - ! -- Arithmetic-mean thickness and logarithmic-mean hydraulic conductivity - case(2) - if (k1*k2 > DZERO) then + ! + ! -- Arithmetic-mean thickness and logarithmic-mean hydraulic conductivity + case (2) + if (k1 * k2 > DZERO) then kmean = logmean(k1, k2) else kmean = DZERO - endif + end if condmean = kmean * DHALF * (thick1 + thick2) * width / (cl1 + cl2) - ! - ! -- Arithmetic-mean thickness and harmonic-mean hydraulic conductivity - case(3) + ! + ! -- Arithmetic-mean thickness and harmonic-mean hydraulic conductivity + case (3) denom = (k1 * cl2 + k2 * cl1) if (denom > DZERO) then kmean = k1 * k2 / denom @@ -3053,18 +3002,18 @@ function logmean(d1, d2) ! ------------------------------------------------------------------------------ ! drat = d2 / d1 - if(drat <= DLNLOW .or. drat >= DLNHIGH) then + if (drat <= DLNLOW .or. drat >= DLNHIGH) then logmean = (d2 - d1) / log(drat) else logmean = DHALF * (d1 + d2) - endif + end if ! ! -- Return return end function logmean - function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & - iavgmeth) result(hyeff) + function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & + iavgmeth) result(hyeff) ! ****************************************************************************** ! hyeff_calc -- Calculate the effective horizontal hydraulic conductivity from ! an ellipse using a specified direction (unit vector vg1, vg2, vg3). @@ -3077,7 +3026,7 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & ! downward from the (x, y) plane ! ang3 is the rotation of the conductivity ellipsoid about the major ! axis -! vg1, vg2, and vg3 are the components of a unit vector in model coordinates +! vg1, vg2, and vg3 are the components of a unit vector in model coordinates ! in the direction of the connection between cell n and m ! iavgmeth is the averaging method. If zero, then use harmonic averaging. ! if one, then use arithmetic averaging. @@ -3102,7 +3051,7 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & integer(I4B), intent(in) :: iavgmeth ! -- local real(DP) :: s1, s2, s3, c1, c2, c3 - real(DP), dimension(3,3) :: r + real(DP), dimension(3, 3) :: r real(DP) :: ve1, ve2, ve3 real(DP) :: denom, dnum, d1, d2, d3 ! ------------------------------------------------------------------------------ @@ -3116,15 +3065,15 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & c3 = cos(ang3) ! ! -- Rotation matrix - r(1,1) = c1*c2 - r(1,2) = c1*s2*s3 - s1*c3 - r(1,3) = -c1*s2*c3 - s1*s3 - r(2,1) = s1*c2 - r(2,2) = s1*s2*s3 + c1*c3 - r(2,3) = -s1*s2*c3 + c1*s3 - r(3,1) = s2 - r(3,2) = -c2*s3 - r(3,3) = c2*c3 + r(1, 1) = c1 * c2 + r(1, 2) = c1 * s2 * s3 - s1 * c3 + r(1, 3) = -c1 * s2 * c3 - s1 * s3 + r(2, 1) = s1 * c2 + r(2, 2) = s1 * s2 * s3 + c1 * c3 + r(2, 3) = -s1 * s2 * c3 + c1 * s3 + r(3, 1) = s2 + r(3, 2) = -c2 * s3 + r(3, 3) = c2 * c3 ! ! -- Unit vector in direction of n-m connection in a local coordinate ! system aligned with the ellipse axes @@ -3132,7 +3081,7 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & ve2 = r(1, 2) * vg1 + r(2, 2) * vg2 + r(3, 2) * vg3 ve3 = r(1, 3) * vg1 + r(2, 3) * vg2 + r(3, 3) * vg3 ! - ! -- Effective hydraulic conductivity calculated using harmonic (1) + ! -- Effective hydraulic conductivity calculated using harmonic (1) ! or arithmetic (2) weighting hyeff = DZERO if (iavgmeth == 0) then @@ -3140,9 +3089,9 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & ! -- Arithmetic weighting. If principal direction corresponds exactly with ! unit vector then set to principal direction. Otherwise weight it. dnum = DONE - d1 = ve1 ** 2 - d2 = ve2 ** 2 - d3 = ve3 ** 2 + d1 = ve1**2 + d2 = ve2**2 + d3 = ve3**2 if (ve1 /= DZERO) then dnum = dnum * k11 d2 = d2 * k11 @@ -3162,7 +3111,7 @@ function hyeff_calc(k11, k22, k33, ang1, ang2, ang3, vg1, vg2, vg3, & if (denom > DZERO) hyeff = dnum / denom else if (iavgmeth == 1) then ! -- arithmetic - hyeff = ve1 ** 2 * k11 + ve2 ** 2 * k22 + ve3 ** 2 * k33 + hyeff = ve1**2 * k11 + ve2**2 * k22 + ve3**2 * k33 end if ! ! -- Return @@ -3171,7 +3120,7 @@ end function hyeff_calc subroutine calc_spdis(this, flowja) ! ****************************************************************************** -! calc_spdis -- Calculate the 3 conmponents of specific discharge +! calc_spdis -- Calculate the 3 conmponents of specific discharge ! at the cell center. ! ****************************************************************************** ! @@ -3229,11 +3178,11 @@ subroutine calc_spdis(this, flowja) ! ------------------------------------------------------------------------------ ! ! -- Ensure dis has necessary information - if(this%icalcspdis /= 0 .and. this%dis%con%ianglex == 0) then - call store_error('Error. ANGLDEGX not provided in ' // & - 'discretization file. ANGLDEGX required for ' // & + if (this%icalcspdis /= 0 .and. this%dis%con%ianglex == 0) then + call store_error('Error. ANGLDEGX not provided in '// & + 'discretization file. ANGLDEGX required for '// & 'calculation of specific discharge.', terminate=.TRUE.) - endif + end if ! ! -- Find max number of connections and allocate weight arrays nc = 0 @@ -3246,30 +3195,30 @@ subroutine calc_spdis(this, flowja) do m = 1, this%nedges if (this%nodedge(m) == n) then ic = ic + 1 - endif - enddo + end if + end do ! ! -- Set max number of connections for any cell if (ic > nc) nc = ic end do ! ! -- Allocate storage arrays needed for cell-centered spdis calculation - allocate(vi(nc)) - allocate(di(nc)) - allocate(viz(nc)) - allocate(diz(nc)) - allocate(nix(nc)) - allocate(niy(nc)) - allocate(wix(nc)) - allocate(wiy(nc)) - allocate(wiz(nc)) - allocate(bix(nc)) - allocate(biy(nc)) + allocate (vi(nc)) + allocate (di(nc)) + allocate (viz(nc)) + allocate (diz(nc)) + allocate (nix(nc)) + allocate (niy(nc)) + allocate (wix(nc)) + allocate (wiy(nc)) + allocate (wiz(nc)) + allocate (bix(nc)) + allocate (biy(nc)) ! ! -- Go through each cell and calculate specific discharge do n = 1, this%dis%nodes ! - ! -- first calculate geometric properties for x and y directions and + ! -- first calculate geometric properties for x and y directions and ! the specific discharge at a face (vi) ic = 0 iz = 0 @@ -3308,7 +3257,7 @@ subroutine calc_spdis(this, flowja) ic = ic + 1 dz = thksatnm(this%ibound(n), this%ibound(m), & this%icelltype(n), this%icelltype(m), & - this%inewton, ihc, this%iusgnrhc, & + this%inewton, ihc, this%iusgnrhc, & this%hnew(n), this%hnew(m), this%sat(n), this%sat(m), & this%dis%top(n), this%dis%top(m), this%dis%bot(n), & this%dis%bot(m), this%satomega, this%satmin) @@ -3330,8 +3279,8 @@ subroutine calc_spdis(this, flowja) vi(ic) = flowja(ipos) / area else vi(ic) = DZERO - endif - endif + end if + end if end do ! ! -- Look through edge flows that may have been provided by an exchange @@ -3355,12 +3304,12 @@ subroutine calc_spdis(this, flowja) vi(ic) = this%propsedge(1, m) / area else vi(ic) = DZERO - endif - endif - endif - enddo + end if + end if + end if + end do ! - ! -- Assign numnber of vertical and horizontal connections + ! -- Assign number of vertical and horizontal connections ncz = iz nc = ic ! @@ -3371,7 +3320,7 @@ subroutine calc_spdis(this, flowja) dsumz = DZERO do iz = 1, ncz dsumz = dsumz + diz(iz) - enddo + end do denom = (ncz - DONE) if (denom < DZERO) denom = DZERO dsumz = dsumz + DEM10 * dsumz @@ -3381,13 +3330,13 @@ subroutine calc_spdis(this, flowja) wiz(iz) = wiz(iz) / denom else wiz(iz) = DZERO - endif - enddo - endif + end if + end do + end if vz = DZERO do iz = 1, ncz vz = vz + wiz(iz) * viz(iz) - enddo + end do ! ! -- distance-based weighting nc = ic @@ -3399,18 +3348,18 @@ subroutine calc_spdis(this, flowja) wiy(ic) = di(ic) * abs(niy(ic)) dsumx = dsumx + wix(ic) dsumy = dsumy + wiy(ic) - enddo + end do ! ! -- Finish computing omega weights. Add a tiny bit ! to dsum so that the normalized omega weight later - ! evaluates to (essentially) 1 in the case of a single + ! evaluates to (essentially) 1 in the case of a single ! relevant connection, avoiding 0/0. dsumx = dsumx + DEM10 * dsumx dsumy = dsumy + DEM10 * dsumy do ic = 1, nc wix(ic) = (dsumx - wix(ic)) * abs(nix(ic)) wiy(ic) = (dsumy - wiy(ic)) * abs(niy(ic)) - enddo + end do ! ! -- compute B weights dsumx = DZERO @@ -3420,7 +3369,7 @@ subroutine calc_spdis(this, flowja) biy(ic) = wiy(ic) * sign(DONE, niy(ic)) dsumx = dsumx + wix(ic) * abs(nix(ic)) dsumy = dsumy + wiy(ic) * abs(niy(ic)) - enddo + end do if (dsumx > DZERO) dsumx = DONE / dsumx if (dsumy > DZERO) dsumy = DONE / dsumy axy = DZERO @@ -3430,7 +3379,7 @@ subroutine calc_spdis(this, flowja) biy(ic) = biy(ic) * dsumy axy = axy + bix(ic) * niy(ic) ayx = ayx + biy(ic) * nix(ic) - enddo + end do ! ! -- Calculate specific discharge. The divide by zero checking below ! is problematic for cells with only one flow, such as can happen @@ -3444,12 +3393,12 @@ subroutine calc_spdis(this, flowja) do ic = 1, nc vx = vx + (bix(ic) - axy * biy(ic)) * vi(ic) vy = vy + (biy(ic) - ayx * bix(ic)) * vi(ic) - enddo + end do denom = DONE - axy * ayx if (denom /= DZERO) then vx = vx / denom vy = vy / denom - endif + end if ! this%spdis(1, n) = vx this%spdis(2, n) = vy @@ -3458,20 +3407,20 @@ subroutine calc_spdis(this, flowja) end do ! ! -- cleanup - deallocate(vi) - deallocate(di) - deallocate(nix) - deallocate(niy) - deallocate(wix) - deallocate(wiy) - deallocate(wiz) - deallocate(bix) - deallocate(biy) + deallocate (vi) + deallocate (di) + deallocate (nix) + deallocate (niy) + deallocate (wix) + deallocate (wiy) + deallocate (wiz) + deallocate (bix) + deallocate (biy) ! ! -- return return end subroutine calc_spdis - + subroutine sav_spdis(this, ibinun) ! ****************************************************************************** ! sav_spdis -- save specific discharge in binary format to ibinun @@ -3494,14 +3443,15 @@ subroutine sav_spdis(this, ibinun) text = ' DATA-SPDIS' naux = 3 auxtxt(:) = [' qx', ' qy', ' qz'] - call this%dis%record_srcdst_list_header(text, this%name_model, this%packName, & - this%name_model, this%packName, naux, auxtxt, ibinun, this%dis%nodes, & - this%iout) + call this%dis%record_srcdst_list_header(text, this%name_model, & + this%packName, this%name_model, & + this%packName, naux, auxtxt, ibinun, & + this%dis%nodes, this%iout) ! ! -- Write a zero for Q, and then write qx, qy, qz as aux variables do n = 1, this%dis%nodes - call this%dis%record_mf6_list_entry(ibinun, n, n, DZERO, naux, & - this%spdis(:, n)) + call this%dis%record_mf6_list_entry(ibinun, n, n, DZERO, naux, & + this%spdis(:, n)) end do ! ! -- return @@ -3531,9 +3481,10 @@ subroutine sav_sat(this, ibinun) text = ' DATA-SAT' naux = 1 auxtxt(:) = [' sat'] - call this%dis%record_srcdst_list_header(text, this%name_model, this%packName, & - this%name_model, this%packName, naux, auxtxt, ibinun, this%dis%nodes, & - this%iout) + call this%dis%record_srcdst_list_header(text, this%name_model, & + this%packName, this%name_model, & + this%packName, naux, auxtxt, ibinun, & + this%dis%nodes, this%iout) ! ! -- Write a zero for Q, and then write saturation as an aux variables do n = 1, this%dis%nodes @@ -3567,7 +3518,7 @@ subroutine increase_edge_count(this, nedges) return end subroutine increase_edge_count - subroutine set_edge_properties(this, nodedge, ihcedge, q, area, nx, ny, & + subroutine set_edge_properties(this, nodedge, ihcedge, q, area, nx, ny, & distance) ! ****************************************************************************** ! edge_count -- provide the npf package with edge properties. @@ -3611,33 +3562,33 @@ end subroutine set_edge_properties !< function calcSatThickness(this, n, m, ihc) result(satThickness) class(GwfNpfType) :: this !< this NPF instance - integer(I4B) :: n !< node n - integer(I4B) :: m !< node m - integer(I4B) :: ihc !< 1 = horizonal connection, 0 for vertical - real(DP) :: satThickness !< saturated thickness - - satThickness = thksatnm(this%ibound(n), & - this%ibound(m), & - this%icelltype(n), & - this%icelltype(m), & - this%inewton, & - ihc, & - this%iusgnrhc, & - this%hnew(n), & - this%hnew(m), & - this%sat(n), & - this%sat(m), & - this%dis%top(n), & - this%dis%top(m), & - this%dis%bot(n), & - this%dis%bot(m), & - this%satomega, & - this%satmin) + integer(I4B) :: n !< node n + integer(I4B) :: m !< node m + integer(I4B) :: ihc !< 1 = horizonal connection, 0 for vertical + real(DP) :: satThickness !< saturated thickness + + satThickness = thksatnm(this%ibound(n), & + this%ibound(m), & + this%icelltype(n), & + this%icelltype(m), & + this%inewton, & + ihc, & + this%iusgnrhc, & + this%hnew(n), & + this%hnew(m), & + this%sat(n), & + this%sat(m), & + this%dis%top(n), & + this%dis%top(m), & + this%dis%bot(n), & + this%dis%bot(m), & + this%satomega, & + this%satmin) end function calcSatThickness - function thksatnm(ibdn, ibdm, ictn, ictm, inwtup, ihc, iusg, & - hn, hm, satn, satm, topn, topm, botn, botm, & + function thksatnm(ibdn, ibdm, ictn, ictm, inwtup, ihc, iusg, & + hn, hm, satn, satm, topn, topm, botn, botm, & satomega, satminopt) result(res) ! ****************************************************************************** ! thksatnm -- calculate saturated thickness at interface between two cells @@ -3684,21 +3635,37 @@ function thksatnm(ibdn, ibdm, ictn, ictm, inwtup, ihc, iusg, & end if ! ! -- If either n or m is inactive then saturated thickness is zero - if(ibdn == 0 .or. ibdm == 0) then + if (ibdn == 0 .or. ibdm == 0) then res = DZERO - ! - ! -- if both cells are non-convertible then use average cell thickness - elseif(ictn == 0 .and. ictm == 0) then - res = DHALF * (topn - botn + topm - botm) - ! - ! -- At least one of the cells is convertible, so calculate average saturated - ! thickness + ! + ! -- if both cells are non-convertible then use average cell thickness + elseif (ictn == 0 .and. ictm == 0) then + thksatn = topn - botn + thksatm = topm - botm + ! + ! -- If staggered connection, subtract parts of cell that are above and + ! below the sill top and bottom elevations + if (ihc == 2) then + ! + ! -- Calculate sill_top and sill_bot + sill_top = min(topn, topm) + sill_bot = max(botn, botm) + ! + ! -- Saturated thickness is sill_top - sill_bot + thksatn = max(sill_top - sill_bot, DZERO) + thksatm = thksatn + end if + ! + res = DHALF * (thksatn + thksatm) + ! + ! -- At least one of the cells is convertible, so calculate average saturated + ! thickness else if (inwtup == 1) then ! -- set flag used to determine if bottom of cells n and m are ! significantly different indk = 0 - if (abs(botm-botn) < DEM2) indk = 1 + if (abs(botm - botn) < DEM2) indk = 1 ! -- recalculate saturation if using MODFLOW-USG saturation ! calculation approach if (iusg == 1 .and. indk == 0) then @@ -3729,7 +3696,7 @@ function thksatnm(ibdn, ibdm, ictn, ictm, inwtup, ihc, iusg, & ! ! -- If staggered connection, subtract parts of cell that are above and ! below the sill top and bottom elevations - if(ihc == 2) then + if (ihc == 2) then ! ! -- Calculate sill_top and sill_bot sill_top = min(topn, topm) @@ -3742,14 +3709,14 @@ function thksatnm(ibdn, ibdm, ictn, ictm, inwtup, ihc, iusg, & ! -- Calculate saturated thickness for cells n and m thksatn = max(min(tpn, sill_top) - sill_bot, DZERO) thksatm = max(min(tpm, sill_top) - sill_bot, DZERO) - endif + end if ! res = DHALF * (thksatn + thksatm) end if - endif + end if ! ! -- Return return end function thksatnm - + end module GwfNpfModule diff --git a/src/Model/GroundWaterFlow/gwf3npf8idm.f90 b/src/Model/GroundWaterFlow/gwf3npf8idm.f90 new file mode 100644 index 00000000000..9a7d39579d3 --- /dev/null +++ b/src/Model/GroundWaterFlow/gwf3npf8idm.f90 @@ -0,0 +1,705 @@ +module GwfNpfInputModule + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwf_npf_param_definitions + public gwf_npf_aggregate_definitions + public gwf_npf_block_definitions + public GwfNpfParamFoundType + + type GwfNpfParamFoundType + logical :: ipakcb = .false. + logical :: iprflow = .false. + logical :: cellavg = .false. + logical :: ithickstrt = .false. + logical :: cvoptions = .false. + logical :: ivarcv = .false. + logical :: idewatcv = .false. + logical :: iperched = .false. + logical :: rewet_record = .false. + logical :: irewet = .false. + logical :: wetfct = .false. + logical :: iwetit = .false. + logical :: ihdwet = .false. + logical :: xt3doptions = .false. + logical :: ixt3d = .false. + logical :: ixt3drhs = .false. + logical :: isavspdis = .false. + logical :: isavsat = .false. + logical :: ik22overk = .false. + logical :: ik33overk = .false. + logical :: tvk_filerecord = .false. + logical :: tvk6 = .false. + logical :: filein = .false. + logical :: tvk6_filename = .false. + logical :: inewton = .false. + logical :: iusgnrhc = .false. + logical :: inwtupw = .false. + logical :: satmin = .false. + logical :: satomega = .false. + logical :: icelltype = .false. + logical :: k = .false. + logical :: k22 = .false. + logical :: k33 = .false. + logical :: angle1 = .false. + logical :: angle2 = .false. + logical :: angle3 = .false. + logical :: wetdry = .false. + end type GwfNpfParamFoundType + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ipakcb = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'SAVE_FLOWS', & ! tag name + 'IPAKCB', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_iprflow = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'PRINT_FLOWS', & ! tag name + 'IPRFLOW', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_cellavg = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'ALTERNATIVE_CELL_AVERAGING', & ! tag name + 'CELLAVG', & ! fortran variable + 'STRING', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ithickstrt = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'THICKSTRT', & ! tag name + 'ITHICKSTRT', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_cvoptions = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'CVOPTIONS', & ! tag name + 'CVOPTIONS', & ! fortran variable + 'RECORD VARIABLECV DEWATERED', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ivarcv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'VARIABLECV', & ! tag name + 'IVARCV', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_idewatcv = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEWATERED', & ! tag name + 'IDEWATCV', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_iperched = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'PERCHED', & ! tag name + 'IPERCHED', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_rewet_record = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'REWET_RECORD', & ! tag name + 'REWET_RECORD', & ! fortran variable + 'RECORD REWET WETFCT IWETIT IHDWET', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_irewet = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'REWET', & ! tag name + 'IREWET', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_wetfct = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'WETFCT', & ! tag name + 'WETFCT', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_iwetit = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'IWETIT', & ! tag name + 'IWETIT', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ihdwet = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'IHDWET', & ! tag name + 'IHDWET', & ! fortran variable + 'INTEGER', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_xt3doptions = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'XT3DOPTIONS', & ! tag name + 'XT3DOPTIONS', & ! fortran variable + 'RECORD XT3D RHS', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ixt3d = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'XT3D', & ! tag name + 'IXT3D', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ixt3drhs = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'RHS', & ! tag name + 'IXT3DRHS', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_isavspdis = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'SAVE_SPECIFIC_DISCHARGE', & ! tag name + 'ISAVSPDIS', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_isavsat = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'SAVE_SATURATION', & ! tag name + 'ISAVSAT', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ik22overk = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'K22OVERK', & ! tag name + 'IK22OVERK', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_ik33overk = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'K33OVERK', & ! tag name + 'IK33OVERK', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_tvk_filerecord = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'TVK_FILERECORD', & ! tag name + 'TVK_FILERECORD', & ! fortran variable + 'RECORD TVK6 FILEIN TVK6_FILENAME', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_tvk6 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'TVK6', & ! tag name + 'TVK6', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_filein = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'FILEIN', & ! tag name + 'FILEIN', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_tvk6_filename = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'TVK6_FILENAME', & ! tag name + 'TVK6_FILENAME', & ! fortran variable + 'STRING', & ! type + '', & ! shape + .true., & ! required + .true., & ! multi-record + .true., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_inewton = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEV_NO_NEWTON', & ! tag name + 'INEWTON', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_iusgnrhc = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEV_MODFLOWUSG_UPSTREAM_WEIGHTED_SATURATION', & ! tag name + 'IUSGNRHC', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_inwtupw = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEV_MODFLOWNWT_UPSTREAM_WEIGHTING', & ! tag name + 'INWTUPW', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_satmin = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEV_MINIMUM_SATURATED_THICKNESS', & ! tag name + 'SATMIN', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_satomega = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'OPTIONS', & ! block + 'DEV_OMEGA', & ! tag name + 'SATOMEGA', & ! fortran variable + 'DOUBLE', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_icelltype = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'ICELLTYPE', & ! tag name + 'ICELLTYPE', & ! fortran variable + 'INTEGER1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_k = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'K', & ! tag name + 'K', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .true., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_k22 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'K22', & ! tag name + 'K22', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_k33 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'K33', & ! tag name + 'K33', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_angle1 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'ANGLE1', & ! tag name + 'ANGLE1', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_angle2 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'ANGLE2', & ! tag name + 'ANGLE2', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_angle3 = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'ANGLE3', & ! tag name + 'ANGLE3', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwfnpf_wetdry = InputParamDefinitionType & + ( & + 'GWF', & ! component + 'NPF', & ! subcomponent + 'GRIDDATA', & ! block + 'WETDRY', & ! tag name + 'WETDRY', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwf_npf_param_definitions(*) = & + [ & + gwfnpf_ipakcb, & + gwfnpf_iprflow, & + gwfnpf_cellavg, & + gwfnpf_ithickstrt, & + gwfnpf_cvoptions, & + gwfnpf_ivarcv, & + gwfnpf_idewatcv, & + gwfnpf_iperched, & + gwfnpf_rewet_record, & + gwfnpf_irewet, & + gwfnpf_wetfct, & + gwfnpf_iwetit, & + gwfnpf_ihdwet, & + gwfnpf_xt3doptions, & + gwfnpf_ixt3d, & + gwfnpf_ixt3drhs, & + gwfnpf_isavspdis, & + gwfnpf_isavsat, & + gwfnpf_ik22overk, & + gwfnpf_ik33overk, & + gwfnpf_tvk_filerecord, & + gwfnpf_tvk6, & + gwfnpf_filein, & + gwfnpf_tvk6_filename, & + gwfnpf_inewton, & + gwfnpf_iusgnrhc, & + gwfnpf_inwtupw, & + gwfnpf_satmin, & + gwfnpf_satomega, & + gwfnpf_icelltype, & + gwfnpf_k, & + gwfnpf_k22, & + gwfnpf_k33, & + gwfnpf_angle1, & + gwfnpf_angle2, & + gwfnpf_angle3, & + gwfnpf_wetdry & + ] + + type(InputParamDefinitionType), parameter :: & + gwf_npf_aggregate_definitions(*) = & + [ & + InputParamDefinitionType :: & + ] + + type(InputBlockDefinitionType), parameter :: & + gwf_npf_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .true., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'GRIDDATA', & ! blockname + .true., & ! required + .false. & ! aggregate + ) & + ] + +end module GwfNpfInputModule diff --git a/src/Model/GroundWaterFlow/gwf3obs8.f90 b/src/Model/GroundWaterFlow/gwf3obs8.f90 index 8027f8f3b4b..15490abbcbf 100644 --- a/src/Model/GroundWaterFlow/gwf3obs8.f90 +++ b/src/Model/GroundWaterFlow/gwf3obs8.f90 @@ -1,13 +1,13 @@ module GwfObsModule use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, MAXOBSTYPES - use BaseDisModule, only: DisBaseType - use GwfIcModule, only: GwfIcType - use ObserveModule, only: ObserveType - use ObsModule, only: ObsType - use SimModule, only: count_errors, store_error, & - store_error_unit + use ConstantsModule, only: LINELENGTH, MAXOBSTYPES + use BaseDisModule, only: DisBaseType + use GwfIcModule, only: GwfIcType + use ObserveModule, only: ObserveType + use ObsModule, only: ObsType + use SimModule, only: count_errors, store_error, & + store_error_unit implicit none private @@ -15,9 +15,9 @@ module GwfObsModule type, extends(ObsType) :: GwfObsType ! -- Private members - type(GwfIcType), pointer, private :: ic => null() ! initial conditions - real(DP), dimension(:), pointer, contiguous, private :: x => null() ! head - real(DP), dimension(:), pointer, contiguous, private :: flowja => null() ! intercell flows + type(GwfIcType), pointer, private :: ic => null() ! initial conditions + real(DP), dimension(:), pointer, contiguous, private :: x => null() ! head + real(DP), dimension(:), pointer, contiguous, private :: flowja => null() ! intercell flows contains ! -- Public procedures procedure, public :: gwf_obs_ar @@ -42,11 +42,11 @@ subroutine gwf_obs_cr(obs, inobs) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(GwfObsType), pointer, intent(out) :: obs + type(GwfObsType), pointer, intent(out) :: obs integer(I4B), pointer, intent(in) :: inobs ! ------------------------------------------------------------------------------ ! - allocate(obs) + allocate (obs) call obs%allocate_scalars() obs%active = .false. obs%inputFilename = '' @@ -63,8 +63,8 @@ subroutine gwf_obs_ar(this, ic, x, flowja) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwfObsType), intent(inout) :: this - type(GwfIcType), pointer, intent(in) :: ic + class(GwfObsType), intent(inout) :: this + type(GwfIcType), pointer, intent(in) :: ic real(DP), dimension(:), pointer, contiguous, intent(in) :: x real(DP), dimension(:), pointer, contiguous, intent(in) :: flowja ! ------------------------------------------------------------------------------ @@ -90,7 +90,7 @@ subroutine gwf_obs_df(this, iout, pkgname, filtyp, dis) integer(I4B), intent(in) :: iout character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: filtyp - class(DisBaseType), pointer :: dis + class(DisBaseType), pointer :: dis ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ @@ -124,7 +124,7 @@ subroutine gwf_obs_bd(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwfObsType), intent(inout) :: this + class(GwfObsType), intent(inout) :: this ! -- local integer(I4B) :: i, jaindex, nodenumber real(DP) :: v @@ -149,7 +149,7 @@ subroutine gwf_obs_bd(this) case ('FLOW-JA-FACE') call this%SaveOneSimval(obsrv, this%flowja(jaindex)) case default - msg = 'Error: Unrecognized observation type: ' // trim(obsrv%ObsTypeId) + msg = 'Error: Unrecognized observation type: '//trim(obsrv%ObsTypeId) call store_error(msg) end select end do @@ -188,9 +188,9 @@ subroutine gwf_obs_da(this) class(GwfObsType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! - nullify(this%ic) - nullify(this%x) - nullify(this%flowja) + nullify (this%ic) + nullify (this%x) + nullify (this%flowja) call this%ObsType%obs_da() ! return @@ -226,10 +226,10 @@ subroutine gwf_process_head_drawdown_obs_id(obsrv, dis, inunitobs, iout) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1 integer(I4B) :: icol, istart, istop @@ -251,7 +251,7 @@ subroutine gwf_process_head_drawdown_obs_id(obsrv, dis, inunitobs, iout) ermsg = 'Error reading data from ID string' call store_error(ermsg) call store_error_unit(inunitobs) - endif + end if ! return end subroutine gwf_process_head_drawdown_obs_id @@ -264,16 +264,16 @@ subroutine gwf_process_intercell_obs_id(obsrv, dis, inunitobs, iout) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1, nn2 integer(I4B) :: icol, istart, istop, jaidx character(len=LINELENGTH) :: ermsg, strng ! formats - 70 format('Error: No connection exists between cells identified in text: ',a) +70 format('Error: No connection exists between cells identified in text: ', a) ! ------------------------------------------------------------------------------ ! ! -- Initialize variables @@ -288,32 +288,32 @@ subroutine gwf_process_intercell_obs_id(obsrv, dis, inunitobs, iout) if (nn1 > 0) then obsrv%NodeNumber = nn1 else - ermsg = 'Error reading data from ID string: ' // strng(istart:istop) + ermsg = 'Error reading data from ID string: '//strng(istart:istop) call store_error(ermsg) - endif + end if ! ! Get node number, with option for ID string to be either node ! number or lay, row, column (when dis is structured). nn2 = dis%noder_from_string(icol, istart, istop, inunitobs, & - iout, strng, .false.) + iout, strng, .false.) if (nn2 > 0) then obsrv%NodeNumber2 = nn2 else - ermsg = 'Error reading data from ID string: ' // strng(istart:istop) + ermsg = 'Error reading data from ID string: '//strng(istart:istop) call store_error(ermsg) - endif + end if ! ! -- store JA index - jaidx = dis%con%getjaindex(nn1,nn2) - if (jaidx==0) then - write(ermsg,70)trim(strng) + jaidx = dis%con%getjaindex(nn1, nn2) + if (jaidx == 0) then + write (ermsg, 70) trim(strng) call store_error(ermsg) - endif + end if obsrv%JaIndex = jaidx ! if (count_errors() > 0) then call store_error_unit(inunitobs) - endif + end if ! return end subroutine gwf_process_intercell_obs_id diff --git a/src/Model/GroundWaterFlow/gwf3oc8.f90 b/src/Model/GroundWaterFlow/gwf3oc8.f90 index fcf7b037453..12e635b7963 100644 --- a/src/Model/GroundWaterFlow/gwf3oc8.f90 +++ b/src/Model/GroundWaterFlow/gwf3oc8.f90 @@ -1,10 +1,10 @@ module GwfOcModule - use BaseDisModule, only: DisBaseType - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMODELNAME - use OutputControlModule, only: OutputControlType - use OutputControlDataModule, only: OutputControlDataType, ocd_cr + use BaseDisModule, only: DisBaseType + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMODELNAME + use OutputControlModule, only: OutputControlType + use OutputControlDataModule, only: OutputControlDataType, ocd_cr implicit none private @@ -19,8 +19,8 @@ module GwfOcModule contains procedure :: oc_ar end type GwfOcType - - contains + +contains !> @ brief Create GwfOcType !! @@ -30,13 +30,13 @@ module GwfOcModule !< subroutine oc_cr(ocobj, name_model, inunit, iout) ! -- dummy - type(GwfOcType), pointer :: ocobj !< GwfOcType object - character(len=*), intent(in) :: name_model !< name of the model - integer(I4B), intent(in) :: inunit !< unit number for input - integer(I4B), intent(in) :: iout !< unit number for output + type(GwfOcType), pointer :: ocobj !< GwfOcType object + character(len=*), intent(in) :: name_model !< name of the model + integer(I4B), intent(in) :: inunit !< unit number for input + integer(I4B), intent(in) :: iout !< unit number for output ! ! -- Create the object - allocate(ocobj) + allocate (ocobj) ! ! -- Allocate scalars call ocobj%allocate_scalars(name_model) @@ -59,42 +59,42 @@ end subroutine oc_cr !< subroutine oc_ar(this, head, dis, dnodata) ! -- dummy - class(GwfOcType) :: this !< GwtOcType object - real(DP), dimension(:), pointer, contiguous, intent(in) :: head !< model head - class(DisBaseType), pointer, intent(in) :: dis !< model discretization package - real(DP), intent(in) :: dnodata !< no data value + class(GwfOcType) :: this !< GwtOcType object + real(DP), dimension(:), pointer, contiguous, intent(in) :: head !< model head + class(DisBaseType), pointer, intent(in) :: dis !< model discretization package + real(DP), intent(in) :: dnodata !< no data value ! -- local integer(I4B) :: i, nocdobj, inodata - type(OutputControlDataType), pointer :: ocdobjptr + type(OutputControlDataType), pointer :: ocdobjptr real(DP), dimension(:), pointer, contiguous :: nullvec => null() ! ! -- Initialize variables inodata = 0 nocdobj = 2 - allocate(this%ocdobj(nocdobj)) + allocate (this%ocdobj(nocdobj)) do i = 1, nocdobj call ocd_cr(ocdobjptr) select case (i) case (1) - call ocdobjptr%init_dbl('BUDGET', nullvec, dis, 'PRINT LAST ', & - 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & + call ocdobjptr%init_dbl('BUDGET', nullvec, dis, 'PRINT LAST ', & + 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & this%iout, dnodata) case (2) - call ocdobjptr%init_dbl('HEAD', head, dis, 'PRINT LAST ', & - 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & + call ocdobjptr%init_dbl('HEAD', head, dis, 'PRINT LAST ', & + 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & this%iout, dnodata) end select this%ocdobj(i) = ocdobjptr - deallocate(ocdobjptr) - enddo + deallocate (ocdobjptr) + end do ! ! -- Read options or set defaults if this package not on - if(this%inunit > 0) then + if (this%inunit > 0) then call this%read_options() - endif + end if ! ! -- Return return end subroutine oc_ar - + end module GwfOcModule diff --git a/src/Model/GroundWaterFlow/gwf3rch8.f90 b/src/Model/GroundWaterFlow/gwf3rch8.f90 index 1535c408134..e91e9594cfd 100644 --- a/src/Model/GroundWaterFlow/gwf3rch8.f90 +++ b/src/Model/GroundWaterFlow/gwf3rch8.f90 @@ -17,36 +17,36 @@ module RchModule private public :: rch_create ! - character(len=LENFTYPE) :: ftype = 'RCH' - character(len=LENPACKAGENAME) :: text = ' RCH' - character(len=LENPACKAGENAME) :: texta = ' RCHA' + character(len=LENFTYPE) :: ftype = 'RCH' + character(len=LENPACKAGENAME) :: text = ' RCH' + character(len=LENPACKAGENAME) :: texta = ' RCHA' ! type, extends(BndType) :: RchType integer(I4B), pointer :: inirch => NULL() - integer(I4B), dimension(:), pointer, contiguous :: nodesontop => NULL() ! User provided cell numbers; nodelist is cells where recharge is applied) + integer(I4B), dimension(:), pointer, contiguous :: nodesontop => NULL() ! User provided cell numbers; nodelist is cells where recharge is applied) logical, private :: fixed_cell = .false. logical, private :: read_as_arrays = .false. contains procedure :: rch_allocate_scalars - procedure :: bnd_options => rch_options - procedure :: read_dimensions => rch_read_dimensions - procedure :: read_initial_attr => rch_read_initial_attr - procedure :: bnd_rp => rch_rp + procedure :: bnd_options => rch_options + procedure :: read_dimensions => rch_read_dimensions + procedure :: read_initial_attr => rch_read_initial_attr + procedure :: bnd_rp => rch_rp procedure :: set_nodesontop - procedure :: bnd_cf => rch_cf - procedure :: bnd_fc => rch_fc - procedure :: bnd_da => rch_da - procedure :: define_listlabel => rch_define_listlabel - procedure, public :: bnd_rp_ts => rch_rp_ts + procedure :: bnd_cf => rch_cf + procedure :: bnd_fc => rch_fc + procedure :: bnd_da => rch_da + procedure :: define_listlabel => rch_define_listlabel + procedure, public :: bnd_rp_ts => rch_rp_ts procedure, private :: rch_rp_array procedure, private :: rch_rp_list procedure, private :: default_nodelist ! -- for observations - procedure, public :: bnd_obs_supported => rch_obs_supported + procedure, public :: bnd_obs_supported => rch_obs_supported procedure, public :: bnd_df_obs => rch_df_obs end type RchType - contains +contains subroutine rch_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ****************************************************************************** @@ -57,12 +57,12 @@ subroutine rch_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- dummy + ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -70,7 +70,7 @@ subroutine rch_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate recharge object and scalar variables - allocate(rchobj) + allocate (rchobj) packobj => rchobj ! ! -- create name and memory path @@ -88,8 +88,8 @@ subroutine rch_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%id = id packobj%ibcnum = ibcnum packobj%ncolbnd = 1 - packobj%iscloc = 1 ! sfac applies to recharge rate - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%iscloc = 1 ! sfac applies to recharge rate + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! indxconvertflux is Column index of bound that will be multiplied by ! cell area to convert flux rates to flow rates packobj%indxconvertflux = 1 @@ -109,7 +109,7 @@ subroutine rch_allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(RchType), intent(inout) :: this + class(RchType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars @@ -139,39 +139,39 @@ subroutine rch_options(this, option, found) use SimModule, only: store_error implicit none ! -- dummy - class(RchType), intent(inout) :: this + class(RchType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: ermsg ! -- formats - character(len=*),parameter :: fmtihact = & - "(4x, 'RECHARGE WILL BE APPLIED TO HIGHEST ACTIVE CELL.')" - character(len=*),parameter :: fmtfixedcell = & - "(4x, 'RECHARGE WILL BE APPLIED TO SPECIFIED CELL.')" + character(len=*), parameter :: fmtihact = & + &"(4x, 'RECHARGE WILL BE APPLIED TO HIGHEST ACTIVE CELL.')" + character(len=*), parameter :: fmtfixedcell = & + &"(4x, 'RECHARGE WILL BE APPLIED TO SPECIFIED CELL.')" character(len=*), parameter :: fmtreadasarrays = & - "(4x, 'RECHARGE INPUT WILL BE READ AS ARRAY(S).')" + &"(4x, 'RECHARGE INPUT WILL BE READ AS ARRAY(S).')" ! ------------------------------------------------------------------------------ ! ! -- Check for FIXED_CELL and READASARRAYS select case (option) case ('FIXED_CELL') this%fixed_cell = .true. - write(this%iout, fmtfixedcell) + write (this%iout, fmtfixedcell) found = .true. case ('READASARRAYS') if (this%dis%supports_layers()) then this%read_as_arrays = .true. this%text = texta else - ermsg = 'READASARRAYS option is not compatible with selected' // & + ermsg = 'READASARRAYS option is not compatible with selected'// & ' discretization type.' call store_error(ermsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Write option - write(this%iout, fmtreadasarrays) + write (this%iout, fmtreadasarrays) ! found = .true. case default @@ -194,7 +194,7 @@ subroutine rch_read_dimensions(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_unit ! -- dummy - class(RchType),intent(inout) :: this + class(RchType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: keyword integer(I4B) :: ierr @@ -214,38 +214,39 @@ subroutine rch_read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('MAXBOUND') - this%maxbound = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)') 'MAXBOUND = ', this%maxbound - case default - write(errmsg,'(4x,a,a)') & - 'Unknown '//trim(this%text)//' DIMENSION: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('MAXBOUND') + this%maxbound = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'MAXBOUND = ', this%maxbound + case default + write (errmsg, '(4x,a,a)') & + 'Unknown '//trim(this%text)//' DIMENSION: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do ! - write(this%iout,'(1x,a)')'END OF '//trim(adjustl(this%text))//' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' else call store_error('Required DIMENSIONS block not found.') call this%parser%StoreErrorUnit() - endif - endif + end if + end if ! ! -- verify dimensions were set - if(this%maxbound <= 0) then - write(errmsg, '(1x,a)') & + if (this%maxbound <= 0) then + write (errmsg, '(1x,a)') & 'MAXBOUND must be an integer greater than zero.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Call define_listlabel to construct the list label that is written ! when PRINT_INPUT option is used. @@ -264,12 +265,12 @@ subroutine rch_read_initial_attr(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(RchType),intent(inout) :: this + class(RchType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! if (this%read_as_arrays) then call this%default_nodelist() - endif + end if ! return end subroutine rch_read_initial_attr @@ -288,7 +289,7 @@ subroutine rch_rp(this) use SimModule, only: store_error implicit none ! -- dummy - class(RchType),intent(inout) :: this + class(RchType), intent(inout) :: this ! -- local integer(I4B) :: ierr integer(I4B) :: node, n @@ -297,19 +298,19 @@ subroutine rch_rp(this) logical :: supportopenclose character(len=LINELENGTH) :: line ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" - character(len=*), parameter :: fmtnbd = & - "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6, & - &') IS GREATER THAN MAXIMUM(',I6,')')" - character(len=*), parameter :: fmtdimlayered = & - "('When READASARRAYS is specified for the selected discretization" // & - " package, DIMENSIONS block must be omitted.')" + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtnbd = & + "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6, & + &') IS GREATER THAN MAXIMUM(',I6,')')" + character(len=*), parameter :: fmtdimlayered = & + "('When READASARRAYS is specified for the selected discretization & + &package, DIMENSIONS block must be omitted.')" ! ------------------------------------------------------------------------------ ! - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. @@ -320,8 +321,9 @@ subroutine rch_rp(this) ! When reading a list, OPEN/CLOSE is handled by list reader, ! so supportOpenClose needs to be false in call the GetBlock. ! When reading as arrays, set supportOpenClose as desired. - call this%parser%GetBlock('PERIOD', isfound, ierr) - if(isfound) then + call this%parser%GetBlock('PERIOD', isfound, ierr, & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -334,21 +336,21 @@ subroutine rch_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) if (this%read_as_arrays) then - write(errmsg, fmtdimlayered) + write (errmsg, fmtdimlayered) call store_error(errmsg) - endif + end if call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- Read data if ionper == kper inrech = 0 inirch = 0 - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- Remove all time-series links associated with this package call this%TsManager%Reset(this%packName) @@ -361,23 +363,23 @@ subroutine rch_rp(this) else ! -- Read RECHARGE, IRCH, and AUX variables as arrays call this%rch_rp_array(line, inrech) - endif - ! + end if + ! else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + write (this%iout, fmtlsp) trim(this%filtyp) + end if ! ! -- If recharge was read, then multiply by cell area. If inrech = 2, then ! recharge is begin managed as a time series, and the time series object ! will multiply the recharge rate by the cell area. - if(inrech == 1) then + if (inrech == 1) then do n = 1, this%nbound node = this%nodelist(n) if (node > 0) then this%bound(1, n) = this%bound(1, n) * this%dis%get_area(node) end if - enddo - endif + end do + end if ! ! -- return return @@ -395,9 +397,9 @@ subroutine rch_rp_array(this, line, inrech) use ArrayHandlersModule, only: ifind implicit none ! -- dummy - class(RchType), intent(inout) :: this + class(RchType), intent(inout) :: this character(len=LINELENGTH), intent(inout) :: line - integer(I4B), intent(inout) :: inrech + integer(I4B), intent(inout) :: inrech ! -- local integer(I4B) :: n integer(I4B) :: ipos @@ -413,14 +415,14 @@ subroutine rch_rp_array(this, line, inrech) real(DP), dimension(:), pointer :: bndArrayPtr => null() real(DP), dimension(:), pointer :: auxArrayPtr => null() real(DP), dimension(:), pointer :: auxMultArray => null() - type(TimeArraySeriesLinkType), pointer :: tasLink => null() + type(TimeArraySeriesLinkType), pointer :: tasLink => null() ! -- formats - character(len=*),parameter :: fmtrchauxmult = & + character(len=*), parameter :: fmtrchauxmult = & "(4x, 'THE RECHARGE ARRAY IS BEING MULTIPLED BY THE AUXILIARY ARRAY WITH & &THE NAME: ', A)" ! -- data - data aname(1) /' LAYER OR NODE INDEX'/ - data aname(2) /' RECHARGE'/ + data aname(1)/' LAYER OR NODE INDEX'/ + data aname(2)/' RECHARGE'/ ! ! ------------------------------------------------------------------------------ ! @@ -444,15 +446,15 @@ subroutine rch_rp_array(this, line, inrech) if (keyword == 'TIMEARRAYSERIES') then ! -- Get time-array series name call this%parser%GetStringCaps(tasName) - jcol = 1 ! for recharge rate - bndArrayPtr => this%bound(jcol,:) + jcol = 1 ! for recharge rate + bndArrayPtr => this%bound(jcol, :) ! Make a time-array-series link and add it to the list of links ! contained in the TimeArraySeriesManagerType object. convertflux = .true. - call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & - this%iprpak, tasName, 'RECHARGE', & - convertFlux, this%nodelist, & - this%parser%iuactive) + call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & + this%iprpak, tasName, 'RECHARGE', & + convertFlux, this%nodelist, & + this%parser%iuactive) lpos = this%TasManager%CountLinks() tasLink => this%TasManager%GetLink(lpos) inrech = 2 @@ -461,10 +463,11 @@ subroutine rch_rp_array(this, line, inrech) ! -- Read the recharge array, then indicate ! that recharge was read by setting inrech call this%dis%read_layer_array(this%nodelist, this%bound, & - this%ncolbnd, this%maxbound, 1, aname(2), this%parser%iuactive, & - this%iout) + this%ncolbnd, this%maxbound, 1, & + aname(2), this%parser%iuactive, & + this%iout) inrech = 1 - endif + end if ! case ('IRCH') ! @@ -474,25 +477,26 @@ subroutine rch_rp_array(this, line, inrech) call store_error('IRCH IS NOT FIRST VARIABLE IN & &PERIOD BLOCK OR IT IS SPECIFIED MORE THAN ONCE.') call this%parser%StoreErrorUnit() - endif + end if ! ! -- Read the IRCH array call this%dis%nlarray_to_nodelist(this%nodelist, this%maxbound, & - this%nbound, aname(1), this%parser%iuactive, this%iout) + this%nbound, aname(1), & + this%parser%iuactive, this%iout) ! ! -- set flag to indicate that irch array has been read this%inirch = 1 ! ! -- if fixed_cell option not set, then need to store nodelist ! in the nodesontop array - if(.not. this%fixed_cell) call this%set_nodesontop() + if (.not. this%fixed_cell) call this%set_nodesontop() ! case default ! ! -- Check for auxname, and if found, then read into auxvar array found = .false. ipos = ifind(this%auxname, keyword) - if(ipos > 0) then + if (ipos > 0) then found = .true. atemp = keyword ! @@ -503,37 +507,37 @@ subroutine rch_rp_array(this, line, inrech) ! -- Get time-array series name call this%parser%GetStringCaps(tasName) jauxcol = jauxcol + 1 - auxArrayPtr => this%auxvar(jauxcol,:) + auxArrayPtr => this%auxvar(jauxcol, :) ! Make a time-array-series link and add it to the list of links ! contained in the TimeArraySeriesManagerType object. convertflux = .false. - call this%TasManager%MakeTasLink(this%packName, auxArrayPtr, & - this%iprpak, tasName, & - this%auxname(ipos), convertFlux, & - this%nodelist, & - this%parser%iuactive) + call this%TasManager%MakeTasLink(this%packName, auxArrayPtr, & + this%iprpak, tasName, & + this%auxname(ipos), convertFlux, & + this%nodelist, & + this%parser%iuactive) else ! ! -- Read the aux variable array call this%dis%read_layer_array(this%nodelist, this%auxvar, & - this%naux, this%maxbound, ipos, atemp, this%parser%iuactive, & - this%iout) - endif - endif + this%naux, this%maxbound, ipos, & + atemp, this%parser%iuactive, this%iout) + end if + end if ! ! -- Nothing found - if(.not. found) then + if (.not. found) then call this%parser%GetCurrentLine(line) - errmsg = 'LOOKING FOR VALID VARIABLE NAME. FOUND: ' // trim(line) + errmsg = 'LOOKING FOR VALID VARIABLE NAME. FOUND: '//trim(line) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- If this aux variable has been designated as a multiplier array ! by presence of AUXMULTNAME, set local pointer appropriately. if (this%iauxmultcol > 0 .and. this%iauxmultcol == ipos) then - auxMultArray => this%auxvar(this%iauxmultcol,:) - endif + auxMultArray => this%auxvar(this%iauxmultcol, :) + end if end select ! ! -- Increment the number of variables read @@ -547,18 +551,18 @@ subroutine rch_rp_array(this, line, inrech) if (associated(auxMultArray)) then if (associated(tasLink)) then tasLink%RMultArray => auxMultArray - endif - endif + end if + end if ! ! -- If recharge was read and auxmultcol was specified, then multiply ! the recharge rate by the multplier column - if(inrech == 1 .and. this%iauxmultcol > 0) then - write(this%iout, fmtrchauxmult) this%auxname(this%iauxmultcol) + if (inrech == 1 .and. this%iauxmultcol > 0) then + write (this%iout, fmtrchauxmult) this%auxname(this%iauxmultcol) do n = 1, this%nbound - this%bound(this%iscloc, n) = this%bound(this%iscloc, n) * & - this%auxvar(this%iauxmultcol, n) - enddo - endif + this%bound(this%iscloc, n) = this%bound(this%iscloc, n) * & + this%auxvar(this%iauxmultcol, n) + end do + end if ! return end subroutine rch_rp_array @@ -573,7 +577,7 @@ subroutine rch_rp_list(this, inrech) implicit none ! -- dummy class(RchType), intent(inout) :: this - integer(I4B), intent(inout) :: inrech + integer(I4B), intent(inout) :: inrech ! -- local integer(I4B) :: maxboundorig, nlist ! @@ -585,20 +589,20 @@ subroutine rch_rp_list(this, inrech) ! ! -- read the list of recharge values; scale the recharge by auxmultcol ! if it is specified. - call this%dis%read_list(this%parser%iuactive, this%iout, this%iprpak, & - nlist, this%inamedbound, this%iauxmultcol, & - this%nodelist, this%bound, this%auxvar, & - this%auxname, this%boundname, this%listlabel, & - this%packName, this%tsManager, this%iscloc, & - this%indxconvertflux) + call this%dis%read_list(this%parser%iuactive, this%iout, this%iprpak, & + nlist, this%inamedbound, this%iauxmultcol, & + this%nodelist, this%bound, this%auxvar, & + this%auxname, this%boundname, this%listlabel, & + this%packName, this%tsManager, this%iscloc, & + this%indxconvertflux) this%nbound = nlist if (this%maxbound > maxboundorig) then ! -- The arrays that belong to BndType have been extended. ! Now, RCH array nodesontop needs to be recreated. if (associated(this%nodesontop)) then - deallocate(this%nodesontop) - endif - endif + deallocate (this%nodesontop) + end if + end if if (.not. this%fixed_cell) call this%set_nodesontop() inrech = 1 ! @@ -617,21 +621,21 @@ subroutine set_nodesontop(this) ! ------------------------------------------------------------------------------ implicit none ! -- dummy - class(RchType),intent(inout) :: this + class(RchType), intent(inout) :: this ! -- local integer(I4B) :: n ! -- formats ! ------------------------------------------------------------------------------ ! ! -- allocate if necessary - if(.not. associated(this%nodesontop)) then - allocate(this%nodesontop(this%maxbound)) - endif + if (.not. associated(this%nodesontop)) then + allocate (this%nodesontop(this%maxbound)) + end if ! ! -- copy nodelist into nodesontop do n = 1, this%nbound this%nodesontop(n) = this%nodelist(n) - enddo + end do ! ! -- return return @@ -654,7 +658,7 @@ subroutine rch_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no recharge - if(this%nbound == 0) return + if (this%nbound == 0) return ! ! -- Calculate hcof and rhs for each recharge entry do i = 1, this%nbound @@ -675,23 +679,23 @@ subroutine rch_cf(this, reset_mover) ! ! -- reset nodelist to highest active if (.not. this%fixed_cell) then - if(this%ibound(node) == 0) & + if (this%ibound(node) == 0) & call this%dis%highest_active(node, this%ibound) this%nodelist(i) = node - endif + end if ! ! -- Set rhs and hcof this%hcof(i) = DZERO - this%rhs(i) = -this%bound(1,i) - if(this%ibound(node) <= 0) then + this%rhs(i) = -this%bound(1, i) + if (this%ibound(node) <= 0) then this%rhs(i) = DZERO cycle - endif - if(this%ibound(node) == 10000) then + end if + if (this%ibound(node) == 10000) then this%rhs(i) = DZERO cycle - endif - enddo + end if + end do ! ! -- return return @@ -727,7 +731,7 @@ subroutine rch_fc(this, rhs, ia, idxglo, amatsln) rhs(n) = rhs(n) + this%rhs(i) ipos = ia(n) amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) - enddo + end do ! ! -- return return @@ -753,7 +757,7 @@ subroutine rch_da(this) call mem_deallocate(this%inirch) ! ! -- arrays - if(associated(this%nodesontop)) deallocate(this%nodesontop) + if (associated(this%nodesontop)) deallocate (this%nodesontop) ! ! -- return return @@ -771,23 +775,23 @@ subroutine rch_define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'RECHARGE' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'RECHARGE' ! if(this%multindex > 0) & ! write(this%listlabel, '(a, a16)') trim(this%listlabel), 'MULTIPLIER' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -812,15 +816,15 @@ subroutine default_nodelist(this) ! ------------------------------------------------------------------------------ ! ! -- set variables - if(this%dis%ndim == 3) then + if (this%dis%ndim == 3) then nlay = this%dis%mshape(1) nrow = this%dis%mshape(2) ncol = this%dis%mshape(3) - elseif(this%dis%ndim == 2) then + elseif (this%dis%ndim == 2) then nlay = this%dis%mshape(1) nrow = 1 ncol = this%dis%mshape(2) - endif + end if ! ! -- Populate nodelist ipos = 1 @@ -831,8 +835,8 @@ subroutine default_nodelist(this) noder = this%dis%get_nodenumber(nodeu, 0) this%nodelist(ipos) = noder ipos = ipos + 1 - enddo - enddo + end do + end do ! ! Set flag that indicates IRCH has been assigned, and assign nbound. this%inirch = 1 @@ -840,51 +844,51 @@ subroutine default_nodelist(this) ! ! -- if fixed_cell option not set, then need to store nodelist ! in the nodesontop array - if(.not. this%fixed_cell) call this%set_nodesontop() + if (.not. this%fixed_cell) call this%set_nodesontop() ! ! -- return end subroutine default_nodelist ! -- Procedures related to observations - logical function rch_obs_supported(this) - ! ****************************************************************************** - ! rch_obs_supported - ! -- Return true because RCH package supports observations. - ! -- Overrides BndType%bnd_obs_supported() - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - implicit none - class(RchType) :: this - ! ------------------------------------------------------------------------------ - rch_obs_supported = .true. - ! - ! -- return - return - end function rch_obs_supported + logical function rch_obs_supported(this) + ! ****************************************************************************** + ! rch_obs_supported + ! -- Return true because RCH package supports observations. + ! -- Overrides BndType%bnd_obs_supported() + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + implicit none + class(RchType) :: this + ! ------------------------------------------------------------------------------ + rch_obs_supported = .true. + ! + ! -- return + return + end function rch_obs_supported - subroutine rch_df_obs(this) - ! ****************************************************************************** - ! rch_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by RCH package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ - implicit none - ! -- dummy - class(RchType) :: this - ! -- local - integer(I4B) :: indx - ! ------------------------------------------------------------------------------ - call this%obs%StoreObsType('rch', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor - ! - ! -- return - return - end subroutine rch_df_obs + subroutine rch_df_obs(this) + ! ****************************************************************************** + ! rch_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by RCH package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ + implicit none + ! -- dummy + class(RchType) :: this + ! -- local + integer(I4B) :: indx + ! ------------------------------------------------------------------------------ + call this%obs%StoreObsType('rch', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor + ! + ! -- return + return + end subroutine rch_df_obs ! ! -- Procedure related to time series @@ -900,15 +904,15 @@ subroutine rch_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) case (1) tslink%Text = 'RECHARGE' end select - endif - enddo + end if + end do ! return end subroutine rch_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3riv8.f90 b/src/Model/GroundWaterFlow/gwf3riv8.f90 index 9c2605e9cf1..f14e93fa2f7 100644 --- a/src/Model/GroundWaterFlow/gwf3riv8.f90 +++ b/src/Model/GroundWaterFlow/gwf3riv8.f90 @@ -13,8 +13,8 @@ module rivmodule public :: riv_create public :: RivType ! - character(len=LENFTYPE) :: ftype = 'RIV' - character(len=LENPACKAGENAME) :: text = ' RIV' + character(len=LENFTYPE) :: ftype = 'RIV' + character(len=LENPACKAGENAME) :: text = ' RIV' ! type, extends(BndType) :: RivType contains @@ -43,10 +43,10 @@ subroutine riv_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -54,7 +54,7 @@ subroutine riv_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(rivobj) + allocate (rivobj) packobj => rivobj ! ! -- create name and memory path @@ -67,17 +67,17 @@ subroutine riv_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! -- initialize package call packobj%pack_initialize() - packobj%inunit=inunit - packobj%iout=iout - packobj%id=id + packobj%inunit = inunit + packobj%iout = iout + packobj%id = id packobj%ibcnum = ibcnum - packobj%ncolbnd=3 ! stage, conductance, rbot - packobj%iscloc=2 !sfac applies to conductance - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ncolbnd = 3 ! stage, conductance, rbot + packobj%iscloc = 2 !sfac applies to conductance + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return -end subroutine riv_create + end subroutine riv_create subroutine riv_options(this, option, found) ! ****************************************************************************** @@ -90,21 +90,21 @@ subroutine riv_options(this, option, found) ! ------------------------------------------------------------------------------ use InputOutputModule, only: urword ! -- dummy - class(RivType), intent(inout) :: this + class(RivType), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local ! ------------------------------------------------------------------------------ ! select case (option) - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case default - ! - ! -- No options found - found = .false. + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + found = .true. + case default + ! + ! -- No options found + found = .false. end select ! ! -- return @@ -122,7 +122,7 @@ subroutine riv_ck(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(RivType),intent(inout) :: this + class(RivType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg integer(I4B) :: i @@ -132,35 +132,35 @@ subroutine riv_ck(this) real(DP) :: rbot ! -- formats character(len=*), parameter :: fmtriverr = & - "('RIV BOUNDARY (',i0,') RIVER BOTTOM (',f10.4,') IS LESS " // & - "THAN CELL BOTTOM (',f10.4,')')" + "('RIV BOUNDARY (',i0,') RIVER BOTTOM (',f10.4,') IS LESS & + &THAN CELL BOTTOM (',f10.4,')')" character(len=*), parameter :: fmtriverr2 = & - "('RIV BOUNDARY (',i0,') RIVER STAGE (',f10.4,') IS LESS " // & - "THAN RIVER BOTTOM (',f10.4,')')" + "('RIV BOUNDARY (',i0,') RIVER STAGE (',f10.4,') IS LESS & + &THAN RIVER BOTTOM (',f10.4,')')" character(len=*), parameter :: fmtriverr3 = & - "('RIV BOUNDARY (',i0,') RIVER STAGE (',f10.4,') IS LESS " // & - "THAN CELL BOTTOM (',f10.4,')')" + "('RIV BOUNDARY (',i0,') RIVER STAGE (',f10.4,') IS LESS & + &THAN CELL BOTTOM (',f10.4,')')" ! ------------------------------------------------------------------------------ ! ! -- check stress period data do i = 1, this%nbound - node = this%nodelist(i) - bt = this%dis%bot(node) - stage = this%bound(1,i) - rbot = this%bound(3,i) - ! -- accumulate errors - if (rbot < bt .and. this%icelltype(node) /= 0) then - write(errmsg, fmt=fmtriverr) i, rbot, bt - call store_error(errmsg) - end if - if (stage < rbot) then - write(errmsg, fmt=fmtriverr2) i, stage, rbot - call store_error(errmsg) - end if - if (stage < bt .and. this%icelltype(node) /= 0) then - write(errmsg, fmt=fmtriverr3) i, stage, bt - call store_error(errmsg) - end if + node = this%nodelist(i) + bt = this%dis%bot(node) + stage = this%bound(1, i) + rbot = this%bound(3, i) + ! -- accumulate errors + if (rbot < bt .and. this%icelltype(node) /= 0) then + write (errmsg, fmt=fmtriverr) i, rbot, bt + call store_error(errmsg) + end if + if (stage < rbot) then + write (errmsg, fmt=fmtriverr2) i, stage, rbot + call store_error(errmsg) + end if + if (stage < bt .and. this%icelltype(node) /= 0) then + write (errmsg, fmt=fmtriverr3) i, stage, bt + call store_error(errmsg) + end if end do ! ! -- write summary of river package error messages @@ -172,7 +172,7 @@ subroutine riv_ck(this) return end subroutine riv_ck -subroutine riv_cf(this, reset_mover) + subroutine riv_cf(this, reset_mover) ! ****************************************************************************** ! riv_cf -- Formulate the HCOF and RHS terms ! Subroutine: (1) skip in no rivs @@ -191,38 +191,38 @@ subroutine riv_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no rivs - if(this%nbound.eq.0) return + if (this%nbound .eq. 0) return ! ! -- pakmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() - endif + end if ! ! -- Calculate hcof and rhs for each riv entry - do i=1,this%nbound - node=this%nodelist(i) - if(this%ibound(node)<=0) then - this%hcof(i)=DZERO - this%rhs(i)=DZERO + do i = 1, this%nbound + node = this%nodelist(i) + if (this%ibound(node) <= 0) then + this%hcof(i) = DZERO + this%rhs(i) = DZERO cycle - endif - hriv=this%bound(1,i) - criv=this%bound(2,i) - rbot=this%bound(3,i) - if(this%xnew(node)<=rbot) then - this%rhs(i)=-criv*(hriv-rbot) + end if + hriv = this%bound(1, i) + criv = this%bound(2, i) + rbot = this%bound(3, i) + if (this%xnew(node) <= rbot) then + this%rhs(i) = -criv * (hriv - rbot) this%hcof(i) = DZERO else - this%rhs(i) = -criv*hriv + this%rhs(i) = -criv * hriv this%hcof(i) = -criv - endif - enddo + end if + end do ! ! -- return return -end subroutine riv_cf + end subroutine riv_cf subroutine riv_fc(this, rhs, ia, idxglo, amatsln) ! ************************************************************************** @@ -243,9 +243,9 @@ subroutine riv_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() - endif + end if ! ! -- Copy package rhs and hcof into solution rhs and amat do i = 1, this%nbound @@ -256,13 +256,13 @@ subroutine riv_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active and this river cell is discharging, ! store available water (as positive value). - stage = this%bound(1,i) - if(this%imover == 1 .and. this%xnew(n) > stage) then - cond = this%bound(2,i) + stage = this%bound(1, i) + if (this%imover == 1 .and. this%xnew(n) > stage) then + cond = this%bound(2, i) qriv = cond * (this%xnew(n) - stage) call this%pakmvrobj%accumulate_qformvr(i, qriv) - endif - enddo + end if + end do ! ! -- return return @@ -280,23 +280,23 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STAGE' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOTTOM EL.' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STAGE' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'CONDUCTANCE' + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOTTOM EL.' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -304,7 +304,7 @@ end subroutine define_listlabel ! -- Procedures related to observations -logical function riv_obs_supported(this) + logical function riv_obs_supported(this) ! ****************************************************************************** ! riv_obs_supported ! -- Return true because RIV package supports observations. @@ -313,28 +313,28 @@ logical function riv_obs_supported(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - implicit none - class(RivType) :: this + implicit none + class(RivType) :: this ! ------------------------------------------------------------------------------ - riv_obs_supported = .true. - return -end function riv_obs_supported + riv_obs_supported = .true. + return + end function riv_obs_supported subroutine riv_df_obs(this) - ! ****************************************************************************** - ! riv_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by RIV package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! riv_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by RIV package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ implicit none ! -- dummy class(RivType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ call this%obs%StoreObsType('riv', .true., indx) this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor ! @@ -361,7 +361,7 @@ subroutine riv_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) @@ -372,8 +372,8 @@ subroutine riv_rp_ts(this) case (3) tslink%Text = 'RBOT' end select - endif - enddo + end if + end do ! return end subroutine riv_rp_ts diff --git a/src/Model/GroundWaterFlow/gwf3sfr8.f90 b/src/Model/GroundWaterFlow/gwf3sfr8.f90 index a19d9243379..649445fa55e 100644 --- a/src/Model/GroundWaterFlow/gwf3sfr8.f90 +++ b/src/Model/GroundWaterFlow/gwf3sfr8.f90 @@ -7,28 +7,28 @@ module SfrModule ! use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & - DZERO, DPREC, DEM30, DEM6, DEM5, DEM4, DEM2, & - DHALF, DP6, DTWOTHIRDS, DP7, DP9, DP99, DP999, & - DONE, D1P1, DFIVETHIRDS, DTWO, DPI, DEIGHT, & - DHUNDRED, DEP20, & - NAMEDBOUNDFLAG, LENBOUNDNAME, LENFTYPE, & - LENPACKAGENAME, LENPAKLOC, MAXCHARLEN, & - LENBUDTXT, & - DHNOFLO, DHDRY, DNODATA, & - TABLEFT, TABCENTER, TABRIGHT, & - MNORMAL - use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & - sQuadraticSaturationDerivative, & - sQSaturationDerivative, & - sCubicSaturation, sChSmooth + use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & + DZERO, DPREC, DEM30, DEM6, DEM5, DEM4, DEM2, & + DHALF, DP6, DTWOTHIRDS, DP7, DP9, DP99, DP999, & + DONE, D1P1, DFIVETHIRDS, DTWO, DPI, DEIGHT, & + DHUNDRED, DEP20, & + NAMEDBOUNDFLAG, LENBOUNDNAME, LENFTYPE, & + LENPACKAGENAME, LENPAKLOC, MAXCHARLEN, & + LENBUDTXT, & + DHNOFLO, DHDRY, DNODATA, & + TABLEFT, TABCENTER, TABRIGHT, & + MNORMAL + use SmoothingModule, only: sQuadraticSaturation, sQSaturation, & + sQuadraticSaturationDerivative, & + sQSaturationDerivative, & + sCubicSaturation, sChSmooth use BndModule, only: BndType use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr use TableModule, only: TableType, table_cr use ObserveModule, only: ObserveType use InputOutputModule, only: extract_idnum_or_bndname use BaseDisModule, only: DisBaseType - use SimModule, only: count_errors, store_error, store_error_unit, & + use SimModule, only: count_errors, store_error, store_error_unit, & store_warning use SimVariablesModule, only: errmsg, warnmsg use GwfSfrCrossSectionUtilsModule, only: get_saturated_topwidth, & @@ -40,8 +40,8 @@ module SfrModule ! implicit none ! - character(len=LENFTYPE) :: ftype = 'SFR' !< package ftype string - character(len=LENPACKAGENAME) :: text = ' SFR' !< package budget string + character(len=LENFTYPE) :: ftype = 'SFR' !< package ftype string + character(len=LENPACKAGENAME) :: text = ' SFR' !< package budget string ! private public :: sfr_create @@ -51,5514 +51,5580 @@ module SfrModule ! -- scalars ! -- for budgets ! -- characters - character(len=16), dimension(:), pointer, contiguous :: csfrbudget => NULL() !< advanced package budget names - character(len=16), dimension(:), pointer, contiguous :: cauxcbc => NULL() !< aux names - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: sfrname => null() !< internal SFR reach name + character(len=16), dimension(:), pointer, contiguous :: csfrbudget => NULL() !< advanced package budget names + character(len=16), dimension(:), pointer, contiguous :: cauxcbc => NULL() !< aux names + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: sfrname => null() !< internal SFR reach name ! -- integers - integer(I4B), pointer :: iprhed => null() !< flag for printing stages to listing file - integer(I4B), pointer :: istageout => null() !< flag and unit number for binary stage output - integer(I4B), pointer :: ibudgetout => null() !< flag and unit number for binary sfr budget output - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file - integer(I4B), pointer :: ipakcsv => null() !< flag and unit number for package convergence information - integer(I4B), pointer :: idiversions => null() !< flag indicating if there are any diversions - integer(I4B), pointer :: nconn => NULL() !< number of reach connections - integer(I4B), pointer :: maxsfrpicard => NULL() !< maximum number of Picard iteration calls to SFR solve - integer(I4B), pointer :: maxsfrit => NULL() !< maximum number of iterations in SFR solve - integer(I4B), pointer :: bditems => NULL() !< number of SFR budget items - integer(I4B), pointer :: cbcauxitems => NULL() !< number of aux items in cell-by-cell budget file - integer(I4B), pointer :: icheck => NULL() !< flag indicating if input should be checked (default is yes) - integer(I4B), pointer :: iconvchk => NULL() !< flag indicating of final convergence run is executed - integer(I4B), pointer :: gwfiss => NULL() !< groundwater model steady-state flag - integer(I4B), pointer :: ianynone => null() !< number of reaches with 'none' connection + integer(I4B), pointer :: iprhed => null() !< flag for printing stages to listing file + integer(I4B), pointer :: istageout => null() !< flag and unit number for binary stage output + integer(I4B), pointer :: ibudgetout => null() !< flag and unit number for binary sfr budget output + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + integer(I4B), pointer :: ipakcsv => null() !< flag and unit number for package convergence information + integer(I4B), pointer :: idiversions => null() !< flag indicating if there are any diversions + integer(I4B), pointer :: nconn => NULL() !< number of reach connections + integer(I4B), pointer :: maxsfrpicard => NULL() !< maximum number of Picard iteration calls to SFR solve + integer(I4B), pointer :: maxsfrit => NULL() !< maximum number of iterations in SFR solve + integer(I4B), pointer :: bditems => NULL() !< number of SFR budget items + integer(I4B), pointer :: cbcauxitems => NULL() !< number of aux items in cell-by-cell budget file + integer(I4B), pointer :: icheck => NULL() !< flag indicating if input should be checked (default is yes) + integer(I4B), pointer :: iconvchk => NULL() !< flag indicating of final convergence run is executed + integer(I4B), pointer :: gwfiss => NULL() !< groundwater model steady-state flag + integer(I4B), pointer :: ianynone => null() !< number of reaches with 'none' connection ! -- double precision - real(DP), pointer :: unitconv => NULL() !< unit conversion factor (SI to model units) - real(DP), pointer :: dmaxchg => NULL() !< maximum depth change allowed - real(DP), pointer :: deps => NULL() !< perturbation value + real(DP), pointer :: unitconv => NULL() !< unit conversion factor (SI to model units) + real(DP), pointer :: dmaxchg => NULL() !< maximum depth change allowed + real(DP), pointer :: deps => NULL() !< perturbation value ! -- integer vectors - integer(I4B), dimension(:), pointer, contiguous :: isfrorder => null() !< sfr reach order determined from DAG of upstream reaches - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< CRS row pointer for SFR reaches - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< CRS column pointers for SFR reach connections + integer(I4B), dimension(:), pointer, contiguous :: isfrorder => null() !< sfr reach order determined from DAG of upstream reaches + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< CRS row pointer for SFR reaches + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< CRS column pointers for SFR reach connections ! -- double precision output vectors - real(DP), dimension(:), pointer, contiguous :: qoutflow => null() !< reach downstream flow - real(DP), dimension(:), pointer, contiguous :: qextoutflow => null() !< reach discharge to external boundary - real(DP), dimension(:), pointer, contiguous :: qauxcbc => null() !< aux value - real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< temporary vector + real(DP), dimension(:), pointer, contiguous :: qoutflow => null() !< reach downstream flow + real(DP), dimension(:), pointer, contiguous :: qextoutflow => null() !< reach discharge to external boundary + real(DP), dimension(:), pointer, contiguous :: qauxcbc => null() !< aux value + real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< temporary vector ! ! -- sfr budget object - type(BudgetObjectType), pointer :: budobj => null() !< SFR budget object + type(BudgetObjectType), pointer :: budobj => null() !< SFR budget object ! ! -- sfr table objects - type(TableType), pointer :: stagetab => null() !< reach stage table written to the listing file - type(TableType), pointer :: pakcsvtab => null() !< SFR package convergence table + type(TableType), pointer :: stagetab => null() !< reach stage table written to the listing file + type(TableType), pointer :: pakcsvtab => null() !< SFR package convergence table ! ! -- sfr reach data - integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< ibound array for SFR reaches that defines active, inactive, and constant reaches - integer(I4B), dimension(:), pointer, contiguous :: igwfnode => null() !< groundwater node connected to SFR reaches - integer(I4B), dimension(:), pointer, contiguous :: igwftopnode => null() !< highest active groundwater node under SFR reaches - real(DP), dimension(:), pointer, contiguous :: length => null() !< reach length - real(DP), dimension(:), pointer, contiguous :: width => null() !< reach width - real(DP), dimension(:), pointer, contiguous :: strtop => null() !< reach bed top elevation - real(DP), dimension(:), pointer, contiguous :: bthick => null() !< reach bed thickness - real(DP), dimension(:), pointer, contiguous :: hk => null() !< vertical hydraulic conductivity of reach bed sediments - real(DP), dimension(:), pointer, contiguous :: slope => null() !< reach slope - integer(I4B), dimension(:), pointer, contiguous :: nconnreach => null() !< number of connections for each reach - real(DP), dimension(:), pointer, contiguous :: ustrf => null() !< upstream flow fraction for upstream connections - real(DP), dimension(:), pointer, contiguous :: ftotnd => null() !< total fraction of connected reaches that are not diversions - integer(I4B), dimension(:), pointer, contiguous :: ndiv => null() !< number of diversions for each reach - real(DP), dimension(:), pointer, contiguous :: usflow => null() !< upstream reach flow - real(DP), dimension(:), pointer, contiguous :: dsflow => null() !< downstream reach flow - real(DP), dimension(:), pointer, contiguous :: depth => null() !< reach depth - real(DP), dimension(:), pointer, contiguous :: stage => null() !< reach stage - real(DP), dimension(:), pointer, contiguous :: gwflow => null() !< flow from groundwater to reach - real(DP), dimension(:), pointer, contiguous :: simevap => null() !< simulated reach evaporation - real(DP), dimension(:), pointer, contiguous :: simrunoff => null() !< simulated reach runoff - real(DP), dimension(:), pointer, contiguous :: stage0 => null() !< previous reach stage iterate - real(DP), dimension(:), pointer, contiguous :: usflow0 => null() !< previous upstream reach flow iterate + integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< ibound array for SFR reaches that defines active, inactive, and constant reaches + integer(I4B), dimension(:), pointer, contiguous :: igwfnode => null() !< groundwater node connected to SFR reaches + integer(I4B), dimension(:), pointer, contiguous :: igwftopnode => null() !< highest active groundwater node under SFR reaches + real(DP), dimension(:), pointer, contiguous :: length => null() !< reach length + real(DP), dimension(:), pointer, contiguous :: width => null() !< reach width + real(DP), dimension(:), pointer, contiguous :: strtop => null() !< reach bed top elevation + real(DP), dimension(:), pointer, contiguous :: bthick => null() !< reach bed thickness + real(DP), dimension(:), pointer, contiguous :: hk => null() !< vertical hydraulic conductivity of reach bed sediments + real(DP), dimension(:), pointer, contiguous :: slope => null() !< reach slope + integer(I4B), dimension(:), pointer, contiguous :: nconnreach => null() !< number of connections for each reach + real(DP), dimension(:), pointer, contiguous :: ustrf => null() !< upstream flow fraction for upstream connections + real(DP), dimension(:), pointer, contiguous :: ftotnd => null() !< total fraction of connected reaches that are not diversions + integer(I4B), dimension(:), pointer, contiguous :: ndiv => null() !< number of diversions for each reach + real(DP), dimension(:), pointer, contiguous :: usflow => null() !< upstream reach flow + real(DP), dimension(:), pointer, contiguous :: dsflow => null() !< downstream reach flow + real(DP), dimension(:), pointer, contiguous :: depth => null() !< reach depth + real(DP), dimension(:), pointer, contiguous :: stage => null() !< reach stage + real(DP), dimension(:), pointer, contiguous :: gwflow => null() !< flow from groundwater to reach + real(DP), dimension(:), pointer, contiguous :: simevap => null() !< simulated reach evaporation + real(DP), dimension(:), pointer, contiguous :: simrunoff => null() !< simulated reach runoff + real(DP), dimension(:), pointer, contiguous :: stage0 => null() !< previous reach stage iterate + real(DP), dimension(:), pointer, contiguous :: usflow0 => null() !< previous upstream reach flow iterate ! -- cross-section data - integer(I4B), pointer :: ncrossptstot => null() !< total number of cross-section points - integer(I4B), dimension(:), pointer, contiguous :: ncrosspts => null() !< number of cross-section points for each reach - integer(I4B), dimension(:), pointer, contiguous :: iacross => null() !< pointers to cross-section data for each reach - real(DP), dimension(:), pointer, contiguous :: station => null() !< cross-section station (x-position) data - real(DP), dimension(:), pointer, contiguous :: xsheight => null() !< cross-section height data - real(DP), dimension(:), pointer, contiguous :: xsrough => null() !< cross-section roughness data + integer(I4B), pointer :: ncrossptstot => null() !< total number of cross-section points + integer(I4B), dimension(:), pointer, contiguous :: ncrosspts => null() !< number of cross-section points for each reach + integer(I4B), dimension(:), pointer, contiguous :: iacross => null() !< pointers to cross-section data for each reach + real(DP), dimension(:), pointer, contiguous :: station => null() !< cross-section station (x-position) data + real(DP), dimension(:), pointer, contiguous :: xsheight => null() !< cross-section height data + real(DP), dimension(:), pointer, contiguous :: xsrough => null() !< cross-section roughness data ! -- connection data - integer(I4B), dimension(:), pointer, contiguous :: idir => null() !< reach connection direction - integer(I4B), dimension(:), pointer, contiguous :: idiv => null() !< reach connection diversion number - real(DP), dimension(:), pointer, contiguous :: qconn => null() !< reach connection flow + integer(I4B), dimension(:), pointer, contiguous :: idir => null() !< reach connection direction + integer(I4B), dimension(:), pointer, contiguous :: idiv => null() !< reach connection diversion number + real(DP), dimension(:), pointer, contiguous :: qconn => null() !< reach connection flow ! -- boundary data - real(DP), dimension(:), pointer, contiguous :: rough => null() !< reach Manning's roughness coefficient (SI units) - real(DP), dimension(:), pointer, contiguous :: rain => null() !< reach rainfall - real(DP), dimension(:), pointer, contiguous :: evap => null() !< reach potential evaporation - real(DP), dimension(:), pointer, contiguous :: inflow => null() !< reach upstream inflow - real(DP), dimension(:), pointer, contiguous :: runoff => null() !< reach maximum runoff - real(DP), dimension(:), pointer, contiguous :: sstage => null() !< reach specified stage + real(DP), dimension(:), pointer, contiguous :: rough => null() !< reach Manning's roughness coefficient (SI units) + real(DP), dimension(:), pointer, contiguous :: rain => null() !< reach rainfall + real(DP), dimension(:), pointer, contiguous :: evap => null() !< reach potential evaporation + real(DP), dimension(:), pointer, contiguous :: inflow => null() !< reach upstream inflow + real(DP), dimension(:), pointer, contiguous :: runoff => null() !< reach maximum runoff + real(DP), dimension(:), pointer, contiguous :: sstage => null() !< reach specified stage ! -- reach aux variables - real(DP), dimension(:,:), pointer, contiguous :: rauxvar => null() !< reach aux variable + real(DP), dimension(:, :), pointer, contiguous :: rauxvar => null() !< reach aux variable ! -- diversion data - integer(I4B), dimension(:), pointer, contiguous :: iadiv => null() !< row pointer for reach diversions - integer(I4B), dimension(:), pointer, contiguous :: divreach => null() !< diversion reach - character (len=10), dimension(:), pointer, contiguous :: divcprior => null() !< diversion rule - real(DP), dimension(:), pointer, contiguous :: divflow => null() !< specified diversion flow value - real(DP), dimension(:), pointer, contiguous :: divq => null() !< simulated diversion flow + integer(I4B), dimension(:), pointer, contiguous :: iadiv => null() !< row pointer for reach diversions + integer(I4B), dimension(:), pointer, contiguous :: divreach => null() !< diversion reach + character(len=10), dimension(:), pointer, contiguous :: divcprior => null() !< diversion rule + real(DP), dimension(:), pointer, contiguous :: divflow => null() !< specified diversion flow value + real(DP), dimension(:), pointer, contiguous :: divq => null() !< simulated diversion flow ! ! -- density variables - integer(I4B), pointer :: idense !< flag indicating if density corrections are active - real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() !< density terms + integer(I4B), pointer :: idense !< flag indicating if density corrections are active + real(DP), dimension(:, :), pointer, contiguous :: denseterms => null() !< density terms + ! + ! -- viscosity variables + real(DP), dimension(:, :), pointer, contiguous :: viscratios => null() !< viscosity ratios (1: sfr vsc ratio; 2: gwf vsc ratio) ! ! -- type bound procedures - contains - procedure :: sfr_allocate_scalars - procedure :: sfr_allocate_arrays - procedure :: bnd_options => sfr_options - procedure :: read_dimensions => sfr_read_dimensions - ! procedure :: set_pointers => sfr_set_pointers - procedure :: bnd_ar => sfr_ar - procedure :: bnd_rp => sfr_rp - procedure :: bnd_ad => sfr_ad - procedure :: bnd_cf => sfr_cf - procedure :: bnd_fc => sfr_fc - procedure :: bnd_fn => sfr_fn - procedure :: bnd_cc => sfr_cc - procedure :: bnd_cq => sfr_cq - procedure :: bnd_ot_package_flows => sfr_ot_package_flows - procedure :: bnd_ot_dv => sfr_ot_dv - procedure :: bnd_ot_bdsummary => sfr_ot_bdsummary - procedure :: bnd_da => sfr_da - procedure :: define_listlabel - ! -- methods for observations - procedure, public :: bnd_obs_supported => sfr_obs_supported - procedure, public :: bnd_df_obs => sfr_df_obs - procedure, public :: bnd_rp_obs => sfr_rp_obs - procedure, public :: bnd_bd_obs => sfr_bd_obs - ! -- private procedures - procedure, private :: sfr_set_stressperiod - procedure, private :: sfr_solve - procedure, private :: sfr_update_flows - procedure, private :: sfr_calc_qgwf - procedure, private :: sfr_calc_cond - procedure, private :: sfr_calc_qman - procedure, private :: sfr_calc_qd - procedure, private :: sfr_calc_qsource - procedure, private :: sfr_calc_div - ! -- geometry - procedure, private :: calc_area_wet - procedure, private :: calc_perimeter_wet - procedure, private :: calc_surface_area - procedure, private :: calc_surface_area_wet - procedure, private :: calc_top_width_wet - ! -- reading - procedure, private :: sfr_read_packagedata - procedure, private :: sfr_read_crossection - procedure, private :: sfr_read_connectiondata - procedure, private :: sfr_read_diversions - ! -- calculations - procedure, private :: sfr_calc_reach_depth - procedure, private :: sfr_calc_xs_depth - ! -- error checking - procedure, private :: sfr_check_reaches - procedure, private :: sfr_check_connections - procedure, private :: sfr_check_diversions - procedure, private :: sfr_check_ustrf - ! -- budget - procedure, private :: sfr_setup_budobj - procedure, private :: sfr_fill_budobj - ! -- table - procedure, private :: sfr_setup_tableobj - ! -- density - procedure :: sfr_activate_density - procedure, private :: sfr_calculate_density_exchange + contains + procedure :: sfr_allocate_scalars + procedure :: sfr_allocate_arrays + procedure :: bnd_options => sfr_options + procedure :: read_dimensions => sfr_read_dimensions + ! procedure :: set_pointers => sfr_set_pointers + procedure :: bnd_ar => sfr_ar + procedure :: bnd_rp => sfr_rp + procedure :: bnd_ad => sfr_ad + procedure :: bnd_cf => sfr_cf + procedure :: bnd_fc => sfr_fc + procedure :: bnd_fn => sfr_fn + procedure :: bnd_cc => sfr_cc + procedure :: bnd_cq => sfr_cq + procedure :: bnd_ot_package_flows => sfr_ot_package_flows + procedure :: bnd_ot_dv => sfr_ot_dv + procedure :: bnd_ot_bdsummary => sfr_ot_bdsummary + procedure :: bnd_da => sfr_da + procedure :: define_listlabel + ! -- methods for observations + procedure, public :: bnd_obs_supported => sfr_obs_supported + procedure, public :: bnd_df_obs => sfr_df_obs + procedure, public :: bnd_rp_obs => sfr_rp_obs + procedure, public :: bnd_bd_obs => sfr_bd_obs + ! -- private procedures + procedure, private :: sfr_set_stressperiod + procedure, private :: sfr_solve + procedure, private :: sfr_update_flows + procedure, private :: sfr_calc_qgwf + procedure, private :: sfr_calc_cond + procedure, private :: sfr_calc_qman + procedure, private :: sfr_calc_qd + procedure, private :: sfr_calc_qsource + procedure, private :: sfr_calc_div + ! -- geometry + procedure, private :: calc_area_wet + procedure, private :: calc_perimeter_wet + procedure, private :: calc_surface_area + procedure, private :: calc_surface_area_wet + procedure, private :: calc_top_width_wet + ! -- reading + procedure, private :: sfr_read_packagedata + procedure, private :: sfr_read_crossection + procedure, private :: sfr_read_connectiondata + procedure, private :: sfr_read_diversions + ! -- calculations + procedure, private :: sfr_calc_reach_depth + procedure, private :: sfr_calc_xs_depth + ! -- error checking + procedure, private :: sfr_check_reaches + procedure, private :: sfr_check_connections + procedure, private :: sfr_check_diversions + procedure, private :: sfr_check_ustrf + ! -- budget + procedure, private :: sfr_setup_budobj + procedure, private :: sfr_fill_budobj + ! -- table + procedure, private :: sfr_setup_tableobj + ! -- density + procedure :: sfr_activate_density + procedure, private :: sfr_calculate_density_exchange + ! -- viscosity + procedure :: sfr_activate_viscosity end type SfrType - contains +contains - !> @ brief Create a new package object + !> @ brief Create a new package object !! !! Create a new SFR Package object !! - !< - subroutine sfr_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) - ! -- modules - use MemoryHelperModule, only: create_mem_path - ! -- dummy variables - class(BndType), pointer :: packobj !< pointer to default package type - integer(I4B),intent(in) :: id !< package id - integer(I4B),intent(in) :: ibcnum !< boundary condition number - integer(I4B),intent(in) :: inunit !< unit number of SFR package input file - integer(I4B),intent(in) :: iout !< unit number of model listing file - character(len=*), intent(in) :: namemodel !< model name - character(len=*), intent(in) :: pakname !< package name - ! -- local variables - type(SfrType), pointer :: sfrobj - ! - ! -- allocate the object and assign values to object variables - allocate(sfrobj) - packobj => sfrobj - ! - ! -- create name and memory path - call packobj%set_names(ibcnum, namemodel, pakname, ftype) - packobj%text = text - ! - ! -- allocate scalars - call sfrobj%sfr_allocate_scalars() - ! - ! -- initialize package - call packobj%pack_initialize() + !< + subroutine sfr_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) + ! -- modules + use MemoryHelperModule, only: create_mem_path + ! -- dummy variables + class(BndType), pointer :: packobj !< pointer to default package type + integer(I4B), intent(in) :: id !< package id + integer(I4B), intent(in) :: ibcnum !< boundary condition number + integer(I4B), intent(in) :: inunit !< unit number of SFR package input file + integer(I4B), intent(in) :: iout !< unit number of model listing file + character(len=*), intent(in) :: namemodel !< model name + character(len=*), intent(in) :: pakname !< package name + ! -- local variables + type(SfrType), pointer :: sfrobj + ! + ! -- allocate the object and assign values to object variables + allocate (sfrobj) + packobj => sfrobj + ! + ! -- create name and memory path + call packobj%set_names(ibcnum, namemodel, pakname, ftype) + packobj%text = text + ! + ! -- allocate scalars + call sfrobj%sfr_allocate_scalars() + ! + ! -- initialize package + call packobj%pack_initialize() - packobj%inunit = inunit - packobj%iout = iout - packobj%id = id - packobj%ibcnum = ibcnum - packobj%ncolbnd = 4 - packobj%iscloc = 0 ! not supported - packobj%isadvpak = 1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') - ! - ! -- return - return - end subroutine sfr_create + packobj%inunit = inunit + packobj%iout = iout + packobj%id = id + packobj%ibcnum = ibcnum + packobj%ncolbnd = 4 + packobj%iscloc = 0 ! not supported + packobj%isadvpak = 1 + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') + ! + ! -- return + return + end subroutine sfr_create - !> @ brief Allocate scalars + !> @ brief Allocate scalars !! !! Allocate and initialize scalars for the SFR package. The base model !! allocate scalars method is also called. !! - !< - subroutine sfr_allocate_scalars(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate, mem_setptr - use MemoryHelperModule, only: create_mem_path - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - ! - ! -- call standard BndType allocate scalars - call this%BndType%allocate_scalars() - ! - ! -- allocate the object and assign values to object variables - call mem_allocate(this%iprhed, 'IPRHED', this%memoryPath) - call mem_allocate(this%istageout, 'ISTAGEOUT', this%memoryPath) - call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath) - call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath) - call mem_allocate(this%ipakcsv, 'IPAKCSV', this%memoryPath) - call mem_allocate(this%idiversions, 'IDIVERSIONS', this%memoryPath) - call mem_allocate(this%maxsfrpicard, 'MAXSFRPICARD', this%memoryPath) - call mem_allocate(this%maxsfrit, 'MAXSFRIT', this%memoryPath) - call mem_allocate(this%bditems, 'BDITEMS', this%memoryPath) - call mem_allocate(this%cbcauxitems, 'CBCAUXITEMS', this%memoryPath) - call mem_allocate(this%unitconv, 'UNITCONV', this%memoryPath) - call mem_allocate(this%dmaxchg, 'DMAXCHG', this%memoryPath) - call mem_allocate(this%deps, 'DEPS', this%memoryPath) - call mem_allocate(this%nconn, 'NCONN', this%memoryPath) - call mem_allocate(this%icheck, 'ICHECK', this%memoryPath) - call mem_allocate(this%iconvchk, 'ICONVCHK', this%memoryPath) - call mem_allocate(this%idense, 'IDENSE', this%memoryPath) - call mem_allocate(this%ianynone, 'IANYNONE', this%memoryPath) - call mem_allocate(this%ncrossptstot, 'NCROSSPTSTOT', this%memoryPath) - ! - ! -- set pointer to gwf iss - call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model)) - ! - ! -- Set values - this%iprhed = 0 - this%istageout = 0 - this%ibudgetout = 0 - this%ibudcsv = 0 - this%ipakcsv = 0 - this%idiversions = 0 - this%maxsfrpicard = 100 - this%maxsfrit = 100 - this%bditems = 8 - this%cbcauxitems = 1 - this%unitconv = DONE - this%dmaxchg = DEM5 - this%deps = DP999 * this%dmaxchg - this%nconn = 0 - this%icheck = 1 - this%iconvchk = 1 - this%idense = 0 - this%ianynone = 0 - this%ncrossptstot = 0 - ! - ! -- return - return - end subroutine sfr_allocate_scalars + !< + subroutine sfr_allocate_scalars(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate, mem_setptr + use MemoryHelperModule, only: create_mem_path + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! + ! -- call standard BndType allocate scalars + call this%BndType%allocate_scalars() + ! + ! -- allocate the object and assign values to object variables + call mem_allocate(this%iprhed, 'IPRHED', this%memoryPath) + call mem_allocate(this%istageout, 'ISTAGEOUT', this%memoryPath) + call mem_allocate(this%ibudgetout, 'IBUDGETOUT', this%memoryPath) + call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath) + call mem_allocate(this%ipakcsv, 'IPAKCSV', this%memoryPath) + call mem_allocate(this%idiversions, 'IDIVERSIONS', this%memoryPath) + call mem_allocate(this%maxsfrpicard, 'MAXSFRPICARD', this%memoryPath) + call mem_allocate(this%maxsfrit, 'MAXSFRIT', this%memoryPath) + call mem_allocate(this%bditems, 'BDITEMS', this%memoryPath) + call mem_allocate(this%cbcauxitems, 'CBCAUXITEMS', this%memoryPath) + call mem_allocate(this%unitconv, 'UNITCONV', this%memoryPath) + call mem_allocate(this%dmaxchg, 'DMAXCHG', this%memoryPath) + call mem_allocate(this%deps, 'DEPS', this%memoryPath) + call mem_allocate(this%nconn, 'NCONN', this%memoryPath) + call mem_allocate(this%icheck, 'ICHECK', this%memoryPath) + call mem_allocate(this%iconvchk, 'ICONVCHK', this%memoryPath) + call mem_allocate(this%idense, 'IDENSE', this%memoryPath) + call mem_allocate(this%ianynone, 'IANYNONE', this%memoryPath) + call mem_allocate(this%ncrossptstot, 'NCROSSPTSTOT', this%memoryPath) + ! + ! -- set pointer to gwf iss + call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model)) + ! + ! -- Set values + this%iprhed = 0 + this%istageout = 0 + this%ibudgetout = 0 + this%ibudcsv = 0 + this%ipakcsv = 0 + this%idiversions = 0 + this%maxsfrpicard = 100 + this%maxsfrit = 100 + this%bditems = 8 + this%cbcauxitems = 1 + this%unitconv = DONE + this%dmaxchg = DEM5 + this%deps = DP999 * this%dmaxchg + this%nconn = 0 + this%icheck = 1 + this%iconvchk = 1 + this%idense = 0 + this%ivsc = 0 + this%ianynone = 0 + this%ncrossptstot = 0 + ! + ! -- return + return + end subroutine sfr_allocate_scalars - !> @ brief Allocate arrays + !> @ brief Allocate arrays !! !! Allocate and initialize array for the SFR package. !! - !< - subroutine sfr_allocate_arrays(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - ! - ! -- allocate character array for budget text - allocate(this%csfrbudget(this%bditems)) - call mem_allocate(this%sfrname, LENBOUNDNAME, this%maxbound, & - 'SFRNAME', this%memoryPath) - ! - ! -- variables originally in SfrDataType - call mem_allocate(this%iboundpak, this%maxbound, 'IBOUNDPAK', this%memoryPath) - call mem_allocate(this%igwfnode, this%maxbound, 'IGWFNODE', this%memoryPath) - call mem_allocate(this%igwftopnode, this%maxbound, 'IGWFTOPNODE', this%memoryPath) - call mem_allocate(this%length, this%maxbound, 'LENGTH', this%memoryPath) - call mem_allocate(this%width, this%maxbound, 'WIDTH', this%memoryPath) - call mem_allocate(this%strtop, this%maxbound, 'STRTOP', this%memoryPath) - call mem_allocate(this%bthick, this%maxbound, 'BTHICK', this%memoryPath) - call mem_allocate(this%hk, this%maxbound, 'HK', this%memoryPath) - call mem_allocate(this%slope, this%maxbound, 'SLOPE', this%memoryPath) - call mem_allocate(this%nconnreach, this%maxbound, 'NCONNREACH', this%memoryPath) - call mem_allocate(this%ustrf, this%maxbound, 'USTRF', this%memoryPath) - call mem_allocate(this%ftotnd, this%maxbound, 'FTOTND', this%memoryPath) - call mem_allocate(this%ndiv, this%maxbound, 'NDIV', this%memoryPath) - call mem_allocate(this%usflow, this%maxbound, 'USFLOW', this%memoryPath) - call mem_allocate(this%dsflow, this%maxbound, 'DSFLOW', this%memoryPath) - call mem_allocate(this%depth, this%maxbound, 'DEPTH', this%memoryPath) - call mem_allocate(this%stage, this%maxbound, 'STAGE', this%memoryPath) - call mem_allocate(this%gwflow, this%maxbound, 'GWFLOW', this%memoryPath) - call mem_allocate(this%simevap, this%maxbound, 'SIMEVAP', this%memoryPath) - call mem_allocate(this%simrunoff, this%maxbound, 'SIMRUNOFF', this%memoryPath) - call mem_allocate(this%stage0, this%maxbound, 'STAGE0', this%memoryPath) - call mem_allocate(this%usflow0, this%maxbound, 'USFLOW0', this%memoryPath) - ! - ! -- reach order and connection data - call mem_allocate(this%isfrorder, this%maxbound, 'ISFRORDER', this%memoryPath) - call mem_allocate(this%ia, this%maxbound+1, 'IA', this%memoryPath) - call mem_allocate(this%ja, 0, 'JA', this%memoryPath) - call mem_allocate(this%idir, 0, 'IDIR', this%memoryPath) - call mem_allocate(this%idiv, 0, 'IDIV', this%memoryPath) - call mem_allocate(this%qconn, 0, 'QCONN', this%memoryPath) + !< + subroutine sfr_allocate_arrays(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- allocate character array for budget text + allocate (this%csfrbudget(this%bditems)) + call mem_allocate(this%sfrname, LENBOUNDNAME, this%maxbound, & + 'SFRNAME', this%memoryPath) + ! + ! -- variables originally in SfrDataType + call mem_allocate(this%iboundpak, this%maxbound, 'IBOUNDPAK', & + this%memoryPath) + call mem_allocate(this%igwfnode, this%maxbound, 'IGWFNODE', this%memoryPath) + call mem_allocate(this%igwftopnode, this%maxbound, 'IGWFTOPNODE', & + this%memoryPath) + call mem_allocate(this%length, this%maxbound, 'LENGTH', this%memoryPath) + call mem_allocate(this%width, this%maxbound, 'WIDTH', this%memoryPath) + call mem_allocate(this%strtop, this%maxbound, 'STRTOP', this%memoryPath) + call mem_allocate(this%bthick, this%maxbound, 'BTHICK', this%memoryPath) + call mem_allocate(this%hk, this%maxbound, 'HK', this%memoryPath) + call mem_allocate(this%slope, this%maxbound, 'SLOPE', this%memoryPath) + call mem_allocate(this%nconnreach, this%maxbound, 'NCONNREACH', & + this%memoryPath) + call mem_allocate(this%ustrf, this%maxbound, 'USTRF', this%memoryPath) + call mem_allocate(this%ftotnd, this%maxbound, 'FTOTND', this%memoryPath) + call mem_allocate(this%ndiv, this%maxbound, 'NDIV', this%memoryPath) + call mem_allocate(this%usflow, this%maxbound, 'USFLOW', this%memoryPath) + call mem_allocate(this%dsflow, this%maxbound, 'DSFLOW', this%memoryPath) + call mem_allocate(this%depth, this%maxbound, 'DEPTH', this%memoryPath) + call mem_allocate(this%stage, this%maxbound, 'STAGE', this%memoryPath) + call mem_allocate(this%gwflow, this%maxbound, 'GWFLOW', this%memoryPath) + call mem_allocate(this%simevap, this%maxbound, 'SIMEVAP', this%memoryPath) + call mem_allocate(this%simrunoff, this%maxbound, 'SIMRUNOFF', & + this%memoryPath) + call mem_allocate(this%stage0, this%maxbound, 'STAGE0', this%memoryPath) + call mem_allocate(this%usflow0, this%maxbound, 'USFLOW0', this%memoryPath) + ! + ! -- reach order and connection data + call mem_allocate(this%isfrorder, this%maxbound, 'ISFRORDER', & + this%memoryPath) + call mem_allocate(this%ia, this%maxbound + 1, 'IA', this%memoryPath) + call mem_allocate(this%ja, 0, 'JA', this%memoryPath) + call mem_allocate(this%idir, 0, 'IDIR', this%memoryPath) + call mem_allocate(this%idiv, 0, 'IDIV', this%memoryPath) + call mem_allocate(this%qconn, 0, 'QCONN', this%memoryPath) + ! + ! -- boundary data + call mem_allocate(this%rough, this%maxbound, 'ROUGH', this%memoryPath) + call mem_allocate(this%rain, this%maxbound, 'RAIN', this%memoryPath) + call mem_allocate(this%evap, this%maxbound, 'EVAP', this%memoryPath) + call mem_allocate(this%inflow, this%maxbound, 'INFLOW', this%memoryPath) + call mem_allocate(this%runoff, this%maxbound, 'RUNOFF', this%memoryPath) + call mem_allocate(this%sstage, this%maxbound, 'SSTAGE', this%memoryPath) + ! + ! -- aux variables + call mem_allocate(this%rauxvar, this%naux, this%maxbound, & + 'RAUXVAR', this%memoryPath) + ! + ! -- diversion variables + call mem_allocate(this%iadiv, this%maxbound + 1, 'IADIV', this%memoryPath) + call mem_allocate(this%divreach, 0, 'DIVREACH', this%memoryPath) + call mem_allocate(this%divflow, 0, 'DIVFLOW', this%memoryPath) + call mem_allocate(this%divq, 0, 'DIVQ', this%memoryPath) + ! + ! -- cross-section data + call mem_allocate(this%ncrosspts, this%maxbound, 'NCROSSPTS', & + this%memoryPath) + call mem_allocate(this%iacross, this%maxbound + 1, 'IACROSS', & + this%memoryPath) + call mem_allocate(this%station, this%ncrossptstot, 'STATION', & + this%memoryPath) + call mem_allocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', & + this%memoryPath) + call mem_allocate(this%xsrough, this%ncrossptstot, 'XSROUGH', & + this%memoryPath) + ! + ! -- initialize variables + this%iacross(1) = 0 + do i = 1, this%maxbound + this%iboundpak(i) = 1 + this%igwfnode(i) = 0 + this%igwftopnode(i) = 0 + this%length(i) = DZERO + this%width(i) = DZERO + this%strtop(i) = DZERO + this%bthick(i) = DZERO + this%hk(i) = DZERO + this%slope(i) = DZERO + this%nconnreach(i) = 0 + this%ustrf(i) = DZERO + this%ftotnd(i) = DZERO + this%ndiv(i) = 0 + this%usflow(i) = DZERO + this%dsflow(i) = DZERO + this%depth(i) = DZERO + this%stage(i) = DZERO + this%gwflow(i) = DZERO + this%simevap(i) = DZERO + this%simrunoff(i) = DZERO + this%stage0(i) = DZERO + this%usflow0(i) = DZERO ! ! -- boundary data - call mem_allocate(this%rough, this%maxbound, 'ROUGH', this%memoryPath) - call mem_allocate(this%rain, this%maxbound, 'RAIN', this%memoryPath) - call mem_allocate(this%evap, this%maxbound, 'EVAP', this%memoryPath) - call mem_allocate(this%inflow, this%maxbound, 'INFLOW', this%memoryPath) - call mem_allocate(this%runoff, this%maxbound, 'RUNOFF', this%memoryPath) - call mem_allocate(this%sstage, this%maxbound, 'SSTAGE', this%memoryPath) + this%rough(i) = DZERO + this%rain(i) = DZERO + this%evap(i) = DZERO + this%inflow(i) = DZERO + this%runoff(i) = DZERO + this%sstage(i) = DZERO ! ! -- aux variables - call mem_allocate(this%rauxvar, this%naux, this%maxbound, & - 'RAUXVAR', this%memoryPath) - ! - ! -- diversion variables - call mem_allocate(this%iadiv, this%maxbound+1, 'IADIV', this%memoryPath) - call mem_allocate(this%divreach, 0, 'DIVREACH', this%memoryPath) - call mem_allocate(this%divflow, 0, 'DIVFLOW', this%memoryPath) - call mem_allocate(this%divq, 0, 'DIVQ', this%memoryPath) - ! - ! -- cross-section data - call mem_allocate(this%ncrosspts, this%maxbound, 'NCROSSPTS', this%memoryPath) - call mem_allocate(this%iacross, this%maxbound+1, 'IACROSS', this%memoryPath) - call mem_allocate(this%station, this%ncrossptstot, 'STATION', this%memoryPath) - call mem_allocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', this%memoryPath) - call mem_allocate(this%xsrough, this%ncrossptstot, 'XSROUGH', this%memoryPath) - ! - ! -- initialize variables - this%iacross(1) = 0 - do i = 1, this%maxbound - this%iboundpak(i) = 1 - this%igwfnode(i) = 0 - this%igwftopnode(i) = 0 - this%length(i) = DZERO - this%width(i) = DZERO - this%strtop(i) = DZERO - this%bthick(i) = DZERO - this%hk(i) = DZERO - this%slope(i) = DZERO - this%nconnreach(i) = 0 - this%ustrf(i) = DZERO - this%ftotnd(i) = DZERO - this%ndiv(i) = 0 - this%usflow(i) = DZERO - this%dsflow(i) = DZERO - this%depth(i) = DZERO - this%stage(i) = DZERO - this%gwflow(i) = DZERO - this%simevap(i) = DZERO - this%simrunoff(i) = DZERO - this%stage0(i) = DZERO - this%usflow0(i) = DZERO - ! - ! -- boundary data - this%rough(i) = DZERO - this%rain(i) = DZERO - this%evap(i) = DZERO - this%inflow(i) = DZERO - this%runoff(i) = DZERO - this%sstage(i) = DZERO - ! - ! -- aux variables - do j = 1, this%naux - this%rauxvar(j, i) = DZERO - end do - ! - ! -- cross-section data - this%ncrosspts(i) = 0 - this%iacross(i+1) = 0 - end do - ! - ! -- initialize additional cross-section data - do i = 1, this%ncrossptstot - this%station(i) = DZERO - this%xsheight(i) = DZERO - this%xsrough(i) = DZERO + do j = 1, this%naux + this%rauxvar(j, i) = DZERO end do ! - !-- fill csfrbudget - this%csfrbudget(1) = ' RAINFALL' - this%csfrbudget(2) = ' EVAPORATION' - this%csfrbudget(3) = ' RUNOFF' - this%csfrbudget(4) = ' EXT-INFLOW' - this%csfrbudget(5) = ' GWF' - this%csfrbudget(6) = ' EXT-OUTFLOW' - this%csfrbudget(7) = ' FROM-MVR' - this%csfrbudget(8) = ' TO-MVR' - ! - ! -- allocate and initialize budget output data - call mem_allocate(this%qoutflow, this%maxbound, 'QOUTFLOW', this%memoryPath) - call mem_allocate(this%qextoutflow, this%maxbound, 'QEXTOUTFLOW', this%memoryPath) + ! -- cross-section data + this%ncrosspts(i) = 0 + this%iacross(i + 1) = 0 + end do + ! + ! -- initialize additional cross-section data + do i = 1, this%ncrossptstot + this%station(i) = DZERO + this%xsheight(i) = DZERO + this%xsrough(i) = DZERO + end do + ! + !-- fill csfrbudget + this%csfrbudget(1) = ' RAINFALL' + this%csfrbudget(2) = ' EVAPORATION' + this%csfrbudget(3) = ' RUNOFF' + this%csfrbudget(4) = ' EXT-INFLOW' + this%csfrbudget(5) = ' GWF' + this%csfrbudget(6) = ' EXT-OUTFLOW' + this%csfrbudget(7) = ' FROM-MVR' + this%csfrbudget(8) = ' TO-MVR' + ! + ! -- allocate and initialize budget output data + call mem_allocate(this%qoutflow, this%maxbound, 'QOUTFLOW', this%memoryPath) + call mem_allocate(this%qextoutflow, this%maxbound, 'QEXTOUTFLOW', & + this%memoryPath) + do i = 1, this%maxbound + this%qoutflow(i) = DZERO + this%qextoutflow(i) = DZERO + end do + ! + ! -- allocate and initialize dbuff + if (this%istageout > 0) then + call mem_allocate(this%dbuff, this%maxbound, 'DBUFF', this%memoryPath) do i = 1, this%maxbound - this%qoutflow(i) = DZERO - this%qextoutflow(i) = DZERO - end do - ! - ! -- allocate and initialize dbuff - if (this%istageout > 0) then - call mem_allocate(this%dbuff, this%maxbound, 'DBUFF', this%memoryPath) - do i = 1, this%maxbound - this%dbuff(i) = DZERO - end do - else - call mem_allocate(this%dbuff, 0, 'DBUFF', this%memoryPath) - end if - ! - ! -- allocate character array for budget text - allocate(this%cauxcbc(this%cbcauxitems)) - ! - ! -- allocate and initialize qauxcbc - call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', this%memoryPath) - do i = 1, this%cbcauxitems - this%qauxcbc(i) = DZERO + this%dbuff(i) = DZERO end do - ! - !-- fill cauxcbc - this%cauxcbc(1) = 'FLOW-AREA ' - ! - ! -- allocate denseterms to size 0 - call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath) - ! - ! -- return - return - end subroutine sfr_allocate_arrays + else + call mem_allocate(this%dbuff, 0, 'DBUFF', this%memoryPath) + end if + ! + ! -- allocate character array for budget text + allocate (this%cauxcbc(this%cbcauxitems)) + ! + ! -- allocate and initialize qauxcbc + call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', & + this%memoryPath) + do i = 1, this%cbcauxitems + this%qauxcbc(i) = DZERO + end do + ! + ! -- fill cauxcbc + this%cauxcbc(1) = 'FLOW-AREA ' + ! + ! -- allocate denseterms to size 0 + call mem_allocate(this%denseterms, 3, 0, 'DENSETERMS', this%memoryPath) + ! + ! -- allocate viscratios to size 0 + call mem_allocate(this%viscratios, 2, 0, 'VISCRATIOS', this%memoryPath) + ! + ! -- return + return + end subroutine sfr_allocate_arrays - !> @ brief Read dimensions for package + !> @ brief Read dimensions for package !! !! Read dimensions for the SFR package. !! - !< - subroutine sfr_read_dimensions(this) - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character (len=LINELENGTH) :: keyword - integer(I4B) :: ierr - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - ! - ! -- initialize dimensions to 0 - this%maxbound = 0 - ! - ! -- get dimensions block - call this%parser%GetBlock('DIMENSIONS', isFound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse dimensions block if detected - if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('NREACHES') - this%maxbound = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)')'NREACHES = ', this%maxbound - case default - write(errmsg,'(2a)') & - 'Unknown ' // trim(this%text) // ' dimension: ', trim(keyword) - call store_error(errmsg) - end select - end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' DIMENSIONS' - else - call store_error('Required dimensions block not found.') - end if - ! - ! -- verify dimensions were set - if(this%maxbound < 1) then - write(errmsg, '(a)') & - 'NREACHES was not specified or was specified incorrectly.' - call store_error(errmsg) - endif - ! - ! -- write summary of error messages for block - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - ! - ! -- Call define_listlabel to construct the list label that is written - ! when PRINT_INPUT option is used. - call this%define_listlabel() - ! - ! -- Define default cross-section data size - this%ncrossptstot = this%maxbound - ! - ! -- Allocate arrays in package superclass - call this%sfr_allocate_arrays() - ! - ! -- read package data - call this%sfr_read_packagedata() - ! - ! -- read cross-section data - call this%sfr_read_crossection() - ! - ! -- read connection data - call this%sfr_read_connectiondata() - ! - ! -- read diversion data - call this%sfr_read_diversions() - ! - ! -- setup the budget object - call this%sfr_setup_budobj() - ! - ! -- setup the stage table object - call this%sfr_setup_tableobj() - ! - ! -- return - return - end subroutine sfr_read_dimensions + !< + subroutine sfr_read_dimensions(this) + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: keyword + integer(I4B) :: ierr + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + ! + ! -- initialize dimensions to 0 + this%maxbound = 0 + ! + ! -- get dimensions block + call this%parser%GetBlock('DIMENSIONS', isFound, ierr, & + supportOpenClose=.true.) + ! + ! -- parse dimensions block if detected + if (isfound) then + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('NREACHES') + this%maxbound = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NREACHES = ', this%maxbound + case default + write (errmsg, '(2a)') & + 'Unknown '//trim(this%text)//' dimension: ', trim(keyword) + call store_error(errmsg) + end select + end do + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' + else + call store_error('Required dimensions block not found.') + end if + ! + ! -- verify dimensions were set + if (this%maxbound < 1) then + write (errmsg, '(a)') & + 'NREACHES was not specified or was specified incorrectly.' + call store_error(errmsg) + end if + ! + ! -- write summary of error messages for block + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- Call define_listlabel to construct the list label that is written + ! when PRINT_INPUT option is used. + call this%define_listlabel() + ! + ! -- Define default cross-section data size + this%ncrossptstot = this%maxbound + ! + ! -- Allocate arrays in package superclass + call this%sfr_allocate_arrays() + ! + ! -- read package data + call this%sfr_read_packagedata() + ! + ! -- read cross-section data + call this%sfr_read_crossection() + ! + ! -- read connection data + call this%sfr_read_connectiondata() + ! + ! -- read diversion data + call this%sfr_read_diversions() + ! + ! -- setup the budget object + call this%sfr_setup_budobj() + ! + ! -- setup the stage table object + call this%sfr_setup_tableobj() + ! + ! -- return + return + end subroutine sfr_read_dimensions - !> @ brief Read additional options for package + !> @ brief Read additional options for package !! !! Read additional options for SFR package. !! - !< - subroutine sfr_options(this, option, found) - ! -- modules - use OpenSpecModule, only: access, form - use InputOutputModule, only: getunit, openfile - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - character(len=*), intent(inout) :: option !< option keyword string - logical(LGP), intent(inout) :: found !< boolean indicating if option found - ! -- local variables - real(DP) :: r - character(len=MAXCHARLEN) :: fname - character(len=MAXCHARLEN) :: keyword - ! -- formats - character(len=*),parameter :: fmtunitconv = & - "(4x, 'UNIT CONVERSION VALUE (',g0,') SPECIFIED.')" - character(len=*),parameter :: fmtpicard = & - "(4x, 'MAXIMUM SFR PICARD ITERATION VALUE (',i0,') SPECIFIED.')" - character(len=*),parameter :: fmtiter = & - "(4x, 'MAXIMUM SFR ITERATION VALUE (',i0,') SPECIFIED.')" - character(len=*),parameter :: fmtdmaxchg = & - "(4x, 'MAXIMUM DEPTH CHANGE VALUE (',g0,') SPECIFIED.')" - character(len=*),parameter :: fmtsfrbin = & - "(4x, 'SFR ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, & - &'OPENED ON UNIT: ', I0)" - ! - ! -- Check for SFR options - select case (option) - case ('PRINT_STAGE') - this%iprhed = 1 - write(this%iout,'(4x,a)') trim(adjustl(this%text))// & - ' STAGES WILL BE PRINTED TO LISTING FILE.' - found = .true. - case('STAGE') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%istageout = getunit() - call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', MNORMAL) - write(this%iout,fmtsfrbin) & - 'STAGE', trim(adjustl(fname)), this%istageout - found = .true. - else - call store_error('Optional stage keyword must be followed by fileout.') - end if - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', MNORMAL) - write(this%iout,fmtsfrbin) & - 'BUDGET', trim(adjustl(fname)), this%ibudgetout - found = .true. - else - call store_error('Optional budget keyword must be ' // & - 'followed by fileout.') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtsfrbin) & - 'BUDGET CSV', trim(adjustl(fname)), this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case('PACKAGE_CONVERGENCE') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ipakcsv = getunit() - call openfile(this%ipakcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtsfrbin) & - 'PACKAGE_CONVERGENCE', trim(adjustl(fname)), this%ipakcsv - found = .true. - else - call store_error('Optional package_convergence keyword must be ' // & - 'followed by fileout.') - end if - case('UNIT_CONVERSION') - this%unitconv = this%parser%GetDouble() - write(this%iout, fmtunitconv) this%unitconv - found = .true. - case('MAXIMUM_PICARD_ITERATIONS') - this%maxsfrpicard = this%parser%GetInteger() - write(this%iout, fmtpicard) this%maxsfrpicard - found = .true. - case('MAXIMUM_ITERATIONS') - this%maxsfrit = this%parser%GetInteger() - write(this%iout, fmtiter) this%maxsfrit - found = .true. - case('MAXIMUM_DEPTH_CHANGE') - r = this%parser%GetDouble() - this%dmaxchg = r - this%deps = DP999 * r - write(this%iout, fmtdmaxchg) this%dmaxchg - found = .true. - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - ! - ! -- right now these are options that are only available in the - ! development version and are not included in the documentation. - ! These options are only available when IDEVELOPMODE in - ! constants module is set to 1 - case('DEV_NO_CHECK') - call this%parser%DevOpt() - this%icheck = 0 - write(this%iout, '(4x,A)') 'SFR CHECKS OF REACH GEOMETRY ' // & - 'RELATIVE TO MODEL GRID AND ' // & - 'REASONABLE PARAMETERS WILL NOT ' // & - 'BE PERFORMED.' - found = .true. - case('DEV_NO_FINAL_CHECK') - call this%parser%DevOpt() - this%iconvchk = 0 - write(this%iout, '(4x,a)') & - & 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN STREAM FLOW ROUTING ' // & - & 'STAGES AND FLOWS WILL NOT BE MADE' - found = .true. - ! - ! -- no valid options found - case default - ! - ! -- No options found - found = .false. - end select - ! - ! -- return - return - end subroutine sfr_options + !< + subroutine sfr_options(this, option, found) + ! -- modules + use OpenSpecModule, only: access, form + use InputOutputModule, only: getunit, openfile + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + character(len=*), intent(inout) :: option !< option keyword string + logical(LGP), intent(inout) :: found !< boolean indicating if option found + ! -- local variables + real(DP) :: r + character(len=MAXCHARLEN) :: fname + character(len=MAXCHARLEN) :: keyword + ! -- formats + character(len=*), parameter :: fmtunitconv = & + &"(4x, 'UNIT CONVERSION VALUE (',g0,') SPECIFIED.')" + character(len=*), parameter :: fmtpicard = & + &"(4x, 'MAXIMUM SFR PICARD ITERATION VALUE (',i0,') SPECIFIED.')" + character(len=*), parameter :: fmtiter = & + &"(4x, 'MAXIMUM SFR ITERATION VALUE (',i0,') SPECIFIED.')" + character(len=*), parameter :: fmtdmaxchg = & + &"(4x, 'MAXIMUM DEPTH CHANGE VALUE (',g0,') SPECIFIED.')" + character(len=*), parameter :: fmtsfrbin = & + "(4x, 'SFR ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, & + &'OPENED ON UNIT: ', I0)" + ! + ! -- Check for SFR options + found = .true. + select case (option) + case ('PRINT_STAGE') + this%iprhed = 1 + write (this%iout, '(4x,a)') trim(adjustl(this%text))// & + ' STAGES WILL BE PRINTED TO LISTING FILE.' + case ('STAGE') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%istageout = getunit() + call openfile(this%istageout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', MNORMAL) + write (this%iout, fmtsfrbin) & + 'STAGE', trim(adjustl(fname)), this%istageout + else + call store_error('Optional stage keyword must & + &be followed by fileout.') + end if + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', MNORMAL) + write (this%iout, fmtsfrbin) & + 'BUDGET', trim(adjustl(fname)), this%ibudgetout + else + call store_error('Optional budget keyword must be '// & + 'followed by fileout.') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtsfrbin) & + 'BUDGET CSV', trim(adjustl(fname)), this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('PACKAGE_CONVERGENCE') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ipakcsv = getunit() + call openfile(this%ipakcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtsfrbin) & + 'PACKAGE_CONVERGENCE', trim(adjustl(fname)), this%ipakcsv + else + call store_error('Optional package_convergence keyword must be '// & + 'followed by fileout.') + end if + case ('UNIT_CONVERSION') + this%unitconv = this%parser%GetDouble() + write (this%iout, fmtunitconv) this%unitconv + case ('MAXIMUM_PICARD_ITERATIONS') + this%maxsfrpicard = this%parser%GetInteger() + write (this%iout, fmtpicard) this%maxsfrpicard + case ('MAXIMUM_ITERATIONS') + this%maxsfrit = this%parser%GetInteger() + write (this%iout, fmtiter) this%maxsfrit + case ('MAXIMUM_DEPTH_CHANGE') + r = this%parser%GetDouble() + this%dmaxchg = r + this%deps = DP999 * r + write (this%iout, fmtdmaxchg) this%dmaxchg + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + ! + ! -- right now these are options that are only available in the + ! development version and are not included in the documentation. + ! These options are only available when IDEVELOPMODE in + ! constants module is set to 1 + case ('DEV_NO_CHECK') + call this%parser%DevOpt() + this%icheck = 0 + write (this%iout, '(4x,A)') 'SFR CHECKS OF REACH GEOMETRY '// & + 'RELATIVE TO MODEL GRID AND '// & + 'REASONABLE PARAMETERS WILL NOT '// & + 'BE PERFORMED.' + case ('DEV_NO_FINAL_CHECK') + call this%parser%DevOpt() + this%iconvchk = 0 + write (this%iout, '(4x,a)') & + 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN STREAM FLOW ROUTING & + &STAGES AND FLOWS WILL NOT BE MADE' + ! + ! -- no valid options found + case default + ! + ! -- No options found + found = .false. + end select + ! + ! -- return + return + end subroutine sfr_options - !> @ brief Allocate and read method for package + !> @ brief Allocate and read method for package !! !! Method to read and prepare period data for the SFR package. !! - !< - subroutine sfr_ar(this) - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - integer(I4B) :: n - integer(I4B) :: ierr - ! - ! -- allocate and read observations - call this%obs%obs_ar() - ! - ! -- call standard BndType allocate scalars - call this%BndType%allocate_arrays() - ! - ! -- set boundname for each connection - if (this%inamedbound /= 0) then - do n = 1, this%maxbound - this%boundname(n) = this%sfrname(n) - end do - endif - ! - ! -- copy igwfnode into nodelist + !< + subroutine sfr_ar(this) + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + integer(I4B) :: n + integer(I4B) :: ierr + ! + ! -- allocate and read observations + call this%obs%obs_ar() + ! + ! -- call standard BndType allocate scalars + call this%BndType%allocate_arrays() + ! + ! -- set boundname for each connection + if (this%inamedbound /= 0) then do n = 1, this%maxbound - this%nodelist(n) = this%igwfnode(n) + this%boundname(n) = this%sfrname(n) end do - ! - ! -- check the sfr data - call this%sfr_check_reaches() + end if + ! + ! -- copy boundname into boundname_cst + call this%copy_boundname() + ! + ! -- copy igwfnode into nodelist + do n = 1, this%maxbound + this%nodelist(n) = this%igwfnode(n) + end do + ! + ! -- check the sfr data + call this%sfr_check_reaches() - ! -- check the connection data - call this%sfr_check_connections() + ! -- check the connection data + call this%sfr_check_connections() - ! -- check the diversion data - if (this%idiversions /= 0) then - call this%sfr_check_diversions() - end if - ! - ! -- terminate if errors were detected in any of the static sfr data - ierr = count_errors() - if (ierr > 0) then - call this%parser%StoreErrorUnit() - end if - ! - ! -- setup pakmvrobj - if (this%imover /= 0) then - allocate(this%pakmvrobj) - call this%pakmvrobj%ar(this%maxbound, this%maxbound, this%memoryPath) - endif - ! - ! -- return - return - end subroutine sfr_ar + ! -- check the diversion data + if (this%idiversions /= 0) then + call this%sfr_check_diversions() + end if + ! + ! -- terminate if errors were detected in any of the static sfr data + ierr = count_errors() + if (ierr > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- setup pakmvrobj + if (this%imover /= 0) then + allocate (this%pakmvrobj) + call this%pakmvrobj%ar(this%maxbound, this%maxbound, this%memoryPath) + end if + ! + ! -- return + return + end subroutine sfr_ar - !> @ brief Read packagedata for the package + !> @ brief Read packagedata for the package !! !! Method to read packagedata for each reach for the SFR package. !! - !< - subroutine sfr_read_packagedata(this) - ! -- modules - use TimeSeriesManagerModule, only: read_value_or_time_series_adv - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character(len=LINELENGTH) :: text - character(len=LINELENGTH) :: cellid - character(len=LINELENGTH) :: keyword - character (len=10) :: cnum - character(len=LENBOUNDNAME) :: bndName - character(len=LENBOUNDNAME) :: bndNameTemp - character(len=LENBOUNDNAME) :: manningname - character(len=LENBOUNDNAME) :: ustrfname - character(len=50), dimension(:), allocatable :: caux - integer(I4B) :: n, ierr, ival - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - integer(I4B) :: i - integer(I4B) :: ii - integer(I4B) :: jj - integer(I4B) :: iaux - integer(I4B) :: nconzero - integer(I4B) :: ipos - integer, allocatable, dimension(:) :: nboundchk - real(DP), pointer :: bndElem => null() - ! - ! -- allocate space for checking sfr reach data - allocate(nboundchk(this%maxbound)) - do i = 1, this%maxbound - nboundchk(i) = 0 - enddo - nconzero = 0 - ! - ! -- allocate local storage for aux variables - if (this%naux > 0) then - allocate(caux(this%naux)) - end if - ! - ! -- read reach data - call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse reaches block if detected - if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & - ' PACKAGEDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - ! -- read reach number - n = this%parser%GetInteger() + !< + subroutine sfr_read_packagedata(this) + ! -- modules + use TimeSeriesManagerModule, only: read_value_or_time_series_adv + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: text + character(len=LINELENGTH) :: cellid + character(len=LINELENGTH) :: keyword + character(len=10) :: cnum + character(len=LENBOUNDNAME) :: bndName + character(len=LENBOUNDNAME) :: bndNameTemp + character(len=LENBOUNDNAME) :: manningname + character(len=LENBOUNDNAME) :: ustrfname + character(len=50), dimension(:), allocatable :: caux + integer(I4B) :: n, ierr, ival + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + integer(I4B) :: i + integer(I4B) :: ii + integer(I4B) :: jj + integer(I4B) :: iaux + integer(I4B) :: nconzero + integer(I4B) :: ipos + integer, allocatable, dimension(:) :: nboundchk + real(DP), pointer :: bndElem => null() + ! + ! -- allocate space for checking sfr reach data + allocate (nboundchk(this%maxbound)) + do i = 1, this%maxbound + nboundchk(i) = 0 + end do + nconzero = 0 + ! + ! -- allocate local storage for aux variables + if (this%naux > 0) then + allocate (caux(this%naux)) + end if + ! + ! -- read reach data + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + supportOpenClose=.true.) + ! + ! -- parse reaches block if detected + if (isfound) then + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & + ' PACKAGEDATA' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + ! -- read reach number + n = this%parser%GetInteger() - if (n < 1 .or. n > this%maxbound) then - write(errmsg,'(a,1x,a,1x,i0)') & - 'Reach number (rno) must be greater than 0 and less', & - 'than or equal to', this%maxbound - call store_error(errmsg) - cycle - end if + if (n < 1 .or. n > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0)') & + 'Reach number (rno) must be greater than 0 and less', & + 'than or equal to', this%maxbound + call store_error(errmsg) + cycle + end if - ! -- increment nboundchk - nboundchk(n) = nboundchk(n) + 1 - ! - ! -- get model node number - call this%parser%GetCellid(this%dis%ndim, cellid, flag_string=.true.) - this%igwfnode(n) = this%dis%noder_from_cellid(cellid, & - this%inunit, this%iout, flag_string=.true.) - this%igwftopnode(n) = this%igwfnode(n) - ! - ! -- read the cellid string and determine if 'none' is specified - if (this%igwfnode(n) < 1) then - call this%parser%GetStringCaps(keyword) - this%ianynone = this%ianynone + 1 - if (keyword /= 'NONE') then - write(cnum, '(i0)') n - errmsg = 'Cell ID (' // trim(cellid) // & - ') for unconnected reach ' // trim(cnum) // & - ' must be NONE' - call store_error(errmsg) - end if - end if - ! -- get reach length - this%length(n) = this%parser%GetDouble() - ! -- get reach width - this%width(n) = this%parser%GetDouble() - ! -- get reach slope - this%slope(n) = this%parser%GetDouble() - ! -- get reach stream bottom - this%strtop(n) = this%parser%GetDouble() - ! -- get reach bed thickness - this%bthick(n) = this%parser%GetDouble() - ! -- get reach bed hk - this%hk(n) = this%parser%GetDouble() - ! -- get reach roughness - call this%parser%GetStringCaps(manningname) - ! -- get number of connections for reach - ival = this%parser%GetInteger() - this%nconnreach(n) = ival - this%nconn = this%nconn + ival - if (ival < 0) then - write(errmsg, '(a,1x,i0,1x,a,i0,a)') & - 'NCON for reach', n, & - 'must be greater than or equal to 0 (', ival, ').' + ! -- increment nboundchk + nboundchk(n) = nboundchk(n) + 1 + ! + ! -- get model node number + call this%parser%GetCellid(this%dis%ndim, cellid, flag_string=.true.) + this%igwfnode(n) = this%dis%noder_from_cellid(cellid, this%inunit, & + this%iout, & + flag_string=.true.) + this%igwftopnode(n) = this%igwfnode(n) + ! + ! -- read the cellid string and determine if 'none' is specified + if (this%igwfnode(n) < 1) then + call this%parser%GetStringCaps(keyword) + this%ianynone = this%ianynone + 1 + if (keyword /= 'NONE') then + write (cnum, '(i0)') n + errmsg = 'Cell ID ('//trim(cellid)// & + ') for unconnected reach '//trim(cnum)// & + ' must be NONE' call store_error(errmsg) - else if (ival == 0) then - nconzero = nconzero + 1 - end if - ! -- get upstream fraction for reach - call this%parser%GetString(ustrfname) - ! -- get number of diversions for reach - ival = this%parser%GetInteger() - this%ndiv(n) = ival - if (ival > 0) then - this%idiversions = 1 - else if (ival < 0) then - ival = 0 end if + end if + ! -- get reach length + this%length(n) = this%parser%GetDouble() + ! -- get reach width + this%width(n) = this%parser%GetDouble() + ! -- get reach slope + this%slope(n) = this%parser%GetDouble() + ! -- get reach stream bottom + this%strtop(n) = this%parser%GetDouble() + ! -- get reach bed thickness + this%bthick(n) = this%parser%GetDouble() + ! -- get reach bed hk + this%hk(n) = this%parser%GetDouble() + ! -- get reach roughness + call this%parser%GetStringCaps(manningname) + ! -- get number of connections for reach + ival = this%parser%GetInteger() + this%nconnreach(n) = ival + this%nconn = this%nconn + ival + if (ival < 0) then + write (errmsg, '(a,1x,i0,1x,a,i0,a)') & + 'NCON for reach', n, & + 'must be greater than or equal to 0 (', ival, ').' + call store_error(errmsg) + else if (ival == 0) then + nconzero = nconzero + 1 + end if + ! -- get upstream fraction for reach + call this%parser%GetString(ustrfname) + ! -- get number of diversions for reach + ival = this%parser%GetInteger() + this%ndiv(n) = ival + if (ival > 0) then + this%idiversions = 1 + else if (ival < 0) then + ival = 0 + end if - ! -- get aux data - do iaux = 1, this%naux - call this%parser%GetString(caux(iaux)) - end do + ! -- get aux data + do iaux = 1, this%naux + call this%parser%GetString(caux(iaux)) + end do - ! -- set default bndName - write(cnum,'(i10.10)') n - bndName = 'Reach' // cnum + ! -- set default bndName + write (cnum, '(i10.10)') n + bndName = 'Reach'//cnum - ! -- get reach name - if (this%inamedbound /= 0) then - call this%parser%GetStringCaps(bndNameTemp) - if (bndNameTemp /= '') then - bndName = bndNameTemp - endif - !this%boundname(n) = bndName + ! -- get reach name + if (this%inamedbound /= 0) then + call this%parser%GetStringCaps(bndNameTemp) + if (bndNameTemp /= '') then + bndName = bndNameTemp end if - this%sfrname(n) = bndName - ! - ! -- set Mannings - text = manningname - jj = 1 !for 'ROUGH' - bndElem => this%rough(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'MANNING') - ! - ! -- set upstream fraction - text = ustrfname - jj = 1 ! For 'USTRF' - bndElem => this%ustrf(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'USTRF') - ! - ! -- get aux data - do jj = 1, this%naux - text = caux(jj) - ii = n - bndElem => this%rauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & - this%auxname(jj)) - end do - ! - ! -- initialize sstage to the top of the reach - ! this value would be used by simple routing reaches - ! on kper = 1 and kstp = 1 if a stage is not specified - ! on the status line for the reach - this%sstage(n) = this%strtop(n) - + !this%boundname(n) = bndName + end if + this%sfrname(n) = bndName + ! + ! -- set Mannings + text = manningname + jj = 1 !for 'ROUGH' + bndElem => this%rough(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'MANNING') + ! + ! -- set upstream fraction + text = ustrfname + jj = 1 ! For 'USTRF' + bndElem => this%ustrf(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'USTRF') + ! + ! -- get aux data + do jj = 1, this%naux + text = caux(jj) + ii = n + bndElem => this%rauxvar(jj, ii) + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & + this%auxname(jj)) end do - write(this%iout,'(1x,a)') & - 'END OF '//trim(adjustl(this%text))//' PACKAGEDATA' - else - call store_error('REQUIRED PACKAGEDATA BLOCK NOT FOUND.') - end if - ! - ! -- Check to make sure that every reach is specified and that no reach - ! is specified more than once. - do i = 1, this%maxbound - if (nboundchk(i) == 0) then - write(errmsg, '(a,i0,1x,a)') & - 'Information for reach ', i, 'not specified in packagedata block.' - call store_error(errmsg) - else if (nboundchk(i) > 1) then - write(errmsg, '(a,1x,i0,1x,a,1x,i0)') & - 'Reach information specified', nboundchk(i), 'times for reach', i - call store_error(errmsg) - endif - end do - deallocate(nboundchk) - ! - ! -- Submit warning message if any reach has zero connections - if (nconzero > 0) then - write(warnmsg, '(a,1x,a,1x,a,1x,i0,1x, a)') & - 'SFR Package', trim(this%packName), & - 'has', nconzero, 'reach(es) with zero connections.' - call store_warning(warnmsg) - endif - ! - ! -- terminate if errors encountered in reach block - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - ! - ! -- initialize the cross-section data - ipos = 1 - this%iacross(1) = ipos - do i = 1, this%maxbound - this%ncrosspts(i) = 1 - this%station(ipos) = this%width(i) - this%xsheight(ipos) = DZERO - this%xsrough(ipos) = DONE - ipos = ipos + 1 - this%iacross(i+1) = ipos + ! + ! -- initialize sstage to the top of the reach + ! this value would be used by simple routing reaches + ! on kper = 1 and kstp = 1 if a stage is not specified + ! on the status line for the reach + this%sstage(n) = this%strtop(n) + end do - ! - ! -- deallocate local storage for aux variables - if (this%naux > 0) then - deallocate(caux) + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' PACKAGEDATA' + else + call store_error('REQUIRED PACKAGEDATA BLOCK NOT FOUND.') + end if + ! + ! -- Check to make sure that every reach is specified and that no reach + ! is specified more than once. + do i = 1, this%maxbound + if (nboundchk(i) == 0) then + write (errmsg, '(a,i0,1x,a)') & + 'Information for reach ', i, 'not specified in packagedata block.' + call store_error(errmsg) + else if (nboundchk(i) > 1) then + write (errmsg, '(a,1x,i0,1x,a,1x,i0)') & + 'Reach information specified', nboundchk(i), 'times for reach', i + call store_error(errmsg) end if - ! - ! -- return - return - end subroutine sfr_read_packagedata - - !> @ brief Read crosssection block for the package + end do + deallocate (nboundchk) + ! + ! -- Submit warning message if any reach has zero connections + if (nconzero > 0) then + write (warnmsg, '(a,1x,a,1x,a,1x,i0,1x, a)') & + 'SFR Package', trim(this%packName), & + 'has', nconzero, 'reach(es) with zero connections.' + call store_warning(warnmsg) + end if + ! + ! -- terminate if errors encountered in reach block + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- initialize the cross-section data + ipos = 1 + this%iacross(1) = ipos + do i = 1, this%maxbound + this%ncrosspts(i) = 1 + this%station(ipos) = this%width(i) + this%xsheight(ipos) = DZERO + this%xsrough(ipos) = DONE + ipos = ipos + 1 + this%iacross(i + 1) = ipos + end do + ! + ! -- deallocate local storage for aux variables + if (this%naux > 0) then + deallocate (caux) + end if + ! + ! -- return + return + end subroutine sfr_read_packagedata + + !> @ brief Read crosssection block for the package !! !! Method to read crosssection data for the SFR package. !! - !< - subroutine sfr_read_crossection(this) - ! -- modules - use MemoryManagerModule, only: mem_reallocate - use sfrCrossSectionManager, only: cross_section_cr, SfrCrossSection - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character(len=LINELENGTH) :: keyword - character(len=LINELENGTH) :: line - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - integer(I4B) :: n - integer(I4B) :: ierr - integer(I4B) :: ncrossptstot - integer, allocatable, dimension(:) :: nboundchk - type(SfrCrossSection), pointer :: cross_data => null() - ! - ! -- read cross-section data - call this%parser%GetBlock('CROSSSECTIONS', isfound, ierr, & - supportOpenClose=.true., & - blockRequired=.false.) + !< + subroutine sfr_read_crossection(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + use sfrCrossSectionManager, only: cross_section_cr, SfrCrossSection + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: keyword + character(len=LINELENGTH) :: line + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + integer(I4B) :: n + integer(I4B) :: ierr + integer(I4B) :: ncrossptstot + integer, allocatable, dimension(:) :: nboundchk + type(SfrCrossSection), pointer :: cross_data => null() + ! + ! -- read cross-section data + call this%parser%GetBlock('CROSSSECTIONS', isfound, ierr, & + supportOpenClose=.true., & + blockRequired=.false.) + ! + ! -- parse reach connectivity block if detected + if (isfound) then + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' CROSSSECTIONS' ! - ! -- parse reach connectivity block if detected - if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' CROSSSECTIONS' + ! -- allocate and initialize local variables for reach cross-sections + allocate (nboundchk(this%maxbound)) + do n = 1, this%maxbound + nboundchk(n) = 0 + end do + ! + ! -- create and initialize cross-section data + call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound) + call cross_data%initialize(this%ncrossptstot, this%ncrosspts, & + this%iacross, & + this%station, this%xsheight, & + this%xsrough) + ! + ! -- read all of the entries in the block + readtable: do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit ! - ! -- allocate and initialize local variables for reach cross-sections - allocate(nboundchk(this%maxbound)) - do n = 1, this%maxbound - nboundchk(n) = 0 - end do + ! -- get reach number + n = this%parser%GetInteger() ! - ! -- create and initialize cross-section data - call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound) - call cross_data%initialize(this%ncrossptstot, this%ncrosspts, & - this%iacross, & - this%station, this%xsheight, & - this%xsrough) + ! -- check for reach number error + if (n < 1 .or. n > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0)') & + 'SFR reach in crosssections block is less than one or greater', & + 'than NREACHES:', n + call store_error(errmsg) + cycle readtable + end if ! - ! -- read all of the entries in the block - readtable: do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - ! - ! -- get reach number - n = this%parser%GetInteger() - ! - ! -- check for reach number error - if (n < 1 .or. n > this%maxbound) then - write(errmsg, '(a,1x,a,1x,i0)') & - 'SFR reach in crosssections block is less than one or greater', & - 'than NREACHES:', n - call store_error(errmsg) - cycle readtable - endif - ! - ! -- increment nboundchk - nboundchk(n) = nboundchk(n) + 1 - ! - ! -- read FILE keyword - call this%parser%GetStringCaps(keyword) - select case (keyword) - case('TAB6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TAB6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - cycle readtable - end if - call this%parser%GetString(line) - call cross_data%read_table(n, this%width(n), & - trim(adjustl(line))) - case default - write(errmsg,'(a,1x,i4,1x,a)') & - 'CROSS-SECTION TABLE ENTRY for REACH ', n, & - 'MUST INCLUDE TAB6 KEYWORD' - call store_error(errmsg) - cycle readtable - end select - end do readtable - - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' CROSSSECTIONS' - + ! -- increment nboundchk + nboundchk(n) = nboundchk(n) + 1 ! - ! -- check for duplicate sfr crosssections - do n = 1, this%maxbound - if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & - 'Cross-section data for reach', n, & - 'specified', nboundchk(n), 'times.' + ! -- read FILE keyword + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('TAB6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TAB6 keyword must be followed by "FILEIN" '// & + 'then by filename.' call store_error(errmsg) + cycle readtable end if - end do - ! - ! -- terminate if errors encountered in cross-sections block - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + call this%parser%GetString(line) + call cross_data%read_table(n, this%width(n), & + trim(adjustl(line))) + case default + write (errmsg, '(a,1x,i4,1x,a)') & + 'CROSS-SECTION TABLE ENTRY for REACH ', n, & + 'MUST INCLUDE TAB6 KEYWORD' + call store_error(errmsg) + cycle readtable + end select + end do readtable + + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' CROSSSECTIONS' + + ! + ! -- check for duplicate sfr crosssections + do n = 1, this%maxbound + if (nboundchk(n) > 1) then + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & + 'Cross-section data for reach', n, & + 'specified', nboundchk(n), 'times.' + call store_error(errmsg) end if + end do + ! + ! -- terminate if errors encountered in cross-sections block + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- determine the current size of cross-section data + ncrossptstot = cross_data%get_ncrossptstot() + ! + ! -- reallocate sfr package cross-section data + if (ncrossptstot /= this%ncrossptstot) then + this%ncrossptstot = ncrossptstot + call mem_reallocate(this%station, this%ncrossptstot, 'STATION', & + this%memoryPath) + call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', & + this%memoryPath) + call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', & + this%memoryPath) + end if + ! + ! -- write cross-section data to the model listing file + call cross_data%output(this%width, this%rough) + ! + ! -- pack cross-section data + call cross_data%pack(this%ncrossptstot, this%ncrosspts, & + this%iacross, & + this%station, & + this%xsheight, & + this%xsrough) + ! + ! -- deallocate temporary local storage for reach cross-sections + deallocate (nboundchk) + call cross_data%destroy() + deallocate (cross_data) + nullify (cross_data) + end if + ! + ! -- return + return + end subroutine sfr_read_crossection + + !> @ brief Read connectiondata for the package + !! + !! Method to read connectiondata for each reach for the SFR package. + !! + !< + subroutine sfr_read_connectiondata(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + use SparseModule, only: sparsematrix + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: line + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + integer(I4B) :: n + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: jj + integer(I4B) :: jcol + integer(I4B) :: jcol2 + integer(I4B) :: nja + integer(I4B) :: ival + integer(I4B) :: idir + integer(I4B) :: ierr + integer(I4B) :: nconnmax + integer(I4B) :: nup + integer(I4B) :: ipos + integer(I4B) :: istat + integer(I4B), dimension(:), pointer, contiguous :: rowmaxnnz => null() + integer, allocatable, dimension(:) :: nboundchk + integer, allocatable, dimension(:, :) :: iconndata + type(sparsematrix), pointer :: sparse => null() + integer(I4B), dimension(:), allocatable :: iup + integer(I4B), dimension(:), allocatable :: order + type(dag) :: sfr_dag + ! + ! -- allocate and initialize local variables for reach connections + allocate (nboundchk(this%maxbound)) + do n = 1, this%maxbound + nboundchk(n) = 0 + end do + ! + ! -- calculate the number of non-zero entries (size of ja maxtrix) + nja = 0 + nconnmax = 0 + allocate (rowmaxnnz(this%maxbound)) + do n = 1, this%maxbound + ival = this%nconnreach(n) + if (ival < 0) ival = 0 + rowmaxnnz(n) = ival + 1 + nja = nja + ival + 1 + if (ival > nconnmax) then + nconnmax = ival + end if + end do + ! + ! -- reallocate connection data for package + call mem_reallocate(this%ja, nja, 'JA', this%memoryPath) + call mem_reallocate(this%idir, nja, 'IDIR', this%memoryPath) + call mem_reallocate(this%idiv, nja, 'IDIV', this%memoryPath) + call mem_reallocate(this%qconn, nja, 'QCONN', this%memoryPath) + ! + ! -- initialize connection data + do n = 1, nja + this%idir(n) = 0 + this%idiv(n) = 0 + this%qconn(n) = DZERO + end do + ! + ! -- allocate space for iconndata + allocate (iconndata(nconnmax, this%maxbound)) + ! + ! -- initialize iconndata + do n = 1, this%maxbound + do j = 1, nconnmax + iconndata(j, n) = 0 + end do + end do + ! + ! -- allocate space for connectivity + allocate (sparse) + ! + ! -- set up sparse + call sparse%init(this%maxbound, this%maxbound, rowmaxnnz) + ! + ! -- read connection data + call this%parser%GetBlock('CONNECTIONDATA', isfound, ierr, & + supportOpenClose=.true.) + ! + ! -- parse reach connectivity block if detected + if (isfound) then + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' CONNECTIONDATA' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit ! - ! -- determine the current size of cross-section data - ncrossptstot = cross_data%get_ncrossptstot() + ! -- get reach number + n = this%parser%GetInteger() ! - ! -- reallocate sfr package cross-section data - if (ncrossptstot /= this%ncrossptstot) then - this%ncrossptstot = ncrossptstot - call mem_reallocate(this%station, this%ncrossptstot, 'STATION', this%memoryPath) - call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', this%memoryPath) - call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', this%memoryPath) + ! -- check for error + if (n < 1 .or. n > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0)') & + 'SFR reach in connectiondata block is less than one or greater', & + 'than NREACHES:', n + call store_error(errmsg) + cycle end if ! - ! -- write cross-section data to the model listing file - call cross_data%output(this%width, this%rough) + ! -- increment nboundchk + nboundchk(n) = nboundchk(n) + 1 ! - ! -- pack cross-section data - call cross_data%pack(this%ncrossptstot, this%ncrosspts, & - this%iacross, & - this%station, & - this%xsheight, & - this%xsrough) + ! -- add diagonal connection for reach + call sparse%addconnection(n, n, 1) ! - ! -- deallocate temporary local storage for reach cross-sections - deallocate(nboundchk) - call cross_data%destroy() - deallocate(cross_data) - nullify(cross_data) - end if - ! - ! -- return - return - end subroutine sfr_read_crossection + ! -- fill off diagonals + do i = 1, this%nconnreach(n) + ! + ! -- get connected reach + ival = this%parser%GetInteger() + ! + ! -- save connection data to temporary iconndata + iconndata(i, n) = ival + ! + ! -- determine idir + if (ival < 0) then + idir = -1 + ival = abs(ival) + elseif (ival == 0) then + call store_error('Missing or zero connection reach in line:') + call store_error(line) + else + idir = 1 + end if + if (ival > this%maxbound) then + call store_error('Reach number exceeds NREACHES in line:') + call store_error(line) + end if + ! + ! -- add connection to sparse + call sparse%addconnection(n, ival, 1) + end do + end do + + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' CONNECTIONDATA' - !> @ brief Read connectiondata for the package - !! - !! Method to read connectiondata for each reach for the SFR package. - !! - !< - subroutine sfr_read_connectiondata(this) - ! -- modules - use MemoryManagerModule, only: mem_reallocate - use SparseModule, only: sparsematrix - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character (len=LINELENGTH) :: line - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - integer(I4B) :: n - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: jj - integer(I4B) :: jcol - integer(I4B) :: jcol2 - integer(I4B) :: nja - integer(I4B) :: ival - integer(I4B) :: idir - integer(I4B) :: ierr - integer(I4B) :: nconnmax - integer(I4B) :: nup - integer(I4B) :: ipos - integer(I4B) :: istat - integer(I4B), dimension(:), pointer, contiguous :: rowmaxnnz => null() - integer, allocatable, dimension(:) :: nboundchk - integer, allocatable, dimension(:,:) :: iconndata - type(sparsematrix), pointer :: sparse => null() - integer(I4B), dimension(:), allocatable :: iup - integer(I4B), dimension(:), allocatable :: order - type(dag) :: sfr_dag - ! - ! -- allocate and initialize local variables for reach connections - allocate(nboundchk(this%maxbound)) do n = 1, this%maxbound - nboundchk(n) = 0 + ! + ! -- check for missing or duplicate sfr connections + if (nboundchk(n) == 0) then + write (errmsg, '(a,1x,i0)') & + 'No connection data specified for reach', n + call store_error(errmsg) + else if (nboundchk(n) > 1) then + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & + 'Connection data for reach', n, & + 'specified', nboundchk(n), 'times.' + call store_error(errmsg) + end if end do - ! - ! -- calculate the number of non-zero entries (size of ja maxtrix) - nja = 0 - nconnmax = 0 - allocate(rowmaxnnz(this%maxbound)) - do n = 1, this%maxbound - ival = this%nconnreach(n) - if (ival < 0) ival = 0 - rowmaxnnz(n) = ival + 1 - nja = nja + ival + 1 - if (ival > nconnmax) then - nconnmax = ival + else + call store_error('Required connectiondata block not found.') + end if + ! + ! -- terminate if errors encountered in connectiondata block + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- create ia and ja from sparse + call sparse%filliaja(this%ia, this%ja, ierr, sort=.TRUE.) + ! + ! -- test for error condition + if (ierr /= 0) then + write (errmsg, '(a,3(1x,a))') & + 'Could not fill', trim(this%packName), & + 'package IA and JA connection data.', & + 'Check connectivity data in connectiondata block.' + call store_error(errmsg) + end if + ! + ! -- fill flat connection storage + do n = 1, this%maxbound + do j = this%ia(n) + 1, this%ia(n + 1) - 1 + jcol = this%ja(j) + do jj = 1, this%nconnreach(n) + jcol2 = iconndata(jj, n) + if (abs(jcol2) == jcol) then + idir = 1 + if (jcol2 < 0) then + idir = -1 + end if + this%idir(j) = idir + exit + end if + end do + end do + end do + ! + ! -- deallocate temporary local storage for reach connections + deallocate (rowmaxnnz) + deallocate (nboundchk) + deallocate (iconndata) + ! + ! -- destroy sparse + call sparse%destroy() + deallocate (sparse) + ! + ! -- calculate reach order using DAG + ! + ! -- initialize the DAG + call sfr_dag%set_vertices(this%maxbound) + ! + ! -- fill DAG + fill_dag: do n = 1, this%maxbound + ! + ! -- determine the number of upstream reaches + nup = 0 + do j = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(j) > 0) then + nup = nup + 1 end if end do ! - ! -- reallocate connection data for package - call mem_reallocate(this%ja, nja, 'JA', this%memoryPath) - call mem_reallocate(this%idir, nja, 'IDIR', this%memoryPath) - call mem_reallocate(this%idiv, nja, 'IDIV', this%memoryPath) - call mem_reallocate(this%qconn, nja, 'QCONN', this%memoryPath) - ! - ! -- initialize connection data - do n = 1, nja - this%idir(n) = 0 - this%idiv(n) = 0 - this%qconn(n) = DZERO - end do + ! -- cycle if nu upstream reacches + if (nup == 0) cycle fill_dag ! - ! -- allocate space for iconndata - allocate(iconndata(nconnmax, this%maxbound)) + ! -- allocate local storage + allocate (iup(nup)) ! - ! -- initialize iconndata - do n = 1, this%maxbound - do j = 1, nconnmax - iconndata(j, n) = 0 - end do + ! -- fill local storage + ipos = 1 + do j = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(j) > 0) then + iup(ipos) = this%ja(j) + ipos = ipos + 1 + end if end do ! - ! -- allocate space for connectivity - allocate(sparse) + ! -- add upstream connections to DAG + call sfr_dag%set_edges(n, iup) ! - ! -- set up sparse - call sparse%init(this%maxbound, this%maxbound, rowmaxnnz) - ! - ! -- read connection data - call this%parser%GetBlock('CONNECTIONDATA', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse reach connectivity block if detected - if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' CONNECTIONDATA' + ! -- clean up local storage + deallocate (iup) + end do fill_dag + ! + ! -- perform toposort on DAG + call sfr_dag%toposort(order, istat) + ! + ! -- write warning if circular dependency + if (istat == -1) then + write (warnmsg, '(a)') & + trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') cannot calculate a '// & + 'Directed Asyclic Graph for reach connectivity because '// & + 'of circular dependency. Using the reach number for '// & + 'solution ordering.' + call store_warning(warnmsg) + end if + ! + ! -- fill isfrorder + do n = 1, this%maxbound + if (istat == 0) then + this%isfrorder(n) = order(n) + else + this%isfrorder(n) = n + end if + end do + ! + ! -- clean up DAG and remaining local storage + call sfr_dag%destroy() + if (istat == 0) then + deallocate (order) + end if + ! + ! -- return + return + end subroutine sfr_read_connectiondata + + !> @ brief Read diversions for the package + !! + !! Method to read diversions for the SFR package. + !! + !< + subroutine sfr_read_diversions(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=10) :: cnum + character(len=10) :: cval + integer(I4B) :: j + integer(I4B) :: n + integer(I4B) :: ierr + integer(I4B) :: ival + integer(I4B) :: i0 + integer(I4B) :: ipos + integer(I4B) :: jpos + integer(I4B) :: ndiv + integer(I4B) :: ndiversions + integer(I4B) :: idivreach + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + integer(I4B) :: idiv + integer, allocatable, dimension(:) :: iachk + integer, allocatable, dimension(:) :: nboundchk + ! + ! -- determine the total number of diversions and fill iadiv + ndiversions = 0 + i0 = 1 + this%iadiv(1) = i0 + do n = 1, this%maxbound + ndiversions = ndiversions + this%ndiv(n) + i0 = i0 + this%ndiv(n) + this%iadiv(n + 1) = i0 + end do + ! + ! -- reallocate memory for diversions + if (ndiversions > 0) then + call mem_reallocate(this%divreach, ndiversions, 'DIVREACH', & + this%memoryPath) + allocate (this%divcprior(ndiversions)) + call mem_reallocate(this%divflow, ndiversions, 'DIVFLOW', this%memoryPath) + call mem_reallocate(this%divq, ndiversions, 'DIVQ', this%memoryPath) + end if + ! + ! -- inititialize diversion flow + do n = 1, ndiversions + this%divflow(n) = DZERO + this%divq(n) = DZERO + end do + ! + ! -- read diversions + call this%parser%GetBlock('DIVERSIONS', isfound, ierr, & + supportOpenClose=.true., & + blockRequired=.false.) + ! + ! -- parse reach connectivity block if detected + if (isfound) then + if (this%idiversions /= 0) then + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & + ' DIVERSIONS' + ! + ! -- allocate and initialize local variables for diversions + ndiv = 0 + do n = 1, this%maxbound + ndiv = ndiv + this%ndiv(n) + end do + allocate (iachk(this%maxbound + 1)) + allocate (nboundchk(ndiv)) + iachk(1) = 1 + do n = 1, this%maxbound + iachk(n + 1) = iachk(n) + this%ndiv(n) + end do + do n = 1, ndiv + nboundchk(n) = 0 + end do + ! + ! -- read diversion data do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit ! ! -- get reach number n = this%parser%GetInteger() - ! - ! -- check for error if (n < 1 .or. n > this%maxbound) then - write(errmsg, '(a,1x,a,1x,i0)') & - 'SFR reach in connectiondata block is less than one or greater', & - 'than NREACHES:', n + write (cnum, '(i0)') n + errmsg = 'Reach number should be between 1 and '// & + trim(cnum)//'.' call store_error(errmsg) cycle - endif - ! - ! -- increment nboundchk - nboundchk(n) = nboundchk(n) + 1 - ! - ! -- add diagonal connection for reach - call sparse%addconnection(n, n, 1) - ! - ! -- fill off diagonals - do i = 1, this%nconnreach(n) - ! - ! -- get connected reach - ival = this%parser%GetInteger() - ! - ! -- save connection data to temporary iconndata - iconndata(i, n) = ival - ! - ! -- determine idir - if (ival < 0) then - idir = -1 - ival = abs(ival) - elseif (ival == 0) then - call store_error('Missing or zero connection reach in line:') - call store_error(line) - else - idir = 1 - end if - if (ival > this%maxbound) then - call store_error('Reach number exceeds NREACHES in line:') - call store_error(line) - endif - ! - ! -- add connection to sparse - call sparse%addconnection(n, ival, 1) - end do - end do - - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' CONNECTIONDATA' - - do n = 1, this%maxbound + end if ! - ! -- check for missing or duplicate sfr connections - if (nboundchk(n) == 0) then - write(errmsg,'(a,1x,i0)') & - 'No connection data specified for reach', n - call store_error(errmsg) - else if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & - 'Connection data for reach', n, & - 'specified', nboundchk(n), 'times.' + ! -- make sure reach has at least one diversion + if (this%ndiv(n) < 1) then + write (cnum, '(i0)') n + errmsg = 'Diversions cannot be specified '// & + 'for reach '//trim(cnum) call store_error(errmsg) + cycle end if - end do - else - call store_error('Required connectiondata block not found.') - end if - ! - ! -- terminate if errors encountered in connectiondata block - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - ! - ! -- create ia and ja from sparse - call sparse%filliaja(this%ia, this%ja, ierr, sort=.TRUE.) - ! - ! -- test for error condition - if (ierr /= 0) then - write(errmsg, '(a,3(1x,a))') & - 'Could not fill', trim(this%packName), & - 'package IA and JA connection data.', & - 'Check connectivity data in connectiondata block.' - call store_error(errmsg) - end if - ! - ! -- fill flat connection storage - do n = 1, this%maxbound - do j = this%ia(n) + 1, this%ia(n+1) - 1 - jcol = this%ja(j) - do jj = 1, this%nconnreach(n) - jcol2 = iconndata(jj, n) - if (abs(jcol2) == jcol) then - idir = 1 - if (jcol2 < 0) then - idir = -1 - end if - this%idir(j) = idir - exit - end if - end do - end do - end do - ! - ! -- deallocate temporary local storage for reach connections - deallocate(rowmaxnnz) - deallocate(nboundchk) - deallocate(iconndata) - ! - ! -- destroy sparse - call sparse%destroy() - deallocate(sparse) - ! - ! -- calculate reach order using DAG - ! - ! -- initialize the DAG - call sfr_dag%set_vertices(this%maxbound) - ! - ! -- fill DAG - fill_dag: do n = 1, this%maxbound - ! - ! -- determine the number of upstream reaches - nup = 0 - do j = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(j) > 0) then - nup = nup + 1 - end if - end do - ! - ! -- cycle if nu upstream reacches - if (nup == 0) cycle fill_dag - ! - ! -- allocate local storage - allocate(iup(nup)) - ! - ! -- fill local storage - ipos = 1 - do j = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(j) > 0) then - iup(ipos) = this%ja(j) - ipos = ipos + 1 + ! + ! -- read diversion number + ival = this%parser%GetInteger() + if (ival < 1 .or. ival > this%ndiv(n)) then + write (cnum, '(i0)') n + errmsg = 'Reach '//trim(cnum) + write (cnum, '(i0)') this%ndiv(n) + errmsg = trim(errmsg)//' diversion number should be between '// & + '1 and '//trim(cnum)//'.' + call store_error(errmsg) + cycle end if - end do - ! - ! -- add upstream connections to DAG - call sfr_dag%set_edges(n, iup) - ! - ! -- clean up local storage - deallocate(iup) - end do fill_dag - ! - ! -- perform toposort on DAG - call sfr_dag%toposort(order, istat) - ! - ! -- write warning if circular dependency - if (istat == -1) then - write(warnmsg,'(a)') & - trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) // ') cannot calculate a ' // & - 'Directed Asyclic Graph for reach connectivity because ' // & - 'of circular dependency. Using the reach number for ' // & - 'solution ordering.' - call store_warning(warnmsg) - end if - ! - ! -- fill isfrorder - do n = 1, this%maxbound - if (istat == 0) then - this%isfrorder(n) = order(n) - else - this%isfrorder(n) = n - end if - end do - ! - ! -- clean up DAG and remaining local storage - call sfr_dag%destroy() - if (istat == 0) then - deallocate(order) - end if - ! - ! -- return - return - end subroutine sfr_read_connectiondata + ! -- increment nboundchk + ipos = iachk(n) + ival - 1 + nboundchk(ipos) = nboundchk(ipos) + 1 - !> @ brief Read diversions for the package - !! - !! Method to read diversions for the SFR package. - !! - !< - subroutine sfr_read_diversions(this) - ! -- modules - use MemoryManagerModule, only: mem_reallocate - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character (len=10) :: cnum - character (len=10) :: cval - integer(I4B) :: j - integer(I4B) :: n - integer(I4B) :: ierr - integer(I4B) :: ival - integer(I4B) :: i0 - integer(I4B) :: ipos - integer(I4B) :: jpos - integer(I4B) :: ndiv - integer(I4B) :: ndiversions - integer(I4B) :: idivreach - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - integer(I4B) :: idiv - integer, allocatable, dimension(:) :: iachk - integer, allocatable, dimension(:) :: nboundchk - ! - ! -- determine the total number of diversions and fill iadiv - ndiversions = 0 - i0 = 1 - this%iadiv(1) = i0 - do n = 1, this%maxbound - ndiversions = ndiversions + this%ndiv(n) - i0 = i0 + this%ndiv(n) - this%iadiv(n+1) = i0 - end do - ! - ! -- reallocate memory for diversions - if (ndiversions > 0) then - call mem_reallocate(this%divreach, ndiversions, 'DIVREACH', this%memoryPath) - allocate(this%divcprior(ndiversions)) - call mem_reallocate(this%divflow, ndiversions, 'DIVFLOW', this%memoryPath) - call mem_reallocate(this%divq, ndiversions, 'DIVQ', this%memoryPath) - end if - ! - ! -- inititialize diversion flow - do n = 1, ndiversions - this%divflow(n) = DZERO - this%divq(n) = DZERO - end do - ! - ! -- read diversions - call this%parser%GetBlock('DIVERSIONS', isfound, ierr, & - supportOpenClose=.true., & - blockRequired=.false.) - ! - ! -- parse reach connectivity block if detected - if (isfound) then - if (this%idiversions /= 0) then - write(this%iout,'(/1x,a)') 'PROCESSING ' // trim(adjustl(this%text)) // & - ' DIVERSIONS' + idiv = ival ! - ! -- allocate and initialize local variables for diversions - ndiv = 0 - do n = 1, this%maxbound - ndiv = ndiv + this%ndiv(n) - end do - allocate(iachk(this%maxbound+1)) - allocate(nboundchk(ndiv)) - iachk(1) = 1 - do n = 1, this%maxbound - iachk(n+1) = iachk(n) + this%ndiv(n) - end do - do n = 1, ndiv - nboundchk(n) = 0 - end do + ! -- get target reach for diversion + ival = this%parser%GetInteger() + if (ival < 1 .or. ival > this%maxbound) then + write (cnum, '(i0)') ival + errmsg = 'Diversion target reach number should be '// & + 'between 1 and '//trim(cnum)//'.' + call store_error(errmsg) + cycle + end if + idivreach = ival + jpos = this%iadiv(n) + idiv - 1 + this%divreach(jpos) = idivreach ! - ! -- read diversion data - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - ! - ! -- get reach number - n = this%parser%GetInteger() - if (n < 1 .or. n > this%maxbound) then - write(cnum, '(i0)') n - errmsg = 'Reach number should be between 1 and ' // & - trim(cnum) // '.' - call store_error(errmsg) - cycle - end if - ! - ! -- make sure reach has at least one diversion - if (this%ndiv(n) < 1) then - write(cnum, '(i0)') n - errmsg = 'Diversions cannot be specified ' // & - 'for reach ' // trim(cnum) - call store_error(errmsg) - cycle - end if + ! -- get cprior + call this%parser%GetStringCaps(cval) + ival = -1 + select case (cval) + case ('UPTO') + ival = 0 + case ('THRESHOLD') + ival = -1 + case ('FRACTION') + ival = -2 + case ('EXCESS') + ival = -3 + case default + errmsg = 'Invalid cprior type '//trim(cval)//'.' + call store_error(errmsg) + end select + ! + ! -- set cprior for diversion + this%divcprior(jpos) = cval + end do + + write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(this%text))// & + ' DIVERSIONS' + + do n = 1, this%maxbound + do j = 1, this%ndiv(n) + ipos = iachk(n) + j - 1 ! - ! -- read diversion number - ival = this%parser%GetInteger() - if (ival < 1 .or. ival > this%ndiv(n)) then - write(cnum, '(i0)') n - errmsg = 'Reach ' // trim(cnum) - write(cnum, '(i0)') this%ndiv(n) - errmsg = trim(errmsg) // ' diversion number should be between ' // & - '1 and ' // trim(cnum) // '.' + ! -- check for missing or duplicate reach diversions + if (nboundchk(ipos) == 0) then + write (errmsg, '(a,1x,i0,1x,a,1x,i0)') & + 'No data specified for reach', n, 'diversion', j call store_error(errmsg) - cycle - end if - - ! -- increment nboundchk - ipos = iachk(n) + ival - 1 - nboundchk(ipos) = nboundchk(ipos) + 1 - - idiv = ival - ! - ! -- get target reach for diversion - ival = this%parser%GetInteger() - if (ival < 1 .or. ival > this%maxbound) then - write(cnum, '(i0)') ival - errmsg = 'Diversion target reach number should be ' // & - 'between 1 and ' // trim(cnum) // '.' + else if (nboundchk(ipos) > 1) then + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & + 'Data for reach', n, 'diversion', j, & + 'specified', nboundchk(ipos), 'times' call store_error(errmsg) - cycle end if - idivreach = ival - jpos = this%iadiv(n) + idiv - 1 - this%divreach(jpos) = idivreach - ! - ! -- get cprior - call this%parser%GetStringCaps(cval) - ival = -1 - select case (cval) - case('UPTO') - ival = 0 - case('THRESHOLD') - ival = -1 - case('FRACTION') - ival = -2 - case('EXCESS') - ival = -3 - case default - errmsg = 'Invalid cprior type ' // trim(cval) // '.' - call store_error(errmsg) - end select - ! - ! -- set cprior for diversion - this%divcprior(jpos) = cval - end do - - write(this%iout,'(1x,a)') 'END OF ' // trim(adjustl(this%text)) // & - ' DIVERSIONS' - - do n = 1, this%maxbound - do j = 1, this%ndiv(n) - ipos = iachk(n) + j - 1 - ! - ! -- check for missing or duplicate reach diversions - if (nboundchk(ipos) == 0) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0)') & - 'No data specified for reach', n, 'diversion', j - call store_error(errmsg) - else if (nboundchk(ipos) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'Data for reach', n, 'diversion', j, & - 'specified', nboundchk(ipos), 'times' - call store_error(errmsg) - end if - end do end do - ! - ! -- deallocate local variables - deallocate(iachk) - deallocate(nboundchk) - else - ! - ! -- error condition - write(errmsg,'(a,1x,a)') & - 'A diversions block should not be', & - 'specified if diversions are not specified.' - call store_error(errmsg) - end if + end do + ! + ! -- deallocate local variables + deallocate (iachk) + deallocate (nboundchk) else - if (this%idiversions /= 0) then - call store_error('REQUIRED DIVERSIONS BLOCK NOT FOUND.') - end if + ! + ! -- error condition + write (errmsg, '(a,1x,a)') & + 'A diversions block should not be', & + 'specified if diversions are not specified.' + call store_error(errmsg) end if - ! - ! -- write summary of diversion error messages - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + else + if (this%idiversions /= 0) then + call store_error('REQUIRED DIVERSIONS BLOCK NOT FOUND.') end if - ! - ! -- return - return - end subroutine sfr_read_diversions - + end if + ! + ! -- write summary of diversion error messages + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine sfr_read_diversions - !> @ brief Read and prepare period data for package + !> @ brief Read and prepare period data for package !! !! Method to read and prepare period data for the SFR package. !! - !< - subroutine sfr_rp(this) - ! -- modules - use TdisModule, only: kper, nper - use MemoryManagerModule, only: mem_reallocate - use sfrCrossSectionManager, only: cross_section_cr, SfrCrossSection - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - character(len=LINELENGTH) :: title - character(len=LINELENGTH) :: line - character(len=LINELENGTH) :: crossfile - integer(I4B) :: ierr - integer(I4B) :: n - integer(I4B) :: ichkustrm - integer(I4B) :: ichkcross - integer(I4B) :: ncrossptstot - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - type(SfrCrossSection), pointer :: cross_data => null() - ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - & "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" - character(len=*), parameter :: fmtnbd = & - "(1X,/1X,'The number of active ',A,'S (',I6, & - & ') is greater than maximum (',I6,')')" - ! - ! -- initialize flags - ichkustrm = 0 - ichkcross = 0 - if (kper == 1) then - ichkustrm = 1 - end if - ! - ! -- set nbound to maxbound - this%nbound = this%maxbound + !< + subroutine sfr_rp(this) + ! -- modules + use TdisModule, only: kper, nper + use MemoryManagerModule, only: mem_reallocate + use sfrCrossSectionManager, only: cross_section_cr, SfrCrossSection + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: line + character(len=LINELENGTH) :: crossfile + integer(I4B) :: ierr + integer(I4B) :: n + integer(I4B) :: ichkustrm + integer(I4B) :: ichkcross + integer(I4B) :: ncrossptstot + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + type(SfrCrossSection), pointer :: cross_data => null() + ! -- formats + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtnbd = & + "(1X,/1X,'The number of active ',A,'S (',I6, & + &') is greater than maximum (',I6,')')" + ! + ! -- initialize flags + ichkustrm = 0 + ichkcross = 0 + if (kper == 1) then + ichkustrm = 1 + end if + ! + ! -- set nbound to maxbound + this%nbound = this%maxbound + ! + ! -- Set ionper to the stress period number for which a new block of data + ! will be read. + if (this%ionper < kper) then ! - ! -- Set ionper to the stress period number for which a new block of data - ! will be read. - if (this%ionper < kper) then + ! -- get period block + call this%parser%GetBlock('PERIOD', isfound, ierr, & + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! - ! -- get period block - call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then - ! - ! -- read ionper and check for increasing period numbers - call this%read_check_ionper() + ! -- read ionper and check for increasing period numbers + call this%read_check_ionper() + else + ! + ! -- PERIOD block not found + if (ierr < 0) then + ! -- End of file found; data applies for remainder of simulation. + this%ionper = nper + 1 else - ! - ! -- PERIOD block not found - if (ierr < 0) then - ! -- End of file found; data applies for remainder of simulation. - this%ionper = nper + 1 - else - ! -- Found invalid block - call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end if - endif + ! -- Found invalid block + call this%parser%GetCurrentLine(line) + write (errmsg, fmtblkerr) adjustl(trim(line)) + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end if end if + end if + ! + ! -- Read data if ionper == kper + if (this%ionper == kper) then ! - ! -- Read data if ionper == kper - if(this%ionper==kper) then - ! - ! -- create and initialize cross-section data - call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound) - call cross_data%initialize(this%ncrossptstot, this%ncrosspts, & - this%iacross, & - this%station, this%xsheight, & - this%xsrough) - ! - ! -- setup table for period data - if (this%iprpak /= 0) then - ! - ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(1, 4, this%iout, finalize=.FALSE.) - text = 'NUMBER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'KEYWORD' - call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) - do n = 1, 2 - write(text, '(a,1x,i6)') 'VALUE', n - call this%inputtab%initialize_column(text, 15, alignment=TABCENTER) - end do - end if + ! -- create and initialize cross-section data + call cross_section_cr(cross_data, this%iout, this%iprpak, this%maxbound) + call cross_data%initialize(this%ncrossptstot, this%ncrosspts, & + this%iacross, & + this%station, this%xsheight, & + this%xsrough) + ! + ! -- setup table for period data + if (this%iprpak /= 0) then ! - ! -- read data - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - n = this%parser%GetInteger() - if (n < 1 .or. n > this%maxbound) then - write(errmsg,'(a,1x,a,1x,i0,a)') & - 'Reach number (RNO) must be greater than 0 and', & - 'less than or equal to', this%maxbound, '.' - call store_error(errmsg) - cycle - end if - ! - ! -- read data from the rest of the line - call this%sfr_set_stressperiod(n, ichkustrm, crossfile) - ! - ! -- write line to table - if (this%iprpak /= 0) then - call this%parser%GetCurrentLine(line) - call this%inputtab%line_to_columns(line) - end if - ! - ! -- process cross-section file - if (trim(adjustl(crossfile)) /= 'NONE') then - call cross_data%read_table(n, this%width(n), & - trim(adjustl(crossfile))) - end if + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(1, 4, this%iout, finalize=.FALSE.) + text = 'NUMBER' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'KEYWORD' + call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) + do n = 1, 2 + write (text, '(a,1x,i6)') 'VALUE', n + call this%inputtab%initialize_column(text, 15, alignment=TABCENTER) end do - ! - ! -- write raw period data - if (this%iprpak /= 0) then - call this%inputtab%finalize_table() + end if + ! + ! -- read data + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + n = this%parser%GetInteger() + if (n < 1 .or. n > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0,a)') & + 'Reach number (RNO) must be greater than 0 and', & + 'less than or equal to', this%maxbound, '.' + call store_error(errmsg) + cycle end if ! - ! -- finalize cross-sections - - ! - ! -- determine the current size of cross-section data - ncrossptstot = cross_data%get_ncrossptstot() + ! -- read data from the rest of the line + call this%sfr_set_stressperiod(n, ichkustrm, crossfile) ! - ! -- reallocate sfr package cross-section data - if (ncrossptstot /= this%ncrossptstot) then - this%ncrossptstot = ncrossptstot - call mem_reallocate(this%station, this%ncrossptstot, 'STATION', this%memoryPath) - call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', this%memoryPath) - call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', this%memoryPath) + ! -- write line to table + if (this%iprpak /= 0) then + call this%parser%GetCurrentLine(line) + call this%inputtab%line_to_columns(line) end if ! - ! -- write cross-section data to the model listing file - call cross_data%output(this%width, this%rough, kstp=1, kper=kper) - ! - ! -- pack cross-section data - call cross_data%pack(this%ncrossptstot, this%ncrosspts, & - this%iacross, & - this%station, & - this%xsheight, & - this%xsrough) - ! - ! -- deallocate temporary local storage for reach cross-sections - call cross_data%destroy() - deallocate(cross_data) - nullify(cross_data) - ! - ! -- Reuse data from last stress period - else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + ! -- process cross-section file + if (trim(adjustl(crossfile)) /= 'NONE') then + call cross_data%read_table(n, this%width(n), & + trim(adjustl(crossfile))) + end if + end do ! - ! -- check upstream fraction values - if (ichkustrm /= 0) then - call this%sfr_check_ustrf() + ! -- write raw period data + if (this%iprpak /= 0) then + call this%inputtab%finalize_table() end if ! - ! -- write summary of package block error messages - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + ! -- finalize cross-sections + + ! + ! -- determine the current size of cross-section data + ncrossptstot = cross_data%get_ncrossptstot() + ! + ! -- reallocate sfr package cross-section data + if (ncrossptstot /= this%ncrossptstot) then + this%ncrossptstot = ncrossptstot + call mem_reallocate(this%station, this%ncrossptstot, 'STATION', & + this%memoryPath) + call mem_reallocate(this%xsheight, this%ncrossptstot, 'XSHEIGHT', & + this%memoryPath) + call mem_reallocate(this%xsrough, this%ncrossptstot, 'XSROUGH', & + this%memoryPath) end if ! - ! -- return - return - end subroutine sfr_rp + ! -- write cross-section data to the model listing file + call cross_data%output(this%width, this%rough, kstp=1, kper=kper) + ! + ! -- pack cross-section data + call cross_data%pack(this%ncrossptstot, this%ncrosspts, & + this%iacross, & + this%station, & + this%xsheight, & + this%xsrough) + ! + ! -- deallocate temporary local storage for reach cross-sections + call cross_data%destroy() + deallocate (cross_data) + nullify (cross_data) + ! + ! -- Reuse data from last stress period + else + write (this%iout, fmtlsp) trim(this%filtyp) + end if + ! + ! -- check upstream fraction values + if (ichkustrm /= 0) then + call this%sfr_check_ustrf() + end if + ! + ! -- write summary of package block error messages + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine sfr_rp - !> @ brief Advance the package + !> @ brief Advance the package !! !! Advance data in the SFR package. The method sets advances !! time series, time array series, and observation data. !! - !< - subroutine sfr_ad(this) - ! -- modules - use TimeSeriesManagerModule, only: var_timeseries - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: n - integer(I4B) :: iaux - ! - ! -- Most advanced package AD routines have to restore state if - ! the solution failed and the time step is being retried with a smaller - ! step size. This is not needed here because there is no old stage - ! or storage effects in the stream. - ! - ! -- Advance the time series manager - call this%TsManager%ad() - ! - ! -- check upstream fractions if time series are being used to - ! define this variable - if (var_timeseries(this%tsManager, this%packName, 'USTRF')) then - call this%sfr_check_ustrf() - end if - ! - ! -- update auxiliary variables by copying from the derived-type time - ! series variable into the bndpackage auxvar variable so that this - ! information is properly written to the GWF budget file - if (this%naux > 0) then - do n = 1, this%maxbound - do iaux = 1, this%naux - if (this%noupdateauxvar(iaux) /= 0) cycle - this%auxvar(iaux, n) = this%rauxvar(iaux, n) - end do - end do - end if - ! - ! -- reset upstream flow to zero and set specified stage + !< + subroutine sfr_ad(this) + ! -- modules + use TimeSeriesManagerModule, only: var_timeseries + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: n + integer(I4B) :: iaux + ! + ! -- Most advanced package AD routines have to restore state if + ! the solution failed and the time step is being retried with a smaller + ! step size. This is not needed here because there is no old stage + ! or storage effects in the stream. + ! + ! -- Advance the time series manager + call this%TsManager%ad() + ! + ! -- check upstream fractions if time series are being used to + ! define this variable + if (var_timeseries(this%tsManager, this%packName, 'USTRF')) then + call this%sfr_check_ustrf() + end if + ! + ! -- update auxiliary variables by copying from the derived-type time + ! series variable into the bndpackage auxvar variable so that this + ! information is properly written to the GWF budget file + if (this%naux > 0) then do n = 1, this%maxbound - this%usflow(n) = DZERO - if (this%iboundpak(n) < 0) then - this%stage(n) = this%sstage(n) - end if + do iaux = 1, this%naux + if (this%noupdateauxvar(iaux) /= 0) cycle + this%auxvar(iaux, n) = this%rauxvar(iaux, n) + end do end do - ! - ! -- pakmvrobj ad - if(this%imover == 1) then - call this%pakmvrobj%ad() - endif - ! - ! -- For each observation, push simulated value and corresponding - ! simulation time from "current" to "preceding" and reset - ! "current" value. - call this%obs%obs_ad() - ! - ! -- return - return - end subroutine sfr_ad + end if + ! + ! -- reset upstream flow to zero and set specified stage + do n = 1, this%maxbound + this%usflow(n) = DZERO + if (this%iboundpak(n) < 0) then + this%stage(n) = this%sstage(n) + end if + end do + ! + ! -- pakmvrobj ad + if (this%imover == 1) then + call this%pakmvrobj%ad() + end if + ! + ! -- For each observation, push simulated value and corresponding + ! simulation time from "current" to "preceding" and reset + ! "current" value. + call this%obs%obs_ad() + ! + ! -- return + return + end subroutine sfr_ad - !> @ brief Formulate the package hcof and rhs terms. + !> @ brief Formulate the package hcof and rhs terms. !! !! Formulate the hcof and rhs terms for the WEL package that will be !! added to the coefficient matrix and right-hand side vector. !! - !< - subroutine sfr_cf(this, reset_mover) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover - ! -- local variables - integer(I4B) :: n - integer(I4B) :: igwfnode - logical(LGP) :: lrm - ! - ! -- return if no sfr reaches - if(this%nbound == 0) return - ! - ! -- find highest active cell - do n = 1, this%nbound - igwfnode = this%igwftopnode(n) - if (igwfnode > 0) then - if (this%ibound(igwfnode) == 0) then - call this%dis%highest_active(igwfnode, this%ibound) - end if + !< + subroutine sfr_cf(this, reset_mover) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover + ! -- local variables + integer(I4B) :: n + integer(I4B) :: igwfnode + logical(LGP) :: lrm + ! + ! -- return if no sfr reaches + if (this%nbound == 0) return + ! + ! -- find highest active cell + do n = 1, this%nbound + igwfnode = this%igwftopnode(n) + if (igwfnode > 0) then + if (this%ibound(igwfnode) == 0) then + call this%dis%highest_active(igwfnode, this%ibound) end if - this%igwfnode(n) = igwfnode - this%nodelist(n) = igwfnode - end do - ! - ! -- pakmvrobj cf - lrm = .true. - if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then - call this%pakmvrobj%cf() - endif - ! - ! -- return - return - end subroutine sfr_cf + end if + this%igwfnode(n) = igwfnode + this%nodelist(n) = igwfnode + end do + ! + ! -- pakmvrobj cf + lrm = .true. + if (present(reset_mover)) lrm = reset_mover + if (this%imover == 1 .and. lrm) then + call this%pakmvrobj%cf() + end if + ! + ! -- return + return + end subroutine sfr_cf - !> @ brief Copy hcof and rhs terms into solution. + !> @ brief Copy hcof and rhs terms into solution. !! - !! Add the hcof and rhs terms for the SFR package to the + !! Add the hcof and rhs terms for the SFR package to the !! coefficient matrix and right-hand side vector. !! - !< - subroutine sfr_fc(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: n - integer(I4B) :: ipos - integer(I4B) :: node - real(DP) :: s0 - real(DP) :: ds - real(DP) :: dsmax - real(DP) :: hgwf - real(DP) :: v - real(DP) :: hhcof - real(DP) :: rrhs + !< + subroutine sfr_fc(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: n + integer(I4B) :: ipos + integer(I4B) :: node + real(DP) :: s0 + real(DP) :: ds + real(DP) :: dsmax + real(DP) :: hgwf + real(DP) :: v + real(DP) :: hhcof + real(DP) :: rrhs + ! + ! -- picard iterations for sfr to achieve good solution regardless + ! of reach order + sfrpicard: do i = 1, this%maxsfrpicard + ! + ! -- initialize maximum stage change for iteration to zero + dsmax = DZERO + ! + ! -- pakmvrobj fc - reset qformvr to zero + if (this%imover == 1) then + call this%pakmvrobj%fc() + end if ! - ! -- picard iterations for sfr to achieve good solution regardless - ! of reach order - sfrpicard: do i = 1, this%maxsfrpicard + ! -- solve for each sfr reach + reachsolve: do j = 1, this%nbound + n = this%isfrorder(j) + node = this%igwfnode(n) + if (node > 0) then + hgwf = this%xnew(node) + else + hgwf = DEP20 + end if ! - ! -- initialize maximum stage change for iteration to zero - dsmax = DZERO + ! -- save previous stage and upstream flow + if (i == 1) then + this%stage0(n) = this%stage(n) + this%usflow0(n) = this%usflow(n) + end if ! - ! -- pakmvrobj fc - reset qformvr to zero - if(this%imover == 1) then - call this%pakmvrobj%fc() - endif + ! -- set initial stage to calculate stage change + s0 = this%stage(n) ! - ! -- solve for each sfr reach - reachsolve: do j = 1, this%nbound - n = this%isfrorder(j) - node = this%igwfnode(n) - if (node > 0) then - hgwf = this%xnew(node) - else - hgwf = DEP20 - end if - ! - ! -- save previous stage and upstream flow - if (i == 1) then - this%stage0(n) = this%stage(n) - this%usflow0(n) = this%usflow(n) - end if - ! - ! -- set initial stage to calculate stage change - s0 = this%stage(n) - ! - ! -- solve for flow in swr - if (this%iboundpak(n) /= 0) then - call this%sfr_solve(n, hgwf, hhcof, rrhs) - else - this%depth(n) = DZERO - this%stage(n) = this%strtop(n) - v = DZERO - call this%sfr_update_flows(n, v, v) - hhcof = DZERO - rrhs = DZERO - end if - ! - ! -- set package hcof and rhs - this%hcof(n) = hhcof - this%rhs(n) = rrhs - ! - ! -- calculate stage change - ds = s0 - this%stage(n) - ! - ! -- evaluate if stage change exceeds dsmax - if (abs(ds) > abs(dsmax)) then - dsmax = ds - end if - - end do reachsolve + ! -- solve for flow in swr + if (this%iboundpak(n) /= 0) then + call this%sfr_solve(n, hgwf, hhcof, rrhs) + else + this%depth(n) = DZERO + this%stage(n) = this%strtop(n) + v = DZERO + call this%sfr_update_flows(n, v, v) + hhcof = DZERO + rrhs = DZERO + end if + ! + ! -- set package hcof and rhs + this%hcof(n) = hhcof + this%rhs(n) = rrhs ! - ! -- evaluate if the sfr picard iterations should be terminated - if (abs(dsmax) <= this%dmaxchg) then - exit sfrpicard + ! -- calculate stage change + ds = s0 - this%stage(n) + ! + ! -- evaluate if stage change exceeds dsmax + if (abs(ds) > abs(dsmax)) then + dsmax = ds end if - - end do sfrpicard - ! - ! -- Copy package rhs and hcof into solution rhs and amat - do n = 1, this%nbound - node = this%nodelist(n) - if (node < 1) cycle - rhs(node) = rhs(node) + this%rhs(n) - ipos = ia(node) - amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(n) - end do + + end do reachsolve ! - ! -- return - return - end subroutine sfr_fc + ! -- evaluate if the sfr picard iterations should be terminated + if (abs(dsmax) <= this%dmaxchg) then + exit sfrpicard + end if + + end do sfrpicard + ! + ! -- Copy package rhs and hcof into solution rhs and amat + do n = 1, this%nbound + node = this%nodelist(n) + if (node < 1) cycle + rhs(node) = rhs(node) + this%rhs(n) + ipos = ia(node) + amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(n) + end do + ! + ! -- return + return + end subroutine sfr_fc - !> @ brief Add Newton-Raphson terms for package into solution. + !> @ brief Add Newton-Raphson terms for package into solution. !! - !! Calculate and add the Newton-Raphson terms for the SFR package to the + !! Calculate and add the Newton-Raphson terms for the SFR package to the !! coefficient matrix and right-hand side vector. !! - !< - subroutine sfr_fn(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: n - integer(I4B) :: ipos - real(DP) :: rterm - real(DP) :: drterm - real(DP) :: rhs1 - real(DP) :: hcof1 - real(DP) :: q1 - real(DP) :: q2 - real(DP) :: hgwf - ! - ! -- Copy package rhs and hcof into solution rhs and amat - do j = 1, this%nbound - i = this%isfrorder(j) - ! -- skip inactive reaches - if (this%iboundpak(i) < 1) cycle - ! -- skip if reach is not connected to gwf - n = this%nodelist(i) - if (n < 1) cycle - ipos = ia(n) - rterm = this%hcof(i) * this%xnew(n) - ! -- calculate perturbed head - hgwf = this%xnew(n) + DEM4 - call this%sfr_solve(i, hgwf, hcof1, rhs1, update=.false.) - q1 = rhs1 - hcof1 * hgwf - ! -- calculate unperturbed head - q2 = this%rhs(i) - this%hcof(i) * this%xnew(n) - ! -- calculate derivative - drterm = (q2 - q1) / DEM4 - ! -- add terms to convert conductance formulation into - ! newton-raphson formulation - amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + drterm - this%hcof(i) - rhs(n) = rhs(n) - rterm + drterm * this%xnew(n) - end do - ! - ! -- return - return - end subroutine sfr_fn + !< + subroutine sfr_fn(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: n + integer(I4B) :: ipos + real(DP) :: rterm + real(DP) :: drterm + real(DP) :: rhs1 + real(DP) :: hcof1 + real(DP) :: q1 + real(DP) :: q2 + real(DP) :: hgwf + ! + ! -- Copy package rhs and hcof into solution rhs and amat + do j = 1, this%nbound + i = this%isfrorder(j) + ! -- skip inactive reaches + if (this%iboundpak(i) < 1) cycle + ! -- skip if reach is not connected to gwf + n = this%nodelist(i) + if (n < 1) cycle + ipos = ia(n) + rterm = this%hcof(i) * this%xnew(n) + ! -- calculate perturbed head + hgwf = this%xnew(n) + DEM4 + call this%sfr_solve(i, hgwf, hcof1, rhs1, update=.false.) + q1 = rhs1 - hcof1 * hgwf + ! -- calculate unperturbed head + q2 = this%rhs(i) - this%hcof(i) * this%xnew(n) + ! -- calculate derivative + drterm = (q2 - q1) / DEM4 + ! -- add terms to convert conductance formulation into + ! newton-raphson formulation + amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + drterm - this%hcof(i) + rhs(n) = rhs(n) - rterm + drterm * this%xnew(n) + end do + ! + ! -- return + return + end subroutine sfr_fn - !> @ brief Convergence check for package. + !> @ brief Convergence check for package. !! !! Perform additional convergence checks on the flow between the SFR package !! and the model it is attached to. !! - !< - subroutine sfr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) - ! -- modules - use TdisModule, only: totim, kstp, kper, delt - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - integer(I4B), intent(in) :: innertot !< total number of inner iterations - integer(I4B), intent(in) :: kiter !< Picard iteration number - integer(I4B), intent(in) :: iend !< flag indicating if this is the last Picard iteration - integer(I4B), intent(in) :: icnvgmod !< flag inficating if the model has met specific convergence criteria - character(len=LENPAKLOC), intent(inout) :: cpak !< string for user node - integer(I4B), intent(inout) :: ipak !< location of the maximum dependent variable change - real(DP), intent(inout) :: dpak !< maximum dependent variable change - ! -- local variables - character(len=LENPAKLOC) :: cloc - character(len=LINELENGTH) :: tag - integer(I4B) :: icheck - integer(I4B) :: ipakfail - integer(I4B) :: locdhmax - integer(I4B) :: locrmax - integer(I4B) :: ntabrows - integer(I4B) :: ntabcols - integer(I4B) :: n - real(DP) :: dh - real(DP) :: r - real(DP) :: dhmax - real(DP) :: rmax - ! - ! -- initialize local variables - icheck = this%iconvchk - ipakfail = 0 - locdhmax = 0 - locrmax = 0 - r = DZERO - dhmax = DZERO - rmax = DZERO - ! - ! -- if not saving package convergence data on check convergence if - ! the model is considered converged - if (this%ipakcsv == 0) then - if (icnvgmod == 0) then - icheck = 0 - end if + !< + subroutine sfr_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) + ! -- modules + use TdisModule, only: totim, kstp, kper, delt + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + integer(I4B), intent(in) :: innertot !< total number of inner iterations + integer(I4B), intent(in) :: kiter !< Picard iteration number + integer(I4B), intent(in) :: iend !< flag indicating if this is the last Picard iteration + integer(I4B), intent(in) :: icnvgmod !< flag inficating if the model has met specific convergence criteria + character(len=LENPAKLOC), intent(inout) :: cpak !< string for user node + integer(I4B), intent(inout) :: ipak !< location of the maximum dependent variable change + real(DP), intent(inout) :: dpak !< maximum dependent variable change + ! -- local variables + character(len=LENPAKLOC) :: cloc + character(len=LINELENGTH) :: tag + integer(I4B) :: icheck + integer(I4B) :: ipakfail + integer(I4B) :: locdhmax + integer(I4B) :: locrmax + integer(I4B) :: ntabrows + integer(I4B) :: ntabcols + integer(I4B) :: n + real(DP) :: dh + real(DP) :: r + real(DP) :: dhmax + real(DP) :: rmax + ! + ! -- initialize local variables + icheck = this%iconvchk + ipakfail = 0 + locdhmax = 0 + locrmax = 0 + r = DZERO + dhmax = DZERO + rmax = DZERO + ! + ! -- if not saving package convergence data on check convergence if + ! the model is considered converged + if (this%ipakcsv == 0) then + if (icnvgmod == 0) then + icheck = 0 + end if ! ! -- saving package convergence data - else + else + ! + ! -- header for package csv + if (.not. associated(this%pakcsvtab)) then ! - ! -- header for package csv - if (.not. associated(this%pakcsvtab)) then - ! - ! -- determine the number of columns and rows - ntabrows = 1 - ntabcols = 9 - ! - ! -- setup table - call table_cr(this%pakcsvtab, this%packName, '') - call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & - lineseparator=.FALSE., separator=',', & - finalize=.FALSE.) - ! - ! -- add columns to package csv - tag = 'total_inner_iterations' - call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) - tag = 'totim' - call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) - tag = 'kper' - call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) - tag = 'kstp' - call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) - tag = 'nouter' - call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) - tag = 'dvmax' - call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) - tag = 'dvmax_loc' - call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) - tag = 'dinflowmax' - call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) - tag = 'dinflowmax_loc' - call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) - end if + ! -- determine the number of columns and rows + ntabrows = 1 + ntabcols = 9 + ! + ! -- setup table + call table_cr(this%pakcsvtab, this%packName, '') + call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & + lineseparator=.FALSE., separator=',', & + finalize=.FALSE.) + ! + ! -- add columns to package csv + tag = 'total_inner_iterations' + call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) + tag = 'totim' + call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) + tag = 'kper' + call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) + tag = 'kstp' + call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) + tag = 'nouter' + call this%pakcsvtab%initialize_column(tag, 10, alignment=TABLEFT) + tag = 'dvmax' + call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) + tag = 'dvmax_loc' + call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) + tag = 'dinflowmax' + call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) + tag = 'dinflowmax_loc' + call this%pakcsvtab%initialize_column(tag, 15, alignment=TABLEFT) end if - ! - ! -- perform package convergence check - if (icheck /= 0) then - final_check: do n = 1, this%maxbound - if (this%iboundpak(n) == 0) cycle - dh = this%stage0(n) - this%stage(n) - ! - ! -- evaluate flow difference if the time step is transient - if (this%gwfiss == 0) then - r = this%usflow0(n) - this%usflow(n) - ! - ! -- normalize flow difference and convert to a depth - r = r * delt / this%calc_surface_area(n) - end if + end if + ! + ! -- perform package convergence check + if (icheck /= 0) then + final_check: do n = 1, this%maxbound + if (this%iboundpak(n) == 0) cycle + dh = this%stage0(n) - this%stage(n) + ! + ! -- evaluate flow difference if the time step is transient + if (this%gwfiss == 0) then + r = this%usflow0(n) - this%usflow(n) ! - ! -- evaluate magnitude of differences - if (n == 1) then + ! -- normalize flow difference and convert to a depth + r = r * delt / this%calc_surface_area(n) + end if + ! + ! -- evaluate magnitude of differences + if (n == 1) then + locdhmax = n + dhmax = dh + locrmax = n + rmax = r + else + if (abs(dh) > abs(dhmax)) then locdhmax = n dhmax = dh + end if + if (abs(r) > abs(rmax)) then locrmax = n rmax = r - else - if (abs(dh) > abs(dhmax)) then - locdhmax = n - dhmax = dh - end if - if (abs(r) > abs(rmax)) then - locrmax = n - rmax = r - end if - end if - end do final_check - ! - ! -- set dpak and cpak - if (ABS(dhmax) > abs(dpak)) then - ipak = locdhmax - dpak = dhmax - write(cloc, "(a,'-',a)") trim(this%packName), 'stage' - cpak = trim(cloc) - end if - if (ABS(rmax) > abs(dpak)) then - ipak = locrmax - dpak = rmax - write(cloc, "(a,'-',a)") trim(this%packName), 'inflow' - cpak = trim(cloc) - end if - ! - ! -- write convergence data to package csv - if (this%ipakcsv /= 0) then - ! - ! -- write the data - call this%pakcsvtab%add_term(innertot) - call this%pakcsvtab%add_term(totim) - call this%pakcsvtab%add_term(kper) - call this%pakcsvtab%add_term(kstp) - call this%pakcsvtab%add_term(kiter) - call this%pakcsvtab%add_term(dhmax) - call this%pakcsvtab%add_term(locdhmax) - call this%pakcsvtab%add_term(rmax) - call this%pakcsvtab%add_term(locrmax) - ! - ! -- finalize the package csv - if (iend == 1) then - call this%pakcsvtab%finalize_table() end if end if + end do final_check + ! + ! -- set dpak and cpak + if (ABS(dhmax) > abs(dpak)) then + ipak = locdhmax + dpak = dhmax + write (cloc, "(a,'-',a)") trim(this%packName), 'stage' + cpak = trim(cloc) + end if + if (ABS(rmax) > abs(dpak)) then + ipak = locrmax + dpak = rmax + write (cloc, "(a,'-',a)") trim(this%packName), 'inflow' + cpak = trim(cloc) end if ! - ! -- return - return - end subroutine sfr_cc - - !> @ brief Calculate package flows. - !! - !! Calculate the flow between connected SFR package control volumes. - !! - !< - subroutine sfr_cq(this, x, flowja, iadv) - ! -- modules - use InputOutputModule, only: ulasav, ubdsv06 - use BudgetModule, only: BudgetType - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - real(DP), dimension(:), intent(in) :: x !< current dependent-variable value - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes - integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package - ! -- local variables - integer(I4B) :: i - real(DP) :: qext - ! -- for budget - integer(I4B) :: n - real(DP) :: qoutflow - real(DP) :: qfrommvr - real(DP) :: qtomvr - ! - ! -- call base functionality in bnd_cq. This will calculate sfr-gwf flows - ! and put them into this%simvals - call this%BndType%bnd_cq(x, flowja, iadv=1) - ! - ! -- Calculate qextoutflow and qoutflow for subsequent budgets - do n = 1, this%maxbound - ! - ! -- mover - qfrommvr = DZERO - qtomvr = DZERO - if (this%imover == 1) then - qfrommvr = this%pakmvrobj%get_qfrommvr(n) - qtomvr = this%pakmvrobj%get_qtomvr(n) - if (qtomvr > DZERO) then - qtomvr = -qtomvr - end if - endif + ! -- write convergence data to package csv + if (this%ipakcsv /= 0) then ! - ! -- external downstream stream flow - qext = this%dsflow(n) - qoutflow = DZERO - if (qext > DZERO) then - qext = -qext - end if - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) cycle - qext = DZERO - exit - end do + ! -- write the data + call this%pakcsvtab%add_term(innertot) + call this%pakcsvtab%add_term(totim) + call this%pakcsvtab%add_term(kper) + call this%pakcsvtab%add_term(kstp) + call this%pakcsvtab%add_term(kiter) + call this%pakcsvtab%add_term(dhmax) + call this%pakcsvtab%add_term(locdhmax) + call this%pakcsvtab%add_term(rmax) + call this%pakcsvtab%add_term(locrmax) ! - ! -- adjust external downstream stream flow using qtomvr - if (qext < DZERO) then - if (qtomvr < DZERO) then - qext = qext - qtomvr - end if - else - qoutflow = this%dsflow(n) - if (qoutflow > DZERO) then - qoutflow = -qoutflow - end if + ! -- finalize the package csv + if (iend == 1) then + call this%pakcsvtab%finalize_table() end if - ! - ! -- set qextoutflow and qoutflow for cell by cell budget - ! output and observations - this%qextoutflow(n) = qext - this%qoutflow(n) = qoutflow - ! - end do - ! - ! -- fill the budget object - call this%sfr_fill_budobj() - ! - ! -- return - return - end subroutine sfr_cq + end if + end if + ! + ! -- return + return + end subroutine sfr_cc - !> @ brief Output package flow terms. + !> @ brief Calculate package flows. !! - !! Output SFR package flow terms. + !! Calculate the flow between connected SFR package control volumes. !! - !< - subroutine sfr_ot_package_flows(this, icbcfl, ibudfl) - ! -- modules - use TdisModule, only: kstp, kper, delt, pertim, totim - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output - integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved - ! -- local variables - integer(I4B) :: ibinun - character (len=20), dimension(:), allocatable :: cellidstr - integer(I4B) :: n - integer(I4B) :: node + !< + subroutine sfr_cq(this, x, flowja, iadv) + ! -- modules + use BudgetModule, only: BudgetType + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + real(DP), dimension(:), intent(in) :: x !< current dependent-variable value + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package + ! -- local variables + integer(I4B) :: i + real(DP) :: qext + ! -- for budget + integer(I4B) :: n + real(DP) :: qoutflow + real(DP) :: qfrommvr + real(DP) :: qtomvr + ! + ! -- call base functionality in bnd_cq. This will calculate sfr-gwf flows + ! and put them into this%simvals + call this%BndType%bnd_cq(x, flowja, iadv=1) + ! + ! -- Calculate qextoutflow and qoutflow for subsequent budgets + do n = 1, this%maxbound ! - ! -- write the flows from the budobj - ibinun = 0 - if(this%ibudgetout /= 0) then - ibinun = this%ibudgetout + ! -- mover + qfrommvr = DZERO + qtomvr = DZERO + if (this%imover == 1) then + qfrommvr = this%pakmvrobj%get_qfrommvr(n) + qtomvr = this%pakmvrobj%get_qtomvr(n) + if (qtomvr > DZERO) then + qtomvr = -qtomvr + end if end if - if(icbcfl == 0) ibinun = 0 - if (ibinun > 0) then - call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & - pertim, totim, this%iout) + ! + ! -- external downstream stream flow + qext = this%dsflow(n) + qoutflow = DZERO + if (qext > DZERO) then + qext = -qext end if + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) cycle + qext = DZERO + exit + end do ! - ! -- Print lake flows table - if (ibudfl /= 0 .and. this%iprflow /= 0) then - ! - ! -- If there are any 'none' gwf connections then need to calculate - ! a vector of cellids and pass that in to the budget flow table because - ! the table assumes that there are maxbound gwf entries, which is not - ! the case if any 'none's are specified. - if (this%ianynone > 0) then - allocate(cellidstr(this%maxbound)) - do n = 1, this%maxbound - node = this%igwfnode(n) - if (node > 0) then - call this%dis%noder_to_string(node, cellidstr(n)) - else - cellidstr(n) = 'NONE' - end if - end do - call this%budobj%write_flowtable(this%dis, kstp, kper, cellidstr) - deallocate(cellidstr) - else - call this%budobj%write_flowtable(this%dis, kstp, kper) + ! -- adjust external downstream stream flow using qtomvr + if (qext < DZERO) then + if (qtomvr < DZERO) then + qext = qext - qtomvr + end if + else + qoutflow = this%dsflow(n) + if (qoutflow > DZERO) then + qoutflow = -qoutflow end if end if ! - ! -- return - return - end subroutine sfr_ot_package_flows + ! -- set qextoutflow and qoutflow for cell by cell budget + ! output and observations + this%qextoutflow(n) = qext + this%qoutflow(n) = qoutflow + ! + end do + ! + ! -- fill the budget object + call this%sfr_fill_budobj() + ! + ! -- return + return + end subroutine sfr_cq - !> @ brief Output package dependent-variable terms. + !> @ brief Output package flow terms. !! - !! Output SFR boundary package dependent-variable terms. + !! Output SFR package flow terms. !! - !< - subroutine sfr_ot_dv(this, idvsave, idvprint) - ! -- modules - use TdisModule, only: kstp, kper, pertim, totim - use InputOutputModule, only: ulasav - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output - integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file - ! -- local variables - character (len=20) :: cellid - integer(I4B) :: ibinun - integer(I4B) :: n - integer(I4B) :: node - real(DP) :: d - real(DP) :: v - real(DP) :: hgwf - real(DP) :: sbot - real(DP) :: depth - real(DP) :: stage - real(DP) :: w - real(DP) :: cond - real(DP) :: grad - ! - ! -- set unit number for binary dependent variable output - ibinun = 0 - if(this%istageout /= 0) then - ibinun = this%istageout - end if - if(idvsave == 0) ibinun = 0 - ! - ! -- write sfr binary output - if (ibinun > 0) then - do n = 1, this%maxbound - d = this%depth(n) - v = this%stage(n) - if (this%iboundpak(n) == 0) then - v = DHNOFLO - else if (d == DZERO) then - v = DHDRY - end if - this%dbuff(n) = v - end do - call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, & - this%maxbound, 1, 1, ibinun) - end if - ! - ! -- print sfr stage and depth table - if (idvprint /= 0 .and. this%iprhed /= 0) then - ! - ! -- set table kstp and kper - call this%stagetab%set_kstpkper(kstp, kper) - ! - ! -- fill stage data + !< + subroutine sfr_ot_package_flows(this, icbcfl, ibudfl) + ! -- modules + use TdisModule, only: kstp, kper, delt, pertim, totim + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output + integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved + ! -- local variables + integer(I4B) :: ibinun + character(len=20), dimension(:), allocatable :: cellidstr + integer(I4B) :: n + integer(I4B) :: node + ! + ! -- write the flows from the budobj + ibinun = 0 + if (this%ibudgetout /= 0) then + ibinun = this%ibudgetout + end if + if (icbcfl == 0) ibinun = 0 + if (ibinun > 0) then + call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & + pertim, totim, this%iout) + end if + ! + ! -- Print lake flows table + if (ibudfl /= 0 .and. this%iprflow /= 0) then + ! + ! -- If there are any 'none' gwf connections then need to calculate + ! a vector of cellids and pass that in to the budget flow table because + ! the table assumes that there are maxbound gwf entries, which is not + ! the case if any 'none's are specified. + if (this%ianynone > 0) then + allocate (cellidstr(this%maxbound)) do n = 1, this%maxbound node = this%igwfnode(n) if (node > 0) then - call this%dis%noder_to_string(node, cellid) - hgwf = this%xnew(node) - else - cellid = 'NONE' - end if - if(this%inamedbound==1) then - call this%stagetab%add_term(this%boundname(n)) - end if - call this%stagetab%add_term(n) - call this%stagetab%add_term(cellid) - depth = this%depth(n) - stage = this%stage(n) - w = this%calc_top_width_wet(n, depth) - call this%stagetab%add_term(stage) - call this%stagetab%add_term(depth) - call this%stagetab%add_term(w) - call this%sfr_calc_cond(n, depth, cond) - if (node > 0) then - sbot = this%strtop(n) - this%bthick(n) - if (hgwf < sbot) then - grad = stage - sbot - else - grad = stage - hgwf - end if - grad = grad / this%bthick(n) - call this%stagetab%add_term(hgwf) - call this%stagetab%add_term(cond) - call this%stagetab%add_term(grad) + call this%dis%noder_to_string(node, cellidstr(n)) else - call this%stagetab%add_term('--') - call this%stagetab%add_term('--') - call this%stagetab%add_term('--') + cellidstr(n) = 'NONE' end if end do + call this%budobj%write_flowtable(this%dis, kstp, kper, cellidstr) + deallocate (cellidstr) + else + call this%budobj%write_flowtable(this%dis, kstp, kper) end if - ! - ! -- return - return - end subroutine sfr_ot_dv - - !> @ brief Output advanced package budget summary. + end if + ! + ! -- return + return + end subroutine sfr_ot_package_flows + + !> @ brief Output package dependent-variable terms. !! - !! Output SFR package budget summary. + !! Output SFR boundary package dependent-variable terms. !! - !< - subroutine sfr_ot_bdsummary(this, kstp, kper, iout, ibudfl) - ! -- module - use TdisModule, only: totim - ! -- dummy - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + !< + subroutine sfr_ot_dv(this, idvsave, idvprint) + ! -- modules + use TdisModule, only: kstp, kper, pertim, totim + use InputOutputModule, only: ulasav + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output + integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file + ! -- local variables + character(len=20) :: cellid + integer(I4B) :: ibinun + integer(I4B) :: n + integer(I4B) :: node + real(DP) :: d + real(DP) :: v + real(DP) :: hgwf + real(DP) :: sbot + real(DP) :: depth + real(DP) :: stage + real(DP) :: w + real(DP) :: cond + real(DP) :: grad + ! + ! -- set unit number for binary dependent variable output + ibinun = 0 + if (this%istageout /= 0) then + ibinun = this%istageout + end if + if (idvsave == 0) ibinun = 0 + ! + ! -- write sfr binary output + if (ibinun > 0) then + do n = 1, this%maxbound + d = this%depth(n) + v = this%stage(n) + if (this%iboundpak(n) == 0) then + v = DHNOFLO + else if (d == DZERO) then + v = DHDRY + end if + this%dbuff(n) = v + end do + call ulasav(this%dbuff, ' STAGE', kstp, kper, pertim, totim, & + this%maxbound, 1, 1, ibinun) + end if + ! + ! -- print sfr stage and depth table + if (idvprint /= 0 .and. this%iprhed /= 0) then ! - call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) + ! -- set table kstp and kper + call this%stagetab%set_kstpkper(kstp, kper) ! - ! -- return - return - end subroutine sfr_ot_bdsummary - - !> @ brief Deallocate package memory + ! -- fill stage data + do n = 1, this%maxbound + node = this%igwfnode(n) + if (node > 0) then + call this%dis%noder_to_string(node, cellid) + hgwf = this%xnew(node) + else + cellid = 'NONE' + end if + if (this%inamedbound == 1) then + call this%stagetab%add_term(this%boundname(n)) + end if + call this%stagetab%add_term(n) + call this%stagetab%add_term(cellid) + depth = this%depth(n) + stage = this%stage(n) + w = this%calc_top_width_wet(n, depth) + call this%stagetab%add_term(stage) + call this%stagetab%add_term(depth) + call this%stagetab%add_term(w) + call this%sfr_calc_cond(n, depth, cond, stage, hgwf) + if (node > 0) then + sbot = this%strtop(n) - this%bthick(n) + if (hgwf < sbot) then + grad = stage - sbot + else + grad = stage - hgwf + end if + grad = grad / this%bthick(n) + call this%stagetab%add_term(hgwf) + call this%stagetab%add_term(cond) + call this%stagetab%add_term(grad) + else + call this%stagetab%add_term('--') + call this%stagetab%add_term('--') + call this%stagetab%add_term('--') + end if + end do + end if + ! + ! -- return + return + end subroutine sfr_ot_dv + + !> @ brief Output advanced package budget summary. + !! + !! Output SFR package budget summary. + !! + !< + subroutine sfr_ot_bdsummary(this, kstp, kper, iout, ibudfl) + ! -- module + use TdisModule, only: totim + ! -- dummy + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + ! + call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) + ! + ! -- return + return + end subroutine sfr_ot_bdsummary + + !> @ brief Deallocate package memory !! !! Deallocate SFR package scalars and arrays. !! - !< - subroutine sfr_da(this) - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! - ! -- deallocate arrays - call mem_deallocate(this%qoutflow) - call mem_deallocate(this%qextoutflow) - deallocate(this%csfrbudget) - call mem_deallocate(this%sfrname, 'SFRNAME', this%memoryPath) - call mem_deallocate(this%dbuff) - deallocate(this%cauxcbc) - call mem_deallocate(this%qauxcbc) - call mem_deallocate(this%iboundpak) - call mem_deallocate(this%igwfnode) - call mem_deallocate(this%igwftopnode) - call mem_deallocate(this%length) - call mem_deallocate(this%width) - call mem_deallocate(this%strtop) - call mem_deallocate(this%bthick) - call mem_deallocate(this%hk) - call mem_deallocate(this%slope) - call mem_deallocate(this%nconnreach) - call mem_deallocate(this%ustrf) - call mem_deallocate(this%ftotnd) - call mem_deallocate(this%usflow) - call mem_deallocate(this%dsflow) - call mem_deallocate(this%depth) - call mem_deallocate(this%stage) - call mem_deallocate(this%gwflow) - call mem_deallocate(this%simevap) - call mem_deallocate(this%simrunoff) - call mem_deallocate(this%stage0) - call mem_deallocate(this%usflow0) - call mem_deallocate(this%denseterms) - ! - ! -- deallocate reach order and connection data - call mem_deallocate(this%isfrorder) - call mem_deallocate(this%ia) - call mem_deallocate(this%ja) - call mem_deallocate(this%idir) - call mem_deallocate(this%idiv) - call mem_deallocate(this%qconn) - ! - ! -- deallocate boundary data - call mem_deallocate(this%rough) - call mem_deallocate(this%rain) - call mem_deallocate(this%evap) - call mem_deallocate(this%inflow) - call mem_deallocate(this%runoff) - call mem_deallocate(this%sstage) - ! - ! -- deallocate aux variables - call mem_deallocate(this%rauxvar) - ! - ! -- deallocate diversion variables - call mem_deallocate(this%iadiv) - call mem_deallocate(this%divreach) - if (associated(this%divcprior)) then - deallocate(this%divcprior) - end if - call mem_deallocate(this%divflow) - call mem_deallocate(this%divq) - call mem_deallocate(this%ndiv) - ! - ! -- deallocate cross-section data - call mem_deallocate(this%ncrosspts) - call mem_deallocate(this%iacross) - call mem_deallocate(this%station) - call mem_deallocate(this%xsheight) - call mem_deallocate(this%xsrough) - ! - ! -- deallocate budobj - call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) - ! - ! -- deallocate stage table - if (this%iprhed > 0) then - call this%stagetab%table_da() - deallocate(this%stagetab) - nullify(this%stagetab) - end if - ! - ! -- deallocate package csv table - if (this%ipakcsv > 0) then - call this%pakcsvtab%table_da() - deallocate(this%pakcsvtab) - nullify(this%pakcsvtab) - end if - ! - ! -- deallocate scalars - call mem_deallocate(this%iprhed) - call mem_deallocate(this%istageout) - call mem_deallocate(this%ibudgetout) - call mem_deallocate(this%ibudcsv) - call mem_deallocate(this%ipakcsv) - call mem_deallocate(this%idiversions) - call mem_deallocate(this%maxsfrpicard) - call mem_deallocate(this%maxsfrit) - call mem_deallocate(this%bditems) - call mem_deallocate(this%cbcauxitems) - call mem_deallocate(this%unitconv) - call mem_deallocate(this%dmaxchg) - call mem_deallocate(this%deps) - call mem_deallocate(this%nconn) - call mem_deallocate(this%icheck) - call mem_deallocate(this%iconvchk) - call mem_deallocate(this%idense) - call mem_deallocate(this%ianynone) - call mem_deallocate(this%ncrossptstot) - nullify(this%gwfiss) - ! - ! -- call base BndType deallocate - call this%BndType%bnd_da() - ! - ! -- return - return - end subroutine sfr_da + !< + subroutine sfr_da(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! + ! -- deallocate arrays + call mem_deallocate(this%qoutflow) + call mem_deallocate(this%qextoutflow) + deallocate (this%csfrbudget) + call mem_deallocate(this%sfrname, 'SFRNAME', this%memoryPath) + call mem_deallocate(this%dbuff) + deallocate (this%cauxcbc) + call mem_deallocate(this%qauxcbc) + call mem_deallocate(this%iboundpak) + call mem_deallocate(this%igwfnode) + call mem_deallocate(this%igwftopnode) + call mem_deallocate(this%length) + call mem_deallocate(this%width) + call mem_deallocate(this%strtop) + call mem_deallocate(this%bthick) + call mem_deallocate(this%hk) + call mem_deallocate(this%slope) + call mem_deallocate(this%nconnreach) + call mem_deallocate(this%ustrf) + call mem_deallocate(this%ftotnd) + call mem_deallocate(this%usflow) + call mem_deallocate(this%dsflow) + call mem_deallocate(this%depth) + call mem_deallocate(this%stage) + call mem_deallocate(this%gwflow) + call mem_deallocate(this%simevap) + call mem_deallocate(this%simrunoff) + call mem_deallocate(this%stage0) + call mem_deallocate(this%usflow0) + call mem_deallocate(this%denseterms) + call mem_deallocate(this%viscratios) + ! + ! -- deallocate reach order and connection data + call mem_deallocate(this%isfrorder) + call mem_deallocate(this%ia) + call mem_deallocate(this%ja) + call mem_deallocate(this%idir) + call mem_deallocate(this%idiv) + call mem_deallocate(this%qconn) + ! + ! -- deallocate boundary data + call mem_deallocate(this%rough) + call mem_deallocate(this%rain) + call mem_deallocate(this%evap) + call mem_deallocate(this%inflow) + call mem_deallocate(this%runoff) + call mem_deallocate(this%sstage) + ! + ! -- deallocate aux variables + call mem_deallocate(this%rauxvar) + ! + ! -- deallocate diversion variables + call mem_deallocate(this%iadiv) + call mem_deallocate(this%divreach) + if (associated(this%divcprior)) then + deallocate (this%divcprior) + end if + call mem_deallocate(this%divflow) + call mem_deallocate(this%divq) + call mem_deallocate(this%ndiv) + ! + ! -- deallocate cross-section data + call mem_deallocate(this%ncrosspts) + call mem_deallocate(this%iacross) + call mem_deallocate(this%station) + call mem_deallocate(this%xsheight) + call mem_deallocate(this%xsrough) + ! + ! -- deallocate budobj + call this%budobj%budgetobject_da() + deallocate (this%budobj) + nullify (this%budobj) + ! + ! -- deallocate stage table + if (this%iprhed > 0) then + call this%stagetab%table_da() + deallocate (this%stagetab) + nullify (this%stagetab) + end if + ! + ! -- deallocate package csv table + if (this%ipakcsv > 0) then + call this%pakcsvtab%table_da() + deallocate (this%pakcsvtab) + nullify (this%pakcsvtab) + end if + ! + ! -- deallocate scalars + call mem_deallocate(this%iprhed) + call mem_deallocate(this%istageout) + call mem_deallocate(this%ibudgetout) + call mem_deallocate(this%ibudcsv) + call mem_deallocate(this%ipakcsv) + call mem_deallocate(this%idiversions) + call mem_deallocate(this%maxsfrpicard) + call mem_deallocate(this%maxsfrit) + call mem_deallocate(this%bditems) + call mem_deallocate(this%cbcauxitems) + call mem_deallocate(this%unitconv) + call mem_deallocate(this%dmaxchg) + call mem_deallocate(this%deps) + call mem_deallocate(this%nconn) + call mem_deallocate(this%icheck) + call mem_deallocate(this%iconvchk) + call mem_deallocate(this%idense) + call mem_deallocate(this%ianynone) + call mem_deallocate(this%ncrossptstot) + nullify (this%gwfiss) + ! + ! -- call base BndType deallocate + call this%BndType%bnd_da() + ! + ! -- return + return + end subroutine sfr_da - !> @ brief Define the list label for the package + !> @ brief Define the list label for the package !! !! Method defined the list label for the SFR package. The list label is !! the heading that is written to iout when PRINT_INPUT option is used. !! - !< - subroutine define_listlabel(this) - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - ! - ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' - else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif - ! - ! -- return - return - end subroutine define_listlabel - + !< + subroutine define_listlabel(this) + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object ! - ! -- Procedures related to observations (type-bound) - - !> @brief Determine if observations are supported. + ! -- create the header list label + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + else + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if + ! + ! -- return + return + end subroutine define_listlabel + + ! + ! -- Procedures related to observations (type-bound) + + !> @brief Determine if observations are supported. !! !! Function to determine if observations are supported by the SFR package. !! Observations are supported by the SFR package. !! !! @return sfr_obs_supported boolean indicating if observations are supported !! - !< - logical function sfr_obs_supported(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! - ! -- set boolean - sfr_obs_supported = .true. - ! - ! -- return - return - end function sfr_obs_supported - + !< + logical function sfr_obs_supported(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! + ! -- set boolean + sfr_obs_supported = .true. + ! + ! -- return + return + end function sfr_obs_supported - !> @brief Define the observation types available in the package + !> @brief Define the observation types available in the package !! !! Method to define the observation types available in the SFR package. !! - !< - subroutine sfr_df_obs(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: indx - ! - ! -- Store obs type and assign procedure pointer - ! for stage observation type. - call this%obs%StoreObsType('stage', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for inflow observation type. - call this%obs%StoreObsType('inflow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for inflow observation type. - call this%obs%StoreObsType('ext-inflow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for rainfall observation type. - call this%obs%StoreObsType('rainfall', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for runoff observation type. - call this%obs%StoreObsType('runoff', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for evaporation observation type. - call this%obs%StoreObsType('evaporation', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for outflow observation type. - call this%obs%StoreObsType('outflow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for ext-outflow observation type. - call this%obs%StoreObsType('ext-outflow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for to-mvr observation type. - call this%obs%StoreObsType('to-mvr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for sfr-frommvr observation type. - call this%obs%StoreObsType('from-mvr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for sfr observation type. - call this%obs%StoreObsType('sfr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for upstream flow observation type. - call this%obs%StoreObsType('upstream-flow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for downstream flow observation type. - call this%obs%StoreObsType('downstream-flow', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for depth observation type. - call this%obs%StoreObsType('depth', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for wetted-perimeter observation type. - call this%obs%StoreObsType('wet-perimeter', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for wetted-area observation type. - call this%obs%StoreObsType('wet-area', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for wetted-width observation type. - call this%obs%StoreObsType('wet-width', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID - ! - ! -- return - return - end subroutine sfr_df_obs - + !< + subroutine sfr_df_obs(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: indx + ! + ! -- Store obs type and assign procedure pointer + ! for stage observation type. + call this%obs%StoreObsType('stage', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for inflow observation type. + call this%obs%StoreObsType('inflow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for inflow observation type. + call this%obs%StoreObsType('ext-inflow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for rainfall observation type. + call this%obs%StoreObsType('rainfall', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for runoff observation type. + call this%obs%StoreObsType('runoff', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for evaporation observation type. + call this%obs%StoreObsType('evaporation', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for outflow observation type. + call this%obs%StoreObsType('outflow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for ext-outflow observation type. + call this%obs%StoreObsType('ext-outflow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for to-mvr observation type. + call this%obs%StoreObsType('to-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for sfr-frommvr observation type. + call this%obs%StoreObsType('from-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for sfr observation type. + call this%obs%StoreObsType('sfr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for upstream flow observation type. + call this%obs%StoreObsType('upstream-flow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for downstream flow observation type. + call this%obs%StoreObsType('downstream-flow', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for depth observation type. + call this%obs%StoreObsType('depth', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for wetted-perimeter observation type. + call this%obs%StoreObsType('wet-perimeter', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for wetted-area observation type. + call this%obs%StoreObsType('wet-area', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for wetted-width observation type. + call this%obs%StoreObsType('wet-width', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => sfr_process_obsID + ! + ! -- return + return + end subroutine sfr_df_obs - !> @brief Save observations for the package + !> @brief Save observations for the package !! !! Method to save simulated values for the SFR package. !! - !< - subroutine sfr_bd_obs(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: n - real(DP) :: v - character(len=100) :: msg - type(ObserveType), pointer :: obsrv => null() - ! - ! Write simulated values for all sfr observations - if (this%obs%npakobs > 0) then - call this%obs%obs_bd_clear() - do i=1 ,this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv - do j = 1, obsrv%indxbnds_count - n = obsrv%indxbnds(j) - v = DZERO - select case (obsrv%ObsTypeId) - case ('STAGE') - v = this%stage(n) - case ('TO-MVR') - v = DNODATA - if (this%imover == 1) then - v = this%pakmvrobj%get_qtomvr(n) - if (v > DZERO) then - v = -v - end if - end if - case ('FROM-MVR') - v = DNODATA - if (this%imover == 1) then - v = this%pakmvrobj%get_qfrommvr(n) - end if - case ('EXT-INFLOW') - v = this%inflow(n) - case ('INFLOW') - v = this%usflow(n) - case ('OUTFLOW') - v = this%qoutflow(n) - case ('EXT-OUTFLOW') - v = this%qextoutflow(n) - case ('RAINFALL') - v = this%rain(n) - case ('RUNOFF') - v = this%simrunoff(n) - case ('EVAPORATION') - v = this%simevap(n) - case ('SFR') - v = this%gwflow(n) - case ('UPSTREAM-FLOW') - v = this%usflow(n) - if (this%imover == 1) then - v = v + this%pakmvrobj%get_qfrommvr(n) - end if - case ('DOWNSTREAM-FLOW') - v = this%dsflow(n) - if (v > DZERO) then - v = -v - end if - case ('DEPTH') - v = this%depth(n) - case ('WET-PERIMETER') - v = this%calc_perimeter_wet(n, this%depth(n)) - case ('WET-AREA') - v = this%calc_area_wet(n, this%depth(n)) - case ('WET-WIDTH') - v = this%calc_top_width_wet(n, this%depth(n)) - case default - msg = 'Unrecognized observation type: ' // trim(obsrv%ObsTypeId) - call store_error(msg) - end select - call this%obs%SaveOneSimval(obsrv, v) - end do + !< + subroutine sfr_bd_obs(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: n + real(DP) :: v + character(len=100) :: msg + type(ObserveType), pointer :: obsrv => null() + ! + ! Write simulated values for all sfr observations + if (this%obs%npakobs > 0) then + call this%obs%obs_bd_clear() + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv + do j = 1, obsrv%indxbnds_count + n = obsrv%indxbnds(j) + v = DZERO + select case (obsrv%ObsTypeId) + case ('STAGE') + v = this%stage(n) + case ('TO-MVR') + v = DNODATA + if (this%imover == 1) then + v = this%pakmvrobj%get_qtomvr(n) + if (v > DZERO) then + v = -v + end if + end if + case ('FROM-MVR') + v = DNODATA + if (this%imover == 1) then + v = this%pakmvrobj%get_qfrommvr(n) + end if + case ('EXT-INFLOW') + v = this%inflow(n) + case ('INFLOW') + v = this%usflow(n) + case ('OUTFLOW') + v = this%qoutflow(n) + case ('EXT-OUTFLOW') + v = this%qextoutflow(n) + case ('RAINFALL') + v = this%rain(n) + case ('RUNOFF') + v = this%simrunoff(n) + case ('EVAPORATION') + v = this%simevap(n) + case ('SFR') + v = this%gwflow(n) + case ('UPSTREAM-FLOW') + v = this%usflow(n) + if (this%imover == 1) then + v = v + this%pakmvrobj%get_qfrommvr(n) + end if + case ('DOWNSTREAM-FLOW') + v = this%dsflow(n) + if (v > DZERO) then + v = -v + end if + case ('DEPTH') + v = this%depth(n) + case ('WET-PERIMETER') + v = this%calc_perimeter_wet(n, this%depth(n)) + case ('WET-AREA') + v = this%calc_area_wet(n, this%depth(n)) + case ('WET-WIDTH') + v = this%calc_top_width_wet(n, this%depth(n)) + case default + msg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId) + call store_error(msg) + end select + call this%obs%SaveOneSimval(obsrv, v) end do - ! - ! -- write summary of package error messages - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - end if + end do ! - ! -- return - return - end subroutine sfr_bd_obs - + ! -- write summary of package error messages + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + end if + ! + ! -- return + return + end subroutine sfr_bd_obs - !> @brief Read and prepare observations for a package + !> @brief Read and prepare observations for a package !! !! Method to read and prepare observations for a SFR package. !! - !< - subroutine sfr_rp_obs(this) - ! -- modules - use TdisModule, only: kper - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: nn1 - character(len=LENBOUNDNAME) :: bname - logical(LGP) :: jfound - class(ObserveType), pointer :: obsrv => null() - ! -- formats - 10 format('Boundary "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') - 30 format('Boundary name not provided for observation "',a, & - '" in package "',a,'"') - ! - ! -- process each package observation - ! only done the first stress period since boundaries are fixed - ! for the simulation - if (kper == 1) then - do i = 1, this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv - ! - ! -- get node number 1 - nn1 = obsrv%NodeNumber - if (nn1 == NAMEDBOUNDFLAG) then - bname = obsrv%FeatureName - if (bname /= '') then - ! -- Observation location(s) is(are) based on a boundary name. - ! Iterate through all boundaries to identify and store - ! corresponding index(indices) in bound array. - jfound = .false. - do j = 1, this%maxbound - if (this%boundname(j) == bname) then - jfound = .true. - call obsrv%AddObsIndex(j) - endif - enddo - if (.not. jfound) then - write(errmsg,10) trim(bname), trim(obsrv%name), trim(this%packName) - call store_error(errmsg) - endif - else - write(errmsg,30) trim(obsrv%name), trim(this%packName) + !< + subroutine sfr_rp_obs(this) + ! -- modules + use TdisModule, only: kper + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: nn1 + character(len=LENBOUNDNAME) :: bname + logical(LGP) :: jfound + class(ObserveType), pointer :: obsrv => null() + ! -- formats +10 format('Boundary "', a, '" for observation "', a, & + '" is invalid in package "', a, '"') +30 format('Boundary name not provided for observation "', a, & + '" in package "', a, '"') + ! + ! -- process each package observation + ! only done the first stress period since boundaries are fixed + ! for the simulation + if (kper == 1) then + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv + ! + ! -- get node number 1 + nn1 = obsrv%NodeNumber + if (nn1 == NAMEDBOUNDFLAG) then + bname = obsrv%FeatureName + if (bname /= '') then + ! -- Observation location(s) is(are) based on a boundary name. + ! Iterate through all boundaries to identify and store + ! corresponding index(indices) in bound array. + jfound = .false. + do j = 1, this%maxbound + if (this%boundname(j) == bname) then + jfound = .true. + call obsrv%AddObsIndex(j) + end if + end do + if (.not. jfound) then + write (errmsg, 10) & + trim(bname), trim(obsrv%name), trim(this%packName) call store_error(errmsg) - endif - else if (nn1 < 1 .or. nn1 > this%maxbound) then - write(errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - 'reach must be greater than 0 and less than or equal to', & - this%maxbound, '(specified value is ', nn1, ')' + end if + else + write (errmsg, 30) trim(obsrv%name), trim(this%packName) call store_error(errmsg) + end if + else if (nn1 < 1 .or. nn1 > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + 'reach must be greater than 0 and less than or equal to', & + this%maxbound, '(specified value is ', nn1, ')' + call store_error(errmsg) + else + if (obsrv%indxbnds_count == 0) then + call obsrv%AddObsIndex(nn1) else - if (obsrv%indxbnds_count == 0) then - call obsrv%AddObsIndex(nn1) - else - errmsg = 'Programming error in sfr_rp_obs' + errmsg = 'Programming error in sfr_rp_obs' + call store_error(errmsg) + end if + end if + ! + ! -- catch non-cumulative observation assigned to observation defined + ! by a boundname that is assigned to more than one element + if (obsrv%ObsTypeId == 'STAGE' .or. & + obsrv%ObsTypeId == 'DEPTH' .or. & + obsrv%ObsTypeId == 'WET-PERIMETER' .or. & + obsrv%ObsTypeId == 'WET-AREA' .or. & + obsrv%ObsTypeId == 'WET-WIDTH') then + nn1 = obsrv%NodeNumber + if (nn1 == NAMEDBOUNDFLAG) then + if (obsrv%indxbnds_count > 1) then + write (errmsg, '(a,3(1x,a))') & + trim(adjustl(obsrv%ObsTypeId)), & + 'for observation', trim(adjustl(obsrv%Name)), & + ' must be assigned to a reach with a unique boundname.' call store_error(errmsg) end if end if - ! - ! -- catch non-cumulative observation assigned to observation defined - ! by a boundname that is assigned to more than one element - if (obsrv%ObsTypeId == 'STAGE' .or. & - obsrv%ObsTypeId == 'DEPTH' .or. & - obsrv%ObsTypeId == 'WET-PERIMETER' .or. & - obsrv%ObsTypeId == 'WET-AREA' .or. & - obsrv%ObsTypeId == 'WET-WIDTH') then - nn1 = obsrv%NodeNumber - if (nn1 == NAMEDBOUNDFLAG) then - if (obsrv%indxbnds_count > 1) then - write(errmsg, '(a,3(1x,a))') & - trim(adjustl(obsrv%ObsTypeId)), & - 'for observation', trim(adjustl(obsrv%Name)), & - ' must be assigned to a reach with a unique boundname.' - call store_error(errmsg) - end if - end if + end if + ! + ! -- check that node number 1 is valid; call store_error if not + do j = 1, obsrv%indxbnds_count + nn1 = obsrv%indxbnds(j) + if (nn1 < 1 .or. nn1 > this%maxbound) then + write (errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), & + 'reach must be greater than 0 and less than or equal to', & + this%maxbound, '(specified value is ', nn1, ')' + call store_error(errmsg) end if - ! - ! -- check that node number 1 is valid; call store_error if not - do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) - if (nn1 < 1 .or. nn1 > this%maxbound) then - write(errmsg, '(a,1x,a,1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), & - 'reach must be greater than 0 and less than or equal to', & - this%maxbound, '(specified value is ', nn1, ')' - call store_error(errmsg) - end if - end do end do - ! - ! -- evaluate if there are any observation errors - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - end if + end do ! - ! -- return - return - end subroutine sfr_rp_obs - + ! -- evaluate if there are any observation errors + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + end if ! - ! -- Procedures related to observations (NOT type-bound) + ! -- return + return + end subroutine sfr_rp_obs + + ! + ! -- Procedures related to observations (NOT type-bound) - !> @brief Process observation IDs for a package + !> @brief Process observation IDs for a package !! !! Method to process observation ID strings for a SFR package. !! - !< - subroutine sfr_process_obsID(obsrv, dis, inunitobs, iout) - ! -- dummy variables - type(ObserveType), intent(inout) :: obsrv !< Observation object - class(DisBaseType), intent(in) :: dis !< Discretization object - integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file - integer(I4B), intent(in) :: iout !< model listing file unit number - ! -- local variables - integer(I4B) :: nn1 - integer(I4B) :: icol - integer(I4B) :: istart - integer(I4B) :: istop - character(len=LINELENGTH) :: strng - character(len=LENBOUNDNAME) :: bndname - ! - ! -- initialize local variables - strng = obsrv%IDstring - ! - ! -- Extract reach number from strng and store it. - ! If 1st item is not an integer(I4B), it should be a - ! boundary name--deal with it. - icol = 1 - ! - ! -- get reach number or boundary name - call extract_idnum_or_bndname(strng, icol, istart, istop, nn1, bndname) - if (nn1 == NAMEDBOUNDFLAG) then - obsrv%FeatureName = bndname - endif - ! - ! -- store reach number (NodeNumber) - obsrv%NodeNumber = nn1 - ! - ! -- return - return - end subroutine sfr_process_obsID - + !< + subroutine sfr_process_obsID(obsrv, dis, inunitobs, iout) + ! -- dummy variables + type(ObserveType), intent(inout) :: obsrv !< Observation object + class(DisBaseType), intent(in) :: dis !< Discretization object + integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file + integer(I4B), intent(in) :: iout !< model listing file unit number + ! -- local variables + integer(I4B) :: nn1 + integer(I4B) :: icol + integer(I4B) :: istart + integer(I4B) :: istop + character(len=LINELENGTH) :: strng + character(len=LENBOUNDNAME) :: bndname + ! + ! -- initialize local variables + strng = obsrv%IDstring + ! + ! -- Extract reach number from strng and store it. + ! If 1st item is not an integer(I4B), it should be a + ! boundary name--deal with it. + icol = 1 ! - ! -- private sfr methods + ! -- get reach number or boundary name + call extract_idnum_or_bndname(strng, icol, istart, istop, nn1, bndname) + if (nn1 == NAMEDBOUNDFLAG) then + obsrv%FeatureName = bndname + end if ! + ! -- store reach number (NodeNumber) + obsrv%NodeNumber = nn1 + ! + ! -- return + return + end subroutine sfr_process_obsID + + ! + ! -- private sfr methods + ! - !> @brief Set period data + !> @brief Set period data !! !! Method to read and set period data for a SFR package reach. !! - !< - subroutine sfr_set_stressperiod(this, n, ichkustrm, crossfile) - ! -- modules - use TimeSeriesManagerModule, only: read_value_or_time_series_adv - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - integer(I4B), intent(inout) :: ichkustrm !< flag indicating if upstream fraction data specified - character(len=LINELENGTH), intent(inout) :: crossfile !< cross-section file name - ! -- local variables - character(len=10) :: cnum - character(len=LINELENGTH) :: text - character(len=LINELENGTH) :: caux - character(len=LINELENGTH) :: keyword - integer(I4B) :: ival - integer(I4B) :: ii - integer(I4B) :: jj - integer(I4B) :: idiv - integer(I4B) :: ixserror - character (len=10) :: cp - real(DP) :: divq - real(DP), pointer :: bndElem => null() + !< + subroutine sfr_set_stressperiod(this, n, ichkustrm, crossfile) + ! -- modules + use TimeSeriesManagerModule, only: read_value_or_time_series_adv + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + integer(I4B), intent(inout) :: ichkustrm !< flag indicating if upstream fraction data specified + character(len=LINELENGTH), intent(inout) :: crossfile !< cross-section file name + ! -- local variables + character(len=10) :: cnum + character(len=LINELENGTH) :: text + character(len=LINELENGTH) :: caux + character(len=LINELENGTH) :: keyword + integer(I4B) :: ival + integer(I4B) :: ii + integer(I4B) :: jj + integer(I4B) :: idiv + integer(I4B) :: ixserror + character(len=10) :: cp + real(DP) :: divq + real(DP), pointer :: bndElem => null() + ! + ! -- initialize variables + crossfile = 'NONE' + ! + ! -- read line + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('STATUS') + ichkustrm = 1 + call this%parser%GetStringCaps(text) + if (text == 'INACTIVE') then + this%iboundpak(n) = 0 + else if (text == 'ACTIVE') then + this%iboundpak(n) = 1 + else if (text == 'SIMPLE') then + this%iboundpak(n) = -1 + else + write (errmsg, '(2a)') & + 'Unknown '//trim(this%text)//' sfr status keyword: ', trim(text) + call store_error(errmsg) + end if + case ('MANNING') + call this%parser%GetString(text) + jj = 1 ! For 'MANNING' + bndElem => this%rough(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'MANNING') + case ('STAGE') + call this%parser%GetString(text) + jj = 1 ! For 'STAGE' + bndElem => this%sstage(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'STAGE') + case ('RAINFALL') + call this%parser%GetString(text) + jj = 1 ! For 'RAIN' + bndElem => this%rain(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'RAIN') + case ('EVAPORATION') + call this%parser%GetString(text) + jj = 1 ! For 'EVAP' + bndElem => this%evap(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'MANNING') + case ('RUNOFF') + call this%parser%GetString(text) + jj = 1 ! For 'RUNOFF' + bndElem => this%runoff(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'RUNOFF') + case ('INFLOW') + call this%parser%GetString(text) + jj = 1 ! For 'INFLOW' + bndElem => this%inflow(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'INFLOW') + case ('DIVERSION') + ! + ! -- make sure reach has at least one diversion + if (this%ndiv(n) < 1) then + write (cnum, '(i0)') n + errmsg = 'diversions cannot be specified for reach '//trim(cnum) + call store_error(errmsg) + end if ! - ! -- initialize variables - crossfile = 'NONE' + ! -- read diversion number + ival = this%parser%GetInteger() + if (ival < 1 .or. ival > this%ndiv(n)) then + write (cnum, '(i0)') n + errmsg = 'Reach '//trim(cnum) + write (cnum, '(i0)') this%ndiv(n) + errmsg = trim(errmsg)//' diversion number should be between 1 '// & + 'and '//trim(cnum)//'.' + call store_error(errmsg) + end if + idiv = ival + ! + ! -- read value + call this%parser%GetString(text) + ii = this%iadiv(n) + idiv - 1 + jj = 1 ! For 'DIVERSION' + bndElem => this%divflow(ii) + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, & + 'DIVFLOW') + ! + ! -- if diversion cprior is 'fraction', ensure that 0.0 <= fraction <= 1.0 + cp = this%divcprior(ii) + divq = this%divflow(ii) + if (cp == 'FRACTION' .and. (divq < DZERO .or. divq > DONE)) then + write (errmsg, '(a,1x,i0,a)') & + 'cprior is type FRACTION for diversion no.', ii, & + ', but divflow not within the range 0.0 to 1.0' + call store_error(errmsg) + end if + case ('UPSTREAM_FRACTION') + ichkustrm = 1 + call this%parser%GetString(text) + jj = 1 ! For 'USTRF' + bndElem => this%ustrf(n) + call read_value_or_time_series_adv(text, n, jj, bndElem, & + this%packName, 'BND', & + this%tsManager, this%iprpak, 'USTRF') + + case ('CROSS_SECTION') + ixserror = 0 ! - ! -- read line + ! -- read FILE keyword call this%parser%GetStringCaps(keyword) select case (keyword) - case ('STATUS') - ichkustrm = 1 - call this%parser%GetStringCaps(text) - if (text == 'INACTIVE') then - this%iboundpak(n) = 0 - else if (text == 'ACTIVE') then - this%iboundpak(n) = 1 - else if (text == 'SIMPLE') then - this%iboundpak(n) = -1 - else - write(errmsg,'(2a)') & - 'Unknown ' // trim(this%text) // ' sfr status keyword: ', trim(text) - call store_error(errmsg) - end if - case ('MANNING') - call this%parser%GetString(text) - jj = 1 ! For 'MANNING' - bndElem => this%rough(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'MANNING') - case ('STAGE') - call this%parser%GetString(text) - jj = 1 ! For 'STAGE' - bndElem => this%sstage(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'STAGE') - case ('RAINFALL') - call this%parser%GetString(text) - jj = 1 ! For 'RAIN' - bndElem => this%rain(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RAIN') - case ('EVAPORATION') - call this%parser%GetString(text) - jj = 1 ! For 'EVAP' - bndElem => this%evap(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'MANNING') - case ('RUNOFF') - call this%parser%GetString(text) - jj = 1 ! For 'RUNOFF' - bndElem => this%runoff(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RUNOFF') - case ('INFLOW') - call this%parser%GetString(text) - jj = 1 ! For 'INFLOW' - bndElem => this%inflow(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'INFLOW') - case ('DIVERSION') - ! - ! -- make sure reach has at least one diversion - if (this%ndiv(n) < 1) then - write(cnum, '(i0)') n - errmsg = 'diversions cannot be specified for reach ' // trim(cnum) - call store_error(errmsg) - end if - ! - ! -- read diversion number - ival = this%parser%GetInteger() - if (ival < 1 .or. ival > this%ndiv(n)) then - write(cnum, '(i0)') n - errmsg = 'Reach ' // trim(cnum) - write(cnum, '(i0)') this%ndiv(n) - errmsg = trim(errmsg) // ' diversion number should be between 1 ' // & - 'and ' // trim(cnum) // '.' - call store_error(errmsg) - end if - idiv = ival - ! - ! -- read value - call this%parser%GetString(text) - ii = this%iadiv(n) + idiv - 1 - jj = 1 ! For 'DIVERSION' - bndElem => this%divflow(ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'DIVFLOW') - ! - ! -- if diversion cprior is 'fraction', ensure that 0.0 <= fraction <= 1.0 - cp = this%divcprior(ii) - divq = this%divflow(ii) - if (cp == 'FRACTION' .and. (divq < DZERO .or. divq > DONE)) then - write(errmsg,'(a,1x,i0,a)') & - 'cprior is type FRACTION for diversion no.', ii, & - ', but divflow not within the range 0.0 to 1.0' - call store_error(errmsg) - endif - case ('UPSTREAM_FRACTION') - ichkustrm = 1 - call this%parser%GetString(text) - jj = 1 ! For 'USTRF' - bndElem => this%ustrf(n) - call read_value_or_time_series_adv(text, n, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'USTRF') - - case ('CROSS_SECTION') - ixserror = 0 - ! - ! -- read FILE keyword - call this%parser%GetStringCaps(keyword) - select case (keyword) - case('TAB6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TAB6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - ixserror = 1 - end if - if (ixserror == 0) then - call this%parser%GetString(crossfile) - end if - case default - write(errmsg,'(a,1x,i4,1x,a)') & - 'CROSS-SECTION TABLE ENTRY for REACH ', n, & - 'MUST INCLUDE TAB6 KEYWORD' - call store_error(errmsg) - end select - - case ('AUXILIARY') - call this%parser%GetStringCaps(caux) - do jj = 1, this%naux - if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle - call this%parser%GetString(text) - ii = n - bndElem => this%rauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & - this%auxname(jj)) - exit - end do - - case default - write(errmsg,'(a,a)') & - 'Unknown ' // trim(this%text) // ' sfr data keyword: ', & - trim(keyword) // '.' + case ('TAB6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TAB6 keyword must be followed by "FILEIN" '// & + 'then by filename.' call store_error(errmsg) + ixserror = 1 + end if + if (ixserror == 0) then + call this%parser%GetString(crossfile) + end if + case default + write (errmsg, '(a,1x,i4,1x,a)') & + 'CROSS-SECTION TABLE ENTRY for REACH ', n, & + 'MUST INCLUDE TAB6 KEYWORD' + call store_error(errmsg) end select - ! - ! -- return - return - end subroutine sfr_set_stressperiod + case ('AUXILIARY') + call this%parser%GetStringCaps(caux) + do jj = 1, this%naux + if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle + call this%parser%GetString(text) + ii = n + bndElem => this%rauxvar(jj, ii) + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & + this%auxname(jj)) + exit + end do + + case default + write (errmsg, '(a,a)') & + 'Unknown '//trim(this%text)//' sfr data keyword: ', & + trim(keyword)//'.' + call store_error(errmsg) + end select + ! + ! -- return + return + end subroutine sfr_set_stressperiod - !> @brief Solve reach continuity equation + !> @brief Solve reach continuity equation !! !! Method to solve the continuity equation for a SFR package reach. !! - !< - subroutine sfr_solve(this, n, h, hcof, rhs, update) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: h !< groundwater head in cell connected to reach - real(DP), intent(inout) :: hcof !< coefficient term added to the diagonal - real(DP), intent(inout) :: rhs !< right-hand side term - logical(LGP), intent(in), optional :: update !< boolean indicating if the reach depth and stage variables should be updated to current iterate - ! -- local variables - logical(LGP) :: lupdate - integer(I4B) :: i - integer(I4B) :: ii - integer(I4B) :: n2 - integer(I4B) :: isolve - integer(I4B) :: iic - integer(I4B) :: iic2 - integer(I4B) :: iic3 - integer(I4B) :: iic4 - integer(I4B) :: ibflg - real(DP) :: hgwf - real(DP) :: sa - real(DP) :: qu - real(DP) :: qi - real(DP) :: qr - real(DP) :: qe - real(DP) :: qro - real(DP) :: qmp - real(DP) :: qsrc - real(DP) :: qfrommvr - real(DP) :: qgwf - real(DP) :: qmpsrc - real(DP) :: qc - real(DP) :: qt - real(DP) :: tp - real(DP) :: bt - real(DP) :: hsfr - real(DP) :: cstr - real(DP) :: qd - real(DP) :: en1 - real(DP) :: en2 - real(DP) :: qen1 - real(DP) :: f1, f2 - real(DP) :: qgwf1 - real(DP) :: qgwf2 - real(DP) :: qgwfp - real(DP) :: qgwfold - real(DP) :: fhstr1 - real(DP) :: fhstr2 - real(DP) :: d1 - real(DP) :: d2 - real(DP) :: dpp - real(DP) :: dx - real(DP) :: q1 - real(DP) :: q2 - real(DP) :: derv - real(DP) :: dlh - real(DP) :: dlhold - real(DP) :: fp - real(DP) :: err - real(DP) :: errold - real(DP) :: sumleak - real(DP) :: sumrch - real(DP) :: gwfhcof - real(DP) :: gwfrhs - ! - ! -- Process optional dummy variables - if (present(update)) then - lupdate = update - else - lupdate = .true. - end if - ! - ! -- calculate hgwf - hgwf = h - ! - ! - hcof = DZERO - rhs = DZERO - ! - ! -- initialize d1, d2, q1, q2, qsrc, and qgwf - d1 = DZERO - d2 = DZERO - q1 = DZERO - q2 = DZERO - qsrc = DZERO - qgwf = DZERO - qgwfold = DZERO - ! - ! -- calculate initial depth assuming a wide cross-section and ignore - ! groundwater leakage - ! -- calculate upstream flow - qu = DZERO - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) < 0) cycle - n2 = this%ja(i) - do ii = this%ia(n2) + 1, this%ia(n2+1) - 1 - if (this%idir(ii) > 0) cycle - if (this%ja(ii) /= n) cycle - qu = qu + this%qconn(ii) - end do + !< + subroutine sfr_solve(this, n, h, hcof, rhs, update) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: h !< groundwater head in cell connected to reach + real(DP), intent(inout) :: hcof !< coefficient term added to the diagonal + real(DP), intent(inout) :: rhs !< right-hand side term + logical(LGP), intent(in), optional :: update !< boolean indicating if the reach depth and stage variables should be updated to current iterate + ! -- local variables + logical(LGP) :: lupdate + integer(I4B) :: i + integer(I4B) :: ii + integer(I4B) :: n2 + integer(I4B) :: isolve + integer(I4B) :: iic + integer(I4B) :: iic2 + integer(I4B) :: iic3 + integer(I4B) :: iic4 + integer(I4B) :: ibflg + real(DP) :: hgwf + real(DP) :: sa + real(DP) :: qu + real(DP) :: qi + real(DP) :: qr + real(DP) :: qe + real(DP) :: qro + real(DP) :: qmp + real(DP) :: qsrc + real(DP) :: qfrommvr + real(DP) :: qgwf + real(DP) :: qmpsrc + real(DP) :: qc + real(DP) :: qt + real(DP) :: tp + real(DP) :: bt + real(DP) :: hsfr + real(DP) :: cstr + real(DP) :: qd + real(DP) :: en1 + real(DP) :: en2 + real(DP) :: qen1 + real(DP) :: f1, f2 + real(DP) :: qgwf1 + real(DP) :: qgwf2 + real(DP) :: qgwfp + real(DP) :: qgwfold + real(DP) :: fhstr1 + real(DP) :: fhstr2 + real(DP) :: d1 + real(DP) :: d2 + real(DP) :: dpp + real(DP) :: dx + real(DP) :: q1 + real(DP) :: q2 + real(DP) :: derv + real(DP) :: dlh + real(DP) :: dlhold + real(DP) :: fp + real(DP) :: err + real(DP) :: errold + real(DP) :: sumleak + real(DP) :: sumrch + real(DP) :: gwfhcof + real(DP) :: gwfrhs + ! + ! -- Process optional dummy variables + if (present(update)) then + lupdate = update + else + lupdate = .true. + end if + ! + ! -- calculate hgwf + hgwf = h + ! + ! + hcof = DZERO + rhs = DZERO + ! + ! -- initialize d1, d2, q1, q2, qsrc, and qgwf + d1 = DZERO + d2 = DZERO + q1 = DZERO + q2 = DZERO + qsrc = DZERO + qgwf = DZERO + qgwfold = DZERO + ! + ! -- calculate initial depth assuming a wide cross-section and ignore + ! groundwater leakage + ! -- calculate upstream flow + qu = DZERO + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) < 0) cycle + n2 = this%ja(i) + do ii = this%ia(n2) + 1, this%ia(n2 + 1) - 1 + if (this%idir(ii) > 0) cycle + if (this%ja(ii) /= n) cycle + qu = qu + this%qconn(ii) end do - this%usflow(n) = qu - ! -- calculate remaining terms - sa = this%calc_surface_area(n) - qi = this%inflow(n) - qr = this%rain(n) * sa - qe = this%evap(n) * sa - qro = this%runoff(n) - ! - ! -- Water mover term; assume that it goes in at the upstream end of the reach - qfrommvr = DZERO - if(this%imover == 1) then - qfrommvr = this%pakmvrobj%get_qfrommvr(n) - endif + end do + this%usflow(n) = qu + ! -- calculate remaining terms + sa = this%calc_surface_area(n) + qi = this%inflow(n) + qr = this%rain(n) * sa + qe = this%evap(n) * sa + qro = this%runoff(n) + ! + ! -- Water mover term; assume that it goes in at the upstream end of the reach + qfrommvr = DZERO + if (this%imover == 1) then + qfrommvr = this%pakmvrobj%get_qfrommvr(n) + end if + ! + ! -- calculate sum of sources to the reach excluding groundwater leakage + qc = qu + qi + qr - qe + qro + qfrommvr + ! + ! -- adjust runoff or evaporation if sum of sources is negative + if (qc < DZERO) then ! - ! -- calculate sum of sources to the reach excluding groundwater leakage - qc = qu + qi + qr - qe + qro + qfrommvr + ! -- calculate sources without et + qt = qu + qi + qr + qro + qfrommvr ! - ! -- adjust runoff or evaporation if sum of sources is negative - if (qc < DZERO) then - ! - ! -- calculate sources without et - qt = qu + qi + qr + qro + qfrommvr - ! - ! -- runoff exceeds sources of water for reach - if (qt < DZERO) then - qro = -(qu + qi + qr + qfrommvr) - qe = DZERO + ! -- runoff exceeds sources of water for reach + if (qt < DZERO) then + qro = -(qu + qi + qr + qfrommvr) + qe = DZERO ! ! -- evaporation exceeds sources of water for reach + else + qe = qu + qi + qr + qro + qfrommvr + end if + qc = qu + qi + qr - qe + qro + qfrommvr + end if + ! + ! -- set simulated evaporation and runoff + this%simevap(n) = qe + this%simrunoff(n) = qro + ! + ! -- calculate flow at the middle of the reach and excluding groundwater leakage + qmp = qu + qi + qfrommvr + DHALF * (qr - qe + qro) + qmpsrc = qmp + ! + ! -- calculate stream depth at the midpoint + if (this%iboundpak(n) > 0) then + call this%sfr_calc_reach_depth(n, qmp, d1) + else + this%stage(n) = this%sstage(n) + d1 = max(DZERO, this%stage(n) - this%strtop(n)) + end if + ! + ! -- calculate sources/sinks for reach excluding groundwater leakage + call this%sfr_calc_qsource(n, d1, qsrc) + ! + ! -- calculate initial reach stage, downstream flow, and groundwater leakage + tp = this%strtop(n) + bt = tp - this%bthick(n) + hsfr = d1 + tp + qd = MAX(qsrc, DZERO) + qgwf = DZERO + ! + ! -- calculate reach conductance for a unit depth of water + ! if equal to zero will skip iterations + call this%sfr_calc_cond(n, d1, cstr, hsfr, hgwf) + ! + ! -- set flag to skip iterations + isolve = 1 + if (hsfr <= tp .and. hgwf <= tp) isolve = 0 + if (hgwf <= tp .and. qc < DEM30) isolve = 0 + if (cstr < DEM30) isolve = 0 + if (this%iboundpak(n) < 0) isolve = 0 + ! + ! -- iterate to achieve solution + itersol: if (isolve /= 0) then + ! + ! -- estimate initial end points + en1 = DZERO + if (d1 > DEM30) then + if ((tp - hgwf) > DEM30) then + en2 = DP9 * d1 else - qe = qu + qi + qr + qro + qfrommvr + en2 = D1P1 * d1 - (tp - hgwf) end if - qc = qu + qi + qr - qe + qro + qfrommvr + else if ((tp - hgwf) > DEM30) then + en2 = DONE + else + en2 = DP99 * (hgwf - tp) end if ! - ! -- set simulated evaporation and runoff - this%simevap(n) = qe - this%simrunoff(n) = qro - ! - ! -- calculate flow at the middle of the reach and excluding groundwater leakage - qmp = qu + qi + qfrommvr + DHALF * (qr - qe + qro) - qmpsrc = qmp - ! - ! -- calculate stream depth at the midpoint - if (this%iboundpak(n) > 0) then - call this%sfr_calc_reach_depth(n, qmp, d1) + ! -- estimate flow at end points + ! -- end point 1 + if (hgwf > tp) then + call this%sfr_calc_qgwf(n, DZERO, hgwf, qgwf1) + qgwf1 = -qgwf1 + qen1 = qmp - DHALF * qgwf1 else - this%stage(n) = this%sstage(n) - d1 = max(DZERO, this%stage(n) - this%strtop(n)) + qgwf1 = DZERO + qen1 = qmpsrc end if - ! - ! -- calculate sources/sinks for reach excluding groundwater leakage - call this%sfr_calc_qsource(n, d1, qsrc) - ! - ! -- calculate initial reach stage, downstream flow, and groundwater leakage - tp = this%strtop(n) - bt = tp - this%bthick(n) - hsfr = d1 + tp - qd = MAX(qsrc, DZERO) - qgwf = DZERO - ! - ! -- calculate reach conductance for a unit depth of water - ! if equal to zero will skip iterations - call this%sfr_calc_cond(n, d1, cstr) - ! - ! -- set flag to skip iterations - isolve = 1 - if (hsfr <= tp .and. hgwf <= tp) isolve = 0 - if (hgwf <= tp .and. qc < DEM30) isolve = 0 - if (cstr < DEM30) isolve = 0 - if (this%iboundpak(n) < 0) isolve = 0 - ! - ! -- iterate to achieve solution - itersol: if (isolve /= 0) then - ! - ! -- estimate initial end points + if (hgwf > bt) then + call this%sfr_calc_qgwf(n, en2, hgwf, qgwf2) + qgwf2 = -qgwf2 + else + call this%sfr_calc_qgwf(n, en2, bt, qgwf2) + qgwf2 = -qgwf2 + end if + if (qgwf2 > qsrc) qgwf2 = qsrc + ! -- calculate two depths + call this%sfr_calc_reach_depth(n, (qmpsrc - DHALF * qgwf1), d1) + call this%sfr_calc_reach_depth(n, (qmpsrc - DHALF * qgwf2), d2) + ! -- determine roots + if (d1 > DEM30) then + f1 = en1 - d1 + else en1 = DZERO - if (d1 > DEM30) then - if ((tp - hgwf) > DEM30) then - en2 = DP9 * d1 - else - en2 = D1P1 * d1 - (tp - hgwf) - end if - else if ((tp - hgwf) > DEM30) then - en2 = DONE - else - en2 = DP99 * (hgwf - tp) - end if + f1 = en1 - DZERO + end if + if (d2 > DEM30) then + f2 = en2 - d2 + if (f2 < DEM30) en2 = d2 + else + d2 = DZERO + f2 = en2 - DZERO + end if + ! + ! -- iterate to find a solution + dpp = DHALF * (en1 + en2) + dx = dpp + iic = 0 + iic2 = 0 + iic3 = 0 + fhstr1 = DZERO + fhstr2 = DZERO + qgwfp = DZERO + dlhold = DZERO + do i = 1, this%maxsfrit + ibflg = 0 + d1 = dpp + d2 = d1 + DTWO * this%deps + ! -- calculate q at midpoint at both end points + call this%sfr_calc_qman(n, d1, q1) + call this%sfr_calc_qman(n, d2, q2) + ! -- calculate groundwater leakage at both end points + call this%sfr_calc_qgwf(n, d1, hgwf, qgwf1) + qgwf1 = -qgwf1 + call this%sfr_calc_qgwf(n, d2, hgwf, qgwf2) + qgwf2 = -qgwf2 ! - ! -- estimate flow at end points - ! -- end point 1 - if (hgwf > tp) then - call this%sfr_calc_qgwf(n, DZERO, hgwf, qgwf1) - qgwf1 = -qgwf1 - qen1 = qmp - DHALF * qgwf1 - else - qgwf1 = DZERO - qen1 = qmpsrc - end if - if (hgwf > bt) then - call this%sfr_calc_qgwf(n, en2, hgwf, qgwf2) - qgwf2 = -qgwf2 - else - call this%sfr_calc_qgwf(n, en2, bt, qgwf2) - qgwf2 = -qgwf2 - end if - if (qgwf2 > qsrc) qgwf2 = qsrc - ! -- calculate two depths - call this%sfr_calc_reach_depth(n, (qmpsrc-DHALF*qgwf1), d1) - call this%sfr_calc_reach_depth(n, (qmpsrc-DHALF*qgwf2), d2) - ! -- determine roots - if (d1 > DEM30) then - f1 = en1 - d1 - else - en1 = DZERO - f1 = en1 - DZERO - end if - if (d2 > DEM30) then - f2 = en2 - d2 - if (f2 < DEM30) en2 = d2 + if (qgwf1 >= qsrc) then + en2 = dpp + dpp = DHALF * (en1 + en2) + call this%sfr_calc_qgwf(n, dpp, hgwf, qgwfp) + qgwfp = -qgwfp + if (qgwfp > qsrc) qgwfp = qsrc + call this%sfr_calc_reach_depth(n, (qmpsrc - DHALF * qgwfp), dx) + ibflg = 1 else - d2 = DZERO - f2 = en2 - DZERO + fhstr1 = (qmpsrc - DHALF * qgwf1) - q1 + fhstr2 = (qmpsrc - DHALF * qgwf2) - q2 end if ! - ! -- iterate to find a solution - dpp = DHALF * (en1 + en2) - dx = dpp - iic = 0 - iic2 = 0 - iic3 = 0 - fhstr1 = DZERO - fhstr2 = DZERO - qgwfp = DZERO - dlhold = DZERO - do i = 1, this%maxsfrit - ibflg = 0 - d1 = dpp - d2 = d1 + DTWO * this%deps - ! -- calculate q at midpoint at both end points - call this%sfr_calc_qman(n, d1, q1) - call this%sfr_calc_qman(n, d2, q2) - ! -- calculate groundwater leakage at both end points - call this%sfr_calc_qgwf(n, d1, hgwf, qgwf1) - qgwf1 = -qgwf1 - call this%sfr_calc_qgwf(n, d2, hgwf, qgwf2) - qgwf2 = -qgwf2 - ! - if (qgwf1 >= qsrc) then - en2 = dpp - dpp = DHALF * (en1 + en2) - call this%sfr_calc_qgwf(n, dpp, hgwf, qgwfp) - qgwfp = -qgwfp - if (qgwfp > qsrc) qgwfp = qsrc - call this%sfr_calc_reach_depth(n, (qmpsrc-DHALF*qgwfp), dx) - ibflg = 1 - else - fhstr1 = (qmpsrc-DHALF*qgwf1) - q1 - fhstr2 = (qmpsrc-DHALF*qgwf2) - q2 + if (ibflg == 0) then + derv = DZERO + if (abs(d1 - d2) > DZERO) then + derv = (fhstr1 - fhstr2) / (d1 - d2) end if - ! - if (ibflg == 0) then - derv = DZERO - if (abs(d1-d2) > DZERO) then - derv = (fhstr1-fhstr2) / (d1 - d2) - end if - if (abs(derv) > DEM30) then - dlh = -fhstr1 / derv - else - dlh = DZERO - end if - dpp = d1 + dlh - ! - ! -- updated depth outside of endpoints - use bisection instead - if ((dpp >= en2) .or. (dpp <= en1)) then - if (abs(dlh) > abs(dlhold) .or. dpp < DEM30) then - ibflg = 1 - dpp = DHALF * (en1 + en2) - end if - end if - ! - ! -- check for slow convergence - ! -- set flags to determine if the Newton-Raphson method oscillates - ! or if convergence is slow - if (qgwf1*qgwfold < DEM30) then - iic2 = iic2 + 1 - else - iic2 = 0 - end if - if (qgwf1 < DEM30) then - iic3 = iic3 + 1 - else - iic3 = 0 - end if - if (dlh*dlhold < DEM30 .or. ABS(dlh) > ABS(dlhold)) then - iic = iic + 1 - end if - iic4 = 0 - if (iic3 > 7 .and. iic > 12) then - iic4 = 1 - end if - ! - ! -- switch to bisection when the Newton-Raphson method oscillates - ! or when convergence is slow - if (iic2 > 7 .or. iic > 12 .or. iic4 == 1) then + if (abs(derv) > DEM30) then + dlh = -fhstr1 / derv + else + dlh = DZERO + end if + dpp = d1 + dlh + ! + ! -- updated depth outside of endpoints - use bisection instead + if ((dpp >= en2) .or. (dpp <= en1)) then + if (abs(dlh) > abs(dlhold) .or. dpp < DEM30) then ibflg = 1 dpp = DHALF * (en1 + en2) end if - ! - ! -- Calculate perturbed gwf flow - call this%sfr_calc_qgwf(n, dpp, hgwf, qgwfp) - qgwfp = -qgwfp - if (qgwfp > qsrc) then - qgwfp = qsrc - if (abs(en1-en2) < this%dmaxchg*DEM6) then - call this%sfr_calc_reach_depth(n, (qmpsrc-DHALF*qgwfp), dpp) - end if - end if - call this%sfr_calc_reach_depth(n, (qmpsrc-DHALF*qgwfp), dx) end if ! - ! -- bisection to update end points - fp = dpp - dx - if (ibflg == 1) then - dlh = fp - ! -- change end points - ! -- root is between f1 and fp - if (f1*fp < DZERO) then - en2 = dpp - f2 = fp - ! -- root is between fp and f2 - else - en1 = dpp - f1 = fp - end if - err = min(abs(fp), abs(en2-en1)) + ! -- check for slow convergence + ! -- set flags to determine if the Newton-Raphson method oscillates + ! or if convergence is slow + if (qgwf1 * qgwfold < DEM30) then + iic2 = iic2 + 1 + else + iic2 = 0 + end if + if (qgwf1 < DEM30) then + iic3 = iic3 + 1 else - err = abs(dlh) + iic3 = 0 + end if + if (dlh * dlhold < DEM30 .or. ABS(dlh) > ABS(dlhold)) then + iic = iic + 1 + end if + iic4 = 0 + if (iic3 > 7 .and. iic > 12) then + iic4 = 1 end if ! - ! -- check for convergence and exit if converged - if (err < this%dmaxchg) then - d1 = dpp - qgwf = qgwfp - qd = qsrc - qgwf - exit + ! -- switch to bisection when the Newton-Raphson method oscillates + ! or when convergence is slow + if (iic2 > 7 .or. iic > 12 .or. iic4 == 1) then + ibflg = 1 + dpp = DHALF * (en1 + en2) end if ! - ! -- save iterates - errold = err - dlhold = dlh - if (ibflg == 1) then - qgwfold = qgwfp - else - qgwfold = qgwf1 + ! -- Calculate perturbed gwf flow + call this%sfr_calc_qgwf(n, dpp, hgwf, qgwfp) + qgwfp = -qgwfp + if (qgwfp > qsrc) then + qgwfp = qsrc + if (abs(en1 - en2) < this%dmaxchg * DEM6) then + call this%sfr_calc_reach_depth(n, (qmpsrc - DHALF * qgwfp), dpp) + end if end if + call this%sfr_calc_reach_depth(n, (qmpsrc - DHALF * qgwfp), dx) + end if ! - ! -- end of iteration - end do - end if itersol - - ! -- simple routing option or where depth = 0 and hgwf < bt - if (isolve == 0) then - call this%sfr_calc_qgwf(n, d1, hgwf, qgwf) - qgwf = -qgwf + ! -- bisection to update end points + fp = dpp - dx + if (ibflg == 1) then + dlh = fp + ! -- change end points + ! -- root is between f1 and fp + if (f1 * fp < DZERO) then + en2 = dpp + f2 = fp + ! -- root is between fp and f2 + else + en1 = dpp + f1 = fp + end if + err = min(abs(fp), abs(en2 - en1)) + else + err = abs(dlh) + end if ! - ! -- leakage exceeds inflow - if (qgwf > qsrc) then - d1 = DZERO - call this%sfr_calc_qsource(n, d1, qsrc) - qgwf = qsrc + ! -- check for convergence and exit if converged + if (err < this%dmaxchg) then + d1 = dpp + qgwf = qgwfp + qd = qsrc - qgwf + exit end if - ! -- set qd - qd = qsrc - qgwf - end if - ! - ! -- update sfr stage - hsfr = tp + d1 - ! - ! -- update stored values - if (lupdate) then ! - ! -- save depth and calculate stage - this%depth(n) = d1 - this%stage(n) = hsfr + ! -- save iterates + errold = err + dlhold = dlh + if (ibflg == 1) then + qgwfold = qgwfp + else + qgwfold = qgwf1 + end if ! - ! -- update flows - call this%sfr_update_flows(n, qd, qgwf) - end if + ! -- end of iteration + end do + end if itersol + + ! -- simple routing option or where depth = 0 and hgwf < bt + if (isolve == 0) then + call this%sfr_calc_qgwf(n, d1, hgwf, qgwf) + qgwf = -qgwf ! - ! -- calculate sumleak and sumrch - sumleak = DZERO - sumrch = DZERO - if (this%gwfiss == 0) then - sumleak = qgwf - else - sumleak = qgwf - end if - if (hgwf < bt) then - sumrch = qgwf + ! -- leakage exceeds inflow + if (qgwf > qsrc) then + d1 = DZERO + call this%sfr_calc_qsource(n, d1, qsrc) + qgwf = qsrc end if + ! -- set qd + qd = qsrc - qgwf + end if + ! + ! -- update sfr stage + hsfr = tp + d1 + ! + ! -- update stored values + if (lupdate) then ! - ! -- make final qgwf calculation and obtain - ! gwfhcof and gwfrhs values - call this%sfr_calc_qgwf(n, d1, hgwf, qgwf, gwfhcof, gwfrhs) - ! + ! -- save depth and calculate stage + this%depth(n) = d1 + this%stage(n) = hsfr ! - if (abs(sumleak) > DZERO) then - ! -- stream leakage is not head dependent - if (hgwf < bt) then - rhs = rhs - sumrch + ! -- update flows + call this%sfr_update_flows(n, qd, qgwf) + end if + ! + ! -- calculate sumleak and sumrch + sumleak = DZERO + sumrch = DZERO + if (this%gwfiss == 0) then + sumleak = qgwf + else + sumleak = qgwf + end if + if (hgwf < bt) then + sumrch = qgwf + end if + ! + ! -- make final qgwf calculation and obtain + ! gwfhcof and gwfrhs values + call this%sfr_calc_qgwf(n, d1, hgwf, qgwf, gwfhcof, gwfrhs) + ! + ! + if (abs(sumleak) > DZERO) then + ! -- stream leakage is not head dependent + if (hgwf < bt) then + rhs = rhs - sumrch ! ! -- stream leakage is head dependent - else if ((sumleak-qsrc) < -DEM30) then - if (this%gwfiss == 0) then - rhs = rhs + gwfrhs - sumrch - else - rhs = rhs + gwfrhs - end if - hcof = gwfhcof + else if ((sumleak - qsrc) < -DEM30) then + if (this%gwfiss == 0) then + rhs = rhs + gwfrhs - sumrch + else + rhs = rhs + gwfrhs + end if + hcof = gwfhcof ! ! -- place holder for UZF + else + if (this%gwfiss == 0) then + rhs = rhs - sumleak - sumrch else - if (this%gwfiss == 0) then - rhs = rhs - sumleak - sumrch - else - rhs = rhs - sumleak - end if + rhs = rhs - sumleak end if - ! - ! -- add groundwater leakage - else if (hgwf < bt) then - rhs = rhs - sumrch end if ! - ! -- return - return - end subroutine sfr_solve + ! -- add groundwater leakage + else if (hgwf < bt) then + rhs = rhs - sumrch + end if + ! + ! -- return + return + end subroutine sfr_solve - !> @brief Update flow terms + !> @brief Update flow terms !! - !! Method to update downstream flow and groundwater leakage terms for + !! Method to update downstream flow and groundwater leakage terms for !! a SFR package reach. !! - !< - subroutine sfr_update_flows(this, n, qd, qgwf) - ! -- dummy variables - class(SfrType), intent(inout) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(inout) :: qd !< downstream reach flow - real(DP), intent(in) :: qgwf !< groundwater leakage for reach - ! -- local variables - integer(I4B) :: i - integer(I4B) :: n2 - integer(I4B) :: idiv - integer(I4B) :: jpos - real(DP) :: qdiv - real(DP) :: f - ! - ! -- update reach terms - ! - ! -- save final downstream stream flow - this%dsflow(n) = qd - ! - ! -- save groundwater leakage - this%gwflow(n) = qgwf + !< + subroutine sfr_update_flows(this, n, qd, qgwf) + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(inout) :: qd !< downstream reach flow + real(DP), intent(in) :: qgwf !< groundwater leakage for reach + ! -- local variables + integer(I4B) :: i + integer(I4B) :: n2 + integer(I4B) :: idiv + integer(I4B) :: jpos + real(DP) :: qdiv + real(DP) :: f + ! + ! -- update reach terms + ! + ! -- save final downstream stream flow + this%dsflow(n) = qd + ! + ! -- save groundwater leakage + this%gwflow(n) = qgwf + ! + ! -- route downstream flow + if (qd > DZERO) then + ! + ! -- route water to diversions + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) cycle + idiv = this%idiv(i) + if (idiv == 0) cycle + jpos = this%iadiv(n) + idiv - 1 + call this%sfr_calc_div(n, idiv, qd, qdiv) + this%qconn(i) = qdiv + this%divq(jpos) = qdiv + end do ! - ! -- route downstream flow - if (qd > DZERO) then - ! - ! -- route water to diversions - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) cycle - idiv = this%idiv(i) - if (idiv == 0) cycle - jpos = this%iadiv(n) + idiv - 1 - call this%sfr_calc_div(n, idiv, qd, qdiv) - this%qconn(i) = qdiv - this%divq(jpos) = qdiv - end do - ! - ! -- Mover terms: store outflow after diversion loss - ! as qformvr and reduce outflow (qd) - ! by how much was actually sent to the mover - if (this%imover == 1) then - call this%pakmvrobj%accumulate_qformvr(n, qd) - qd = MAX(qd - this%pakmvrobj%get_qtomvr(n), DZERO) - endif - ! - ! -- route remaining water to downstream reaches - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) cycle - if (this%idiv(i) > 0) cycle - n2 = this%ja(i) - f = this%ustrf(n2) / this%ftotnd(n) - this%qconn(i) = qd * f - end do - else - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) cycle - this%qconn(i) = DZERO - end do + ! -- Mover terms: store outflow after diversion loss + ! as qformvr and reduce outflow (qd) + ! by how much was actually sent to the mover + if (this%imover == 1) then + call this%pakmvrobj%accumulate_qformvr(n, qd) + qd = MAX(qd - this%pakmvrobj%get_qtomvr(n), DZERO) end if ! - ! -- return - return - end subroutine sfr_update_flows + ! -- route remaining water to downstream reaches + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) cycle + if (this%idiv(i) > 0) cycle + n2 = this%ja(i) + f = this%ustrf(n2) / this%ftotnd(n) + this%qconn(i) = qd * f + end do + else + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) cycle + this%qconn(i) = DZERO + end do + end if + ! + ! -- return + return + end subroutine sfr_update_flows - !> @brief Calculate downstream flow term + !> @brief Calculate downstream flow term !! !! Method to calculate downstream flow for a SFR package reach. !! - !< - subroutine sfr_calc_qd(this, n, depth, hgwf, qgwf, qd) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - real(DP), intent(in) :: hgwf !< groundwater head in connected GWF cell - real(DP), intent(inout) :: qgwf !< groundwater leakage for reach - real(DP), intent(inout) :: qd !< residual - ! -- local variables - real(DP) :: qsrc - ! - ! -- initialize residual - qd = DZERO - ! - ! -- calculate total water sources excluding groundwater leakage - call this%sfr_calc_qsource(n, depth, qsrc) - ! - ! -- estimate groundwater leakage - call this%sfr_calc_qgwf(n, depth, hgwf, qgwf) - if (-qgwf > qsrc) qgwf = -qsrc - ! - ! -- calculate down stream flow - qd = qsrc + qgwf - ! - ! -- limit downstream flow to a positive value - if (qd < DEM30) qd = DZERO - ! - ! -- return - return - end subroutine sfr_calc_qd + !< + subroutine sfr_calc_qd(this, n, depth, hgwf, qgwf, qd) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + real(DP), intent(in) :: hgwf !< groundwater head in connected GWF cell + real(DP), intent(inout) :: qgwf !< groundwater leakage for reach + real(DP), intent(inout) :: qd !< residual + ! -- local variables + real(DP) :: qsrc + ! + ! -- initialize residual + qd = DZERO + ! + ! -- calculate total water sources excluding groundwater leakage + call this%sfr_calc_qsource(n, depth, qsrc) + ! + ! -- estimate groundwater leakage + call this%sfr_calc_qgwf(n, depth, hgwf, qgwf) + if (-qgwf > qsrc) qgwf = -qsrc + ! + ! -- calculate down stream flow + qd = qsrc + qgwf + ! + ! -- limit downstream flow to a positive value + if (qd < DEM30) qd = DZERO + ! + ! -- return + return + end subroutine sfr_calc_qd - !> @brief Calculate sum of sources + !> @brief Calculate sum of sources !! !! Method to calculate the sum of sources for reach, excluding !! reach leakage, for a SFR package reach. !! - !< - subroutine sfr_calc_qsource(this, n, depth, qsrc) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - real(DP), intent(inout) :: qsrc !< sum of sources for reach - ! -- local variables - real(DP) :: qu - real(DP) :: qi - real(DP) :: qr - real(DP) :: qe - real(DP) :: qro - real(DP) :: qfrommvr - real(DP) :: qt - real(DP) :: a - real(DP) :: ae - ! - ! -- initialize residual - qsrc = DZERO - ! - ! -- calculate flow terms - qu = this%usflow(n) - qi = this%inflow(n) - qro = this%runoff(n) - ! - ! -- calculate rainfall and evap - a = this%calc_surface_area(n) - ae = this%calc_surface_area_wet(n, depth) - qr = this%rain(n) * a - qe = this%evap(n) * a - ! - ! -- calculate mover term - qfrommvr = DZERO - if (this%imover == 1) then - qfrommvr = this%pakmvrobj%get_qfrommvr(n) - endif + !< + subroutine sfr_calc_qsource(this, n, depth, qsrc) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + real(DP), intent(inout) :: qsrc !< sum of sources for reach + ! -- local variables + real(DP) :: qu + real(DP) :: qi + real(DP) :: qr + real(DP) :: qe + real(DP) :: qro + real(DP) :: qfrommvr + real(DP) :: qt + real(DP) :: a + real(DP) :: ae + ! + ! -- initialize residual + qsrc = DZERO + ! + ! -- calculate flow terms + qu = this%usflow(n) + qi = this%inflow(n) + qro = this%runoff(n) + ! + ! -- calculate rainfall and evap + a = this%calc_surface_area(n) + ae = this%calc_surface_area_wet(n, depth) + qr = this%rain(n) * a + qe = this%evap(n) * a + ! + ! -- calculate mover term + qfrommvr = DZERO + if (this%imover == 1) then + qfrommvr = this%pakmvrobj%get_qfrommvr(n) + end if + ! + ! -- calculate down stream flow + qsrc = qu + qi + qr - qe + qro + qfrommvr + ! + ! -- adjust runoff or evaporation if sum of sources is negative + if (qsrc < DZERO) then ! - ! -- calculate down stream flow - qsrc = qu + qi + qr - qe + qro + qfrommvr + ! -- calculate sources without et + qt = qu + qi + qr + qro + qfrommvr ! - ! -- adjust runoff or evaporation if sum of sources is negative - if (qsrc < DZERO) then - ! - ! -- calculate sources without et - qt = qu + qi + qr + qro + qfrommvr - ! - ! -- runoff exceeds sources of water for reach - if (qt < DZERO) then - qro = -(qu + qi + qr + qfrommvr) - qe = DZERO + ! -- runoff exceeds sources of water for reach + if (qt < DZERO) then + qro = -(qu + qi + qr + qfrommvr) + qe = DZERO ! ! -- evaporation exceeds sources of water for reach - else - qe = qu + qi + qr + qro + qfrommvr - end if - qsrc = qu + qi + qr - qe + qro + qfrommvr + else + qe = qu + qi + qr + qro + qfrommvr end if - ! - ! -- return - return - end subroutine sfr_calc_qsource - + qsrc = qu + qi + qr - qe + qro + qfrommvr + end if + ! + ! -- return + return + end subroutine sfr_calc_qsource - !> @brief Calculate streamflow + !> @brief Calculate streamflow !! - !! Method to calculate the streamflow using Manning's equation for a + !! Method to calculate the streamflow using Manning's equation for a !! SFR package reach. !! - !< - subroutine sfr_calc_qman(this, n, depth, qman) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - real(DP), intent(inout) :: qman !< streamflow - ! -- local variables - integer(I4B) :: npts - integer(I4B) :: i0 - integer(I4B) :: i1 - real(DP) :: sat - real(DP) :: derv - real(DP) :: s - real(DP) :: r - real(DP) :: aw - real(DP) :: wp - real(DP) :: rh + !< + subroutine sfr_calc_qman(this, n, depth, qman) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + real(DP), intent(inout) :: qman !< streamflow + ! -- local variables + integer(I4B) :: npts + integer(I4B) :: i0 + integer(I4B) :: i1 + real(DP) :: sat + real(DP) :: derv + real(DP) :: s + real(DP) :: r + real(DP) :: aw + real(DP) :: wp + real(DP) :: rh + ! + ! -- initialize variables + qman = DZERO + ! + ! -- calculate Manning's discharge for non-zero depths + if (depth > DZERO) then + npts = this%ncrosspts(n) ! - ! -- initialize variables - qman = DZERO + ! -- set constant terms for Manning's equation + call sChSmooth(depth, sat, derv) + s = this%slope(n) ! - ! -- calculate Manning's discharge for non-zero depths - if (depth > DZERO) then - npts = this%ncrosspts(n) + ! -- calculate the mannings coefficient that is a + ! function of depth + if (npts > 1) then ! - ! -- set constant terms for Manning's equation - call sChSmooth(depth, sat, derv) - s = this%slope(n) + ! -- get the location of the cross-section data for the reach + i0 = this%iacross(n) + i1 = this%iacross(n + 1) - 1 ! - ! -- calculate the mannings coefficient that is a - ! function of depth - if (npts > 1) then - ! - ! -- get the location of the cross-section data for the reach - i0 = this%iacross(n) - i1 = this%iacross(n + 1) - 1 - ! - ! -- get the Manning's sum of the Manning's discharge - ! for each section - qman = get_mannings_section(npts, & - this%station(i0:i1), & - this%xsheight(i0:i1), & - this%xsrough(i0:i1), & - this%rough(n), & - this%unitconv, & - s, & - depth) + ! -- get the Manning's sum of the Manning's discharge + ! for each section + qman = get_mannings_section(npts, & + this%station(i0:i1), & + this%xsheight(i0:i1), & + this%xsrough(i0:i1), & + this%rough(n), & + this%unitconv, & + s, & + depth) + else + r = this%rough(n) + aw = this%calc_area_wet(n, depth) + wp = this%calc_perimeter_wet(n, depth) + if (wp > DZERO) then + rh = aw / wp else - r = this%rough(n) - aw = this%calc_area_wet(n, depth) - wp = this%calc_perimeter_wet(n, depth) - if (wp > DZERO) then - rh = aw / wp - else - rh = DZERO - end if - qman = this%unitconv * aw * (rh**DTWOTHIRDS) * sqrt(s) / r + rh = DZERO end if - ! - ! -- calculate stream flow - qman = sat * qman + qman = this%unitconv * aw * (rh**DTWOTHIRDS) * sqrt(s) / r end if ! - ! -- return - return - end subroutine sfr_calc_qman - + ! -- calculate stream flow + qman = sat * qman + end if + ! + ! -- return + return + end subroutine sfr_calc_qman - !> @brief Calculate reach-aquifer exchange + !> @brief Calculate reach-aquifer exchange !! !! Method to calculate the reach-aquifer exchange for a SFR package reach. !! The reach-aquifer exchange is relative to the reach. Calculated flow !! is positive if flow is from the aquifer to the reach. !! - !< - subroutine sfr_calc_qgwf(this, n, depth, hgwf, qgwf, gwfhcof, gwfrhs) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - real(DP), intent(in) :: hgwf !< head in GWF cell connected to reach - real(DP), intent(inout) :: qgwf !< reach-aquifer exchange - real(DP), intent(inout), optional :: gwfhcof !< diagonal coefficient term for reach - real(DP), intent(inout), optional :: gwfrhs !< right-hand side term for reach - ! -- local variables - integer(I4B) :: node - real(DP) :: tp - real(DP) :: bt - real(DP) :: hsfr - real(DP) :: htmp - real(DP) :: cond - real(DP) :: sat - real(DP) :: derv - real(DP) :: gwfhcof0 - real(DP) :: gwfrhs0 - ! - ! -- initialize qgwf - qgwf = DZERO - ! - ! -- skip sfr-aquifer exchange in external cells - node = this%igwfnode(n) - if (node < 1) return - ! - ! -- skip sfr-aquifer exchange in inactive cells - if (this%ibound(node) == 0) return - ! - ! -- calculate saturation - call sChSmooth(depth, sat, derv) - ! - ! -- calculate conductance - call this%sfr_calc_cond(n, depth, cond) - ! - ! -- calculate groundwater leakage - tp = this%strtop(n) - bt = tp - this%bthick(n) - hsfr = tp + depth - htmp = hgwf - if (htmp < bt) then - htmp = bt - end if - qgwf = sat * cond * (htmp - hsfr) - gwfrhs0 = -sat * cond * hsfr - gwfhcof0 = -sat * cond - ! - ! Add density contributions, if active - if (this%idense /= 0) then - call this%sfr_calculate_density_exchange(n, hsfr, hgwf, cond, tp, & - qgwf, gwfhcof0, gwfrhs0) - end if - ! - ! -- Set gwfhcof and gwfrhs if present - if (present(gwfhcof)) gwfhcof = gwfhcof0 - if (present(gwfrhs)) gwfrhs = gwfrhs0 - ! - ! -- return - return - end subroutine sfr_calc_qgwf + !< + subroutine sfr_calc_qgwf(this, n, depth, hgwf, qgwf, gwfhcof, gwfrhs) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + real(DP), intent(in) :: hgwf !< head in GWF cell connected to reach + real(DP), intent(inout) :: qgwf !< reach-aquifer exchange + real(DP), intent(inout), optional :: gwfhcof !< diagonal coefficient term for reach + real(DP), intent(inout), optional :: gwfrhs !< right-hand side term for reach + ! -- local variables + integer(I4B) :: node + real(DP) :: tp + real(DP) :: bt + real(DP) :: hsfr + real(DP) :: htmp + real(DP) :: cond + real(DP) :: sat + real(DP) :: derv + real(DP) :: gwfhcof0 + real(DP) :: gwfrhs0 + ! + ! -- initialize qgwf + qgwf = DZERO + ! + ! -- skip sfr-aquifer exchange in external cells + node = this%igwfnode(n) + if (node < 1) return + ! + ! -- skip sfr-aquifer exchange in inactive cells + if (this%ibound(node) == 0) return + ! + ! -- calculate saturation + call sChSmooth(depth, sat, derv) + ! + ! -- terms for calculating direction of gradient across streambed + tp = this%strtop(n) + bt = tp - this%bthick(n) + hsfr = tp + depth + htmp = hgwf + if (htmp < bt) then + htmp = bt + end if + ! + ! -- calculate conductance + call this%sfr_calc_cond(n, depth, cond, hsfr, htmp) + ! + ! -- calculate groundwater leakage + qgwf = sat * cond * (htmp - hsfr) + gwfrhs0 = -sat * cond * hsfr + gwfhcof0 = -sat * cond + ! + ! Add density contributions, if active + if (this%idense /= 0) then + call this%sfr_calculate_density_exchange(n, hsfr, hgwf, cond, tp, & + qgwf, gwfhcof0, gwfrhs0) + end if + ! + ! -- Set gwfhcof and gwfrhs if present + if (present(gwfhcof)) gwfhcof = gwfhcof0 + if (present(gwfrhs)) gwfrhs = gwfrhs0 + ! + ! -- return + return + end subroutine sfr_calc_qgwf - !> @brief Calculate reach-aquifer conductance + !> @brief Calculate reach-aquifer conductance !! !! Method to calculate the reach-aquifer conductance for a SFR package reach. !! - !< - subroutine sfr_calc_cond(this, n, depth, cond) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - real(DP), intent(inout) :: cond !< reach-aquifer conductance - ! -- local variables - integer(I4B) :: node - real(DP) :: wp - ! - ! -- initialize conductance - cond = DZERO - ! - ! -- calculate conductance if GWF cell is active - node = this%igwfnode(n) - if (node > 0) then - if (this%ibound(node) > 0) then - wp = this%calc_perimeter_wet(n, depth) - cond = this%hk(n) * this%length(n) * wp / this%bthick(n) + !< + subroutine sfr_calc_cond(this, n, depth, cond, hsfr, htmp) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + real(DP), intent(inout) :: cond !< reach-aquifer conductance + real(DP), intent(in), optional :: hsfr !< stream stage + real(DP), intent(in), optional :: htmp !< head in gw cell + ! -- local variables + integer(I4B) :: node + real(DP) :: wp + real(DP) :: vscratio + ! + ! -- initialize conductance + cond = DZERO + ! + ! -- initial viscosity ratio to 1 + vscratio = DONE + ! + ! -- calculate conductance if GWF cell is active + node = this%igwfnode(n) + if (node > 0) then + if (this%ibound(node) > 0) then + ! + ! -- direction of gradient across streambed determines which vsc ratio + if (this%ivsc == 1) then + if (hsfr > htmp) then + ! strm stg > gw head + vscratio = this%viscratios(1, n) + else + vscratio = this%viscratios(2, n) + end if end if + wp = this%calc_perimeter_wet(n, depth) + cond = this%hk(n) * vscratio * this%length(n) * wp / this%bthick(n) end if - ! - ! -- return - return - end subroutine sfr_calc_cond - + end if + ! + ! -- return + return + end subroutine sfr_calc_cond - !> @brief Calculate diversion flow + !> @brief Calculate diversion flow !! !! Method to calculate the diversion flow for a diversion connected !! to a SFR package reach. The downstream flow for a reach is passed !! in and adjusted by the diversion flow amount calculated in this !! method. !! - !< - subroutine sfr_calc_div(this, n, i, qd, qdiv) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - integer(I4B), intent(in) :: i !< diversion number in reach - real(DP), intent(inout) :: qd !< remaining downstream flow for reach - real(DP), intent(inout) :: qdiv !< diversion flow for diversion i - ! -- local variables - character (len=10) :: cp - integer(I4B) :: jpos - integer(I4B) :: n2 - real(DP) :: v - ! - ! -- set local variables - jpos = this%iadiv(n) + i - 1 - n2 = this%divreach(jpos) - cp = this%divcprior(jpos) - v = this%divflow(jpos) - ! - ! -- calculate diversion - select case(cp) - ! -- flood diversion - case ('EXCESS') - if (qd < v) then - v = DZERO - else - v = qd - v - end if - ! -- diversion percentage - case ('FRACTION') - v = qd * v - ! -- STR priority algorithm - case ('THRESHOLD') - if (qd < v) then - v = DZERO - end if - ! -- specified diversion - case ('UPTO') - if (v > qd) then - v = qd - end if - case default - v = DZERO - end select - ! - ! -- update upstream from for downstream reaches - qd = qd - v - qdiv = v - ! - ! -- return - return - end subroutine sfr_calc_div + !< + subroutine sfr_calc_div(this, n, i, qd, qdiv) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + integer(I4B), intent(in) :: i !< diversion number in reach + real(DP), intent(inout) :: qd !< remaining downstream flow for reach + real(DP), intent(inout) :: qdiv !< diversion flow for diversion i + ! -- local variables + character(len=10) :: cp + integer(I4B) :: jpos + integer(I4B) :: n2 + real(DP) :: v + ! + ! -- set local variables + jpos = this%iadiv(n) + i - 1 + n2 = this%divreach(jpos) + cp = this%divcprior(jpos) + v = this%divflow(jpos) + ! + ! -- calculate diversion + select case (cp) + ! -- flood diversion + case ('EXCESS') + if (qd < v) then + v = DZERO + else + v = qd - v + end if + ! -- diversion percentage + case ('FRACTION') + v = qd * v + ! -- STR priority algorithm + case ('THRESHOLD') + if (qd < v) then + v = DZERO + end if + ! -- specified diversion + case ('UPTO') + if (v > qd) then + v = qd + end if + case default + v = DZERO + end select + ! + ! -- update upstream from for downstream reaches + qd = qd - v + qdiv = v + ! + ! -- return + return + end subroutine sfr_calc_div - - !> @brief Calculate the depth at the midpoint + !> @brief Calculate the depth at the midpoint !! !! Method to calculate the depth at the midpoint of a reach. !! - !< - subroutine sfr_calc_reach_depth(this, n, q1, d1) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: q1 !< streamflow - real(DP), intent(inout) :: d1 !< stream depth at midpoint of reach - ! -- local variables - real(DP) :: w - real(DP) :: s - real(DP) :: r - real(DP) :: qconst - ! - ! -- initialize slope and roughness - s = this%slope(n) - r = this%rough(n) - ! - ! -- calculate stream depth at the midpoint - if (q1 > DZERO) then - if (this%ncrosspts(n) > 1) then - call this%sfr_calc_xs_depth(n, q1, d1) - else - w = this%station(this%iacross(n)) - qconst = this%unitconv * w * sqrt(s) / r - d1 = (q1 / qconst)**DP6 - end if + !< + subroutine sfr_calc_reach_depth(this, n, q1, d1) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: q1 !< streamflow + real(DP), intent(inout) :: d1 !< stream depth at midpoint of reach + ! -- local variables + real(DP) :: w + real(DP) :: s + real(DP) :: r + real(DP) :: qconst + ! + ! -- initialize slope and roughness + s = this%slope(n) + r = this%rough(n) + ! + ! -- calculate stream depth at the midpoint + if (q1 > DZERO) then + if (this%ncrosspts(n) > 1) then + call this%sfr_calc_xs_depth(n, q1, d1) else - d1 = DZERO + w = this%station(this%iacross(n)) + qconst = this%unitconv * w * sqrt(s) / r + d1 = (q1 / qconst)**DP6 end if - ! - ! -- return - return - end subroutine sfr_calc_reach_depth - + else + d1 = DZERO + end if + ! + ! -- return + return + end subroutine sfr_calc_reach_depth - !> @brief Calculate the depth at the midpoint of a irregular cross-section + !> @brief Calculate the depth at the midpoint of a irregular cross-section !! !! Method to calculate the depth at the midpoint of a reach with a !! irregular cross-section using Newton-Raphson. !! - !< - subroutine sfr_calc_xs_depth(this, n, qrch, d) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: qrch !< streamflow - real(DP), intent(inout) :: d !< stream depth at midpoint of reach - ! -- local variables - integer(I4B) :: iter - real(DP) :: perturbation - real(DP) :: q0 - real(DP) :: q1 - real(DP) :: dq - real(DP) :: derv - real(DP) :: dd - real(DP) :: residual - ! - ! -- initialize variables - perturbation = this%deps * DTWO - d = DZERO - q0 = DZERO + !< + subroutine sfr_calc_xs_depth(this, n, qrch, d) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: qrch !< streamflow + real(DP), intent(inout) :: d !< stream depth at midpoint of reach + ! -- local variables + integer(I4B) :: iter + real(DP) :: perturbation + real(DP) :: q0 + real(DP) :: q1 + real(DP) :: dq + real(DP) :: derv + real(DP) :: dd + real(DP) :: residual + ! + ! -- initialize variables + perturbation = this%deps * DTWO + d = DZERO + q0 = DZERO + residual = q0 - qrch + ! + ! -- Newton-Raphson iteration + nriter: do iter = 1, this%maxsfrit + call this%sfr_calc_qman(n, d + perturbation, q1) + dq = (q1 - q0) + if (dq /= DZERO) then + derv = perturbation / (q1 - q0) + else + derv = DZERO + end if + dd = derv * residual + d = d - dd + call this%sfr_calc_qman(n, d, q0) residual = q0 - qrch ! - ! -- Newton-Raphson iteration - nriter: do iter = 1, this%maxsfrit - call this%sfr_calc_qman(n, d + perturbation, q1) - dq = (q1 - q0) - if (dq /= DZERO) then - derv = perturbation / (q1 - q0) - else - derv = DZERO - end if - dd = derv * residual - d = d - dd - call this%sfr_calc_qman(n, d, q0) - residual = q0 - qrch - ! - ! -- check for convergence - if (abs(dd) < this%dmaxchg) then - exit nriter - end if - end do nriter - ! - ! -- return - return - end subroutine sfr_calc_xs_depth - + ! -- check for convergence + if (abs(dd) < this%dmaxchg) then + exit nriter + end if + end do nriter + ! + ! -- return + return + end subroutine sfr_calc_xs_depth - !> @brief Check reach data + !> @brief Check reach data !! - !! Method to check specified data for a SFR package. This method - !! also creates the tables used to print input data, if this + !! Method to check specified data for a SFR package. This method + !! also creates the tables used to print input data, if this !! option in enabled in the SFR package. !! - !< - subroutine sfr_check_reaches(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - character (len= 5) :: crch - character (len=10) :: cval - character (len=30) :: nodestr - character (len=LINELENGTH) :: title - character (len=LINELENGTH) :: text - integer(I4B) :: n - integer(I4B) :: nn - real(DP) :: btgwf - real(DP) :: bt - ! - ! -- setup inputtab tableobj - if (this%iprpak /= 0) then - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC REACH DATA' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(this%maxbound, 10, this%iout) - text = 'NUMBER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'CELLID' - call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) - text = 'LENGTH' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'WIDTH' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'SLOPE' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'TOP' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'THICKNESS' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'HK' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'ROUGHNESS' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) - text = 'UPSTREAM FRACTION' - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + !< + subroutine sfr_check_reaches(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + character(len=5) :: crch + character(len=10) :: cval + character(len=30) :: nodestr + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: text + integer(I4B) :: n + integer(I4B) :: nn + real(DP) :: btgwf + real(DP) :: bt + ! + ! -- setup inputtab tableobj + if (this%iprpak /= 0) then + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC REACH DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(this%maxbound, 10, this%iout) + text = 'NUMBER' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'CELLID' + call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) + text = 'LENGTH' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'WIDTH' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'SLOPE' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'TOP' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'THICKNESS' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'HK' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'ROUGHNESS' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + text = 'UPSTREAM FRACTION' + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + end if + ! + ! -- check the reach data for simple errors + do n = 1, this%maxbound + write (crch, '(i5)') n + nn = this%igwfnode(n) + if (nn > 0) then + btgwf = this%dis%bot(nn) + call this%dis%noder_to_string(nn, nodestr) + else + nodestr = 'none' end if - ! - ! -- check the reach data for simple errors - do n = 1, this%maxbound - write(crch, '(i5)') n - nn = this%igwfnode(n) - if (nn > 0) then - btgwf = this%dis%bot(nn) - call this%dis%noder_to_string(nn, nodestr) - else - nodestr = 'none' - end if - ! -- check reach length - if (this%length(n) <= DZERO) then - errmsg = 'Reach ' // crch // ' length must be greater than 0.0.' - call store_error(errmsg) - end if - ! -- check reach width - if (this%width(n) <= DZERO) then - errmsg = 'Reach ' // crch // ' width must be greater than 0.0.' - call store_error(errmsg) - end if - ! -- check reach slope - if (this%slope(n) <= DZERO) then - errmsg = 'Reach ' // crch // ' slope must be greater than 0.0.' - call store_error(errmsg) - end if - ! -- check bed thickness and bed hk for reaches connected to GWF - if (nn > 0) then - bt = this%strtop(n) - this%bthick(n) - if (bt <= btgwf .and. this%icheck /= 0) then - write(cval,'(f10.4)') bt - errmsg = 'Reach ' // crch // ' bed bottom (rtp-rbth =' // & - cval // ') must be greater than the bottom of cell (' // & - nodestr - write(cval,'(f10.4)') btgwf - errmsg = trim(adjustl(errmsg)) // '=' // cval // ').' - call store_error(errmsg) - end if - if (this%hk(n) < DZERO) then - errmsg = 'Reach ' // crch // ' hk must be greater than or equal to 0.0.' - call store_error(errmsg) - end if - end if - ! -- check reach roughness - if (this%rough(n) <= DZERO) then - errmsg = 'Reach ' // crch // " Manning's roughness " // & - 'coefficient must be greater than 0.0.' + ! -- check reach length + if (this%length(n) <= DZERO) then + errmsg = 'Reach '//crch//' length must be greater than 0.0.' + call store_error(errmsg) + end if + ! -- check reach width + if (this%width(n) <= DZERO) then + errmsg = 'Reach '//crch//' width must be greater than 0.0.' + call store_error(errmsg) + end if + ! -- check reach slope + if (this%slope(n) <= DZERO) then + errmsg = 'Reach '//crch//' slope must be greater than 0.0.' + call store_error(errmsg) + end if + ! -- check bed thickness and bed hk for reaches connected to GWF + if (nn > 0) then + bt = this%strtop(n) - this%bthick(n) + if (bt <= btgwf .and. this%icheck /= 0) then + write (cval, '(f10.4)') bt + errmsg = 'Reach '//crch//' bed bottom (rtp-rbth ='// & + cval//') must be greater than the bottom of cell ('// & + nodestr + write (cval, '(f10.4)') btgwf + errmsg = trim(adjustl(errmsg))//'='//cval//').' call store_error(errmsg) end if - ! -- check reach upstream fraction - if (this%ustrf(n) < DZERO) then - errmsg = 'Reach ' // crch // ' upstream fraction must be greater ' // & - 'than or equal to 0.0.' + if (this%hk(n) < DZERO) then + errmsg = 'Reach '//crch//' hk must be greater than or equal to 0.0.' call store_error(errmsg) - end if - ! -- write summary of reach information - if (this%iprpak /= 0) then - call this%inputtab%add_term(n) - call this%inputtab%add_term(nodestr) - call this%inputtab%add_term(this%length(n)) - call this%inputtab%add_term(this%width(n)) - call this%inputtab%add_term(this%slope(n)) - call this%inputtab%add_term(this%strtop(n)) - call this%inputtab%add_term(this%bthick(n)) - call this%inputtab%add_term(this%hk(n)) - call this%inputtab%add_term(this%rough(n)) - call this%inputtab%add_term(this%ustrf(n)) - end if - end do - ! - ! -- return - return - end subroutine sfr_check_reaches - + end if + end if + ! -- check reach roughness + if (this%rough(n) <= DZERO) then + errmsg = 'Reach '//crch//" Manning's roughness "// & + 'coefficient must be greater than 0.0.' + call store_error(errmsg) + end if + ! -- check reach upstream fraction + if (this%ustrf(n) < DZERO) then + errmsg = 'Reach '//crch//' upstream fraction must be greater '// & + 'than or equal to 0.0.' + call store_error(errmsg) + end if + ! -- write summary of reach information + if (this%iprpak /= 0) then + call this%inputtab%add_term(n) + call this%inputtab%add_term(nodestr) + call this%inputtab%add_term(this%length(n)) + call this%inputtab%add_term(this%width(n)) + call this%inputtab%add_term(this%slope(n)) + call this%inputtab%add_term(this%strtop(n)) + call this%inputtab%add_term(this%bthick(n)) + call this%inputtab%add_term(this%hk(n)) + call this%inputtab%add_term(this%rough(n)) + call this%inputtab%add_term(this%ustrf(n)) + end if + end do + ! + ! -- return + return + end subroutine sfr_check_reaches - !> @brief Check connection data + !> @brief Check connection data !! - !! Method to check connection data for a SFR package. This method - !! also creates the tables used to print input data, if this + !! Method to check connection data for a SFR package. This method + !! also creates the tables used to print input data, if this !! option in enabled in the SFR package. !! - !< - subroutine sfr_check_connections(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - logical(LGP) :: lreorder - character (len= 5) :: crch - character (len= 5) :: crch2 - character (len=LINELENGTH) :: text - character (len=LINELENGTH) :: title - integer(I4B) :: n - integer(I4B) :: nn - integer(I4B) :: nc - integer(I4B) :: i - integer(I4B) :: ii - integer(I4B) :: j - integer(I4B) :: ifound - integer(I4B) :: ierr - integer(I4B) :: maxconn - integer(I4B) :: ntabcol - ! - ! -- determine if the reaches have been reordered - lreorder = .FALSE. - do j = 1, this%MAXBOUND - n = this%isfrorder(j) - if (n /= j) then - lreorder = .TRUE. - exit - end if - end do - ! - ! -- write message that the solution order h - if (lreorder) then - write(this%iout, '(/,1x,a)') & - trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') REACH SOLUTION HAS BEEN ' // & - 'REORDERED USING A DAG' - ! - ! -- print table - if (this%iprpak /= 0) then - ! - ! -- reset the input table object - ntabcol = 2 - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') REACH SOLUTION ORDER' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) - text = 'ORDER' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'REACH' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - ! - ! -- upstream connection data - do j = 1, this%maxbound - n = this%isfrorder(j) - call this%inputtab%add_term(j) - call this%inputtab%add_term(n) - end do - end if + !< + subroutine sfr_check_connections(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + logical(LGP) :: lreorder + character(len=5) :: crch + character(len=5) :: crch2 + character(len=LINELENGTH) :: text + character(len=LINELENGTH) :: title + integer(I4B) :: n + integer(I4B) :: nn + integer(I4B) :: nc + integer(I4B) :: i + integer(I4B) :: ii + integer(I4B) :: j + integer(I4B) :: ifound + integer(I4B) :: ierr + integer(I4B) :: maxconn + integer(I4B) :: ntabcol + ! + ! -- determine if the reaches have been reordered + lreorder = .FALSE. + do j = 1, this%MAXBOUND + n = this%isfrorder(j) + if (n /= j) then + lreorder = .TRUE. + exit end if - ! - ! -- create input table for reach connections data + end do + ! + ! -- write message that the solution order h + if (lreorder) then + write (this%iout, '(/,1x,a)') & + trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') REACH SOLUTION HAS BEEN '// & + 'REORDERED USING A DAG' + ! + ! -- print table if (this%iprpak /= 0) then - ! - ! -- calculate the maximum number of connections - maxconn = 0 - do n = 1, this%maxbound - maxconn = max(maxconn, this%nconnreach(n)) - end do - ntabcol = 1 + maxconn ! ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC REACH CONNECTION DATA' + ntabcol = 2 + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') REACH SOLUTION ORDER' call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) + text = 'ORDER' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'REACH' call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - do n = 1, maxconn - write(text, '(a,1x,i6)') 'CONN', n - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - end do - end if - ! - ! -- check the reach connections for simple errors - ! -- connection check - do n = 1, this%MAXBOUND - write(crch, '(i5)') n - eachconn: do i = this%ia(n) + 1, this%ia(n+1) - 1 - nn = this%ja(i) - write(crch2, '(i5)') nn - ifound = 0 - connreach: do ii = this%ia(nn) + 1, this%ia(nn+1) - 1 - nc = this%ja(ii) - if (nc == n) then - ifound = 1 - exit connreach - end if - end do connreach - if (ifound /= 1) then - errmsg = 'Reach ' // crch // ' is connected to ' // & - 'reach ' // crch2 // ' but reach ' // crch2 // & - ' is not connected to reach ' // crch // '.' - call store_error(errmsg) - end if - end do eachconn ! - ! -- write connection data to the table - if (this%iprpak /= 0) then + ! -- upstream connection data + do j = 1, this%maxbound + n = this%isfrorder(j) + call this%inputtab%add_term(j) call this%inputtab%add_term(n) - do i = this%ia(n) + 1, this%ia(n+1) - 1 - call this%inputtab%add_term(this%ja(i)) - end do - nn = maxconn - this%nconnreach(n) - do i = 1, nn - call this%inputtab%add_term(' ') - end do - end if - end do - ! - ! -- check for incorrect connections between upstream connections - ! - ! -- check upstream connections for each reach - ierr = 0 - do n = 1, this%maxbound - write(crch, '(i5)') n - eachconnv: do i = this%ia(n) + 1, this%ia(n + 1) - 1 - ! - ! -- skip downstream connections - if (this%idir(i) < 0) cycle eachconnv - nn = this%ja(i) - write(crch2, '(i5)') nn - connreachv: do ii = this%ia(nn) + 1, this%ia(nn+1) - 1 - ! -- skip downstream connections - if (this%idir(ii) < 0) cycle connreachv - nc = this%ja(ii) - ! - ! -- if nc == n then that means reach n is an upstream connection for - ! reach nn and reach nn is an upstream connection for reach n - if (nc == n) then - ierr = ierr + 1 - errmsg = 'Reach ' // crch // ' is connected to ' // & - 'reach ' // crch2 // ' but streamflow from reach ' // & - crch // ' to reach ' // crch2 // ' is not permitted.' - call store_error(errmsg) - exit connreachv - end if - end do connreachv - end do eachconnv - end do - ! - ! -- terminate if connectivity errors - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + end do end if + end if + ! + ! -- create input table for reach connections data + if (this%iprpak /= 0) then ! - ! -- check that downstream reaches for a reach are - ! the upstream reaches for the reach + ! -- calculate the maximum number of connections + maxconn = 0 do n = 1, this%maxbound - write(crch, '(i5)') n - eachconnds: do i = this%ia(n) + 1, this%ia(n+1) - 1 - nn = this%ja(i) - if (this%idir(i) > 0) cycle eachconnds - write(crch2, '(i5)') nn - ifound = 0 - connreachds: do ii = this%ia(nn) + 1, this%ia(nn+1) - 1 - nc = this%ja(ii) - if (nc == n) then - if (this%idir(i) /= this%idir(ii)) then - ifound = 1 - end if - exit connreachds - end if - end do connreachds - if (ifound /= 1) then - errmsg = 'Reach ' // crch // ' downstream connected reach ' // & - 'is reach ' // crch2 // ' but reach ' // crch // ' is not' // & - ' the upstream connected reach for reach ' // crch2 // '.' - call store_error(errmsg) - end if - end do eachconnds + maxconn = max(maxconn, this%nconnreach(n)) end do + ntabcol = 1 + maxconn + ! + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC REACH CONNECTION DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) + text = 'REACH' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + do n = 1, maxconn + write (text, '(a,1x,i6)') 'CONN', n + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + end do + end if + ! + ! -- check the reach connections for simple errors + ! -- connection check + do n = 1, this%MAXBOUND + write (crch, '(i5)') n + eachconn: do i = this%ia(n) + 1, this%ia(n + 1) - 1 + nn = this%ja(i) + write (crch2, '(i5)') nn + ifound = 0 + connreach: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1 + nc = this%ja(ii) + if (nc == n) then + ifound = 1 + exit connreach + end if + end do connreach + if (ifound /= 1) then + errmsg = 'Reach '//crch//' is connected to '// & + 'reach '//crch2//' but reach '//crch2// & + ' is not connected to reach '//crch//'.' + call store_error(errmsg) + end if + end do eachconn ! - ! -- create input table for upstream and downstream connections + ! -- write connection data to the table if (this%iprpak /= 0) then - ! - ! -- calculate the maximum number of upstream connections - maxconn = 0 - do n = 1, this%maxbound - ii = 0 - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) then - ii = ii + 1 - end if - end do - maxconn = max(maxconn, ii) - end do - ntabcol = 1 + maxconn - ! - ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC UPSTREAM REACH ' // & - 'CONNECTION DATA' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) - text = 'REACH' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - do n = 1, maxconn - write(text, '(a,1x,i6)') 'UPSTREAM CONN', n - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - end do - ! - ! -- upstream connection data - do n = 1, this%maxbound - call this%inputtab%add_term(n) - ii = 0 - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) then - call this%inputtab%add_term(this%ja(i)) - ii = ii + 1 - end if - end do - nn = maxconn - ii - do i = 1, nn - call this%inputtab%add_term(' ') - end do - end do - ! - ! -- calculate the maximum number of downstream connections - maxconn = 0 - do n = 1, this%maxbound - ii = 0 - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) < 0) then - ii = ii + 1 - end if - end do - maxconn = max(maxconn, ii) - end do - ntabcol = 1 + maxconn - ! - ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC DOWNSTREAM ' // & - 'REACH CONNECTION DATA' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) - text = 'REACH' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - do n = 1, maxconn - write(text, '(a,1x,i6)') 'DOWNSTREAM CONN', n - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + call this%inputtab%add_term(n) + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + call this%inputtab%add_term(this%ja(i)) end do - ! - ! -- downstream connection data - do n = 1, this%maxbound - call this%inputtab%add_term(n) - ii = 0 - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) < 0) then - call this%inputtab%add_term(this%ja(i)) - ii = ii + 1 - end if - end do - nn = maxconn - ii - do i = 1, nn - call this%inputtab%add_term(' ') - end do + nn = maxconn - this%nconnreach(n) + do i = 1, nn + call this%inputtab%add_term(' ') end do end if - ! - ! -- return - return - end subroutine sfr_check_connections - - - !> @brief Check diversions data - !! - !! Method to check diversion data for a SFR package. This method - !! also creates the tables used to print input data, if this - !! option in enabled in the SFR package. - !! - !< - subroutine sfr_check_diversions(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - character (len=LINELENGTH) :: title - character (len=LINELENGTH) :: text - character (len= 5) :: crch - character (len= 5) :: cdiv - character (len= 5) :: crch2 - character (len=10) :: cprior - integer(I4B) :: maxdiv - integer(I4B) :: n - integer(I4B) :: nn - integer(I4B) :: nc - integer(I4B) :: ii - integer(I4B) :: idiv - integer(I4B) :: ifound - integer(I4B) :: jpos - ! -- format - 10 format('Diversion ',i0,' of reach ',i0, & - ' is invalid or has not been defined.') - ! - ! -- write header - if (this%iprpak /= 0) then - ! - ! -- determine the maximum number of diversions - maxdiv = 0 - do n = 1, this%maxbound - maxdiv = maxdiv + this%ndiv(n) - end do + end do + ! + ! -- check for incorrect connections between upstream connections + ! + ! -- check upstream connections for each reach + ierr = 0 + do n = 1, this%maxbound + write (crch, '(i5)') n + eachconnv: do i = this%ia(n) + 1, this%ia(n + 1) - 1 ! - ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') REACH DIVERSION DATA' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(maxdiv, 4, this%iout) - text = 'REACH' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'DIVERSION' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'REACH 2' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'CPRIOR' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - end if - ! - ! -- check that diversion data are correct - do n = 1, this%maxbound - if (this%ndiv(n) < 1) cycle - write(crch, '(i5)') n - - do idiv = 1, this%ndiv(n) - ! - ! -- determine diversion index - jpos = this%iadiv(n) + idiv - 1 - ! - ! -- write idiv to cdiv - write(cdiv, '(i5)') idiv - ! - ! - nn = this%divreach(jpos) - write(crch2, '(i5)') nn + ! -- skip downstream connections + if (this%idir(i) < 0) cycle eachconnv + nn = this%ja(i) + write (crch2, '(i5)') nn + connreachv: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1 + ! -- skip downstream connections + if (this%idir(ii) < 0) cycle connreachv + nc = this%ja(ii) ! - ! -- make sure diversion reach is connected to current reach - ifound = 0 - if (nn < 1 .or. nn > this%maxbound) then - write(errmsg,10) idiv, n + ! -- if nc == n then that means reach n is an upstream connection for + ! reach nn and reach nn is an upstream connection for reach n + if (nc == n) then + ierr = ierr + 1 + errmsg = 'Reach '//crch//' is connected to '// & + 'reach '//crch2//' but streamflow from reach '// & + crch//' to reach '//crch2//' is not permitted.' call store_error(errmsg) - cycle + exit connreachv end if - connreach: do ii = this%ia(nn) + 1, this%ia(nn+1) - 1 - nc = this%ja(ii) - if (nc == n) then - if (this%idir(ii) > 0) then - ifound = 1 - end if - exit connreach + end do connreachv + end do eachconnv + end do + ! + ! -- terminate if connectivity errors + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- check that downstream reaches for a reach are + ! the upstream reaches for the reach + do n = 1, this%maxbound + write (crch, '(i5)') n + eachconnds: do i = this%ia(n) + 1, this%ia(n + 1) - 1 + nn = this%ja(i) + if (this%idir(i) > 0) cycle eachconnds + write (crch2, '(i5)') nn + ifound = 0 + connreachds: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1 + nc = this%ja(ii) + if (nc == n) then + if (this%idir(i) /= this%idir(ii)) then + ifound = 1 end if - end do connreach - if (ifound /= 1) then - errmsg = 'Reach ' // crch // ' is not a upstream reach for ' // & - 'reach ' // crch2 // ' as a result diversion ' // cdiv // & - ' from reach ' // crch //' to reach ' // crch2 // & - ' is not possible. Check reach connectivity.' - call store_error(errmsg) + exit connreachds end if - ! -- iprior - cprior = this%divcprior(jpos) - ! - ! -- add terms to the table - if (this%iprpak /= 0) then - call this%inputtab%add_term(n) - call this%inputtab%add_term(idiv) - call this%inputtab%add_term(nn) - call this%inputtab%add_term(cprior) + end do connreachds + if (ifound /= 1) then + errmsg = 'Reach '//crch//' downstream connected reach '// & + 'is reach '//crch2//' but reach '//crch//' is not'// & + ' the upstream connected reach for reach '//crch2//'.' + call store_error(errmsg) + end if + end do eachconnds + end do + ! + ! -- create input table for upstream and downstream connections + if (this%iprpak /= 0) then + ! + ! -- calculate the maximum number of upstream connections + maxconn = 0 + do n = 1, this%maxbound + ii = 0 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) then + ii = ii + 1 end if end do + maxconn = max(maxconn, ii) + end do + ntabcol = 1 + maxconn + ! + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC UPSTREAM REACH '// & + 'CONNECTION DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) + text = 'REACH' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + do n = 1, maxconn + write (text, '(a,1x,i6)') 'UPSTREAM CONN', n + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) end do ! - ! -- return - return - end subroutine sfr_check_diversions - - - !> @brief Check upstream fraction data - !! - !! Method to check upstream fraction data for a SFR package. - !! This method also creates the tables used to print input data, - !! if this option in enabled in the SFR package. - !! - !< - subroutine sfr_check_ustrf(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - character (len=LINELENGTH) :: title - character (len=LINELENGTH) :: text - logical(LGP) :: lcycle - logical(LGP) :: ladd - character (len=5) :: crch - character (len=5) :: crch2 - character (len=10) :: cval - integer(I4B) :: maxcols - integer(I4B) :: npairs - integer(I4B) :: ipair - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: n2 - integer(I4B) :: idiv - integer(I4B) :: i0 - integer(I4B) :: i1 - integer(I4B) :: jpos - integer(I4B) :: ids - real(DP) :: f - real(DP) :: rval - ! - ! -- write table header - if (this%iprpak /= 0) then - ! - ! -- determine the maximum number of columns - npairs = 0 - do n = 1, this%maxbound - ipair = 0 - ec: do i = this%ia(n) + 1, this%ia(n+1) - 1 - ! - ! -- skip upstream connections - if (this%idir(i) > 0) cycle ec - n2 = this%ja(i) - ! - ! -- skip inactive downstream reaches - if (this%iboundpak(n2) == 0) cycle ec - ! - ! -- increment ipair and see if it exceeds npairs - ipair = ipair + 1 - npairs = max(npairs, ipair) - end do ec + ! -- upstream connection data + do n = 1, this%maxbound + call this%inputtab%add_term(n) + ii = 0 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) then + call this%inputtab%add_term(this%ja(i)) + ii = ii + 1 + end if end do - maxcols = 1 + npairs * 2 - ! - ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') CONNECTED REACH UPSTREAM ' // & - 'FRACTION DATA' - call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(this%maxbound, maxcols, this%iout) - text = 'REACH' - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - do i = 1, npairs - write(cval, '(i10)') i - text = 'DOWNSTREAM REACH ' // trim(adjustl(cval)) - call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'FRACTION ' // trim(adjustl(cval)) - call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + nn = maxconn - ii + do i = 1, nn + call this%inputtab%add_term(' ') end do - end if + end do ! - ! -- fill diversion number for each connection + ! -- calculate the maximum number of downstream connections + maxconn = 0 do n = 1, this%maxbound - do idiv = 1, this%ndiv(n) - i0 = this%iadiv(n) - i1 = this%iadiv(n+1) - 1 - do jpos = i0, i1 - do i = this%ia(n) + 1, this%ia(n+1) - 1 - n2 = this%ja(i) - if (this%divreach(jpos) == n2) then - this%idiv(i) = jpos - i0 + 1 - exit - end if - end do - end do + ii = 0 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) < 0) then + ii = ii + 1 + end if end do + maxconn = max(maxconn, ii) + end do + ntabcol = 1 + maxconn + ! + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC DOWNSTREAM '// & + 'REACH CONNECTION DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(this%maxbound, ntabcol, this%iout) + text = 'REACH' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + do n = 1, maxconn + write (text, '(a,1x,i6)') 'DOWNSTREAM CONN', n + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) end do ! - ! -- check that the upstream fraction for reach connected by - ! a diversion is zero + ! -- downstream connection data do n = 1, this%maxbound - ! - ! -- determine the number of downstream reaches - ids = 0 - do i = this%ia(n) + 1, this%ia(n+1) - 1 + call this%inputtab%add_term(n) + ii = 0 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 if (this%idir(i) < 0) then - ids = ids + 1 + call this%inputtab%add_term(this%ja(i)) + ii = ii + 1 end if end do - ! - ! -- evaluate the diversions - do idiv = 1, this%ndiv(n) - jpos = this%iadiv(n) + idiv - 1 - n2 = this%divreach(jpos) - f = this%ustrf(n2) - if (f /= DZERO) then - write(errmsg, '(a,2(1x,i0,1x,a),1x,a,g0,a,2(1x,a))') & - 'Reach', n, 'is connected to reach', n2, 'by a diversion', & - 'but the upstream fraction is not equal to zero (', f, '). Check', & - trim(this%packName), 'package diversion and package data.' - if (ids > 1) then - call store_error(errmsg) - else - write(warnmsg, '(a,3(1x,a))') & - trim(warnmsg), 'A warning instead of an error is issued because', & - 'the reach is only connected to the diversion reach in the ', & - 'downstream direction.' - call store_warning(warnmsg) - end if - end if + nn = maxconn - ii + do i = 1, nn + call this%inputtab%add_term(' ') end do end do + end if + ! + ! -- return + return + end subroutine sfr_check_connections + + !> @brief Check diversions data + !! + !! Method to check diversion data for a SFR package. This method + !! also creates the tables used to print input data, if this + !! option in enabled in the SFR package. + !! + !< + subroutine sfr_check_diversions(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: text + character(len=5) :: crch + character(len=5) :: cdiv + character(len=5) :: crch2 + character(len=10) :: cprior + integer(I4B) :: maxdiv + integer(I4B) :: n + integer(I4B) :: nn + integer(I4B) :: nc + integer(I4B) :: ii + integer(I4B) :: idiv + integer(I4B) :: ifound + integer(I4B) :: jpos + ! -- format +10 format('Diversion ', i0, ' of reach ', i0, & + ' is invalid or has not been defined.') + ! + ! -- write header + if (this%iprpak /= 0) then ! - ! -- calculate the total fraction of connected reaches that are - ! not diversions and check that the sum of upstream fractions - ! is equal to 1 for each reach + ! -- determine the maximum number of diversions + maxdiv = 0 do n = 1, this%maxbound - ids = 0 - rval = DZERO - f = DZERO - write(crch, '(i5)') n + maxdiv = maxdiv + this%ndiv(n) + end do + ! + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') REACH DIVERSION DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(maxdiv, 4, this%iout) + text = 'REACH' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'DIVERSION' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'REACH 2' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'CPRIOR' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + end if + ! + ! -- check that diversion data are correct + do n = 1, this%maxbound + if (this%ndiv(n) < 1) cycle + write (crch, '(i5)') n + + do idiv = 1, this%ndiv(n) + ! + ! -- determine diversion index + jpos = this%iadiv(n) + idiv - 1 + ! + ! -- write idiv to cdiv + write (cdiv, '(i5)') idiv + ! + ! + nn = this%divreach(jpos) + write (crch2, '(i5)') nn + ! + ! -- make sure diversion reach is connected to current reach + ifound = 0 + if (nn < 1 .or. nn > this%maxbound) then + write (errmsg, 10) idiv, n + call store_error(errmsg) + cycle + end if + connreach: do ii = this%ia(nn) + 1, this%ia(nn + 1) - 1 + nc = this%ja(ii) + if (nc == n) then + if (this%idir(ii) > 0) then + ifound = 1 + end if + exit connreach + end if + end do connreach + if (ifound /= 1) then + errmsg = 'Reach '//crch//' is not a upstream reach for '// & + 'reach '//crch2//' as a result diversion '//cdiv// & + ' from reach '//crch//' to reach '//crch2// & + ' is not possible. Check reach connectivity.' + call store_error(errmsg) + end if + ! -- iprior + cprior = this%divcprior(jpos) + ! + ! -- add terms to the table if (this%iprpak /= 0) then call this%inputtab%add_term(n) + call this%inputtab%add_term(idiv) + call this%inputtab%add_term(nn) + call this%inputtab%add_term(cprior) end if + end do + end do + ! + ! -- return + return + end subroutine sfr_check_diversions + + !> @brief Check upstream fraction data + !! + !! Method to check upstream fraction data for a SFR package. + !! This method also creates the tables used to print input data, + !! if this option in enabled in the SFR package. + !! + !< + subroutine sfr_check_ustrf(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: text + logical(LGP) :: lcycle + logical(LGP) :: ladd + character(len=5) :: crch + character(len=5) :: crch2 + character(len=10) :: cval + integer(I4B) :: maxcols + integer(I4B) :: npairs + integer(I4B) :: ipair + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: n2 + integer(I4B) :: idiv + integer(I4B) :: i0 + integer(I4B) :: i1 + integer(I4B) :: jpos + integer(I4B) :: ids + real(DP) :: f + real(DP) :: rval + ! + ! -- write table header + if (this%iprpak /= 0) then + ! + ! -- determine the maximum number of columns + npairs = 0 + do n = 1, this%maxbound ipair = 0 - eachconn: do i = this%ia(n) + 1, this%ia(n+1) - 1 - lcycle = .FALSE. - ! - ! -- initialize downstream connection q - this%qconn(i) = DZERO + ec: do i = this%ia(n) + 1, this%ia(n + 1) - 1 ! ! -- skip upstream connections - if (this%idir(i) > 0) then - lcycle = .TRUE. - end if + if (this%idir(i) > 0) cycle ec n2 = this%ja(i) ! ! -- skip inactive downstream reaches - if (this%iboundpak(n2) == 0) then - lcycle = .TRUE. - end if - if (lcycle) then - cycle eachconn - end if - ipair = ipair + 1 - write(crch2, '(i5)') n2 - ids = ids + 1 - ladd = .true. - f = f + this%ustrf(n2) - write(cval, '(f10.4)') this%ustrf(n2) + if (this%iboundpak(n2) == 0) cycle ec ! - ! -- write upstream fractions - if (this%iprpak /= 0) then - call this%inputtab%add_term(n2) - call this%inputtab%add_term(this%ustrf(n2)) - end if - eachdiv: do idiv = 1, this%ndiv(n) - jpos = this%iadiv(n) + idiv - 1 + ! -- increment ipair and see if it exceeds npairs + ipair = ipair + 1 + npairs = max(npairs, ipair) + end do ec + end do + maxcols = 1 + npairs * 2 + ! + ! -- reset the input table object + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') CONNECTED REACH UPSTREAM '// & + 'FRACTION DATA' + call table_cr(this%inputtab, this%packName, title) + call this%inputtab%table_df(this%maxbound, maxcols, this%iout) + text = 'REACH' + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + do i = 1, npairs + write (cval, '(i10)') i + text = 'DOWNSTREAM REACH '//trim(adjustl(cval)) + call this%inputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'FRACTION '//trim(adjustl(cval)) + call this%inputtab%initialize_column(text, 12, alignment=TABCENTER) + end do + end if + ! + ! -- fill diversion number for each connection + do n = 1, this%maxbound + do idiv = 1, this%ndiv(n) + i0 = this%iadiv(n) + i1 = this%iadiv(n + 1) - 1 + do jpos = i0, i1 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + n2 = this%ja(i) if (this%divreach(jpos) == n2) then - ladd = .false. - exit eachdiv + this%idiv(i) = jpos - i0 + 1 + exit end if - end do eachdiv - if (ladd) then - rval = rval + this%ustrf(n2) + end do + end do + end do + end do + ! + ! -- check that the upstream fraction for reach connected by + ! a diversion is zero + do n = 1, this%maxbound + ! + ! -- determine the number of downstream reaches + ids = 0 + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) < 0) then + ids = ids + 1 + end if + end do + ! + ! -- evaluate the diversions + do idiv = 1, this%ndiv(n) + jpos = this%iadiv(n) + idiv - 1 + n2 = this%divreach(jpos) + f = this%ustrf(n2) + if (f /= DZERO) then + write (errmsg, '(a,2(1x,i0,1x,a),1x,a,g0,a,2(1x,a))') & + 'Reach', n, 'is connected to reach', n2, 'by a diversion', & + 'but the upstream fraction is not equal to zero (', f, '). Check', & + trim(this%packName), 'package diversion and package data.' + if (ids > 1) then + call store_error(errmsg) + else + write (warnmsg, '(a,3(1x,a))') & + trim(warnmsg), & + 'A warning instead of an error is issued because', & + 'the reach is only connected to the diversion reach in the ', & + 'downstream direction.' + call store_warning(warnmsg) end if - end do eachconn - this%ftotnd(n) = rval + end if + end do + end do + ! + ! -- calculate the total fraction of connected reaches that are + ! not diversions and check that the sum of upstream fractions + ! is equal to 1 for each reach + do n = 1, this%maxbound + ids = 0 + rval = DZERO + f = DZERO + write (crch, '(i5)') n + if (this%iprpak /= 0) then + call this%inputtab%add_term(n) + end if + ipair = 0 + eachconn: do i = this%ia(n) + 1, this%ia(n + 1) - 1 + lcycle = .FALSE. ! - ! -- write remaining table columns - if (this%iprpak /= 0) then - ipair = ipair + 1 - do i = ipair, npairs - call this%inputtab%add_term(' ') - call this%inputtab%add_term(' ') - end do + ! -- initialize downstream connection q + this%qconn(i) = DZERO + ! + ! -- skip upstream connections + if (this%idir(i) > 0) then + lcycle = .TRUE. end if + n2 = this%ja(i) ! - ! -- evaluate if an error condition has occured - ! the sum of fractions is not equal to 1 - if (ids /= 0) then - if (abs(f-DONE) > DEM6) then - write(errmsg, '(a,1x,i0,1x,a,g0,a,3(1x,a))') & - 'Upstream fractions for reach ', n, 'is not equal to one (', f, & - '). Check', trim(this%packName), 'package reach connectivity and', & - 'package data.' - call store_error(errmsg) + ! -- skip inactive downstream reaches + if (this%iboundpak(n2) == 0) then + lcycle = .TRUE. + end if + if (lcycle) then + cycle eachconn + end if + ipair = ipair + 1 + write (crch2, '(i5)') n2 + ids = ids + 1 + ladd = .true. + f = f + this%ustrf(n2) + write (cval, '(f10.4)') this%ustrf(n2) + ! + ! -- write upstream fractions + if (this%iprpak /= 0) then + call this%inputtab%add_term(n2) + call this%inputtab%add_term(this%ustrf(n2)) + end if + eachdiv: do idiv = 1, this%ndiv(n) + jpos = this%iadiv(n) + idiv - 1 + if (this%divreach(jpos) == n2) then + ladd = .false. + exit eachdiv end if + end do eachdiv + if (ladd) then + rval = rval + this%ustrf(n2) end if - end do + end do eachconn + this%ftotnd(n) = rval ! - ! -- return - return - end subroutine sfr_check_ustrf - + ! -- write remaining table columns + if (this%iprpak /= 0) then + ipair = ipair + 1 + do i = ipair, npairs + call this%inputtab%add_term(' ') + call this%inputtab%add_term(' ') + end do + end if + ! + ! -- evaluate if an error condition has occured + ! the sum of fractions is not equal to 1 + if (ids /= 0) then + if (abs(f - DONE) > DEM6) then + write (errmsg, '(a,1x,i0,1x,a,g0,a,3(1x,a))') & + 'Upstream fractions for reach ', n, 'is not equal to one (', f, & + '). Check', trim(this%packName), 'package reach connectivity and', & + 'package data.' + call store_error(errmsg) + end if + end if + end do + ! + ! -- return + return + end subroutine sfr_check_ustrf - !> @brief Setup budget object for package + !> @brief Setup budget object for package !! !! Method to set up the budget object that stores all the sfr flows - !! The terms listed here must correspond in number and order to the ones + !! The terms listed here must correspond in number and order to the ones !! listed in the sfr_fill_budobj method. !! - !< - subroutine sfr_setup_budobj(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: nbudterm - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: n1 - integer(I4B) :: n2 - integer(I4B) :: maxlist - integer(I4B) :: naux - integer(I4B) :: idx - real(DP) :: q - character(len=LENBUDTXT) :: text - character(len=LENBUDTXT), dimension(1) :: auxtxt - ! - ! -- Determine the number of sfr budget terms. These are fixed for - ! the simulation and cannot change. This includes FLOW-JA-FACE - ! so they can be written to the binary budget files, but these internal - ! flows are not included as part of the budget table. - nbudterm = 8 - if (this%imover == 1) nbudterm = nbudterm + 2 - if (this%naux > 0) nbudterm = nbudterm + 1 - ! - ! -- set up budobj - call budgetobject_cr(this%budobj, this%packName) - call this%budobj%budgetobject_df(this%maxbound, nbudterm, 0, 0, & - ibudcsv=this%ibudcsv) - idx = 0 - ! - ! -- Go through and set up each budget term - text = ' FLOW-JA-FACE' - idx = idx + 1 - maxlist = this%nconn - naux = 1 - auxtxt(1) = ' FLOW-AREA' - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux, auxtxt) - ! - ! -- store connectivity - call this%budobj%budterm(idx)%reset(this%nconn) - q = DZERO - do n = 1, this%maxbound - n1 = n - do i = this%ia(n) + 1, this%ia(n+1) - 1 - n2 = this%ja(i) - call this%budobj%budterm(idx)%update_term(n1, n2, q) - end do - end do - ! - ! -- - text = ' GWF' - idx = idx + 1 - maxlist = this%maxbound - this%ianynone - naux = 1 - auxtxt(1) = ' FLOW-AREA' - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%name_model, & - maxlist, .false., .true., & - naux, auxtxt) - call this%budobj%budterm(idx)%reset(this%maxbound) - q = DZERO - do n = 1, this%maxbound - n2 = this%igwfnode(n) - if (n2 > 0) then - call this%budobj%budterm(idx)%update_term(n, n2, q) - end if + !< + subroutine sfr_setup_budobj(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: nbudterm + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: n1 + integer(I4B) :: n2 + integer(I4B) :: maxlist + integer(I4B) :: naux + integer(I4B) :: idx + real(DP) :: q + character(len=LENBUDTXT) :: text + character(len=LENBUDTXT), dimension(1) :: auxtxt + ! + ! -- Determine the number of sfr budget terms. These are fixed for + ! the simulation and cannot change. This includes FLOW-JA-FACE + ! so they can be written to the binary budget files, but these internal + ! flows are not included as part of the budget table. + nbudterm = 8 + if (this%imover == 1) nbudterm = nbudterm + 2 + if (this%naux > 0) nbudterm = nbudterm + 1 + ! + ! -- set up budobj + call budgetobject_cr(this%budobj, this%packName) + call this%budobj%budgetobject_df(this%maxbound, nbudterm, 0, 0, & + ibudcsv=this%ibudcsv) + idx = 0 + ! + ! -- Go through and set up each budget term + text = ' FLOW-JA-FACE' + idx = idx + 1 + maxlist = this%nconn + naux = 1 + auxtxt(1) = ' FLOW-AREA' + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux, auxtxt) + ! + ! -- store connectivity + call this%budobj%budterm(idx)%reset(this%nconn) + q = DZERO + do n = 1, this%maxbound + n1 = n + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + n2 = this%ja(i) + call this%budobj%budterm(idx)%update_term(n1, n2, q) end do + end do + ! + ! -- + text = ' GWF' + idx = idx + 1 + maxlist = this%maxbound - this%ianynone + naux = 1 + auxtxt(1) = ' FLOW-AREA' + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%name_model, & + maxlist, .false., .true., & + naux, auxtxt) + call this%budobj%budterm(idx)%reset(this%maxbound) + q = DZERO + do n = 1, this%maxbound + n2 = this%igwfnode(n) + if (n2 > 0) then + call this%budobj%budterm(idx)%update_term(n, n2, q) + end if + end do + ! + ! -- + text = ' RAINFALL' + idx = idx + 1 + maxlist = this%maxbound + naux = 0 + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' EVAPORATION' + idx = idx + 1 + maxlist = this%maxbound + naux = 0 + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' RUNOFF' + idx = idx + 1 + maxlist = this%maxbound + naux = 0 + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' EXT-INFLOW' + idx = idx + 1 + maxlist = this%maxbound + naux = 0 + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' EXT-OUTFLOW' + idx = idx + 1 + maxlist = this%maxbound + naux = 0 + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' STORAGE' + idx = idx + 1 + maxlist = this%maxbound + naux = 1 + auxtxt(1) = ' VOLUME' + call this%budobj%budterm(idx)%initialize(text, & + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux, auxtxt) + ! + ! -- + if (this%imover == 1) then ! - ! -- - text = ' RAINFALL' - idx = idx + 1 - maxlist = this%maxbound - naux = 0 - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- - text = ' EVAPORATION' - idx = idx + 1 - maxlist = this%maxbound - naux = 0 - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- - text = ' RUNOFF' - idx = idx + 1 - maxlist = this%maxbound - naux = 0 - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- - text = ' EXT-INFLOW' + ! -- + text = ' FROM-MVR' idx = idx + 1 maxlist = this%maxbound naux = 0 call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- - text = ' EXT-OUTFLOW' + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + ! + ! -- + text = ' TO-MVR' idx = idx + 1 maxlist = this%maxbound naux = 0 call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux) + end if + ! + ! -- + naux = this%naux + if (naux > 0) then ! - ! -- - text = ' STORAGE' + ! -- + text = ' AUXILIARY' idx = idx + 1 maxlist = this%maxbound - naux = 1 - auxtxt(1) = ' VOLUME' call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux, auxtxt) - ! - ! -- - if (this%imover == 1) then - ! - ! -- - text = ' FROM-MVR' - idx = idx + 1 - maxlist = this%maxbound - naux = 0 - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - ! - ! -- - text = ' TO-MVR' - idx = idx + 1 - maxlist = this%maxbound - naux = 0 - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux) - end if - ! - ! -- - naux = this%naux - if (naux > 0) then - ! - ! -- - text = ' AUXILIARY' - idx = idx + 1 - maxlist = this%maxbound - call this%budobj%budterm(idx)%initialize(text, & - this%name_model, & - this%packName, & - this%name_model, & - this%packName, & - maxlist, .false., .false., & - naux, this%auxname) - end if - ! - ! -- if sfr flow for each reach are written to the listing file - if (this%iprflow /= 0) then - call this%budobj%flowtable_df(this%iout, cellids='GWF') - end if - ! - ! -- return - return - end subroutine sfr_setup_budobj + this%name_model, & + this%packName, & + this%name_model, & + this%packName, & + maxlist, .false., .false., & + naux, this%auxname) + end if + ! + ! -- if sfr flow for each reach are written to the listing file + if (this%iprflow /= 0) then + call this%budobj%flowtable_df(this%iout, cellids='GWF') + end if + ! + ! -- return + return + end subroutine sfr_setup_budobj - !> @brief Copy flow terms into budget object for package + !> @brief Copy flow terms into budget object for package !! !! Method to copy flows into the budget object that stores all the sfr flows - !! The terms listed here must correspond in number and order to the ones + !! The terms listed here must correspond in number and order to the ones !! added in the sfr_setup_budobj method. !! - !< - subroutine sfr_fill_budobj(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: naux - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: n1 - integer(I4B) :: n2 - integer(I4B) :: ii - integer(I4B) :: idx - integer(I4B) :: idiv - integer(I4B) :: jpos - real(DP) :: q - real(DP) :: qt - real(DP) :: d - real(DP) :: ca - real(DP) :: a - ! - ! -- initialize counter - idx = 0 - ! - ! -- FLOW JA FACE - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%nconn) - do n = 1, this%maxbound - n1 = n - do i = this%ia(n) + 1, this%ia(n+1) - 1 - n2 = this%ja(i) - ! flow to downstream reaches - if (this%idir(i) < 0) then - qt = this%dsflow(n) - q = -this%qconn(i) + !< + subroutine sfr_fill_budobj(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: naux + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: n1 + integer(I4B) :: n2 + integer(I4B) :: ii + integer(I4B) :: idx + integer(I4B) :: idiv + integer(I4B) :: jpos + real(DP) :: q + real(DP) :: qt + real(DP) :: d + real(DP) :: ca + real(DP) :: a + ! + ! -- initialize counter + idx = 0 + ! + ! -- FLOW JA FACE + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%nconn) + do n = 1, this%maxbound + n1 = n + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + n2 = this%ja(i) + ! flow to downstream reaches + if (this%idir(i) < 0) then + qt = this%dsflow(n) + q = -this%qconn(i) ! flow from upstream reaches - else - qt = this%usflow(n) - do ii = this%ia(n2) + 1, this%ia(n2+1) - 1 - if (this%idir(ii) > 0) cycle - if (this%ja(ii) /= n) cycle - q = this%qconn(ii) - exit - end do - end if - ! calculate flow area - call this%sfr_calc_reach_depth(n, qt, d) - ca = this%calc_area_wet(n, d) - this%qauxcbc(1) = ca - call this%budobj%budterm(idx)%update_term(n1, n2, q, this%qauxcbc) - end do - end do - ! - ! -- GWF (LEAKAGE) - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound - this%ianynone) - do n = 1, this%maxbound - n2 = this%igwfnode(n) - if (n2 > 0) then - a = this%calc_surface_area(n) - this%qauxcbc(1) = a - q = -this%gwflow(n) - call this%budobj%budterm(idx)%update_term(n, n2, q, this%qauxcbc) + else + qt = this%usflow(n) + do ii = this%ia(n2) + 1, this%ia(n2 + 1) - 1 + if (this%idir(ii) > 0) cycle + if (this%ja(ii) /= n) cycle + q = this%qconn(ii) + exit + end do end if + ! calculate flow area + call this%sfr_calc_reach_depth(n, qt, d) + ca = this%calc_area_wet(n, d) + this%qauxcbc(1) = ca + call this%budobj%budterm(idx)%update_term(n1, n2, q, this%qauxcbc) end do - ! - ! -- RAIN - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound + end do + ! + ! -- GWF (LEAKAGE) + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound - this%ianynone) + do n = 1, this%maxbound + n2 = this%igwfnode(n) + if (n2 > 0) then a = this%calc_surface_area(n) - q = this%rain(n) * a - call this%budobj%budterm(idx)%update_term(n, n, q) - end do - ! - ! -- EVAPORATION - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound - q = -this%simevap(n) - call this%budobj%budterm(idx)%update_term(n, n, q) - end do - ! - ! -- RUNOFF - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound - q = this%simrunoff(n) - call this%budobj%budterm(idx)%update_term(n, n, q) + this%qauxcbc(1) = a + q = -this%gwflow(n) + call this%budobj%budterm(idx)%update_term(n, n2, q, this%qauxcbc) + end if + end do + ! + ! -- RAIN + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + a = this%calc_surface_area(n) + q = this%rain(n) * a + call this%budobj%budterm(idx)%update_term(n, n, q) + end do + ! + ! -- EVAPORATION + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + q = -this%simevap(n) + call this%budobj%budterm(idx)%update_term(n, n, q) + end do + ! + ! -- RUNOFF + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + q = this%simrunoff(n) + call this%budobj%budterm(idx)%update_term(n, n, q) + end do + ! + ! -- INFLOW + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + q = this%inflow(n) + call this%budobj%budterm(idx)%update_term(n, n, q) + end do + ! + ! -- EXTERNAL OUTFLOW + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + q = DZERO + do i = this%ia(n) + 1, this%ia(n + 1) - 1 + if (this%idir(i) > 0) cycle + idiv = this%idiv(i) + if (idiv > 0) then + jpos = this%iadiv(n) + idiv - 1 + q = q + this%divq(jpos) + else + q = q + this%qconn(i) + end if end do + q = q - this%dsflow(n) + if (this%imover == 1) then + q = q + this%pakmvrobj%get_qtomvr(n) + end if + call this%budobj%budterm(idx)%update_term(n, n, q) + end do + ! + ! -- STORAGE + idx = idx + 1 + call this%budobj%budterm(idx)%reset(this%maxbound) + do n = 1, this%maxbound + q = DZERO + d = this%depth(n) + a = this%calc_surface_area_wet(n, d) + this%qauxcbc(1) = a * d + call this%budobj%budterm(idx)%update_term(n, n, q, this%qauxcbc) + end do + ! + ! -- MOVER + if (this%imover == 1) then ! - ! -- INFLOW + ! -- FROM MOVER idx = idx + 1 call this%budobj%budterm(idx)%reset(this%maxbound) do n = 1, this%maxbound - q = this%inflow(n) + q = this%pakmvrobj%get_qfrommvr(n) call this%budobj%budterm(idx)%update_term(n, n, q) end do ! - ! -- EXTERNAL OUTFLOW + ! -- TO MOVER idx = idx + 1 call this%budobj%budterm(idx)%reset(this%maxbound) do n = 1, this%maxbound - q = DZERO - do i = this%ia(n) + 1, this%ia(n+1) - 1 - if (this%idir(i) > 0) cycle - idiv = this%idiv(i) - if (idiv > 0) then - jpos = this%iadiv(n) + idiv - 1 - q = q + this%divq(jpos) - else - q = q + this%qconn(i) - end if - end do - q = q - this%dsflow(n) - if (this%imover == 1) then - q = q + this%pakmvrobj%get_qtomvr(n) + q = this%pakmvrobj%get_qtomvr(n) + if (q > DZERO) then + q = -q end if call this%budobj%budterm(idx)%update_term(n, n, q) end do - ! - ! -- STORAGE + end if + ! + ! -- AUXILIARY VARIABLES + naux = this%naux + if (naux > 0) then idx = idx + 1 call this%budobj%budterm(idx)%reset(this%maxbound) do n = 1, this%maxbound q = DZERO - d = this%depth(n) - a = this%calc_surface_area_wet(n, d) - this%qauxcbc(1) = a * d - call this%budobj%budterm(idx)%update_term(n, n, q, this%qauxcbc) + call this%budobj%budterm(idx)%update_term(n, n, q, this%auxvar(:, n)) end do + end if + ! + ! --Terms are filled, now accumulate them for this time step + call this%budobj%accumulate_terms() + ! + ! -- return + return + end subroutine sfr_fill_budobj + + !> @brief Setup stage table object for package + !! + !! Method to set up the table object that is used to write the sfr + !! stage data. The terms listed here must correspond in number and + !! order to the ones written to the stage table in the sfr_ot method. + !! + !< + subroutine sfr_setup_tableobj(this) + ! -- dummy variables + class(SfrType) :: this !< SfrType object + ! -- local variables + integer(I4B) :: nterms + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: text + ! + ! -- setup stage table + if (this%iprhed > 0) then ! - ! -- MOVER - if (this%imover == 1) then - ! - ! -- FROM MOVER - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound - q = this%pakmvrobj%get_qfrommvr(n) - call this%budobj%budterm(idx)%update_term(n, n, q) - end do - ! - ! -- TO MOVER - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound - q = this%pakmvrobj%get_qtomvr(n) - if (q > DZERO) then - q = -q - end if - call this%budobj%budterm(idx)%update_term(n, n, q) - end do + ! -- Determine the number of sfr budget terms. These are fixed for + ! the simulation and cannot change. This includes FLOW-JA-FACE + ! so they can be written to the binary budget files, but these internal + ! flows are not included as part of the budget table. + nterms = 8 + if (this%inamedbound == 1) then + nterms = nterms + 1 end if ! - ! -- AUXILIARY VARIABLES - naux = this%naux - if (naux > 0) then - idx = idx + 1 - call this%budobj%budterm(idx)%reset(this%maxbound) - do n = 1, this%maxbound - q = DZERO - call this%budobj%budterm(idx)%update_term(n, n, q, this%auxvar(:, n)) - end do + ! -- set up table title + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STAGES FOR EACH CONTROL VOLUME' + ! + ! -- set up stage tableobj + call table_cr(this%stagetab, this%packName, title) + call this%stagetab%table_df(this%maxbound, nterms, this%iout, & + transient=.TRUE.) + ! + ! -- Go through and set up table budget term + if (this%inamedbound == 1) then + text = 'NAME' + call this%stagetab%initialize_column(text, LENBOUNDNAME, & + alignment=TABLEFT) end if ! - ! --Terms are filled, now accumulate them for this time step - call this%budobj%accumulate_terms() + ! -- reach number + text = 'NUMBER' + call this%stagetab%initialize_column(text, 10, alignment=TABCENTER) ! - ! -- return - return - end subroutine sfr_fill_budobj - - !> @brief Setup stage table object for package - !! - !! Method to set up the table object that is used to write the sfr - !! stage data. The terms listed here must correspond in number and - !! order to the ones written to the stage table in the sfr_ot method. - !! - !< - subroutine sfr_setup_tableobj(this) - ! -- dummy variables - class(SfrType) :: this !< SfrType object - ! -- local variables - integer(I4B) :: nterms - character(len=LINELENGTH) :: title - character(len=LINELENGTH) :: text + ! -- cellids + text = 'CELLID' + call this%stagetab%initialize_column(text, 20, alignment=TABLEFT) ! - ! -- setup stage table - if (this%iprhed > 0) then - ! - ! -- Determine the number of sfr budget terms. These are fixed for - ! the simulation and cannot change. This includes FLOW-JA-FACE - ! so they can be written to the binary budget files, but these internal - ! flows are not included as part of the budget table. - nterms = 8 - if (this%inamedbound == 1) then - nterms = nterms + 1 - end if - ! - ! -- set up table title - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STAGES FOR EACH CONTROL VOLUME' - ! - ! -- set up stage tableobj - call table_cr(this%stagetab, this%packName, title) - call this%stagetab%table_df(this%maxbound, nterms, this%iout, & - transient=.TRUE.) - ! - ! -- Go through and set up table budget term - if (this%inamedbound == 1) then - text = 'NAME' - call this%stagetab%initialize_column(text, LENBOUNDNAME, alignment=TABLEFT) - end if - ! - ! -- reach number - text = 'NUMBER' - call this%stagetab%initialize_column(text, 10, alignment=TABCENTER) - ! - ! -- cellids - text = 'CELLID' - call this%stagetab%initialize_column(text, 20, alignment=TABLEFT) - ! - ! -- reach stage - text = 'STAGE' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - ! - ! -- reach depth - text = 'DEPTH' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - ! - ! -- reach width - text = 'WIDTH' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - ! - ! -- gwf head - text = 'GWF HEAD' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - ! - ! -- streambed conductance - text = 'STREAMBED CONDUCTANCE' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - ! - ! -- streambed gradient - text = 'STREAMBED GRADIENT' - call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) - end if + ! -- reach stage + text = 'STAGE' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) + ! + ! -- reach depth + text = 'DEPTH' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) + ! + ! -- reach width + text = 'WIDTH' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) + ! + ! -- gwf head + text = 'GWF HEAD' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) ! - ! -- return - return - end subroutine sfr_setup_tableobj - + ! -- streambed conductance + text = 'STREAMBED CONDUCTANCE' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) + ! + ! -- streambed gradient + text = 'STREAMBED GRADIENT' + call this%stagetab%initialize_column(text, 12, alignment=TABCENTER) + end if + ! + ! -- return + return + end subroutine sfr_setup_tableobj - ! -- reach geometry functions + ! -- reach geometry functions - !> @brief Calculate wetted area + !> @brief Calculate wetted area !! !! Function to calculate the wetted area for a SFR package reach. !! - !< - function calc_area_wet(this, n, depth) - ! -- return variable - real(DP) :: calc_area_wet !< wetted area - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - ! -- local variables - integer(I4B) :: npts - integer(I4B) :: i0 - integer(I4B) :: i1 - ! - ! -- Calculate wetted area - npts = this%ncrosspts(n) - i0 = this%iacross(n) - i1 = this%iacross(n + 1) - 1 - if (npts > 1) then - calc_area_wet = get_cross_section_area(npts, this%station(i0:i1), & - this%xsheight(i0:i1), depth) - else - calc_area_wet = this%station(i0) * depth - end if - ! - ! -- return - return - end function calc_area_wet - - - !> @brief Calculate wetted perimeter + !< + function calc_area_wet(this, n, depth) + ! -- return variable + real(DP) :: calc_area_wet !< wetted area + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + ! -- local variables + integer(I4B) :: npts + integer(I4B) :: i0 + integer(I4B) :: i1 + ! + ! -- Calculate wetted area + npts = this%ncrosspts(n) + i0 = this%iacross(n) + i1 = this%iacross(n + 1) - 1 + if (npts > 1) then + calc_area_wet = get_cross_section_area(npts, this%station(i0:i1), & + this%xsheight(i0:i1), depth) + else + calc_area_wet = this%station(i0) * depth + end if + ! + ! -- return + return + end function calc_area_wet + + !> @brief Calculate wetted perimeter !! !! Function to calculate the wetted perimeter for a SFR package reach. !! - !< - function calc_perimeter_wet(this, n, depth) - ! -- return variable - real(DP) :: calc_perimeter_wet !< wetted perimeter - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - ! -- local variables - integer(I4B) :: npts - integer(I4B) :: i0 - integer(I4B) :: i1 - ! - ! -- Calculate wetted perimeter - npts = this%ncrosspts(n) - i0 = this%iacross(n) - i1 = this%iacross(n + 1) - 1 - if (npts > 1) then - calc_perimeter_wet = get_wetted_perimeter(npts, this%station(i0:i1), & - this%xsheight(i0:i1), depth) - else - calc_perimeter_wet = this%station(i0) ! no depth dependence in original implementation - end if - ! - ! -- return - return - end function calc_perimeter_wet + !< + function calc_perimeter_wet(this, n, depth) + ! -- return variable + real(DP) :: calc_perimeter_wet !< wetted perimeter + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + ! -- local variables + integer(I4B) :: npts + integer(I4B) :: i0 + integer(I4B) :: i1 + ! + ! -- Calculate wetted perimeter + npts = this%ncrosspts(n) + i0 = this%iacross(n) + i1 = this%iacross(n + 1) - 1 + if (npts > 1) then + calc_perimeter_wet = get_wetted_perimeter(npts, this%station(i0:i1), & + this%xsheight(i0:i1), depth) + else + calc_perimeter_wet = this%station(i0) ! no depth dependence in original implementation + end if + ! + ! -- return + return + end function calc_perimeter_wet - !> @brief Calculate maximum surface area + !> @brief Calculate maximum surface area !! !! Function to calculate the maximum surface area for a SFR package reach. !! - !< - function calc_surface_area(this, n) - ! -- return variable - real(DP) :: calc_surface_area !< surface area - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - ! -- local variables - integer(I4B) :: npts - integer(I4B) :: i0 - integer(I4B) :: i1 - real(DP) :: top_width - ! - ! -- Calculate surface area - npts = this%ncrosspts(n) - i0 = this%iacross(n) - i1 = this%iacross(n + 1) - 1 - if (npts > 1) then - top_width = get_saturated_topwidth(npts, this%station(i0:i1)) - else - top_width = this%station(i0) - end if - calc_surface_area = top_width * this%length(n) - ! - ! -- return - return - end function calc_surface_area - - !> @brief Calculate wetted surface area + !< + function calc_surface_area(this, n) + ! -- return variable + real(DP) :: calc_surface_area !< surface area + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + ! -- local variables + integer(I4B) :: npts + integer(I4B) :: i0 + integer(I4B) :: i1 + real(DP) :: top_width + ! + ! -- Calculate surface area + npts = this%ncrosspts(n) + i0 = this%iacross(n) + i1 = this%iacross(n + 1) - 1 + if (npts > 1) then + top_width = get_saturated_topwidth(npts, this%station(i0:i1)) + else + top_width = this%station(i0) + end if + calc_surface_area = top_width * this%length(n) + ! + ! -- return + return + end function calc_surface_area + + !> @brief Calculate wetted surface area !! !! Function to calculate the wetted surface area for a SFR package reach. !! - !< - function calc_surface_area_wet(this, n, depth) - ! -- return variable - real(DP) :: calc_surface_area_wet !< wetted surface area - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - ! -- local variables - real(DP) :: top_width - ! - ! -- Calculate wetted surface area - top_width = this%calc_top_width_wet(n, depth) - calc_surface_area_wet = top_width * this%length(n) - ! - ! -- return - return - end function calc_surface_area_wet - - !> @brief Calculate wetted top width + !< + function calc_surface_area_wet(this, n, depth) + ! -- return variable + real(DP) :: calc_surface_area_wet !< wetted surface area + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + ! -- local variables + real(DP) :: top_width + ! + ! -- Calculate wetted surface area + top_width = this%calc_top_width_wet(n, depth) + calc_surface_area_wet = top_width * this%length(n) + ! + ! -- return + return + end function calc_surface_area_wet + + !> @brief Calculate wetted top width !! !! Function to calculate the wetted top width for a SFR package reach. !! - !< - function calc_top_width_wet(this, n, depth) - ! -- return variable - real(DP) :: calc_top_width_wet !< wetted top width - ! -- dummy variables - class(SfrType) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: depth !< reach depth - ! -- local variables - integer(I4B) :: npts - integer(I4B) :: i0 - integer(I4B) :: i1 - real(DP) :: sat - ! - ! -- Calculate wetted top width - npts = this%ncrosspts(n) - i0 = this%iacross(n) - i1 = this%iacross(n + 1) - 1 - sat = sCubicSaturation(DEM5, DZERO, depth, DEM5) - if (npts > 1) then - calc_top_width_wet = sat * get_wetted_topwidth(npts, & - this%station(i0:i1), & - this%xsheight(i0:i1), & - depth) - else - calc_top_width_wet = sat * this%station(i0) - end if - ! - ! -- return - return - end function calc_top_width_wet + !< + function calc_top_width_wet(this, n, depth) + ! -- return variable + real(DP) :: calc_top_width_wet !< wetted top width + ! -- dummy variables + class(SfrType) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: depth !< reach depth + ! -- local variables + integer(I4B) :: npts + integer(I4B) :: i0 + integer(I4B) :: i1 + real(DP) :: sat + ! + ! -- Calculate wetted top width + npts = this%ncrosspts(n) + i0 = this%iacross(n) + i1 = this%iacross(n + 1) - 1 + sat = sCubicSaturation(DEM5, DZERO, depth, DEM5) + if (npts > 1) then + calc_top_width_wet = sat * get_wetted_topwidth(npts, & + this%station(i0:i1), & + this%xsheight(i0:i1), & + depth) + else + calc_top_width_wet = sat * this%station(i0) + end if + ! + ! -- return + return + end function calc_top_width_wet - !> @brief Activate density terms + !> @brief Activate density terms !! !! Method to activate addition of density terms for a SFR package reach. !! - !< - subroutine sfr_activate_density(this) - ! -- modules - use MemoryManagerModule, only: mem_reallocate - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - ! - ! -- Set idense and reallocate denseterms to be of size MAXBOUND - this%idense = 1 - call mem_reallocate(this%denseterms, 3, this%MAXBOUND, 'DENSETERMS', & - this%memoryPath) - do i = 1, this%maxbound - do j = 1, 3 - this%denseterms(j, i) = DZERO - end do + !< + subroutine sfr_activate_density(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- Set idense and reallocate denseterms to be of size MAXBOUND + this%idense = 1 + call mem_reallocate(this%denseterms, 3, this%MAXBOUND, 'DENSETERMS', & + this%memoryPath) + do i = 1, this%maxbound + do j = 1, 3 + this%denseterms(j, i) = DZERO end do - write(this%iout,'(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR SFR & - &PACKAGE: ' // trim(adjustl(this%packName)) - ! - ! -- return - return - end subroutine sfr_activate_density + end do + write (this%iout, '(/1x,a)') 'DENSITY TERMS HAVE BEEN ACTIVATED FOR SFR & + &PACKAGE: '//trim(adjustl(this%packName)) + ! + ! -- return + return + end subroutine sfr_activate_density - !> @brief Calculate density terms + !> @brief Activate viscosity terms !! - !! Method to galculate groundwater-reach density exchange terms for a + !! Method to activate addition of viscosity terms for exhange + !! with groundwater along a SFR package reach. + !! + !< + subroutine sfr_activate_viscosity(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND + this%ivsc = 1 + call mem_reallocate(this%viscratios, 2, this%MAXBOUND, 'VISCRATIOS', & + this%memoryPath) + do i = 1, this%maxbound + do j = 1, 2 + this%viscratios(j, i) = DONE + end do + end do + write (this%iout, '(/1x,a)') 'VISCOSITY HAS BEEN ACTIVATED FOR SFR & + &PACKAGE: '//trim(adjustl(this%packName)) + ! + ! -- return + return + end subroutine sfr_activate_viscosity + + !> @brief Calculate density terms + !! + !! Method to galculate groundwater-reach density exchange terms for a !! SFR package reach. !! !! Member variable used here @@ -5567,94 +5633,94 @@ end subroutine sfr_activate_density !! col 2 is relative density of gwf cell (densegwf / denseref) !! col 3 is elevation of gwf cell !! - !< - subroutine sfr_calculate_density_exchange(this, n, stage, head, cond, & - bots, flow, gwfhcof, gwfrhs) - ! -- dummy variables - class(SfrType),intent(inout) :: this !< SfrType object - integer(I4B), intent(in) :: n !< reach number - real(DP), intent(in) :: stage !< reach stage - real(DP), intent(in) :: head !< head in connected GWF cell - real(DP), intent(in) :: cond !< reach conductance - real(DP), intent(in) :: bots !< bottom elevation of reach - real(DP), intent(inout) :: flow !< calculated flow, updated here with density terms - real(DP), intent(inout) :: gwfhcof !< GWF diagonal coefficient, updated here with density terms - real(DP), intent(inout) :: gwfrhs !< GWF right-hand-side value, updated here with density terms - ! -- local variables - real(DP) :: ss - real(DP) :: hh - real(DP) :: havg - real(DP) :: rdensesfr - real(DP) :: rdensegwf - real(DP) :: rdenseavg - real(DP) :: elevsfr - real(DP) :: elevgwf - real(DP) :: elevavg - real(DP) :: d1 - real(DP) :: d2 - logical(LGP) :: stage_below_bot - logical(LGP) :: head_below_bot + !< + subroutine sfr_calculate_density_exchange(this, n, stage, head, cond, & + bots, flow, gwfhcof, gwfrhs) + ! -- dummy variables + class(SfrType), intent(inout) :: this !< SfrType object + integer(I4B), intent(in) :: n !< reach number + real(DP), intent(in) :: stage !< reach stage + real(DP), intent(in) :: head !< head in connected GWF cell + real(DP), intent(in) :: cond !< reach conductance + real(DP), intent(in) :: bots !< bottom elevation of reach + real(DP), intent(inout) :: flow !< calculated flow, updated here with density terms + real(DP), intent(inout) :: gwfhcof !< GWF diagonal coefficient, updated here with density terms + real(DP), intent(inout) :: gwfrhs !< GWF right-hand-side value, updated here with density terms + ! -- local variables + real(DP) :: ss + real(DP) :: hh + real(DP) :: havg + real(DP) :: rdensesfr + real(DP) :: rdensegwf + real(DP) :: rdenseavg + real(DP) :: elevsfr + real(DP) :: elevgwf + real(DP) :: elevavg + real(DP) :: d1 + real(DP) :: d2 + logical(LGP) :: stage_below_bot + logical(LGP) :: head_below_bot + ! + ! -- Set sfr density to sfr density or gwf density + if (stage >= bots) then + ss = stage + stage_below_bot = .false. + rdensesfr = this%denseterms(1, n) ! sfr rel density + else + ss = bots + stage_below_bot = .true. + rdensesfr = this%denseterms(2, n) ! gwf rel density + end if + ! + ! -- set hh to head or bots + if (head >= bots) then + hh = head + head_below_bot = .false. + rdensegwf = this%denseterms(2, n) ! gwf rel density + else + hh = bots + head_below_bot = .true. + rdensegwf = this%denseterms(1, n) ! sfr rel density + end if + ! + ! -- todo: hack because denseterms not updated in a cf calculation + if (rdensegwf == DZERO) return + ! + ! -- Update flow + if (stage_below_bot .and. head_below_bot) then ! - ! -- Set sfr density to sfr density or gwf density - if (stage >= bots) then - ss = stage - stage_below_bot = .false. - rdensesfr = this%denseterms(1, n) ! sfr rel density - else - ss = bots - stage_below_bot = .true. - rdensesfr = this%denseterms(2, n) ! gwf rel density - end if + ! -- flow is zero, so no terms are updated ! - ! -- set hh to head or bots - if (head >= bots) then - hh = head - head_below_bot = .false. - rdensegwf = this%denseterms(2, n) ! gwf rel density - else - hh = bots - head_below_bot = .true. - rdensegwf = this%denseterms(1, n) ! sfr rel density - end if + else ! - ! -- todo: hack because denseterms not updated in a cf calculation - if (rdensegwf == DZERO) return + ! -- calulate average relative density + rdenseavg = DHALF * (rdensesfr + rdensegwf) ! - ! -- Update flow - if (stage_below_bot .and. head_below_bot) then - ! - ! -- flow is zero, so no terms are updated - ! - else - ! - ! -- calulate average relative density - rdenseavg = DHALF * (rdensesfr + rdensegwf) - ! - ! -- Add contribution of first density term: - ! cond * (denseavg/denseref - 1) * (hgwf - hsfr) - d1 = cond * (rdenseavg - DONE) - gwfhcof = gwfhcof - d1 - gwfrhs = gwfrhs - d1 * ss - d1 = d1 * (hh - ss) - flow = flow + d1 + ! -- Add contribution of first density term: + ! cond * (denseavg/denseref - 1) * (hgwf - hsfr) + d1 = cond * (rdenseavg - DONE) + gwfhcof = gwfhcof - d1 + gwfrhs = gwfrhs - d1 * ss + d1 = d1 * (hh - ss) + flow = flow + d1 + ! + ! -- Add second density term if stage and head not below bottom + if (.not. stage_below_bot .and. .not. head_below_bot) then ! - ! -- Add second density term if stage and head not below bottom - if (.not. stage_below_bot .and. .not. head_below_bot) then - ! - ! -- Add contribution of second density term: - ! cond * (havg - elevavg) * (densegwf - densesfr) / denseref - elevgwf = this%denseterms(3, n) - elevsfr = bots - elevavg = DHALF * (elevsfr + elevgwf) - havg = DHALF * (hh + ss) - d2 = cond * (havg - elevavg) * (rdensegwf - rdensesfr) - gwfrhs = gwfrhs + d2 - flow = flow + d2 - end if + ! -- Add contribution of second density term: + ! cond * (havg - elevavg) * (densegwf - densesfr) / denseref + elevgwf = this%denseterms(3, n) + elevsfr = bots + elevavg = DHALF * (elevsfr + elevgwf) + havg = DHALF * (hh + ss) + d2 = cond * (havg - elevavg) * (rdensegwf - rdensesfr) + gwfrhs = gwfrhs + d2 + flow = flow + d2 end if - ! - ! -- return - return - end subroutine sfr_calculate_density_exchange + end if + ! + ! -- return + return + end subroutine sfr_calculate_density_exchange end module SfrModule diff --git a/src/Model/GroundWaterFlow/gwf3sto8.f90 b/src/Model/GroundWaterFlow/gwf3sto8.f90 index e2ba2d21035..af6af41b322 100644 --- a/src/Model/GroundWaterFlow/gwf3sto8.f90 +++ b/src/Model/GroundWaterFlow/gwf3sto8.f90 @@ -1,14 +1,14 @@ !> @brief This module contains the storage package methods !! !! This module contains the methods used to add the effects of storage -!! on the groundwater flow equation. The contribution of specific +!! on the groundwater flow equation. The contribution of specific !! storage and specific yield can be represented. !! !< module GwfStoModule use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: DZERO, DEM6, DEM4, DHALF, DONE, DTWO, & + use ConstantsModule, only: DZERO, DEM6, DEM4, DHALF, DONE, DTWO, & LENBUDTXT, LINELENGTH use SimVariablesModule, only: errmsg use SimModule, only: store_error, count_errors @@ -26,26 +26,26 @@ module GwfStoModule public :: GwfStoType, sto_cr character(len=LENBUDTXT), dimension(2) :: budtxt = & !< text labels for budget terms - [' STO-SS', ' STO-SY'] + &[' STO-SS', ' STO-SY'] type, extends(NumericalPackageType) :: GwfStoType - integer(I4B), pointer :: istor_coef => null() !< indicates if ss is the storage coefficient - integer(I4B), pointer :: iconf_ss => null() !< indicates if ss is 0 below the top of a layer - integer(I4B), pointer :: iorig_ss => null() !< indicates if the original storage specific storage formulation should be used - integer(I4B), pointer :: iss => null() !< steady state flag: 1 = steady, 0 = transient - integer(I4B), pointer :: iusesy => null() !< flag set if any cell is convertible (0, 1) - integer(I4B), dimension(:), pointer, contiguous :: iconvert => null() !< confined (0) or convertible (1) - real(DP), dimension(:), pointer, contiguous :: ss => null() !< specfic storage or storage coefficient - real(DP), dimension(:), pointer, contiguous :: sy => null() !< specific yield - real(DP), dimension(:), pointer, contiguous :: strgss => null() !< vector of specific storage rates - real(DP), dimension(:), pointer, contiguous :: strgsy => null() !< vector of specific yield rates - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - real(DP), pointer :: satomega => null() !< newton-raphson saturation omega - integer(I4B), pointer :: integratechanges => null() !< indicates if mid-simulation ss and sy changes should be integrated via an additional matrix formulation term - integer(I4B), pointer :: intvs => null() !< TVS (time-varying storage) unit number (0 if unused) - type(TvsType), pointer :: tvs => null() !< TVS object - real(DP), dimension(:), pointer, contiguous, private :: oldss => null() !< previous time step specific storage - real(DP), dimension(:), pointer, contiguous, private :: oldsy => null() !< previous time step specific yield + integer(I4B), pointer :: istor_coef => null() !< indicates if ss is the storage coefficient + integer(I4B), pointer :: iconf_ss => null() !< indicates if ss is 0 below the top of a layer + integer(I4B), pointer :: iorig_ss => null() !< indicates if the original storage specific storage formulation should be used + integer(I4B), pointer :: iss => null() !< steady state flag: 1 = steady, 0 = transient + integer(I4B), pointer :: iusesy => null() !< flag set if any cell is convertible (0, 1) + integer(I4B), dimension(:), pointer, contiguous :: iconvert => null() !< confined (0) or convertible (1) + real(DP), dimension(:), pointer, contiguous :: ss => null() !< specfic storage or storage coefficient + real(DP), dimension(:), pointer, contiguous :: sy => null() !< specific yield + real(DP), dimension(:), pointer, contiguous :: strgss => null() !< vector of specific storage rates + real(DP), dimension(:), pointer, contiguous :: strgsy => null() !< vector of specific yield rates + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + real(DP), pointer :: satomega => null() !< newton-raphson saturation omega + integer(I4B), pointer :: integratechanges => null() !< indicates if mid-simulation ss and sy changes should be integrated via an additional matrix formulation term + integer(I4B), pointer :: intvs => null() !< TVS (time-varying storage) unit number (0 if unused) + type(TvsType), pointer :: tvs => null() !< TVS object + real(DP), dimension(:), pointer, contiguous, private :: oldss => null() !< previous time step specific storage + real(DP), dimension(:), pointer, contiguous, private :: oldsy => null() !< previous time step specific yield contains procedure :: sto_ar procedure :: sto_rp @@ -56,7 +56,7 @@ module GwfStoModule procedure :: sto_bd procedure :: sto_save_model_flows procedure :: sto_da - procedure :: allocate_scalars + procedure :: allocate_scalars procedure, private :: allocate_arrays !procedure, private :: register_handlers procedure, private :: read_options @@ -73,10 +73,10 @@ module GwfStoModule !< subroutine sto_cr(stoobj, name_model, inunit, iout) ! -- dummy variables - type(GwfStoType), pointer :: stoobj !< GwfStoType object - character(len=*), intent(in) :: name_model !< name of model - integer(I4B), intent(in) :: inunit !< package input file unit - integer(I4B), intent(in) :: iout !< model listing file unit + type(GwfStoType), pointer :: stoobj !< GwfStoType object + character(len=*), intent(in) :: name_model !< name of model + integer(I4B), intent(in) :: inunit !< package input file unit + integer(I4B), intent(in) :: iout !< model listing file unit ! ! -- Create the object allocate (stoobj) @@ -108,13 +108,13 @@ subroutine sto_ar(this, dis, ibound) use MemoryManagerModule, only: mem_setptr use MemoryHelperModule, only: create_mem_path ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - class(DisBaseType), pointer, intent(in) :: dis !< model discretization object - integer(I4B), dimension(:), pointer, contiguous :: ibound !< model ibound array + class(GwfStoType) :: this !< GwfStoType object + class(DisBaseType), pointer, intent(in) :: dis !< model discretization object + integer(I4B), dimension(:), pointer, contiguous :: ibound !< model ibound array ! -- local variables ! -- formats character(len=*), parameter :: fmtsto = & - "(1x,/1x,'STO -- STORAGE PACKAGE, VERSION 1, 5/19/2014', & + "(1x,/1x,'STO -- STORAGE PACKAGE, VERSION 1, 5/19/2014', & &' INPUT READ FROM UNIT ', i0, //)" ! ! --print a message identifying the storage package. @@ -158,7 +158,7 @@ subroutine sto_rp(this) use TdisModule, only: kper, nper implicit none ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! -- local variables integer(I4B) :: ierr logical :: isfound, readss, readsy, endOfBlock @@ -166,16 +166,16 @@ subroutine sto_rp(this) character(len=LINELENGTH) :: line, keyword ! -- formats character(len=*), parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,' FROM LAST STRESS PERIOD')" + &"(1X,/1X,'REUSING ',A,' FROM LAST STRESS PERIOD')" character(len=*), parameter :: fmtblkerr = & - "('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" ! -- data data css(0)/' TRANSIENT'/ data css(1)/' STEADY-STATE'/ ! ------------------------------------------------------------------------------ ! ! -- Store ss and sy values from end of last stress period if needed - if(this%integratechanges /= 0) then + if (this%integratechanges /= 0) then call this%save_old_ss_sy() end if ! @@ -184,7 +184,8 @@ subroutine sto_rp(this) ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true., & + blockRequired=.false.) if (isfound) then ! ! -- read ionper and check for increasing period numbers @@ -255,17 +256,17 @@ subroutine sto_ad(this) ! -- modules use TdisModule, only: kstp ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! ! -- Store ss and sy values from end of last time step if needed - if(this%integratechanges /= 0 .and. kstp > 1) then + if (this%integratechanges /= 0 .and. kstp > 1) then call this%save_old_ss_sy() end if ! ! -- TVS - if(this%intvs /= 0) then + if (this%intvs /= 0) then call this%tvs%ad() - endif + end if ! ! -- return return @@ -280,14 +281,14 @@ subroutine sto_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) ! -- modules use TdisModule, only: delt ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - integer(I4B), intent(in) :: kiter !< outer iteration number - real(DP), intent(in), dimension(:) :: hold !< previous heads - real(DP), intent(in), dimension(:) :: hnew !< current heads - integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution - real(DP), dimension(njasln), intent(inout) :: amat !< A matrix - integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution - real(DP), intent(inout), dimension(:) :: rhs !< right-hand side + class(GwfStoType) :: this !< GwfStoType object + integer(I4B), intent(in) :: kiter !< outer iteration number + real(DP), intent(in), dimension(:) :: hold !< previous heads + real(DP), intent(in), dimension(:) :: hnew !< current heads + integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution + real(DP), dimension(njasln), intent(inout) :: amat !< A matrix + integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution + real(DP), intent(inout), dimension(:) :: rhs !< right-hand side ! -- local variables integer(I4B) :: n integer(I4B) :: idiag @@ -307,7 +308,7 @@ subroutine sto_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) real(DP) :: aterm real(DP) :: rhsterm ! -- formats - character(len=*), parameter :: fmtsperror = & + character(len=*), parameter :: fmtsperror = & &"('DETECTED TIME STEP LENGTH OF ZERO. GWF STORAGE PACKAGE CANNOT BE ', & &'USED UNLESS DELT IS NON-ZERO.')" ! @@ -321,7 +322,7 @@ subroutine sto_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) end if ! ! -- set variables - tled = DONE/delt + tled = DONE / delt ! ! -- loop through and calculate storage contribution to hcof and rhs do n = 1, this%dis%nodes @@ -345,7 +346,7 @@ subroutine sto_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) sc1 = SsCapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n)) rho1 = sc1 * tled ! - if(this%integratechanges /= 0) then + if (this%integratechanges /= 0) then ! -- Integration of storage changes (e.g. when using TVS): ! separate the old (start of time step) and new (end of time step) ! primary storage capacities @@ -375,15 +376,15 @@ subroutine sto_fc(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) sc2 = SyCapacity(this%dis%area(n), this%sy(n)) rho2 = sc2 * tled ! - if(this%integratechanges /= 0) then - ! -- Integration of storage changes (e.g. when using TVS): - ! separate the old (start of time step) and new (end of time step) - ! secondary storage capacities + if (this%integratechanges /= 0) then + ! -- Integration of storage changes (e.g. when using TVS): + ! separate the old (start of time step) and new (end of time step) + ! secondary storage capacities sc2old = SyCapacity(this%dis%area(n), this%oldsy(n)) rho2old = sc2old * tled else - ! -- No integration of storage changes: old and new values are - ! identical => normal MF6 storage formulation + ! -- No integration of storage changes: old and new values are + ! identical => normal MF6 storage formulation rho2old = rho2 end if ! @@ -411,14 +412,14 @@ subroutine sto_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) ! -- modules use TdisModule, only: delt ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - integer(I4B), intent(in) :: kiter !< outer iteration number - real(DP), intent(in), dimension(:) :: hold !< previous heads - real(DP), intent(in), dimension(:) :: hnew !< current heads - integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution - real(DP), dimension(njasln), intent(inout) :: amat !< A matrix - integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution - real(DP), intent(inout), dimension(:) :: rhs !< right-hand side + class(GwfStoType) :: this !< GwfStoType object + integer(I4B), intent(in) :: kiter !< outer iteration number + real(DP), intent(in), dimension(:) :: hold !< previous heads + real(DP), intent(in), dimension(:) :: hnew !< current heads + integer(I4B), intent(in) :: njasln !< size of the A matrix for the solution + real(DP), dimension(njasln), intent(inout) :: amat !< A matrix + integer(I4B), intent(in), dimension(:) :: idxglo !< global index model to solution + real(DP), intent(inout), dimension(:) :: rhs !< right-hand side ! -- local variables integer(I4B) :: n integer(I4B) :: idiag @@ -440,7 +441,7 @@ subroutine sto_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) if (this%iss /= 0) return ! ! -- set variables - tled = DONE/delt + tled = DONE / delt ! ! -- loop through and calculate storage contribution to hcof and rhs do n = 1, this%dis%nodes @@ -459,8 +460,8 @@ subroutine sto_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) ! -- storage coefficients sc1 = SsCapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n)) sc2 = SyCapacity(this%dis%area(n), this%sy(n)) - rho1 = sc1*tled - rho2 = sc2*tled + rho1 = sc1 * tled + rho2 = sc2 * tled ! ! -- calculate newton terms for specific storage ! and specific yield @@ -477,7 +478,7 @@ subroutine sto_fn(this, kiter, hold, hnew, njasln, amat, idxglo, rhs) drterm = -(rho1 * derv * h) end if amat(idxglo(idiag)) = amat(idxglo(idiag)) + drterm - rhs(n) = rhs(n) + drterm*h + rhs(n) = rhs(n) + drterm * h end if ! ! -- newton terms for specific yield @@ -509,10 +510,10 @@ subroutine sto_cq(this, flowja, hnew, hold) ! -- modules use TdisModule, only: delt ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< connection flows - real(DP), dimension(:), contiguous, intent(in) :: hnew !< current head - real(DP), dimension(:), contiguous, intent(in) :: hold !< previous head + class(GwfStoType) :: this !< GwfStoType object + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< connection flows + real(DP), dimension(:), contiguous, intent(in) :: hnew !< current head + real(DP), dimension(:), contiguous, intent(in) :: hold !< previous head ! -- local variables integer(I4B) :: n integer(I4B) :: idiag @@ -531,7 +532,7 @@ subroutine sto_cq(this, flowja, hnew, hold) real(DP) :: snold real(DP) :: snnew real(DP) :: aterm - real(DP) :: rhsterm + real(DP) :: rhsterm ! ! -- initialize strg arrays do n = 1, this%dis%nodes @@ -543,7 +544,7 @@ subroutine sto_cq(this, flowja, hnew, hold) if (this%iss == 0) then ! ! -- set variables - tled = DONE/delt + tled = DONE / delt ! ! -- Calculate storage change do n = 1, this%dis%nodes @@ -563,9 +564,9 @@ subroutine sto_cq(this, flowja, hnew, hold) ! ! -- primary storage coefficient sc1 = SsCapacity(this%istor_coef, tp, bt, this%dis%area(n), this%ss(n)) - rho1 = sc1*tled + rho1 = sc1 * tled ! - if(this%integratechanges /= 0) then + if (this%integratechanges /= 0) then ! -- Integration of storage changes (e.g. when using TVS): ! separate the old (start of time step) and new (end of time step) ! primary storage capacities @@ -580,8 +581,8 @@ subroutine sto_cq(this, flowja, hnew, hold) ! ! -- calculate specific storage terms and rate call SsTerms(this%iconvert(n), this%iorig_ss, this%iconf_ss, tp, bt, & - rho1, rho1old, snnew, snold, hnew(n), hold(n), & - aterm, rhsterm, rate) + rho1, rho1old, snnew, snold, hnew(n), hold(n), & + aterm, rhsterm, rate) ! ! -- save rate this%strgss(n) = rate @@ -598,7 +599,7 @@ subroutine sto_cq(this, flowja, hnew, hold) sc2 = SyCapacity(this%dis%area(n), this%sy(n)) rho2 = sc2 * tled ! - if(this%integratechanges /= 0) then + if (this%integratechanges /= 0) then ! -- Integration of storage changes (e.g. when using TVS): ! separate the old (start of time step) and new (end of time ! step) secondary storage capacities @@ -638,9 +639,9 @@ subroutine sto_bd(this, isuppress_output, model_budget) use TdisModule, only: delt use BudgetModule, only: BudgetType, rate_accumulator ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - integer(I4B), intent(in) :: isuppress_output !< flag to suppress model output - type(BudgetType), intent(inout) :: model_budget !< model budget object + class(GwfStoType) :: this !< GwfStoType object + integer(I4B), intent(in) :: isuppress_output !< flag to suppress model output + type(BudgetType), intent(inout) :: model_budget !< model budget object ! -- local variables real(DP) :: rin real(DP) :: rout @@ -668,9 +669,9 @@ end subroutine sto_bd !< subroutine sto_save_model_flows(this, icbcfl, icbcun) ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object - integer(I4B), intent(in) :: icbcfl !< flag to output budget data - integer(I4B), intent(in) :: icbcun !< cell-by-cell file unit number + class(GwfStoType) :: this !< GwfStoType object + integer(I4B), intent(in) :: icbcfl !< flag to output budget data + integer(I4B), intent(in) :: icbcun !< cell-by-cell file unit number ! -- local variables integer(I4B) :: ibinun integer(I4B) :: iprint, nvaluesp, nwidthp @@ -718,12 +719,12 @@ subroutine sto_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! ! -- TVS if (this%intvs /= 0) then call this%tvs%da() - deallocate(this%tvs) + deallocate (this%tvs) end if ! ! -- Deallocate arrays if package is active @@ -735,10 +736,10 @@ subroutine sto_da(this) call mem_deallocate(this%strgsy) ! ! -- deallocate TVS arrays - if(associated(this%oldss)) then + if (associated(this%oldss)) then call mem_deallocate(this%oldss) end if - if(associated(this%oldsy)) then + if (associated(this%oldsy)) then call mem_deallocate(this%oldsy) end if end if @@ -769,7 +770,7 @@ subroutine allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate, mem_setptr ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! ! -- allocate scalars in NumericalPackageType call this%NumericalPackageType%allocate_scalars() @@ -846,25 +847,25 @@ end subroutine allocate_arrays subroutine read_options(this) ! -- modules ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! -- local variables character(len=LINELENGTH) :: keyword, fname integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE "// & - "WHENEVER ICBCFL IS NOT ZERO.')" + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" character(len=*), parameter :: fmtflow = & - "(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + &"(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" character(len=*), parameter :: fmtorigss = & - "(4X,'ORIGINAL_SPECIFIC_STORAGE OPTION:',/, & + "(4X,'ORIGINAL_SPECIFIC_STORAGE OPTION:',/, & &1X,'The original specific storage formulation will be used')" character(len=*), parameter :: fmtstoc = & - "(4X,'STORAGECOEFFICIENT OPTION:',/, & + "(4X,'STORAGECOEFFICIENT OPTION:',/, & &1X,'Read storage coefficient rather than specific storage')" character(len=*), parameter :: fmtconfss = & - "(4X,'SS_CONFINED_ONLY OPTION:',/, & + "(4X,'SS_CONFINED_ONLY OPTION:',/, & &1X,'Specific storage changes only occur under confined conditions')" ! ! -- get options block @@ -891,25 +892,25 @@ subroutine read_options(this) write (this%iout, fmtconfss) case ('TVS6') if (this%intvs /= 0) then - errmsg = 'Multiple TVS6 keywords detected in OPTIONS block.' // & + errmsg = 'Multiple TVS6 keywords detected in OPTIONS block.'// & ' Only one TVS6 entry allowed.' call store_error(errmsg, terminate=.TRUE.) end if call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TVS6 keyword must be followed by "FILEIN" ' // & + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TVS6 keyword must be followed by "FILEIN" '// & 'then by filename.' call store_error(errmsg, terminate=.TRUE.) - endif + end if call this%parser%GetString(fname) this%intvs = GetUnit() call openfile(this%intvs, this%iout, fname, 'TVS') call tvs_cr(this%tvs, this%name_model, this%intvs, this%iout) - ! - ! -- right now these are options that are only available in the - ! development version and are not included in the documentation. - ! These options are only available when IDEVELOPMODE in - ! constants module is set to 1 + ! + ! -- right now these are options that are only available in the + ! development version and are not included in the documentation. + ! These options are only available when IDEVELOPMODE in + ! constants module is set to 1 case ('DEV_ORIGINAL_SPECIFIC_STORAGE') this%iorig_ss = 1 write (this%iout, fmtorigss) @@ -944,7 +945,7 @@ end subroutine read_options subroutine read_data(this) ! -- modules ! -- dummy variables - class(GwfStotype) :: this !< GwfStoType object + class(GwfStotype) :: this !< GwfStoType object ! -- local variables character(len=LINELENGTH) :: keyword character(len=:), allocatable :: line @@ -1079,15 +1080,15 @@ subroutine save_old_ss_sy(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(GwfStoType) :: this !< GwfStoType object + class(GwfStoType) :: this !< GwfStoType object ! -- local variables integer(I4B) :: n ! ! -- Allocate TVS arrays if needed - if(.not. associated(this%oldss)) then + if (.not. associated(this%oldss)) then call mem_allocate(this%oldss, this%dis%nodes, 'OLDSS', this%memoryPath) end if - if(this%iusesy == 1 .and. .not. associated(this%oldsy)) then + if (this%iusesy == 1 .and. .not. associated(this%oldsy)) then call mem_allocate(this%oldsy, this%dis%nodes, 'OLDSY', this%memoryPath) end if ! @@ -1097,7 +1098,7 @@ subroutine save_old_ss_sy(this) end do ! ! -- Save current specific yield, if used - if(this%iusesy == 1) then + if (this%iusesy == 1) then do n = 1, this%dis%nodes this%oldsy(n) = this%sy(n) end do @@ -1106,5 +1107,5 @@ subroutine save_old_ss_sy(this) ! -- Return return end subroutine save_old_ss_sy - + end module GwfStoModule diff --git a/src/Model/GroundWaterFlow/gwf3tvbase8.f90 b/src/Model/GroundWaterFlow/gwf3tvbase8.f90 index 97a3c306d18..3500b2eedfe 100644 --- a/src/Model/GroundWaterFlow/gwf3tvbase8.f90 +++ b/src/Model/GroundWaterFlow/gwf3tvbase8.f90 @@ -180,7 +180,7 @@ subroutine tvbase_allocate_scalars(this) call this%NumericalPackageType%allocate_scalars() ! ! -- Allocate time series manager - allocate(this%tsmanager) + allocate (this%tsmanager) ! return end subroutine tvbase_allocate_scalars @@ -202,8 +202,8 @@ subroutine ar(this, dis) ! -- Create time series manager call tsmanager_cr(this%tsmanager, & this%iout, & - removeTsLinksOnCompletion = .true., & - extendTsToEndOfSimulation = .true.) + removeTsLinksOnCompletion=.true., & + extendTsToEndOfSimulation=.true.) ! ! -- Read options call this%read_options() @@ -213,7 +213,7 @@ subroutine ar(this, dis) call this%tsmanager%tsmanager_df() ! ! -- Terminate if any errors were encountered - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() call ustop() end if @@ -238,54 +238,54 @@ subroutine read_options(this) integer(I4B) :: ierr ! -- formats character(len=*), parameter :: fmtts = & - "(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" + &"(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" ! ! -- Get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, & blockRequired=.false., supportOpenClose=.true.) ! ! -- Parse options block if detected - if(isfound) then - write(this%iout, '(1x,a)') & - 'PROCESSING ' // trim(adjustl(this%packName)) // ' OPTIONS' + if (isfound) then + write (this%iout, '(1x,a)') & + 'PROCESSING '//trim(adjustl(this%packName))//' OPTIONS' do call this%parser%GetNextLine(endOfBlock) - if(endOfBlock) then + if (endOfBlock) then exit end if call this%parser%GetStringCaps(keyword) select case (keyword) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'TIME-VARYING INPUT WILL BE PRINTED.' - case ('TS6') - ! - ! -- Add a time series file - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = & - 'TS6 keyword must be followed by "FILEIN" then by filename.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - call ustop() - end if - call this%parser%GetString(fname) - write(this%iout, fmtts) trim(fname) - call this%tsmanager%add_tsfile(fname, this%inunit) - case default - ! - ! -- Defer to subtype to read the option; - ! -- if the subtype can't handle it, report an error - if(.not. this%read_option(keyword)) then - write(errmsg, '(a,3(1x,a),a)') & - 'Unknown', trim(adjustl(this%packName)), "option '", & - trim(keyword), "'." - call store_error(errmsg) - end if + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') 'TIME-VARYING INPUT WILL BE PRINTED.' + case ('TS6') + ! + ! -- Add a time series file + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = & + 'TS6 keyword must be followed by "FILEIN" then by filename.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + call ustop() + end if + call this%parser%GetString(fname) + write (this%iout, fmtts) trim(fname) + call this%tsmanager%add_tsfile(fname, this%inunit) + case default + ! + ! -- Defer to subtype to read the option; + ! -- if the subtype can't handle it, report an error + if (.not. this%read_option(keyword)) then + write (errmsg, '(a,3(1x,a),a)') & + 'Unknown', trim(adjustl(this%packName)), "option '", & + trim(keyword), "'." + call store_error(errmsg) + end if end select end do - write(this%iout, '(1x,a)') & - 'END OF ' // trim(adjustl(this%packName)) // ' OPTIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%packName))//' OPTIONS' end if ! return @@ -306,40 +306,41 @@ subroutine rp(this) real(DP), pointer :: bndElem => null() ! -- formats character(len=*), parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" character(len=*), parameter :: fmtvalchg = & "(a, ' package: Setting ', a, ' value for cell ', a, ' at start of & &stress period ', i0, ' = ', g12.5)" ! - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- Get stress period data - if(this%ionper < kper) then + if (this%ionper < kper) then ! ! -- Get PERIOD block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- Read ionper and check for increasing period numbers call this%read_check_ionper() else ! ! -- PERIOD block not found - if(ierr < 0) then + if (ierr < 0) then ! -- End of file found; data applies for remainder of simulation. this%ionper = nper + 1 else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) end if end if end if ! ! -- Read data if ionper == kper - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- Reset per-node property change flags call this%reset_change_flags() @@ -347,7 +348,7 @@ subroutine rp(this) haveChanges = .false. do call this%parser%GetNextLine(endOfBlock) - if(endOfBlock) then + if (endOfBlock) then exit end if ! @@ -357,8 +358,8 @@ subroutine rp(this) this%iout) ! ! -- Validate cell ID - if(node < 1 .or. node > this%dis%nodes) then - write(errmsg, '(a,2(1x,a))') & + if (node < 1 .or. node > this%dis%nodes) then + write (errmsg, '(a,2(1x,a))') & 'CELLID', cellid, 'is not in the active model domain.' call store_error(errmsg) cycle @@ -370,8 +371,8 @@ subroutine rp(this) ! -- Get a pointer to the property value given by varName for the node ! -- with the specified cell ID bndElem => this%get_pointer_to_value(node, varName) - if(.not. associated(bndElem)) then - write(errmsg, '(a,3(1x,a),a)') & + if (.not. associated(bndElem)) then + write (errmsg, '(a,3(1x,a),a)') & 'Unknown', trim(adjustl(this%packName)), "variable '", & trim(varName), "'." call store_error(errmsg) @@ -387,7 +388,7 @@ subroutine rp(this) ! ! -- Report value change if (this%iprpak /= 0) then - write(this%iout, fmtvalchg) & + write (this%iout, fmtvalchg) & trim(adjustl(this%packName)), trim(varName), trim(cellid), & kper, bndElem end if @@ -399,13 +400,13 @@ subroutine rp(this) ! ! -- Record that any changes were made at the first time step of the ! -- stress period - if(haveChanges) then + if (haveChanges) then call this%set_changed_at(kper, 1) end if end if ! ! -- Terminate if errors were encountered in the PERIOD block - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() call ustop() end if @@ -432,7 +433,7 @@ subroutine ad(this) ! -- If there are no time series property changes, ! -- there is nothing else to be done numlinks = this%tsmanager%CountLinks('BND') - if(numlinks <= 0) then + if (numlinks <= 0) then return end if ! @@ -442,7 +443,7 @@ subroutine ad(this) ! ! -- Reset node K change flags at all time steps except the first of each ! -- period (the first is done in rp(), to allow non-time series changes) - if(kstp /= 1) then + if (kstp /= 1) then call this%reset_change_flags() end if ! @@ -454,7 +455,7 @@ subroutine ad(this) end do ! ! -- Terminate if there were errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() call ustop() end if @@ -472,7 +473,7 @@ subroutine tvbase_da(this) class(TvBaseType) :: this ! ! -- Deallocate time series manager - deallocate(this%tsmanager) + deallocate (this%tsmanager) ! ! -- Deallocate parent call this%NumericalPackageType%da() diff --git a/src/Model/GroundWaterFlow/gwf3tvk8.f90 b/src/Model/GroundWaterFlow/gwf3tvk8.f90 index dbf48309ca4..48385d07329 100644 --- a/src/Model/GroundWaterFlow/gwf3tvk8.f90 +++ b/src/Model/GroundWaterFlow/gwf3tvk8.f90 @@ -23,13 +23,13 @@ module TvkModule public :: tvk_cr type, extends(TvBaseType) :: TvkType - integer(I4B), pointer :: ik22overk => null() !< NPF flag that k22 is specified as anisotropy ratio - integer(I4B), pointer :: ik33overk => null() !< NPF flag that k33 is specified as anisotropy ratio - real(DP), dimension(:), pointer, contiguous :: k11 => null() !< NPF hydraulic conductivity; if anisotropic, then this is Kx prior to rotation - real(DP), dimension(:), pointer, contiguous :: k22 => null() !< NPF hydraulic conductivity; if specified then this is Ky prior to rotation - real(DP), dimension(:), pointer, contiguous :: k33 => null() !< NPF hydraulic conductivity; if specified then this is Kz prior to rotation - integer(I4B), pointer :: kchangeper => null() !< NPF last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) - integer(I4B), pointer :: kchangestp => null() !< NPF last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), pointer :: ik22overk => null() !< NPF flag that k22 is specified as anisotropy ratio + integer(I4B), pointer :: ik33overk => null() !< NPF flag that k33 is specified as anisotropy ratio + real(DP), dimension(:), pointer, contiguous :: k11 => null() !< NPF hydraulic conductivity; if anisotropic, then this is Kx prior to rotation + real(DP), dimension(:), pointer, contiguous :: k22 => null() !< NPF hydraulic conductivity; if specified then this is Ky prior to rotation + real(DP), dimension(:), pointer, contiguous :: k33 => null() !< NPF hydraulic conductivity; if specified then this is Kz prior to rotation + integer(I4B), pointer :: kchangeper => null() !< NPF last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), pointer :: kchangestp => null() !< NPF last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() !< NPF grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0) contains procedure :: da => tvk_da @@ -55,7 +55,7 @@ subroutine tvk_cr(tvk, name_model, inunit, iout) integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout ! - allocate(tvk) + allocate (tvk) call tvk%init(name_model, 'TVK', 'TVK', inunit, iout) ! return @@ -78,7 +78,7 @@ subroutine tvk_ar_set_pointers(this) &' INPUT READ FROM UNIT ', i0, //)" ! ! -- Print a message identifying the TVK package - write(this%iout, fmttvk) this%inunit + write (this%iout, fmttvk) this%inunit ! ! -- Set pointers to other package variables ! -- NPF @@ -129,14 +129,14 @@ function tvk_get_pointer_to_value(this, n, varName) result(bndElem) real(DP), pointer :: bndElem ! select case (varName) - case ('K') - bndElem => this%k11(n) - case ('K22') - bndElem => this%k22(n) - case ('K33') - bndElem => this%k33(n) - case default - bndElem => null() + case ('K') + bndElem => this%k11(n) + case ('K22') + bndElem => this%k22(n) + case ('K33') + bndElem => this%k33(n) + case default + bndElem => null() end select ! return @@ -205,28 +205,31 @@ subroutine tvk_validate_change(this, n, varName) this%nodekchange(n) = 1 ! ! -- Check the changed value is ok - if(varName == 'K') then - if(this%k11(n) <= DZERO) then + if (varName == 'K') then + if (this%k11(n) <= DZERO) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(this%packName)), 'K', trim(cellstr), this%k11(n) + write (errmsg, fmtkerr) & + trim(adjustl(this%packName)), 'K', trim(cellstr), this%k11(n) call store_error(errmsg) end if - elseif(varName == 'K22') then - if(this%ik22overk == 1) then + elseif (varName == 'K22') then + if (this%ik22overk == 1) then this%k22(n) = this%k22(n) * this%k11(n) end if - if(this%k22(n) <= DZERO) then + if (this%k22(n) <= DZERO) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(this%packName)), 'K22', trim(cellstr), this%k22(n) + write (errmsg, fmtkerr) & + trim(adjustl(this%packName)), 'K22', trim(cellstr), this%k22(n) call store_error(errmsg) end if - elseif(varName == 'K33') then - if(this%ik33overk == 1) then - this%k33(n) = this%k33(n) * this%k33(n) + elseif (varName == 'K33') then + if (this%ik33overk == 1) then + this%k33(n) = this%k33(n) * this%k11(n) end if - if(this%k33(n) <= DZERO) then + if (this%k33(n) <= DZERO) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtkerr) trim(adjustl(this%packName)), 'K33', trim(cellstr), this%k33(n) + write (errmsg, fmtkerr) & + trim(adjustl(this%packName)), 'K33', trim(cellstr), this%k33(n) call store_error(errmsg) end if end if @@ -244,14 +247,14 @@ subroutine tvk_da(this) class(TvkType) :: this ! ! -- Nullify pointers to other package variables - nullify(this%ik22overk) - nullify(this%ik33overk) - nullify(this%k11) - nullify(this%k22) - nullify(this%k33) - nullify(this%kchangeper) - nullify(this%kchangestp) - nullify(this%nodekchange) + nullify (this%ik22overk) + nullify (this%ik33overk) + nullify (this%k11) + nullify (this%k22) + nullify (this%k33) + nullify (this%kchangeper) + nullify (this%kchangestp) + nullify (this%nodekchange) ! ! -- Deallocate parent call tvbase_da(this) diff --git a/src/Model/GroundWaterFlow/gwf3tvs8.f90 b/src/Model/GroundWaterFlow/gwf3tvs8.f90 index 071c86135b0..390810b77e2 100644 --- a/src/Model/GroundWaterFlow/gwf3tvs8.f90 +++ b/src/Model/GroundWaterFlow/gwf3tvs8.f90 @@ -23,10 +23,10 @@ module TvsModule public :: tvs_cr type, extends(TvBaseType) :: TvsType - integer(I4B), pointer :: integratechanges => null() !< STO flag indicating if mid-simulation ss and sy changes should be integrated via an additional matrix formulation term - integer(I4B), pointer :: iusesy => null() !< STO flag set if any cell is convertible (0, 1) - real(DP), dimension(:), pointer, contiguous :: ss => null() !< STO specfic storage or storage coefficient - real(DP), dimension(:), pointer, contiguous :: sy => null() !< STO specific yield + integer(I4B), pointer :: integratechanges => null() !< STO flag indicating if mid-simulation ss and sy changes should be integrated via an additional matrix formulation term + integer(I4B), pointer :: iusesy => null() !< STO flag set if any cell is convertible (0, 1) + real(DP), dimension(:), pointer, contiguous :: ss => null() !< STO specfic storage or storage coefficient + real(DP), dimension(:), pointer, contiguous :: sy => null() !< STO specific yield contains procedure :: da => tvs_da procedure :: ar_set_pointers => tvs_ar_set_pointers @@ -51,7 +51,7 @@ subroutine tvs_cr(tvs, name_model, inunit, iout) integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout ! - allocate(tvs) + allocate (tvs) call tvs%init(name_model, 'TVS', 'TVS', inunit, iout) ! return @@ -74,7 +74,7 @@ subroutine tvs_ar_set_pointers(this) &' INPUT READ FROM UNIT ', i0, //)" ! ! -- Print a message identifying the TVS package - write(this%iout, fmttvs) this%inunit + write (this%iout, fmttvs) this%inunit ! ! -- Set pointers to other package variables ! -- STO @@ -108,12 +108,12 @@ function tvs_read_option(this, keyword) result(success) &'Storage derivative terms will not be added to STO matrix formulation')" ! select case (keyword) - case ('DISABLE_STORAGE_CHANGE_INTEGRATION') - success = .true. - this%integratechanges = 0 - write(this%iout, fmtdsci) - case default - success = .false. + case ('DISABLE_STORAGE_CHANGE_INTEGRATION') + success = .true. + this%integratechanges = 0 + write (this%iout, fmtdsci) + case default + success = .false. end select ! return @@ -134,12 +134,12 @@ function tvs_get_pointer_to_value(this, n, varName) result(bndElem) real(DP), pointer :: bndElem ! select case (varName) - case ('SS') - bndElem => this%ss(n) - case ('SY') - bndElem => this%sy(n) - case default - bndElem => null() + case ('SS') + bndElem => this%ss(n) + case ('SY') + bndElem => this%sy(n) + case default + bndElem => null() end select ! return @@ -202,25 +202,25 @@ subroutine tvs_validate_change(this, n, varName) &in this model (all ICONVERT flags are 0).')" ! ! -- Check the changed value is ok and convert to storage capacity - if(varName == 'SS') then - if(this%ss(n) < DZERO) then + if (varName == 'SS') then + if (this%ss(n) < DZERO) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtserr) trim(adjustl(this%packName)), 'SS', & - trim(cellstr), this%ss(n) + write (errmsg, fmtserr) trim(adjustl(this%packName)), 'SS', & + trim(cellstr), this%ss(n) call store_error(errmsg) - endif - elseif(varName == 'SY') then - if(this%iusesy /= 1) then + end if + elseif (varName == 'SY') then + if (this%iusesy /= 1) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtsyerr) trim(adjustl(this%packName)), 'SY', & - trim(cellstr) + write (errmsg, fmtsyerr) trim(adjustl(this%packName)), 'SY', & + trim(cellstr) call store_error(errmsg) - elseif(this%sy(n) < DZERO) then + elseif (this%sy(n) < DZERO) then call this%dis%noder_to_string(n, cellstr) - write(errmsg, fmtserr) trim(adjustl(this%packName)), 'SY', & - trim(cellstr), this%sy(n) + write (errmsg, fmtserr) trim(adjustl(this%packName)), 'SY', & + trim(cellstr), this%sy(n) call store_error(errmsg) - endif + end if end if ! return @@ -236,10 +236,10 @@ subroutine tvs_da(this) class(TvsType) :: this ! ! -- Nullify pointers to other package variables - nullify(this%integratechanges) - nullify(this%iusesy) - nullify(this%ss) - nullify(this%sy) + nullify (this%integratechanges) + nullify (this%iusesy) + nullify (this%ss) + nullify (this%sy) ! ! -- Deallocate parent call tvbase_da(this) diff --git a/src/Model/GroundWaterFlow/gwf3uzf8.f90 b/src/Model/GroundWaterFlow/gwf3uzf8.f90 index c176acdc8a0..af00f7296db 100644 --- a/src/Model/GroundWaterFlow/gwf3uzf8.f90 +++ b/src/Model/GroundWaterFlow/gwf3uzf8.f90 @@ -2,16 +2,16 @@ module UzfModule use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DEM6, DEM4, DEM2, DEM1, DHALF, & - DONE, DHUNDRED, & - LINELENGTH, LENFTYPE, LENPACKAGENAME, & - LENBOUNDNAME, LENBUDTXT, LENPAKLOC, DNODATA, & - NAMEDBOUNDFLAG, MAXCHARLEN, & - DHNOFLO, DHDRY, & - TABLEFT, TABCENTER, TABRIGHT, & + use ConstantsModule, only: DZERO, DEM6, DEM4, DEM2, DEM1, DHALF, & + DONE, DHUNDRED, & + LINELENGTH, LENFTYPE, LENPACKAGENAME, & + LENBOUNDNAME, LENBUDTXT, LENPAKLOC, DNODATA, & + NAMEDBOUNDFLAG, MAXCHARLEN, & + DHNOFLO, DHDRY, & + TABLEFT, TABCENTER, TABRIGHT, & TABSTRING, TABUCSTRING, TABINTEGER, TABREAL use GenericUtilitiesModule, only: sim_message - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & + use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & mem_deallocate use MemoryHelperModule, only: create_mem_path use SparseModule, only: sparsematrix @@ -29,8 +29,8 @@ module UzfModule implicit none - character(len=LENFTYPE) :: ftype = 'UZF' - character(len=LENPACKAGENAME) :: text = ' UZF CELLS' + character(len=LENFTYPE) :: ftype = 'UZF' + character(len=LENPACKAGENAME) :: text = ' UZF CELLS' private public :: uzf_create @@ -41,62 +41,62 @@ module UzfModule integer(I4B), pointer :: iprwcont => null() integer(I4B), pointer :: iwcontout => null() integer(I4B), pointer :: ibudgetout => null() - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file integer(I4B), pointer :: ipakcsv => null() ! - type(BudgetObjectType), pointer :: budobj => null() - integer(I4B), pointer :: bditems => null() !< number of budget items - integer(I4B), pointer :: nbdtxt => null() !< number of budget text items - character(len=LENBUDTXT), dimension(:), pointer, & - contiguous :: bdtxt => null() !< budget items written to cbc file - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: uzfname => null() + type(BudgetObjectType), pointer :: budobj => null() + integer(I4B), pointer :: bditems => null() !< number of budget items + integer(I4B), pointer :: nbdtxt => null() !< number of budget text items + character(len=LENBUDTXT), dimension(:), pointer, & + contiguous :: bdtxt => null() !< budget items written to cbc file + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: uzfname => null() ! ! -- uzf table objects - type(TableType), pointer :: pakcsvtab => null() + type(TableType), pointer :: pakcsvtab => null() ! ! -- uzf kinematic object - type(UzfCellGroupType), pointer :: uzfobj => null() - type(UzfCellGroupType) :: uzfobjwork + type(UzfCellGroupType), pointer :: uzfobj => null() + type(UzfCellGroupType) :: uzfobjwork ! ! -- pointer to gwf variables - integer(I4B), pointer :: gwfiss => null() - real(DP), dimension(:), pointer, contiguous :: gwftop => null() - real(DP), dimension(:), pointer, contiguous :: gwfbot => null() - real(DP), dimension(:), pointer, contiguous :: gwfarea => null() - real(DP), dimension(:), pointer, contiguous :: gwfhcond => null() + integer(I4B), pointer :: gwfiss => null() + real(DP), dimension(:), pointer, contiguous :: gwftop => null() + real(DP), dimension(:), pointer, contiguous :: gwfbot => null() + real(DP), dimension(:), pointer, contiguous :: gwfarea => null() + real(DP), dimension(:), pointer, contiguous :: gwfhcond => null() ! ! -- uzf data - integer(I4B), pointer :: ntrail => null() - integer(I4B), pointer :: nsets => null() - integer(I4B), pointer :: nwav => null() - integer(I4B), pointer :: nodes => null() - integer(I4B), pointer :: readflag => null() - integer(I4B), pointer :: ietflag => null() !< et flag, 0 is off, 1 or 2 are different types - integer(I4B), pointer :: igwetflag => null() - integer(I4B), pointer :: iseepflag => null() - integer(I4B), pointer :: imaxcellcnt => null() - integer(I4B), pointer :: iuzf2uzf => null() + integer(I4B), pointer :: ntrail => null() + integer(I4B), pointer :: nsets => null() + integer(I4B), pointer :: nwav => null() + integer(I4B), pointer :: nodes => null() + integer(I4B), pointer :: readflag => null() + integer(I4B), pointer :: ietflag => null() !< et flag, 0 is off, 1 or 2 are different types + integer(I4B), pointer :: igwetflag => null() + integer(I4B), pointer :: iseepflag => null() + integer(I4B), pointer :: imaxcellcnt => null() + integer(I4B), pointer :: iuzf2uzf => null() ! -- integer vectors - integer(I4B), dimension(:), pointer, contiguous :: igwfnode => null() - integer(I4B), dimension(:), pointer, contiguous :: ia => null() - integer(I4B), dimension(:), pointer, contiguous :: ja => null() + integer(I4B), dimension(:), pointer, contiguous :: igwfnode => null() + integer(I4B), dimension(:), pointer, contiguous :: ia => null() + integer(I4B), dimension(:), pointer, contiguous :: ja => null() ! -- double precision output vectors - real(DP), dimension(:), pointer, contiguous :: appliedinf => null() - real(DP), dimension(:), pointer, contiguous :: rejinf => null() - real(DP), dimension(:), pointer, contiguous :: rejinf0 => null() - real(DP), dimension(:), pointer, contiguous :: rejinftomvr => null() - real(DP), dimension(:), pointer, contiguous :: infiltration => null() - real(DP), dimension(:), pointer, contiguous :: gwet => null() - real(DP), dimension(:), pointer, contiguous :: uzet => null() - real(DP), dimension(:), pointer, contiguous :: gwd => null() - real(DP), dimension(:), pointer, contiguous :: gwd0 => null() - real(DP), dimension(:), pointer, contiguous :: gwdtomvr => null() - real(DP), dimension(:), pointer, contiguous :: rch => null() - real(DP), dimension(:), pointer, contiguous :: rch0 => null() - real(DP), dimension(:), pointer, contiguous :: qsto => null() !< change in stored mobile water per time for this time step - real(DP), dimension(:), pointer, contiguous :: wcnew => null() !< water content for this time step - real(DP), dimension(:), pointer, contiguous :: wcold => null() !< water content for previous time step + real(DP), dimension(:), pointer, contiguous :: appliedinf => null() + real(DP), dimension(:), pointer, contiguous :: rejinf => null() + real(DP), dimension(:), pointer, contiguous :: rejinf0 => null() + real(DP), dimension(:), pointer, contiguous :: rejinftomvr => null() + real(DP), dimension(:), pointer, contiguous :: infiltration => null() + real(DP), dimension(:), pointer, contiguous :: gwet => null() + real(DP), dimension(:), pointer, contiguous :: uzet => null() + real(DP), dimension(:), pointer, contiguous :: gwd => null() + real(DP), dimension(:), pointer, contiguous :: gwd0 => null() + real(DP), dimension(:), pointer, contiguous :: gwdtomvr => null() + real(DP), dimension(:), pointer, contiguous :: rch => null() + real(DP), dimension(:), pointer, contiguous :: rch0 => null() + real(DP), dimension(:), pointer, contiguous :: qsto => null() !< change in stored mobile water per time for this time step + real(DP), dimension(:), pointer, contiguous :: wcnew => null() !< water content for this time step + real(DP), dimension(:), pointer, contiguous :: wcold => null() !< water content for previous time step ! ! -- timeseries aware variables real(DP), dimension(:), pointer, contiguous :: sinf => null() @@ -106,7 +106,7 @@ module UzfModule real(DP), dimension(:), pointer, contiguous :: ha => null() real(DP), dimension(:), pointer, contiguous :: hroot => null() real(DP), dimension(:), pointer, contiguous :: rootact => null() - real(DP), dimension(:,:), pointer, contiguous :: uauxvar => null() + real(DP), dimension(:, :), pointer, contiguous :: uauxvar => null() ! ! -- convergence check integer(I4B), pointer :: iconvchk => null() @@ -115,10 +115,10 @@ module UzfModule real(DP), dimension(:), pointer, contiguous :: deriv => null() ! ! budget variables - real(DP), pointer :: totfluxtot => null() - integer(I4B), pointer :: issflag => null() - integer(I4B), pointer :: issflagold => null() - integer(I4B), pointer :: istocb => null() + real(DP), pointer :: totfluxtot => null() + integer(I4B), pointer :: issflag => null() + integer(I4B), pointer :: issflagold => null() + integer(I4B), pointer :: istocb => null() ! ! -- uzf cbc budget items integer(I4B), pointer :: cbcauxitems => NULL() @@ -163,7 +163,7 @@ module UzfModule ! -- budget procedure, private :: uzf_setup_budobj procedure, private :: uzf_fill_budobj - + end type UzfType contains @@ -181,10 +181,10 @@ subroutine uzf_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) use MemoryManagerModule, only: mem_allocate ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -192,7 +192,7 @@ subroutine uzf_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(uzfobj) + allocate (uzfobj) packobj => uzfobj ! ! -- create name and memory path @@ -210,9 +210,9 @@ subroutine uzf_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) packobj%id = id packobj%ibcnum = ibcnum packobj%ncolbnd = 1 - packobj%iscloc = 0 ! not supported + packobj%iscloc = 0 ! not supported packobj%isadvpak = 1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') ! ! -- return return @@ -240,7 +240,8 @@ subroutine uzf_ar(this) call this%BndType%allocate_arrays() ! ! -- set pointers now that data is available - call mem_setptr(this%gwfhcond, 'CONDSAT', create_mem_path(this%name_model,'NPF')) + call mem_setptr(this%gwfhcond, 'CONDSAT', create_mem_path(this%name_model, & + 'NPF')) call mem_setptr(this%gwfiss, 'ISS', create_mem_path(this%name_model)) ! ! -- set boundname for each connection @@ -248,7 +249,10 @@ subroutine uzf_ar(this) do n = 1, this%nodes this%boundname(n) = this%uzfname(n) end do - endif + end if + ! + ! -- copy boundname into boundname_cst + call this%copy_boundname() ! ! -- copy igwfnode into nodelist and set water table do i = 1, this%nodes @@ -260,9 +264,9 @@ subroutine uzf_ar(this) ! ! -- setup pakmvrobj if (this%imover /= 0) then - allocate(this%pakmvrobj) + allocate (this%pakmvrobj) call this%pakmvrobj%ar(this%maxbound, this%maxbound, this%memoryPath) - endif + end if ! ! -- return return @@ -277,10 +281,10 @@ subroutine uzf_allocate_arrays(this) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(UzfType), intent(inout) :: this + class(UzfType), intent(inout) :: this ! -- local - integer (I4B) :: i - integer (I4B) :: j + integer(I4B) :: i + integer(I4B) :: j ! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars (now done from AR) @@ -291,8 +295,10 @@ subroutine uzf_allocate_arrays(this) call mem_allocate(this%appliedinf, this%nodes, 'APPLIEDINF', this%memoryPath) call mem_allocate(this%rejinf, this%nodes, 'REJINF', this%memoryPath) call mem_allocate(this%rejinf0, this%nodes, 'REJINF0', this%memoryPath) - call mem_allocate(this%rejinftomvr, this%nodes, 'REJINFTOMVR', this%memoryPath) - call mem_allocate(this%infiltration, this%nodes, 'INFILTRATION', this%memoryPath) + call mem_allocate(this%rejinftomvr, this%nodes, 'REJINFTOMVR', & + this%memoryPath) + call mem_allocate(this%infiltration, this%nodes, 'INFILTRATION', & + this%memoryPath) call mem_allocate(this%gwet, this%nodes, 'GWET', this%memoryPath) call mem_allocate(this%uzet, this%nodes, 'UZET', this%memoryPath) call mem_allocate(this%gwd, this%nodes, 'GWD', this%memoryPath) @@ -304,7 +310,7 @@ subroutine uzf_allocate_arrays(this) call mem_allocate(this%deriv, this%nodes, 'DERIV', this%memoryPath) ! -- integer vectors - call mem_allocate(this%ia, this%dis%nodes+1, 'IA', this%memoryPath) + call mem_allocate(this%ia, this%dis%nodes + 1, 'IA', this%memoryPath) call mem_allocate(this%ja, this%nodes, 'JA', this%memoryPath) ! -- allocate timeseries aware variables @@ -315,8 +321,9 @@ subroutine uzf_allocate_arrays(this) call mem_allocate(this%ha, this%nodes, 'HA', this%memoryPath) call mem_allocate(this%hroot, this%nodes, 'HROOT', this%memoryPath) call mem_allocate(this%rootact, this%nodes, 'ROOTACT', this%memoryPath) - call mem_allocate(this%uauxvar, this%naux, this%nodes, 'UAUXVAR', this%memoryPath) - + call mem_allocate(this%uauxvar, this%naux, this%nodes, 'UAUXVAR', & + this%memoryPath) + ! -- initialize do i = 1, this%nodes this%appliedinf(i) = DZERO @@ -350,12 +357,12 @@ subroutine uzf_allocate_arrays(this) end if end do end do - do i = 1, this%dis%nodes+1 + do i = 1, this%dis%nodes + 1 this%ia(i) = 0 end do ! ! -- allocate and initialize character array for budget text - allocate(this%bdtxt(this%nbdtxt)) + allocate (this%bdtxt(this%nbdtxt)) this%bdtxt(1) = ' UZF-INF' this%bdtxt(2) = ' UZF-GWRCH' this%bdtxt(3) = ' UZF-GWD' @@ -368,11 +375,11 @@ subroutine uzf_allocate_arrays(this) do i = 1, this%nodes this%wcnew(i) = DZERO this%wcold(i) = DZERO - end do + end do ! ! -- allocate character array for aux budget text - allocate(this%cauxcbc(this%cbcauxitems)) - allocate(this%uzfname(this%nodes)) + allocate (this%cauxcbc(this%cbcauxitems)) + allocate (this%uzfname(this%nodes)) ! ! -- allocate and initialize qauxcbc call mem_allocate(this%qauxcbc, this%cbcauxitems, 'QAUXCBC', this%memoryPath) @@ -382,7 +389,7 @@ subroutine uzf_allocate_arrays(this) ! ! -- return return - end subroutine uzf_allocate_arrays + end subroutine uzf_allocate_arrays ! subroutine uzf_options(this, option, found) @@ -400,130 +407,121 @@ subroutine uzf_options(this, option, found) use InputOutputModule, only: urword, getunit, openfile implicit none ! -- dummy - class(uzftype), intent(inout) :: this + class(uzftype), intent(inout) :: this character(len=*), intent(inout) :: option - logical, intent(inout) :: found + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: fname, keyword ! -- formats - character(len=*),parameter :: fmtnotfound= & - "(4x, 'NO UZF OPTIONS WERE FOUND.')" - character(len=*),parameter :: fmtet = & - "(4x, 'ET WILL BE SIMULATED WITHIN UZ AND GW ZONES, WITH LINEAR ', & - &'GWET IF OPTION NOT SPECIFIED OTHERWISE.')" - character(len=*),parameter :: fmtgwetlin = & - "(4x, 'GROUNDWATER ET FUNCTION WILL BE LINEAR.')" - character(len=*),parameter :: fmtgwetsquare = & - "(4x, 'GROUNDWATER ET FUNCTION WILL BE SQUARE WITH SMOOTHING.')" - character(len=*),parameter :: fmtgwseepout = & - "(4x, 'GROUNDWATER DISCHARGE TO LAND SURFACE WILL BE SIMULATED.')" - character(len=*),parameter :: fmtuzetwc = & - "(4x, 'UNSATURATED ET FUNCTION OF WATER CONTENT.')" - character(len=*),parameter :: fmtuzetae = & - "(4x, 'UNSATURATED ET FUNCTION OF AIR ENTRY PRESSURE.')" - character(len=*),parameter :: fmtuznlay = & - "(4x, 'UNSATURATED FLOW WILL BE SIMULATED SEPARATELY IN EACH LAYER.')" - character(len=*),parameter :: fmtuzfbin = & - "(4x, 'UZF ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I0)" - character(len=*),parameter :: fmtuzfopt = & - "(4x, 'UZF ', a, ' VALUE (',g15.7,') SPECIFIED.')" + character(len=*), parameter :: fmtnotfound = & + &"(4x, 'NO UZF OPTIONS WERE FOUND.')" + character(len=*), parameter :: fmtet = & + "(4x, 'ET WILL BE SIMULATED WITHIN UZ AND GW ZONES, WITH LINEAR ', & + &'GWET IF OPTION NOT SPECIFIED OTHERWISE.')" + character(len=*), parameter :: fmtgwetlin = & + &"(4x, 'GROUNDWATER ET FUNCTION WILL BE LINEAR.')" + character(len=*), parameter :: fmtgwetsquare = & + &"(4x, 'GROUNDWATER ET FUNCTION WILL BE SQUARE WITH SMOOTHING.')" + character(len=*), parameter :: fmtgwseepout = & + &"(4x, 'GROUNDWATER DISCHARGE TO LAND SURFACE WILL BE SIMULATED.')" + character(len=*), parameter :: fmtuzetwc = & + &"(4x, 'UNSATURATED ET FUNCTION OF WATER CONTENT.')" + character(len=*), parameter :: fmtuzetae = & + &"(4x, 'UNSATURATED ET FUNCTION OF AIR ENTRY PRESSURE.')" + character(len=*), parameter :: fmtuznlay = & + &"(4x, 'UNSATURATED FLOW WILL BE SIMULATED SEPARATELY IN EACH LAYER.')" + character(len=*), parameter :: fmtuzfbin = & + "(4x, 'UZF ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', & + &a, /4x, 'OPENED ON UNIT: ', I0)" + character(len=*), parameter :: fmtuzfopt = & + &"(4x, 'UZF ', a, ' VALUE (',g15.7,') SPECIFIED.')" ! ------------------------------------------------------------------------------ ! ! + found = .true. select case (option) !case ('PRINT_WATER-CONTENT') ! this%iprwcont = 1 ! write(this%iout,'(4x,a)') trim(adjustl(this%text))// & ! ' WATERCONTENT WILL BE PRINTED TO LISTING FILE.' - ! found = .true. - case('WATER_CONTENT') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%iwcontout = getunit() - call openfile(this%iwcontout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtuzfbin) 'WATER-CONTENT', fname, this%iwcontout - found = .true. - else - call store_error('OPTIONAL WATER_CONTENT KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtuzfbin) 'BUDGET', fname, this%ibudgetout - found = .true. - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtuzfbin) 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case('PACKAGE_CONVERGENCE') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ipakcsv = getunit() - call openfile(this%ipakcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtuzfbin) 'PACKAGE_CONVERGENCE', fname, this%ipakcsv - found = .true. - else - call store_error('OPTIONAL PACKAGE_CONVERGENCE KEYWORD MUST BE ' // & - 'FOLLOWED BY FILEOUT') - end if - case('SIMULATE_ET') - this%ietflag = 1 !default - this%igwetflag = 0 - found = .true. - write(this%iout, fmtet) - case('LINEAR_GWET') - this%igwetflag = 1 - found = .true. - write(this%iout, fmtgwetlin) - case('SQUARE_GWET') - this%igwetflag = 2 - found = .true. - write(this%iout, fmtgwetsquare) - case('SIMULATE_GWSEEP') - this%iseepflag = 1 - found = .true. - write(this%iout, fmtgwseepout) - case('UNSAT_ETWC') - this%ietflag = 1 - found = .true. - write(this%iout, fmtuzetwc) - case('UNSAT_ETAE') - this%ietflag = 2 - found = .true. - write(this%iout, fmtuzetae) - case('MOVER') - this%imover = 1 - found = .true. + case ('WATER_CONTENT') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%iwcontout = getunit() + call openfile(this%iwcontout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtuzfbin) 'WATER-CONTENT', fname, this%iwcontout + else + call store_error('OPTIONAL WATER_CONTENT KEYWORD & + &MUST BE FOLLOWED BY FILEOUT') + end if + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtuzfbin) 'BUDGET', fname, this%ibudgetout + else + call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtuzfbin) 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('PACKAGE_CONVERGENCE') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ipakcsv = getunit() + call openfile(this%ipakcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtuzfbin) 'PACKAGE_CONVERGENCE', fname, this%ipakcsv + else + call store_error('OPTIONAL PACKAGE_CONVERGENCE KEYWORD MUST BE '// & + 'FOLLOWED BY FILEOUT') + end if + case ('SIMULATE_ET') + this%ietflag = 1 !default + this%igwetflag = 0 + write (this%iout, fmtet) + case ('LINEAR_GWET') + this%igwetflag = 1 + write (this%iout, fmtgwetlin) + case ('SQUARE_GWET') + this%igwetflag = 2 + write (this%iout, fmtgwetsquare) + case ('SIMULATE_GWSEEP') + this%iseepflag = 1 + write (this%iout, fmtgwseepout) + case ('UNSAT_ETWC') + this%ietflag = 1 + write (this%iout, fmtuzetwc) + case ('UNSAT_ETAE') + this%ietflag = 2 + write (this%iout, fmtuzetae) + case ('MOVER') + this%imover = 1 ! ! -- right now these are options that are available but may not be available in ! the release (or in documentation) - case('DEV_NO_FINAL_CHECK') - call this%parser%DevOpt() - this%iconvchk = 0 - write(this%iout, '(4x,a)') & - & 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN UZF RECHARGE ' // & - & 'WILL NOT BE MADE' - found = .true. + case ('DEV_NO_FINAL_CHECK') + call this%parser%DevOpt() + this%iconvchk = 0 + write (this%iout, '(4x,a)') & + 'A FINAL CONVERGENCE CHECK OF THE CHANGE IN UZF RECHARGE & + &WILL NOT BE MADE' !case('DEV_MAXIMUM_PERCENT_DIFFERENCE') ! call this%parser%DevOpt() ! r = this%parser%GetDouble() @@ -534,10 +532,9 @@ subroutine uzf_options(this, option, found) ! write(this%iout, fmtuzfopt) 'INVALID MAXIMUM_PERCENT_DIFFERENCE', r ! write(this%iout, fmtuzfopt) 'USING DEFAULT MAXIMUM_PERCENT_DIFFERENCE', this%pdmax ! end if - ! found = .true. - case default - ! -- No options found - found = .false. + case default + ! -- No options found + found = .false. end select ! -- return return @@ -554,14 +551,14 @@ subroutine uzf_readdimensions(this) ! ------------------------------------------------------------------------------ use InputOutputModule, only: urword use SimModule, only: store_error, count_errors - class(uzftype),intent(inout) :: this + class(uzftype), intent(inout) :: this character(len=LINELENGTH) :: keyword integer(I4B) :: ierr logical :: isfound, endOfBlock ! ------------------------------------------------------------------------------ ! ! -- initialize dimensions to -1 - this%nodes= -1 + this%nodes = -1 this%ntrail = 0 this%nsets = 0 ! @@ -571,29 +568,29 @@ subroutine uzf_readdimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(this%text))//' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('NUZFCELLS') - this%nodes = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NUZFCELLS = ', this%nodes - case ('NTRAILWAVES') - this%ntrail = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NTRAILWAVES = ', this%ntrail - case ('NWAVESETS') - this%nsets = this%parser%GetInteger() - write(this%iout,'(4x,a,i0)') 'NTRAILSETS = ', this%nsets - case default - write(errmsg,'(a,a)') & - 'Unknown '// trim(this%text) // ' dimension: ', trim(keyword) - end select + case ('NUZFCELLS') + this%nodes = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NUZFCELLS = ', this%nodes + case ('NTRAILWAVES') + this%ntrail = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NTRAILWAVES = ', this%ntrail + case ('NWAVESETS') + this%nsets = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NTRAILSETS = ', this%nsets + case default + write (errmsg, '(a,a)') & + 'Unknown '//trim(this%text)//' dimension: ', trim(keyword) + end select end do - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(this%text)) // ' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' else call store_error('Required dimensions block not found.') end if @@ -604,19 +601,19 @@ subroutine uzf_readdimensions(this) ! ! -- verify dimensions were set if (this%nodes <= 0) then - write(errmsg, '(a)') & + write (errmsg, '(a)') & 'NUZFCELLS was not specified or was specified incorrectly.' call store_error(errmsg) end if if (this%ntrail <= 0) then - write(errmsg, '(a)') & + write (errmsg, '(a)') & 'NTRAILWAVES was not specified or was specified incorrectly.' call store_error(errmsg) end if ! if (this%nsets <= 0) then - write(errmsg, '(a)') & + write (errmsg, '(a)') & 'NWAVESETS was not specified or was specified incorrectly.' call store_error(errmsg) end if @@ -637,7 +634,7 @@ subroutine uzf_readdimensions(this) call this%uzf_allocate_arrays() ! ! -- initialize uzf group object - allocate(this%uzfobj) + allocate (this%uzfobj) call this%uzfobj%init(this%nodes, this%nwav, this%memoryPath) call this%uzfobjwork%init(1, this%nwav) ! @@ -684,28 +681,28 @@ subroutine uzf_rp(this) character(len=LINELENGTH) :: line logical :: isfound logical :: endOfBlock - integer (I4B) :: i - integer (I4B) :: j - integer (I4B) :: jj + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: jj integer(I4B) :: ierr real(DP), pointer :: bndElem => null() ! -- table output - character (len=20) :: cellid + character(len=20) :: cellid character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag integer(I4B) :: ntabrows integer(I4B) :: ntabcols integer(I4B) :: node !-- formats - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*),parameter :: fmtflow = & - "(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtisvflow = & + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" + character(len=*), parameter :: fmtflow = & + &"(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" ! ------------------------------------------------------------------------------ ! ! -- Set ionper to the stress period number for which a new block of data @@ -717,7 +714,8 @@ subroutine uzf_rp(this) ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true., & + blockRequired=.false.) if (isfound) then ! ! -- read ionper and check for increasing period numbers @@ -731,18 +729,18 @@ subroutine uzf_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- set steady-state flag based on gwfiss this%issflag = this%gwfiss ! ! -- read data if ionper == kper - if(this%ionper==kper) then + if (this%ionper == kper) then ! ! -- write header if (this%iprpak /= 0) then @@ -763,11 +761,11 @@ subroutine uzf_rp(this) end if ! ! -- initialize table and define columns - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper call table_cr(this%inputtab, this%packName, title) - call this%inputtab%table_df(ntabrows, ntabcols, this%iout, & + call this%inputtab%table_df(ntabrows, ntabcols, this%iout, & finalize=.FALSE.) tag = 'NUMBER' call this%inputtab%initialize_column(tag, 10) @@ -793,7 +791,8 @@ subroutine uzf_rp(this) end if if (this%inamedbound == 1) then tag = 'BOUNDNAME' - call this%inputtab%initialize_column(tag, LENBOUNDNAME, alignment=TABLEFT) + call this%inputtab%initialize_column(tag, LENBOUNDNAME, & + alignment=TABLEFT) end if end if ! @@ -805,12 +804,12 @@ subroutine uzf_rp(this) ! -- check for valid uzf node i = this%parser%GetInteger() if (i < 1 .or. i > this%nodes) then - tag = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(tag, '(a,1x,i0)') trim(adjustl(tag)), kper - - write(errmsg,'(a,a,i0,1x,a,i0,a)') & - trim(adjustl(tag)), ': UZFNO ', i, & + tag = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (tag, '(a,1x,i0)') trim(adjustl(tag)), kper + + write (errmsg, '(a,a,i0,1x,a,i0,a)') & + trim(adjustl(tag)), ': UZFNO ', i, & 'must be greater than 0 and less than or equal to ', this%nodes, '.' call store_error(errmsg) cycle @@ -825,65 +824,65 @@ subroutine uzf_rp(this) ! ! -- FINF call this%parser%GetStringCaps(text) - jj = 1 ! For SINF + jj = 1 ! For SINF bndElem => this%sinf(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'SINF') ! ! -- PET call this%parser%GetStringCaps(text) - jj = 1 ! For PET + jj = 1 ! For PET bndElem => this%pet(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'PET') ! ! -- EXTD call this%parser%GetStringCaps(text) - jj = 1 ! For EXTDP + jj = 1 ! For EXTDP bndElem => this%extdp(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'EXTDP') ! ! -- EXTWC call this%parser%GetStringCaps(text) - jj = 1 ! For EXTWC + jj = 1 ! For EXTWC bndElem => this%extwc(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'EXTWC') ! ! -- HA call this%parser%GetStringCaps(text) - jj = 1 ! For HA + jj = 1 ! For HA bndElem => this%ha(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'HA') ! ! -- HROOT call this%parser%GetStringCaps(text) - jj = 1 ! For HROOT + jj = 1 ! For HROOT bndElem => this%hroot(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'HROOT') ! ! -- ROOTACT call this%parser%GetStringCaps(text) - jj = 1 ! For ROOTACT + jj = 1 ! For ROOTACT bndElem => this%rootact(i) - call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, i, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & 'ROOTACT') ! ! -- read auxillary variables do j = 1, this%naux call this%parser%GetStringCaps(text) bndElem => this%uauxvar(j, i) - call read_value_or_time_series_adv(text, i, j, bndElem, this%packName, & + call read_value_or_time_series_adv(text, i, j, bndElem, this%packName, & 'AUX', this%tsManager, this%iprpak, & this%auxname(j)) end do @@ -924,11 +923,11 @@ subroutine uzf_rp(this) if (this%iprpak /= 0) then call this%inputtab%finalize_table() end if - ! - ! -- using stress period data from the previous stress period + ! + ! -- using stress period data from the previous stress period else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + write (this%iout, fmtlsp) trim(this%filtyp) + end if ! ! -- write summary of uzf stress period error messages ierr = count_errors() @@ -937,8 +936,8 @@ subroutine uzf_rp(this) end if ! ! -- set wave data for first stress period and second that follows SS - if ((this%issflag == 0 .AND. kper == 1) .or. & - (kper == 2 .AND. this%issflagold == 1)) then + if ((this%issflag == 0 .AND. kper == 1) .or. & + (kper == 2 .AND. this%issflagold == 1)) then do i = 1, this%nodes call this%uzfobj%setwaves(i) end do @@ -973,7 +972,7 @@ subroutine uzf_ad(this) integer(I4B) :: i integer(I4B) :: ivertflag integer(I4B) :: n, iaux - real (DP) :: rval1, rval2, rval3 + real(DP) :: rval1, rval2, rval3 ! ------------------------------------------------------------------------------ ! ! -- Advance the time series @@ -1006,12 +1005,12 @@ subroutine uzf_ad(this) ! and that doesn't happen until a successful solution is obtained. do i = 1, this%nodes this%wcnew(i) = this%wcold(i) - end do + end do end if ! ! -- advance each uzf obj do i = 1, this%nodes - call this%uzfobj%advance(i) + call this%uzfobj%advance(i) end do ! ! -- update uzf objects with timeseries aware variables @@ -1052,9 +1051,9 @@ subroutine uzf_ad(this) end if ! ! -- pakmvrobj ad - if(this%imover == 1) then - call this%pakmvrobj%ad() - endif + if (this%imover == 1) then + call this%pakmvrobj%ad() + end if ! ! -- For each observation, push simulated value and corresponding ! simulation time from "current" to "preceding" and reset @@ -1084,7 +1083,7 @@ subroutine uzf_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no UZF cells - if(this%nodes == 0) return + if (this%nodes == 0) return ! ! -- Store values at start of outer iteration to compare with calculated ! values for convergence check @@ -1097,9 +1096,9 @@ subroutine uzf_cf(this, reset_mover) ! -- pakmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() - endif + end if ! ! -- return return @@ -1123,9 +1122,9 @@ subroutine uzf_fc(this, rhs, ia, idxglo, amatsln) ! ------------------------------------------------------------------------------ ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() - endif + end if ! ! -- Solve UZF; set reset_state to true so that waves are reset back to ! initial position for each outer iteration @@ -1137,7 +1136,7 @@ subroutine uzf_fc(this, rhs, ia, idxglo, amatsln) rhs(n) = rhs(n) + this%rhs(i) ipos = ia(n) amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) - enddo + end do ! ! -- return return @@ -1241,8 +1240,8 @@ subroutine uzf_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! ! -- setup table call table_cr(this%pakcsvtab, this%packName, '') - call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & - lineseparator=.FALSE., separator=',', & + call this%pakcsvtab%table_df(ntabrows, ntabcols, this%ipakcsv, & + lineseparator=.FALSE., separator=',', & finalize=.FALSE.) ! ! -- add columns to package csv @@ -1320,20 +1319,20 @@ subroutine uzf_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) if (ABS(drejinfmax) > abs(dpak)) then ipak = locdrejinfmax dpak = drejinfmax - write(cloc, "(a,'-',a)") trim(this%packName), 'rejinf' + write (cloc, "(a,'-',a)") trim(this%packName), 'rejinf' cpak = trim(cloc) end if if (ABS(drchmax) > abs(dpak)) then ipak = locdrchmax dpak = drchmax - write(cloc, "(a,'-',a)") trim(this%packName), 'rech' + write (cloc, "(a,'-',a)") trim(this%packName), 'rech' cpak = trim(cloc) end if if (this%iseepflag == 1) then if (ABS(dseepmax) > abs(dpak)) then ipak = locdseepmax dpak = dseepmax - write(cloc, "(a,'-',a)") trim(this%packName), 'seep' + write (cloc, "(a,'-',a)") trim(this%packName), 'seep' cpak = trim(cloc) end if end if @@ -1378,7 +1377,6 @@ subroutine uzf_cq(this, x, flowja, iadv) use TdisModule, only: delt use ConstantsModule, only: LENBOUNDNAME, DZERO, DHNOFLO, DHDRY use BudgetModule, only: BudgetType - use InputOutputModule, only: ulasav, ubdsv06 ! -- dummy class(UzfType), intent(inout) :: this real(DP), dimension(:), intent(in) :: x @@ -1394,7 +1392,7 @@ subroutine uzf_cq(this, x, flowja, iadv) ! -- for observations ! -- formats character(len=*), parameter :: fmttkk = & - "(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" + &"(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" ! ------------------------------------------------------------------------------ ! ! -- Make uzf solution for budget calculations, and then reset waves. @@ -1476,7 +1474,7 @@ subroutine uzf_cq(this, x, flowja, iadv) ! -- return return end subroutine uzf_cq - + function get_storage_change(top, bot, carea, hold, hnew, wcold, wcnew, & thtr, delt, iss) result(qsto) real(DP), intent(in) :: top @@ -1519,35 +1517,35 @@ subroutine uzf_bd(this, model_budget) real(DP) :: ratout integer(I4B) :: isuppress_output isuppress_output = 0 - + ! -- Calculate flow from uzf to gwf (UZF-GWRCH) call rate_accumulator(this%rch, ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%bdtxt(2), & + call model_budget%addentry(ratin, ratout, delt, this%bdtxt(2), & isuppress_output, this%packName) ! -- GW discharge and GW discharge to mover if (this%iseepflag == 1) then call rate_accumulator(-this%gwd, ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%bdtxt(3), & + call model_budget%addentry(ratin, ratout, delt, this%bdtxt(3), & isuppress_output, this%packName) if (this%imover == 1) then call rate_accumulator(-this%gwdtomvr, ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%bdtxt(5), & + call model_budget%addentry(ratin, ratout, delt, this%bdtxt(5), & isuppress_output, this%packName) end if end if - + ! -- groundwater et (gwet array is positive, so switch ratin/ratout) if (this%igwetflag /= 0) then call rate_accumulator(-this%gwet, ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%bdtxt(4), & + call model_budget%addentry(ratin, ratout, delt, this%bdtxt(4), & isuppress_output, this%packName) end if - + return - end subroutine uzf_bd - - subroutine uzf_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) + end subroutine uzf_bd + + subroutine uzf_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) ! ****************************************************************************** ! bnd_ot_model_flows -- write flows to binary file and/or print flows to budget ! ****************************************************************************** @@ -1564,55 +1562,67 @@ subroutine uzf_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) integer(I4B), intent(in) :: icbcun integer(I4B), dimension(:), optional, intent(in) :: imap ! -- local - character (len=LINELENGTH) :: title + character(len=LINELENGTH) :: title integer(I4B) :: itxt ! -- formats ! ------------------------------------------------------------------------------ ! ! -- UZF-GWRCH itxt = 2 - title = trim(adjustl(this%bdtxt(itxt))) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' + title = trim(adjustl(this%bdtxt(itxt)))//' PACKAGE ('// & + trim(this%packName)//') FLOW RATES' call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, this%rch, & - this%ibound, title, this%bdtxt(itxt), this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, this%boundname) + this%outputtab, this%nbound, this%nodelist, & + this%rch, this%ibound, title, this%bdtxt(itxt), & + this%ipakcb, this%dis, this%naux, & + this%name_model, this%name_model, & + this%name_model, this%packName, this%auxname, & + this%auxvar, this%iout, this%inamedbound, & + this%boundname) ! ! -- UZF-GWD if (this%iseepflag == 1) then itxt = 3 - title = trim(adjustl(this%bdtxt(itxt))) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' + title = trim(adjustl(this%bdtxt(itxt)))//' PACKAGE ('// & + trim(this%packName)//') FLOW RATES' call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, -this%gwd, & - this%ibound, title, this%bdtxt(itxt), this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, this%boundname) + this%outputtab, this%nbound, this%nodelist, & + -this%gwd, this%ibound, title, & + this%bdtxt(itxt), this%ipakcb, this%dis, & + this%naux, this%name_model, this%name_model, & + this%name_model, this%packName, this%auxname, & + this%auxvar, this%iout, this%inamedbound, & + this%boundname) ! ! -- UZF-GWD TO-MVR if (this%imover == 1) then itxt = 5 - title = trim(adjustl(this%bdtxt(itxt))) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' + title = trim(adjustl(this%bdtxt(itxt)))//' PACKAGE ('// & + trim(this%packName)//') FLOW RATES' call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, -this%gwdtomvr, & - this%ibound, title, this%bdtxt(itxt), this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, this%boundname) + this%outputtab, this%nbound, this%nodelist, & + -this%gwdtomvr, this%ibound, title, & + this%bdtxt(itxt), this%ipakcb, this%dis, & + this%naux, this%name_model, this%name_model, & + this%name_model, this%packName, & + this%auxname, this%auxvar, this%iout, & + this%inamedbound, this%boundname) end if end if ! ! -- UZF-GWET if (this%igwetflag /= 0) then itxt = 4 - title = trim(adjustl(this%bdtxt(itxt))) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' + title = trim(adjustl(this%bdtxt(itxt)))//' PACKAGE ('// & + trim(this%packName)//') FLOW RATES' call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, -this%gwet, & - this%ibound, title, this%bdtxt(itxt), this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, this%boundname) + this%outputtab, this%nbound, this%nodelist, & + -this%gwet, this%ibound, title, & + this%bdtxt(itxt), this%ipakcb, this%dis, & + this%naux, this%name_model, this%name_model, & + this%name_model, this%packName, this%auxname, & + this%auxvar, this%iout, this%inamedbound, & + this%boundname) end if ! ! -- return @@ -1628,10 +1638,10 @@ subroutine uzf_ot_package_flows(this, icbcfl, ibudfl) ! ! -- write the flows from the budobj ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & pertim, totim, this%iout) @@ -1641,7 +1651,7 @@ subroutine uzf_ot_package_flows(this, icbcfl, ibudfl) if (ibudfl /= 0 .and. this%iprflow /= 0) then call this%budobj%write_flowtable(this%dis, kstp, kper) end if - + end subroutine uzf_ot_package_flows subroutine uzf_ot_dv(this, idvsave, idvprint) @@ -1654,34 +1664,34 @@ subroutine uzf_ot_dv(this, idvsave, idvprint) ! ! -- set unit number for binary dependent variable output ibinun = 0 - if(this%iwcontout /= 0) then + if (this%iwcontout /= 0) then ibinun = this%iwcontout end if - if(idvsave == 0) ibinun = 0 + if (idvsave == 0) ibinun = 0 ! ! -- write uzf binary moisture-content output if (ibinun > 0) then call ulasav(this%wcnew, ' WATER-CONTENT', kstp, kper, pertim, & totim, this%nodes, 1, 1, ibinun) - end if + end if end subroutine uzf_ot_dv - + subroutine uzf_ot_bdsummary(this, kstp, kper, iout, ibudfl) ! -- module use TdisModule, only: totim ! -- dummy - class(UzfType) :: this !< UzfType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + class(UzfType) :: this !< UzfType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written ! call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) ! ! -- return return end subroutine uzf_ot_bdsummary - + subroutine uzf_solve(this, reset_state) ! ****************************************************************************** ! uzf_solve -- Formulate the HCOF and RHS terms @@ -1690,8 +1700,8 @@ subroutine uzf_solve(this, reset_state) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use TdisModule, only : delt - logical, intent(in) :: reset_state !< flag indicating that waves should be reset after solution + use TdisModule, only: delt + logical, intent(in) :: reset_state !< flag indicating that waves should be reset after solution ! -- dummy class(UzfType) :: this ! -- locals @@ -1727,39 +1737,39 @@ subroutine uzf_solve(this, reset_state) ivertflag = this%uzfobj%ivertcon(i) watabold = this%uzfobj%watabold(i) ! - if ( this%ibound(n) > 0 ) then + if (this%ibound(n) > 0) then ! ! -- Water mover added to infiltration qfrommvr = DZERO qformvr = DZERO - if(this%imover == 1) then + if (this%imover == 1) then qfrommvr = this%pakmvrobj%get_qfrommvr(i) - endif + end if ! hgwf = this%xnew(n) m = n ! ! -- solve for current uzf cell - call this%uzfobj%solve(this%uzfobjwork, ivertflag, i, & - this%totfluxtot, this%ietflag, & - this%issflag,this%iseepflag, hgwf, & - qfrommvr, ierr, & - reset_state=reset_state, & - trhs=trhs1, thcof=thcof1, deriv=uzderiv, & + call this%uzfobj%solve(this%uzfobjwork, ivertflag, i, & + this%totfluxtot, this%ietflag, & + this%issflag, this%iseepflag, hgwf, & + qfrommvr, ierr, & + reset_state=reset_state, & + trhs=trhs1, thcof=thcof1, deriv=uzderiv, & watercontent=wc) ! ! -- terminate if an error condition has occurred if (ierr > 0) then - if ( ierr == 1 ) & - errmsg = 'UZF variable NWAVESETS needs to be increased.' - call store_error(errmsg, terminate=.TRUE.) + if (ierr == 1) & + errmsg = 'UZF variable NWAVESETS needs to be increased.' + call store_error(errmsg, terminate=.TRUE.) end if ! ! -- Calculate gwet - if ( this%igwetflag > 0 ) then + if (this%igwetflag > 0) then call this%uzfobj%setgwpet(i) - call this%uzfobj%simgwet(this%igwetflag,i,hgwf,trhs2,thcof2, & - derivgwet) + call this%uzfobj%simgwet(this%igwetflag, i, hgwf, trhs2, thcof2, & + derivgwet) end if ! ! -- distribute PET to deeper cells @@ -1783,23 +1793,23 @@ subroutine uzf_solve(this, reset_state) this%rhs(i) = -trhs1 + trhs2 ! ! -- add spring discharge and rejected infiltration to mover - if(this%imover == 1) then + if (this%imover == 1) then qformvr = this%gwd(i) + this%rejinf(i) call this%pakmvrobj%accumulate_qformvr(i, qformvr) - endif + end if ! ! -- Store water content this%wcnew(i) = wc ! ! -- Calculate change in mobile storage - this%qsto(i) = get_storage_change(this%uzfobj%celtop(i), & - this%uzfobj%celbot(i), & - this%uzfobj%uzfarea(i), & - watabold, & - this%uzfobj%watab(i), & + this%qsto(i) = get_storage_change(this%uzfobj%celtop(i), & + this%uzfobj%celbot(i), & + this%uzfobj%uzfarea(i), & + watabold, & + this%uzfobj%watab(i), & this%wcold(i), this%wcnew(i), & this%uzfobj%thtr(i), delt, this%issflag) - ! + ! end if end do ! @@ -1819,27 +1829,27 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return end subroutine define_listlabel - subroutine findcellabove(this,n,nml) + subroutine findcellabove(this, n, nml) class(UzfType) :: this integer(I4B), intent(in) :: n integer(I4B), intent(inout) :: nml @@ -1848,23 +1858,23 @@ subroutine findcellabove(this,n,nml) ! ! -- return nml = n if no cell is above it nml = n - do ipos = this%dis%con%ia(n)+1, this%dis%con%ia(n+1)-1 + do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ipos) - if(this%dis%con%ihc(ipos) /= 0) then + if (this%dis%con%ihc(ipos) /= 0) then if (n < m) then ! -- m is beneath n else - nml = m ! -- m is above n + nml = m ! -- m is above n exit - endif + end if end if - enddo + end do return - end subroutine findcellabove + end subroutine findcellabove - subroutine read_cell_properties(this) + subroutine read_cell_properties(this) ! ****************************************************************************** -! read_cell_properties -- Read UZF cell properties and set them for +! read_cell_properties -- Read UZF cell properties and set them for ! UzfCellGroup type. ! ****************************************************************************** use InputOutputModule, only: urword @@ -1890,13 +1900,13 @@ subroutine read_cell_properties(this) ! ! ! -- allocate space for node counter and initilize - allocate(rowmaxnnz(this%dis%nodes)) + allocate (rowmaxnnz(this%dis%nodes)) do n = 1, this%dis%nodes rowmaxnnz(n) = 0 end do ! ! -- allocate space for local variables - allocate(nboundchk(this%nodes)) + allocate (nboundchk(this%nodes)) do n = 1, this%nodes nboundchk(n) = 0 end do @@ -1914,33 +1924,33 @@ subroutine read_cell_properties(this) ! ! -- get uzf properties block call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse locations block if detected if (isfound) then - write(this%iout,'(/1x,3a)') 'PROCESSING ', trim(adjustl(this%text)), & - ' PACKAGEDATA' + write (this%iout, '(/1x,3a)') 'PROCESSING ', trim(adjustl(this%text)), & + ' PACKAGEDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit ! ! -- get uzf cell number i = this%parser%GetInteger() - + if (i < 1 .or. i > this%nodes) then - write(errmsg,'(2(a,1x),i0,a)') & - 'IUZNO must be greater than 0 and less than', & - 'or equal to', this%nodes , '.' + write (errmsg, '(2(a,1x),i0,a)') & + 'IUZNO must be greater than 0 and less than', & + 'or equal to', this%nodes, '.' call store_error(errmsg) cycle - end if + end if ! ! -- increment nboundchk nboundchk(i) = nboundchk(i) + 1 ! ! -- store the reduced gwf nodenumber in igwfnode call this%parser%GetCellid(this%dis%ndim, cellid) - ic = this%dis%noder_from_cellid(cellid, & + ic = this%dis%noder_from_cellid(cellid, & this%parser%iuactive, this%iout) this%igwfnode(i) = ic rowmaxnnz(ic) = rowmaxnnz(ic) + 1 @@ -1948,8 +1958,8 @@ subroutine read_cell_properties(this) ! -- landflag landflag = this%parser%GetInteger() if (landflag < 0 .OR. landflag > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & - 'LANDFLAG for uzf cell', i, & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & + 'LANDFLAG for uzf cell', i, & 'must be 0 or 1 (specified value is', landflag, ').' call store_error(errmsg) end if @@ -1957,24 +1967,24 @@ subroutine read_cell_properties(this) ! -- ivertcon ivertcon = this%parser%GetInteger() if (ivertcon < 0 .OR. ivertcon > this%nodes) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,a)') & - 'IVERTCON for uzf cell', i, & - 'must be 0 or less than NUZFCELLS (specified value is', & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,a)') & + 'IVERTCON for uzf cell', i, & + 'must be 0 or less than NUZFCELLS (specified value is', & ivertcon, ').' call store_error(errmsg) end if ! ! -- surfdep - surfdep = this%parser%GetDouble() - if (surfdep <= DZERO .and. landflag > 0) then !need to check for cell thickness - write(errmsg,'(a,1x,i0,1x,a,1x,g0,a)') & - 'SURFDEP for uzf cell', i, & + surfdep = this%parser%GetDouble() + if (surfdep <= DZERO .and. landflag > 0) then !need to check for cell thickness + write (errmsg, '(a,1x,i0,1x,a,1x,g0,a)') & + 'SURFDEP for uzf cell', i, & 'must be greater than 0 (specified value is', surfdep, ').' call store_error(errmsg) end if - if(surfdep >= this%GWFTOP(ic) - this%GWFBOT(ic)) then - write(errmsg,'(a,1x,i0,1x,a)') & - 'SURFDEP for uzf cell', i, & + if (surfdep >= this%GWFTOP(ic) - this%GWFBOT(ic)) then + write (errmsg, '(a,1x,i0,1x,a)') & + 'SURFDEP for uzf cell', i, & 'cannot be greater than the cell thickness.' call store_error(errmsg) end if @@ -1982,8 +1992,8 @@ subroutine read_cell_properties(this) ! -- vks vks = this%parser%GetDouble() if (vks <= DZERO) then - write(errmsg,'(a,1x,i0,1x,a,1x,g0,a)') & - 'VKS for uzf cell', i, & + write (errmsg, '(a,1x,i0,1x,a,1x,g0,a)') & + 'VKS for uzf cell', i, & 'must be greater than 0 (specified value ia', vks, ').' call store_error(errmsg) end if @@ -1991,17 +2001,17 @@ subroutine read_cell_properties(this) ! -- thtr thtr = this%parser%GetDouble() if (thtr <= DZERO) then - write(errmsg,'(a,1x,i0,1x,a,1x,g0,a)') & - 'THTR for uzf cell', i, & - 'must be greater than 0 (specified value is', thtr, ').' + write (errmsg, '(a,1x,i0,1x,a,1x,g0,a)') & + 'THTR for uzf cell', i, & + 'must be greater than 0 (specified value is', thtr, ').' call store_error(errmsg) end if ! ! -- thts thts = this%parser%GetDouble() if (thts <= thtr) then - write(errmsg,'(a,1x,i0,1x,a,1x,g0,a)') & - 'THTS for uzf cell', i, & + write (errmsg, '(a,1x,i0,1x,a,1x,g0,a)') & + 'THTS for uzf cell', i, & 'must be greater than THTR (specified value is', thts, ').' call store_error(errmsg) end if @@ -2009,9 +2019,9 @@ subroutine read_cell_properties(this) ! -- thti thti = this%parser%GetDouble() if (thti < thtr .OR. thti > thts) then - write(errmsg,'(a,1x,i0,1x,a,1x,a,1x,g0,a)') & - 'THTI for uzf cell', i, & - 'must be greater than or equal to THTR AND less than THTS', & + write (errmsg, '(a,1x,i0,1x,a,1x,a,1x,g0,a)') & + 'THTI for uzf cell', i, & + 'must be greater than or equal to THTR AND less than THTS', & '(specified value is', thti, ').' call store_error(errmsg) end if @@ -2019,8 +2029,8 @@ subroutine read_cell_properties(this) ! -- eps eps = this%parser%GetDouble() if (eps < 3.5 .OR. eps > 14) then - write(errmsg,'(a,1x,i0,1x,a,1x,g0,a)') & - 'EPSILON for uzf cell', i, & + write (errmsg, '(a,1x,i0,1x,a,1x,g0,a)') & + 'EPSILON for uzf cell', i, & 'must be between 3.5 and 14.0 (specified value is', eps, ').' call store_error(errmsg) end if @@ -2028,19 +2038,19 @@ subroutine read_cell_properties(this) ! -- boundname if (this%inamedbound == 1) then call this%parser%GetStringCaps(this%uzfname(i)) - endif + end if ! ! -- set data if there are no data errors if (count_errors() == 0) then n = this%igwfnode(i) - call this%uzfobj%setdata(i, this%gwfarea(n), this%gwftop(n), & - this%gwfbot(n), surfdep, vks, thtr, thts, & + call this%uzfobj%setdata(i, this%gwfarea(n), this%gwftop(n), & + this%gwfbot(n), surfdep, vks, thtr, thts, & thti, eps, this%ntrail, landflag, ivertcon) if (ivertcon > 0) then this%iuzf2uzf = 1 end if end if - ! + ! end do else call store_error('Required packagedata block not found.') @@ -2049,11 +2059,11 @@ subroutine read_cell_properties(this) ! -- check for duplicate or missing uzf cells do i = 1, this%nodes if (nboundchk(i) == 0) then - write(errmsg,'(a,1x,i0,a)') & + write (errmsg, '(a,1x,i0,a)') & 'No data specified for uzf cell', i, '.' call store_error(errmsg) else if (nboundchk(i) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'Data for uzf cell', i, 'specified', nboundchk(i), 'times.' call store_error(errmsg) end if @@ -2074,12 +2084,12 @@ subroutine read_cell_properties(this) end do ! ! -- create ia and ja from sparse - call sparse%filliaja(this%ia,this%ja,ierr) + call sparse%filliaja(this%ia, this%ja, ierr) ! ! -- set imaxcellcnt do i = 1, this%dis%nodes jcol = 0 - do j = this%ia(i), this%ia(i+1) - 1 + do j = this%ia(i), this%ia(i + 1) - 1 jcol = jcol + 1 end do if (jcol > this%imaxcellcnt) then @@ -2096,8 +2106,8 @@ subroutine read_cell_properties(this) end if ! ! -- deallocate local variables - deallocate(rowmaxnnz) - deallocate(nboundchk) + deallocate (rowmaxnnz) + deallocate (nboundchk) ! ! -- return return @@ -2105,14 +2115,14 @@ end subroutine read_cell_properties subroutine print_cell_properties(this) ! ****************************************************************************** -! print_cell_properties -- Read UZF cell properties and set them for +! print_cell_properties -- Read UZF cell properties and set them for ! UZFCellGroup type. ! ****************************************************************************** ! ------------------------------------------------------------------------------ ! -- dummy class(UzfType), intent(inout) :: this ! -- local - character (len=20) :: cellid + character(len=20) :: cellid character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag integer(I4B) :: ntabrows @@ -2132,8 +2142,8 @@ subroutine print_cell_properties(this) end if ! ! -- initialize table and define columns - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') STATIC UZF CELL DATA' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') STATIC UZF CELL DATA' call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(ntabrows, ntabcols, this%iout) tag = 'NUMBER' @@ -2192,7 +2202,7 @@ subroutine print_cell_properties(this) return end subroutine print_cell_properties - subroutine check_cell_area(this) + subroutine check_cell_area(this) ! ****************************************************************************** ! check_cell_area -- Check UZF cell areas. ! ****************************************************************************** @@ -2231,8 +2241,8 @@ subroutine check_cell_area(this) area2 = this%uzfobj%uzfarea(i2) d = abs(area - area2) if (d > DEM6) then - write(errmsg,'(2(a,1x,g0,1x,a,1x,i0,1x),a)') & - 'UZF cell area (', area, ') for cell ', i, & + write (errmsg, '(2(a,1x,g0,1x,a,1x,i0,1x),a)') & + 'UZF cell area (', area, ') for cell ', i, & 'does not equal uzf cell area (', area2, ') for cell ', i2, '.' call store_error(errmsg) end if @@ -2243,7 +2253,7 @@ subroutine check_cell_area(this) ! to the GWF cell area do n = 1, this%dis%nodes i0 = this%ia(n) - i1 = this%ia(n+1) + i1 = this%ia(n + 1) ! -- skip gwf cells with no UZF cells if ((i1 - i0) < 1) cycle sumarea = DZERO @@ -2251,8 +2261,8 @@ subroutine check_cell_area(this) cuzfcells = '' do j = i0, i1 - 1 i = this%ja(j) - write(cuzf,'(i0)') i - cuzfcells = trim(adjustl(cuzfcells)) // ' ' // trim(adjustl(cuzf)) + write (cuzf, '(i0)') i + cuzfcells = trim(adjustl(cuzfcells))//' '//trim(adjustl(cuzf)) sumarea = sumarea + this%uzfobj%uzfarea(i) cellarea = this%uzfobj%cellarea(i) end do @@ -2260,9 +2270,9 @@ subroutine check_cell_area(this) d = abs(sumarea - cellarea) if (d > DEM6) then call this%dis%noder_to_string(n, cellid) - write(errmsg,'(a,1x,g0,1x,a,1x,g0,1x,a,1x,a,1x,a,a,a)') & - 'Total uzf cell area (', sumarea, & - ') exceeds the gwf cell area (', cellarea, ') of cell', cellid, & + write (errmsg, '(a,1x,g0,1x,a,1x,g0,1x,a,1x,a,1x,a,a,a)') & + 'Total uzf cell area (', sumarea, & + ') exceeds the gwf cell area (', cellarea, ') of cell', cellid, & 'which includes uzf cell(s): ', trim(adjustl(cuzfcells)), '.' call store_error(errmsg) end if @@ -2305,7 +2315,7 @@ subroutine uzf_df_obs(this) class(UzfType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ ! ! -- Store obs type and assign procedure pointer ! @@ -2394,61 +2404,61 @@ subroutine uzf_bd_obs(this) n = obsrv%indxbnds(ii) v = DNODATA select case (obsrv%ObsTypeId) - case ('UZF-GWRCH') - v = this%rch(n) - case ('UZF-GWD') - v = this%gwd(n) + case ('UZF-GWRCH') + v = this%rch(n) + case ('UZF-GWD') + v = this%gwd(n) + if (v > DZERO) then + v = -v + end if + case ('UZF-GWD-TO-MVR') + if (this%imover == 1) then + v = this%gwdtomvr(n) if (v > DZERO) then v = -v end if - case ('UZF-GWD-TO-MVR') - if (this%imover == 1) then - v = this%gwdtomvr(n) - if (v > DZERO) then - v = -v - end if - end if - case ('UZF-GWET') - if (this%igwetflag > 0) then - v = this%gwet(n) - if (v > DZERO) then - v = -v - end if - end if - case ('INFILTRATION') - v = this%appliedinf(n) - case ('FROM-MVR') - if (this%imover == 1) then - v = this%pakmvrobj%get_qfrommvr(n) - end if - case ('REJ-INF') - v = this%rejinf(n) + end if + case ('UZF-GWET') + if (this%igwetflag > 0) then + v = this%gwet(n) if (v > DZERO) then v = -v end if - case ('REJ-INF-TO-MVR') - if (this%imover == 1) then - v = this%rejinftomvr(n) - if (v > DZERO) then - v = -v - end if + end if + case ('INFILTRATION') + v = this%appliedinf(n) + case ('FROM-MVR') + if (this%imover == 1) then + v = this%pakmvrobj%get_qfrommvr(n) + end if + case ('REJ-INF') + v = this%rejinf(n) + if (v > DZERO) then + v = -v + end if + case ('REJ-INF-TO-MVR') + if (this%imover == 1) then + v = this%rejinftomvr(n) + if (v > DZERO) then + v = -v end if - case ('UZET') - if (this%ietflag /= 0) then - v = this%uzet(n) - if (v > DZERO) then - v = -v - end if + end if + case ('UZET') + if (this%ietflag /= 0) then + v = this%uzet(n) + if (v > DZERO) then + v = -v end if - case ('STORAGE') - v = -this%qsto(n) - case ('NET-INFILTRATION') - v = this%infiltration(n) - case ('WATER-CONTENT') - v = this%uzfobj%get_water_content_at_depth(n, obsrv%obsDepth) - case default - errmsg = 'Unrecognized observation type: ' // trim(obsrv%ObsTypeId) - call store_error(errmsg) + end if + case ('STORAGE') + v = -this%qsto(n) + case ('NET-INFILTRATION') + v = this%infiltration(n) + case ('WATER-CONTENT') + v = this%uzfobj%get_water_content_at_depth(n, obsrv%obsDepth) + case default + errmsg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId) + call store_error(errmsg) end select call this%obs%SaveOneSimval(obsrv, v) end do @@ -2477,7 +2487,7 @@ subroutine uzf_rp_obs(this) real(DP) :: obsdepth real(DP) :: dmax character(len=LENBOUNDNAME) :: bname - class(ObserveType), pointer :: obsrv => null() + class(ObserveType), pointer :: obsrv => null() ! -------------------------------------------------------------------------- ! -- formats 60 format('Invalid node number in OBS input: ', i0) @@ -2507,9 +2517,9 @@ subroutine uzf_rp_obs(this) ! -- Define intPak1 so that obs_theta is stored (for first uzf ! cell if multiple cells share the same boundname). obsrv%intPak1 = j - endif - endif - enddo + end if + end if + end do else ! ! -- get node number @@ -2523,7 +2533,7 @@ subroutine uzf_rp_obs(this) call store_error(errmsg) else obsrv%BndFound = .true. - endif + end if obsrv%CurrentTimeStepEndValue = DZERO call obsrv%AddObsIndex(nn) end if @@ -2533,9 +2543,9 @@ subroutine uzf_rp_obs(this) if (obsrv%ObsTypeId == 'WATER-CONTENT') then n = obsrv%indxbnds_count if (n /= 1) then - write (errmsg, '(a,3(1x,a))') & - trim(adjustl(obsrv%ObsTypeId)), 'for observation', & - trim(adjustl(obsrv%Name)), & + write (errmsg, '(a,3(1x,a))') & + trim(adjustl(obsrv%ObsTypeId)), 'for observation', & + trim(adjustl(obsrv%Name)), & 'must be assigned to a UZF cell with a unique boundname.' call store_error(errmsg, terminate=.TRUE.) end if @@ -2555,21 +2565,21 @@ subroutine uzf_rp_obs(this) ! -- need to think about a way to put bounds on this depth ! -- Also, an observation depth of 0.0, whether a landflag == 1 object ! -- or a subsurface object, is not legit since this would be at a - ! -- a layer interface and therefore a discontinuity. + ! -- a layer interface and therefore a discontinuity. if (obsdepth <= DZERO .or. obsdepth > dmax) then - write (errmsg, '(a,3(1x,a),1x,g0,1x,a,1x,g0,a)') & - trim(adjustl(obsrv%ObsTypeId)), 'for observation', & - trim(adjustl(obsrv%Name)), 'specified depth (', obsdepth, & + write (errmsg, '(a,3(1x,a),1x,g0,1x,a,1x,g0,a)') & + trim(adjustl(obsrv%ObsTypeId)), 'for observation', & + trim(adjustl(obsrv%Name)), 'specified depth (', obsdepth, & ') must be greater than 0.0 and less than ', dmax, '.' call store_error(errmsg) - endif + end if else do j = 1, obsrv%indxbnds_count - nn = obsrv%indxbnds(j) + nn = obsrv%indxbnds(j) if (nn < 1 .or. nn > this%maxbound) then - write (errmsg, '(a,2(1x,a),1x,i0,1x,a,1x,i0,a)') & - trim(adjustl(obsrv%ObsTypeId)), 'uzfno must be greater than 0 ', & - 'and less than or equal to', this%maxbound, & + write (errmsg, '(a,2(1x,a),1x,i0,1x,a,1x,i0,a)') & + trim(adjustl(obsrv%ObsTypeId)), 'uzfno must be greater than 0 ', & + 'and less than or equal to', this%maxbound, & '(specified value is ', nn, ').' call store_error(errmsg) end if @@ -2591,10 +2601,10 @@ subroutine uzf_process_obsID(obsrv, dis, inunitobs, iout) ! -- This procedure is pointed to by ObsDataType%ProcesssIdPtr. It processes ! the ID string of an observation definition for UZF-package observations. ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: n, nn real(DP) :: obsdepth @@ -2602,7 +2612,7 @@ subroutine uzf_process_obsID(obsrv, dis, inunitobs, iout) real(DP) :: r character(len=LINELENGTH) :: strng ! formats - 30 format(i10) +30 format(i10) ! strng = obsrv%IDstring ! -- Extract node number from strng and store it. @@ -2612,7 +2622,7 @@ subroutine uzf_process_obsID(obsrv, dis, inunitobs, iout) ! -- get node number call urword(strng, icol, istart, istop, 1, n, r, iout, inunitobs) read (strng(istart:istop), 30, iostat=istat) nn - if (istat==0) then + if (istat == 0) then ! -- store uzf node number (NodeNumber) obsrv%NodeNumber = nn else @@ -2624,15 +2634,15 @@ subroutine uzf_process_obsID(obsrv, dis, inunitobs, iout) ! so assign NodeNumber as a value that indicates observation ! is for a named boundary or group of boundaries. obsrv%NodeNumber = NAMEDBOUNDFLAG - endif + end if ! ! -- for soil water observation, store depth - if (obsrv%ObsTypeId=='WATER-CONTENT' ) then + if (obsrv%ObsTypeId == 'WATER-CONTENT') then call urword(strng, icol, istart, istop, 3, n, r, iout, inunitobs) obsdepth = r ! -- store observations depth obsrv%Obsdepth = obsdepth - endif + end if ! return end subroutine uzf_process_obsID @@ -2722,24 +2732,24 @@ subroutine uzf_da(this) ! ! -- deallocate uzf objects call this%uzfobj%dealloc() - deallocate(this%uzfobj) - nullify(this%uzfobj) + deallocate (this%uzfobj) + nullify (this%uzfobj) call this%uzfobjwork%dealloc() call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- character arrays - deallocate(this%bdtxt) - deallocate(this%cauxcbc) - deallocate(this%uzfname) + deallocate (this%bdtxt) + deallocate (this%cauxcbc) + deallocate (this%uzfname) ! ! -- package csv table if (this%ipakcsv > 0) then call this%pakcsvtab%table_da() - deallocate(this%pakcsvtab) - nullify(this%pakcsvtab) + deallocate (this%pakcsvtab) + nullify (this%pakcsvtab) end if ! ! -- deallocate scalars @@ -2813,7 +2823,7 @@ end subroutine uzf_da subroutine uzf_setup_budobj(this) ! ****************************************************************************** ! uzf_setup_budobj -- Set up the budget object that stores all the uzf flows -! The terms listed here must correspond in number and order to the ones +! The terms listed here must correspond in number and order to the ones ! listed in the uzf_fill_budobj routine. ! ****************************************************************************** ! @@ -2844,7 +2854,7 @@ subroutine uzf_setup_budobj(this) end if end do ! - ! -- Determine the number of uzf budget terms. These are fixed for + ! -- Determine the number of uzf budget terms. These are fixed for ! the simulation and cannot change. This includes FLOW-JA-FACE ! so they can be written to the binary budget files, but these internal ! flows are not included as part of the budget table. @@ -2889,10 +2899,10 @@ subroutine uzf_setup_budobj(this) end do end if ! - ! -- + ! -- text = ' GWF' idx = idx + 1 - maxlist = this%nodes + maxlist = this%nodes naux = 1 auxtxt(1) = ' FLOW-AREA' call this%budobj%budterm(idx)%initialize(text, & @@ -2909,7 +2919,7 @@ subroutine uzf_setup_budobj(this) call this%budobj%budterm(idx)%update_term(n, n2, q) end do ! - ! -- + ! -- text = ' INFILTRATION' idx = idx + 1 maxlist = this%nodes @@ -2922,7 +2932,7 @@ subroutine uzf_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' REJ-INF' idx = idx + 1 maxlist = this%nodes @@ -2935,7 +2945,7 @@ subroutine uzf_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' UZET' if (this%ietflag /= 0) then idx = idx + 1 @@ -2950,7 +2960,7 @@ subroutine uzf_setup_budobj(this) naux) end if ! - ! -- + ! -- text = ' STORAGE' idx = idx + 1 maxlist = this%nodes @@ -2964,10 +2974,10 @@ subroutine uzf_setup_budobj(this) maxlist, .false., .false., & naux, auxtxt) ! - ! -- + ! -- if (this%imover == 1) then ! - ! -- + ! -- text = ' FROM-MVR' idx = idx + 1 maxlist = this%nodes @@ -2980,7 +2990,7 @@ subroutine uzf_setup_budobj(this) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' REJ-INF-TO-MVR' idx = idx + 1 maxlist = this%nodes @@ -2994,11 +3004,11 @@ subroutine uzf_setup_budobj(this) naux) end if ! - ! -- + ! -- naux = this%naux if (naux > 0) then ! - ! -- + ! -- text = ' AUXILIARY' idx = idx + 1 maxlist = this%maxbound @@ -3018,7 +3028,7 @@ subroutine uzf_setup_budobj(this) ! ! -- return return - + end subroutine uzf_setup_budobj subroutine uzf_fill_budobj(this) @@ -3054,7 +3064,7 @@ subroutine uzf_fill_budobj(this) nlen = 0 do n = 1, this%nodes ivertflag = this%uzfobj%ivertcon(n) - if ( ivertflag > 0 ) then + if (ivertflag > 0) then nlen = nlen + 1 end if end do @@ -3160,7 +3170,7 @@ subroutine uzf_fill_budobj(this) end if call this%budobj%budterm(idx)%update_term(n, n, q) end do - + end if ! ! -- AUXILIARY VARIABLES diff --git a/src/Model/GroundWaterFlow/gwf3vsc8.f90 b/src/Model/GroundWaterFlow/gwf3vsc8.f90 new file mode 100644 index 00000000000..e5f3a6fbf20 --- /dev/null +++ b/src/Model/GroundWaterFlow/gwf3vsc8.f90 @@ -0,0 +1,1546 @@ +! Viscosity Package for representing variable-viscosity groundwater flow + +module GwfVscModule + + use KindModule, only: DP, I4B + use SimModule, only: store_error, store_warning, count_errors + use MemoryManagerModule, only: mem_allocate, mem_reallocate, & + mem_deallocate, mem_setptr + use MemoryHelperModule, only: create_mem_path + use ConstantsModule, only: DHALF, DZERO, DONE, LENMODELNAME, LENAUXNAME, & + DHNOFLO, MAXCHARLEN, LINELENGTH, LENMEMPATH + use TdisModule, only: kper, kstp + use NumericalPackageModule, only: NumericalPackageType + use BaseDisModule, only: DisBaseType + use GwfVscInputDataModule, only: GwfVscInputDataType + use ListsModule, only: basemodellist + + implicit none + + private + public :: GwfVscType + public :: vsc_cr + + type :: ConcentrationPointer + real(DP), dimension(:), pointer :: conc => null() !< pointer to concentration array + integer(I4B), dimension(:), pointer :: icbund => null() !< store pointer to gwt ibound array + end type ConcentrationPointer + + type, extends(NumericalPackageType) :: GwfVscType + integer(I4B), pointer :: thermivisc => null() !< viscosity formulation flag (1:Linear, 2:Nonlinear) + integer(I4B), pointer :: idxtmpr => null() !< if greater than 0 then an index for identifying whether the "species" array is temperature + integer(I4B), pointer :: ioutvisc => null() !< unit number for saving viscosity + integer(I4B), pointer :: iconcset => null() !< if 1 then conc points to a gwt (or gwe) model%x array + integer(I4B), pointer :: ireadelev => null() !< if 1 then elev has been allocated and filled + integer(I4B), dimension(:), pointer, contiguous :: ivisc => null() !< viscosity formulation flag for each species (1:Linear, 2:Nonlinear) + real(DP), pointer :: viscref => null() !< reference fluid viscosity + real(DP), dimension(:), pointer, contiguous :: visc => null() !< viscosity + real(DP), dimension(:), pointer, contiguous :: elev => null() !< cell center elevation (optional; if not specified, then use (top+bot)/2) + integer(I4B), dimension(:), pointer :: ibound => null() !< store pointer to ibound + + integer(I4B), pointer :: nviscspecies => null() !< number of concentration species used in viscosity equation + real(DP), dimension(:), pointer, contiguous :: dviscdc => null() !< linear change in viscosity with change in concentration + real(DP), dimension(:), pointer, contiguous :: cviscref => null() !< reference concentration used in viscosity equation + real(DP), dimension(:), pointer, contiguous :: ctemp => null() !< temporary array of size (nviscspec) to pass to calc_visc_x + character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< names of gwt (or gwe) models used in viscosity equation + character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname !< names of aux columns used in viscosity equation + character(len=LENAUXNAME) :: name_temp_spec = 'TEMPERATURE' + ! + ! -- Viscosity constants + real(DP), pointer :: a2 => null() !< an empirical parameter specified by the user for calculating viscosity + real(DP), pointer :: a3 => null() !< an empirical parameter specified by the user for calculating viscosity + real(DP), pointer :: a4 => null() !< an empirical parameter specified by the user for calculating viscosity + + type(ConcentrationPointer), allocatable, dimension(:) :: modelconc !< concentration (or temperature) pointer for each solute (or heat) transport model + + real(DP), dimension(:), pointer, contiguous :: k11 => null() !< NPF hydraulic conductivity; if anisotropic, then this is Kx prior to rotation + real(DP), dimension(:), pointer, contiguous :: k22 => null() !< NPF hydraulic conductivity; if specified then this is Ky prior to rotation + real(DP), dimension(:), pointer, contiguous :: k33 => null() !< NPF hydraulic conductivity; if specified then this is Kz prior to rotation + real(DP), dimension(:), pointer, contiguous :: k11input => null() !< NPF hydraulic conductivity as originally specified by the user + real(DP), dimension(:), pointer, contiguous :: k22input => null() !< NPF hydraulic conductivity as originally specified by the user + real(DP), dimension(:), pointer, contiguous :: k33input => null() !< NPF hydraulic conductivity as originally specified by the user + integer(I4B), pointer :: kchangeper => null() ! last stress period in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), pointer :: kchangestp => null() ! last time step in which any node K (or K22, or K33) values were changed (0 if unchanged from start of simulation) + integer(I4B), dimension(:), pointer, contiguous :: nodekchange => null() ! grid array of flags indicating for each node whether its K (or K22, or K33) value changed (1) at (kchangeper, kchangestp) or not (0) + + contains + procedure :: vsc_df + procedure :: vsc_ar + procedure, public :: vsc_ar_bnd + procedure :: vsc_rp + procedure :: vsc_ad + procedure, public :: vsc_ad_bnd + procedure :: vsc_ot_dv + procedure :: vsc_da + procedure, private :: vsc_calcvisc + procedure :: allocate_scalars + procedure, private :: allocate_arrays + procedure, private :: read_options + procedure, private :: set_options + procedure, private :: read_dimensions + procedure, private :: read_packagedata + procedure, private :: set_packagedata + procedure, private :: set_npf_pointers + procedure, public :: update_k_with_vsc + procedure, private :: vsc_set_changed_at + procedure, public :: calc_q_visc + procedure, public :: get_visc_ratio + procedure :: set_concentration_pointer + end type GwfVscType + +contains + + function calc_visc(ivisc, viscref, dviscdc, cviscref, conc, & + a2, a3, a4) result(visc) +! ****************************************************************************** +! calc_visc -- generic function to calculate changes in fluid viscosity +! using a linear formulation +! ****************************************************************************** +! +! SPECIFICATIONS: +! ------------------------------------------------------------------------------ + + ! -- dummy + integer(I4B), dimension(:), intent(in) :: ivisc + real(DP), intent(in) :: viscref + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(in) :: conc + real(DP), intent(in) :: a2, a3, a4 + ! -- return + real(DP) :: visc + ! -- local + integer(I4B) :: nviscspec + integer(I4B) :: i + real(DP) :: mu_t + real(DP) :: expon +! ------------------------------------------------------------------------------ + ! + nviscspec = size(dviscdc) + visc = viscref + + do i = 1, nviscspec + if (ivisc(i) == 1) then + visc = visc + dviscdc(i) * (conc(i) - cviscref(i)) + else + expon = -1 * a3 * ((conc(i) - cviscref(i)) / & + ((conc(i) + a4) * (cviscref(i) + a4))) + mu_t = viscref * a2**expon + ! Order matters!! (This assumes we apply the temperature correction after + ! accounting for solute concentrations) + ! If a nonlinear correction is applied, then b/c it takes into account + ! viscref, need to subtract it in this case + ! At most, there will only ever be 1 nonlinear correction + visc = (visc - viscref) + mu_t + end if + ! end if + end do + ! + ! -- return + return + end function calc_visc + + !> @ brief Create a new package object + !! + !! Create a new VSC Package object. + !! + !< + subroutine vsc_cr(vscobj, name_model, inunit, iout) + ! -- dummy + type(GwfVscType), pointer :: vscobj + character(len=*), intent(in) :: name_model + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout +! ------------------------------------------------------------------------------ + ! + ! -- Create the object + allocate (vscobj) + ! + ! -- create name and memory path + call vscobj%set_names(1, name_model, 'VSC', 'VSC') + ! + ! -- Allocate scalars + call vscobj%allocate_scalars() + ! + ! -- Set variables + vscobj%inunit = inunit + vscobj%iout = iout + ! + ! -- Initialize block parser + call vscobj%parser%Initialize(vscobj%inunit, vscobj%iout) + ! + ! -- Return + return + end subroutine vsc_cr + + !> @ brief Define viscosity package options and dimensions + !! + !! Define viscosity package options and dimensions + !! + !< + subroutine vsc_df(this, dis, vsc_input) + ! -- modules + ! -- dummy + class(GwfVscType) :: this !< this viscosity package + class(DisBaseType), pointer, intent(in) :: dis !< pointer to discretization + type(GwfVscInputDataType), optional, intent(in) :: vsc_input !< optional vsc input data, otherwise read from file + ! -- local + ! -- formats + character(len=*), parameter :: fmtvsc = & + "(1x,/1x,'VSC -- Viscosity Package, version 1, 11/15/2022', & + &' input read from unit ', i0, //)" +! ------------------------------------------------------------------------------ + ! + ! --print a message identifying the viscosity package + write (this%iout, fmtvsc) this%inunit + ! + ! -- store pointers to arguments that were passed in + this%dis => dis + + if (.not. present(vsc_input)) then + ! + ! -- Read viscosity options + call this%read_options() + ! + ! -- Read viscosity dimensions + call this%read_dimensions() + else + ! set from input data instead + call this%set_options(vsc_input) + this%nviscspecies = vsc_input%nviscspecies + end if + ! + ! -- Allocate arrays + call this%allocate_arrays(dis%nodes) + + if (.not. present(vsc_input)) then + ! + ! -- Read viscosity packagedata + call this%read_packagedata() + else + ! set from input data instead + call this%set_packagedata(vsc_input) + end if + ! + ! -- Return + return + end subroutine vsc_df + + !> @ brief Allocate and read method for viscosity package + !! + !! Generic method to allocate and read static data for the viscosity + !! package available within the GWF model type. + !! + !< + subroutine vsc_ar(this, ibound) + ! -- modules + ! -- dummy + class(GwfVscType) :: this + integer(I4B), dimension(:), pointer :: ibound + ! -- local + ! -- formats +! ------------------------------------------------------------------------------ + ! + ! -- store pointers to arguments that were passed in + this%ibound => ibound + ! + ! -- Set pointers to npf variables + call this%set_npf_pointers() + ! + ! -- Return + return + end subroutine vsc_ar + + !> @brief Activate viscosity in advanced packages + !! + !! Viscosity ar_bnd rountine to activate viscosity in the advanced + !! packages. This routine is called from gwf_ar() as it moves through each + !! package + !! + !< + subroutine vsc_ar_bnd(this, packobj) + ! -- modules + use BndModule, only: BndType + use DrnModule, only: DrnType + use GhbModule, only: GhbType + use RivModule, only: RivType + use LakModule, only: LakType + use SfrModule, only: SfrType + use MawModule, only: MawType + ! -- dummy + class(GwfVscType) :: this + class(BndType), pointer :: packobj + ! -- local + ! ---------------------------------------------------------------------------- + ! + ! -- Add density terms based on boundary package type + select case (packobj%filtyp) + case ('DRN') + ! + ! -- activate viscosity for the drain package + select type (packobj) + type is (DrnType) + call packobj%bnd_activate_viscosity() + end select + case ('GHB') + ! + ! -- activate viscosity for the drain package + select type (packobj) + type is (GhbType) + call packobj%bnd_activate_viscosity() + end select + case ('RIV') + ! + ! -- activate viscosity for the drain package + select type (packobj) + type is (RivType) + call packobj%bnd_activate_viscosity() + end select + case ('LAK') + ! + ! -- activate viscosity for lake package + select type (packobj) + type is (LakType) + call packobj%lak_activate_viscosity() + end select + + case ('SFR') + ! + ! -- activate viscosity for sfr package + select type (packobj) + type is (SfrType) + call packobj%sfr_activate_viscosity() + end select + + case ('MAW') + ! + ! -- activate viscosity for maw package + select type (packobj) + type is (MawType) + call packobj%maw_activate_viscosity() + end select + + case default + ! + ! -- nothing + end select + ! + ! -- Return + return + end subroutine vsc_ar_bnd + + !> @brief Set pointers to NPF variables + !! + !! Set array and variable pointers from the NPF + !! package for access by VSC. + !! + !< + subroutine set_npf_pointers(this) + ! -- dummy variables + class(GwfVscType) :: this + ! -- local variables + character(len=LENMEMPATH) :: npfMemoryPath + ! + ! -- Set pointers to other package variables + ! -- NPF + npfMemoryPath = create_mem_path(this%name_model, 'NPF') + call mem_setptr(this%k11, 'K11', npfMemoryPath) + call mem_setptr(this%k22, 'K22', npfMemoryPath) + call mem_setptr(this%k33, 'K33', npfMemoryPath) + call mem_setptr(this%k11input, 'K11INPUT', npfMemoryPath) + call mem_setptr(this%k22input, 'K22INPUT', npfMemoryPath) + call mem_setptr(this%k33input, 'K33INPUT', npfMemoryPath) + call mem_setptr(this%kchangeper, 'KCHANGEPER', npfMemoryPath) + call mem_setptr(this%kchangestp, 'KCHANGESTP', npfMemoryPath) + call mem_setptr(this%nodekchange, 'NODEKCHANGE', npfMemoryPath) + ! + return + end subroutine set_npf_pointers + + !> @ brief Read new period data in viscosity package + !! + !! Method to read and prepare period data for the VSC package. + !! + !< + subroutine vsc_rp(this) + ! -- modules + use TdisModule, only: kstp, kper + ! -- dummy + class(GwfVscType) :: this + ! -- local + character(len=LINELENGTH) :: errmsg + integer(I4B) :: i + ! -- formats + character(len=*), parameter :: fmtc = & + "('Viscosity Package does not have a concentration set & + &for species ',i0,'. One or more model names may be specified & + &incorrectly in the PACKAGEDATA block or a GWF-GWT exchange may need & + &to be activated.')" +! ------------------------------------------------------------------------------ + ! + ! -- Check to make sure all concentration pointers have been set + if (kstp * kper == 1) then + do i = 1, this%nviscspecies + if (.not. associated(this%modelconc(i)%conc)) then + write (errmsg, fmtc) i + call store_error(errmsg) + end if + end do + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + end if + ! + ! -- return + return + end subroutine vsc_rp + + !> @ brief Advance the viscosity package + !! + !! Advance data in the VSC package. The method sets or + !! advances time series, time array series, and observation + !! data. + !! + !< + subroutine vsc_ad(this) + ! -- dummy + class(GwfVscType) :: this + ! -- local +! ------------------------------------------------------------------------------ + ! + ! -- update viscosity using the latest concentration/temperature + call this%vsc_calcvisc() + ! + ! -- Return + return + end subroutine vsc_ad + + !> @brief Advance the boundary packages when viscosity is active + !! + !! Update the conductance values associate with inflow from a boundary + !! when VSC package is active. + !< + subroutine vsc_ad_bnd(this, packobj, hnew) + ! -- modules + use BndModule, only: BndType + ! -- dummy + class(GwfVscType) :: this + class(BndType), pointer :: packobj + real(DP), intent(in), dimension(:) :: hnew + ! -- local + integer(I4B) :: i, j + integer(I4B) :: n, locvisc, locelev + integer(I4B), dimension(:), allocatable :: locconc + ! + ! -- initialize + locvisc = 0 + locelev = 0 + allocate (locconc(this%nviscspecies)) + locconc(:) = 0 + ! + ! -- Add viscosity terms for conductance-dependent boundaries + do n = 1, packobj%naux + if (packobj%auxname(n) == 'VISCOSITY') then + locvisc = n + else if (packobj%auxname(n) == 'ELEVATION') then + locelev = n + end if + end do + ! + ! -- find aux columns for conc (or temp.) that affect viscosity + do i = 1, this%nviscspecies + locconc(i) = 0 + do j = 1, packobj%naux + if (this%cauxspeciesname(i) == packobj%auxname(j)) then + locconc(i) = j + exit + end if + end do + if (locconc(i) == 0) then + ! -- one not found, so don't use and mark all as 0 + locconc(:) = 0 + exit + end if + end do + ! + ! -- apply viscosity terms to inflow from boundary based on package type + select case (packobj%filtyp) + case ('GHB', 'DRN', 'RIV') + ! + ! -- general head, drain, and river boundary + call vsc_ad_standard_bnd(packobj, hnew, this%visc, this%viscref, & + locelev, locvisc, locconc, this%dviscdc, & + this%cviscref, this%ivisc, this%a2, this%a3, & + this%a4, this%ctemp) + case ('LAK') + ! + ! -- lake + ! Update 'viscratios' internal to lak such that they are + ! automatically applied in the LAK calc_cond() routine + call vsc_ad_lak(packobj, this%visc, this%viscref, this%elev, locvisc, & + locconc, this%dviscdc, this%cviscref, this%ivisc, & + this%a2, this%a3, this%a4, this%ctemp) + case ('SFR') + ! + ! -- streamflow routing + ! Update 'viscratios' internal to sfr such that they are + ! automatically applied in the SFR calc_cond() routine + call vsc_ad_sfr(packobj, this%visc, this%viscref, this%elev, locvisc, & + locconc, this%dviscdc, this%cviscref, this%ivisc, & + this%a2, this%a3, this%a4, this%ctemp) + case ('MAW') + ! + ! -- multi-aquifer well + call vsc_ad_maw(packobj, this%visc, this%viscref, this%elev, locvisc, & + locconc, this%dviscdc, this%cviscref, this%ivisc, & + this%a2, this%a3, this%a4, this%ctemp) + case ('UZF') + ! + ! -- unsaturated-zone flow + case default + ! + ! -- nothing + end select + ! + ! -- deallocate + deallocate (locconc) + ! + ! -- Return + return + end subroutine vsc_ad_bnd + + !> @brief advance ghb while accounting for viscosity + !! + !! When flow enters from ghb boundary type, take into account the effects + !! of viscosity on the user-specified conductance terms + !< + subroutine vsc_ad_standard_bnd(packobj, hnew, visc, viscref, locelev, & + locvisc, locconc, dviscdc, cviscref, & + ivisc, a2, a3, a4, ctemp) + ! -- modules + use BndModule, only: BndType + class(BndType), pointer :: packobj + ! -- dummy + real(DP), intent(in), dimension(:) :: hnew + real(DP), intent(in), dimension(:) :: visc + real(DP), intent(in) :: a2, a3, a4 + real(DP), intent(in) :: viscref + integer(I4B), intent(in) :: locelev + integer(I4B), intent(in) :: locvisc + integer(I4B), dimension(:), intent(in) :: locconc + integer(I4B), dimension(:), intent(in) :: ivisc + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(inout) :: ctemp + ! -- local + integer(I4B) :: n + integer(I4B) :: node + real(DP) :: viscbnd +! ------------------------------------------------------------------------------- + ! + ! -- Process density terms for each GHB + do n = 1, packobj%nbound + node = packobj%nodelist(n) + ! + ! -- Check if boundary cell is active, cycle if not + if (packobj%ibound(node) <= 0) cycle + ! + ! -- calculate the viscosity associcated with the boundary + viscbnd = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, & + cviscref, ctemp, ivisc, a2, a3, a4, & + packobj%auxvar) + ! + ! -- update boundary conductance based on viscosity effects + packobj%bound(2, n) = update_bnd_cond(viscbnd, viscref, & + packobj%condinput(n)) + ! + end do + ! + ! -- Return + return + end subroutine vsc_ad_standard_bnd + + !> @brief Update sfr-related viscosity ratios + !! + !! When the viscosity package is active, update the viscosity ratio that is + !! applied to the hydraulic conductivity specified in the SFR package + !< + subroutine vsc_ad_sfr(packobj, visc, viscref, elev, locvisc, locconc, & + dviscdc, cviscref, ivisc, a2, a3, a4, ctemp) + ! -- modules + use BndModule, only: BndType + use SfrModule, only: SfrType + class(BndType), pointer :: packobj + ! -- dummy + real(DP), intent(in) :: viscref + real(DP), intent(in) :: a2, a3, a4 + integer(I4B), intent(in) :: locvisc + integer(I4B), dimension(:), intent(in) :: locconc + integer(I4B), dimension(:), intent(in) :: ivisc + real(DP), dimension(:), intent(in) :: visc + real(DP), dimension(:), intent(in) :: elev + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(inout) :: ctemp + ! -- local + integer(I4B) :: n + integer(I4B) :: node + real(DP) :: viscsfr +! ------------------------------------------------------------------------------- + ! + ! -- update viscosity ratios for updating hyd. cond (and conductance) + select type (packobj) + type is (SfrType) + do n = 1, packobj%nbound + ! + ! -- get gwf node number + node = packobj%nodelist(n) + ! + ! -- Check if boundary cell is active, cycle if not + if (packobj%ibound(node) <= 0) cycle + ! + ! -- + ! + ! -- calculate the viscosity associcated with the boundary + viscsfr = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, & + cviscref, ctemp, ivisc, a2, a3, a4, & + packobj%auxvar) + ! + ! -- fill sfr relative viscosity into column 1 of viscratios + packobj%viscratios(1, n) = calc_vsc_ratio(viscref, viscsfr) + ! + ! -- fill gwf relative viscosity into column 2 of viscratios + packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node)) + end do + end select + ! + ! -- Return + return + end subroutine vsc_ad_sfr + + !> @brief Update lak-related viscosity ratios + !! + !! When the viscosity package is active, update the viscosity ratio that is + !! applied to the lakebed conductance calculated in the LAK package + !< + subroutine vsc_ad_lak(packobj, visc, viscref, elev, locvisc, locconc, & + dviscdc, cviscref, ivisc, a2, a3, a4, ctemp) + ! -- modules + use BndModule, only: BndType + use LakModule, only: LakType + class(BndType), pointer :: packobj + ! -- dummy + real(DP), intent(in) :: viscref + real(DP), intent(in) :: a2, a3, a4 + integer(I4B), intent(in) :: locvisc + integer(I4B), dimension(:), intent(in) :: locconc + integer(I4B), dimension(:), intent(in) :: ivisc + real(DP), dimension(:), intent(in) :: visc + real(DP), dimension(:), intent(in) :: elev + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(inout) :: ctemp + ! -- local + integer(I4B) :: n + integer(I4B) :: node + real(DP) :: visclak +! ------------------------------------------------------------------------------- + ! + ! -- update viscosity ratios for updating hyd. cond (and conductance) + select type (packobj) + type is (LakType) + do n = 1, packobj%nbound + ! + ! -- get gwf node number + node = packobj%nodelist(n) + ! + ! -- Check if boundary cell is active, cycle if not + if (packobj%ibound(node) <= 0) cycle + ! + ! -- + ! + ! -- calculate the viscosity associcated with the boundary + visclak = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, & + cviscref, ctemp, ivisc, a2, a3, a4, & + packobj%auxvar) + ! + ! -- fill lak relative viscosity into column 1 of viscratios + packobj%viscratios(1, n) = calc_vsc_ratio(viscref, visclak) + ! + ! -- fill gwf relative viscosity into column 2 of viscratios + packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node)) + end do + end select + ! + ! -- Return + return + end subroutine vsc_ad_lak + + !> @brief Update maw-related viscosity ratios + !! + !! When the viscosity package is active, update the viscosity ratio that is + !! applied to the conductance calculated in the MAW package + !< + subroutine vsc_ad_maw(packobj, visc, viscref, elev, locvisc, locconc, & + dviscdc, cviscref, ivisc, a2, a3, a4, ctemp) + ! -- modules + use BndModule, only: BndType + use MawModule, only: MawType + class(BndType), pointer :: packobj + ! -- dummy + real(DP), intent(in) :: viscref + real(DP), intent(in) :: a2, a3, a4 + integer(I4B), intent(in) :: locvisc + integer(I4B), dimension(:), intent(in) :: locconc + integer(I4B), dimension(:), intent(in) :: ivisc + real(DP), dimension(:), intent(in) :: visc + real(DP), dimension(:), intent(in) :: elev + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(inout) :: ctemp + ! -- local + integer(I4B) :: n + integer(I4B) :: node + real(DP) :: viscmaw +! ------------------------------------------------------------------------------- + ! + ! -- update viscosity ratios for updating hyd. cond (and conductance) + select type (packobj) + type is (MawType) + do n = 1, packobj%nbound + ! + ! -- get gwf node number + node = packobj%nodelist(n) + ! + ! -- Check if boundary cell is active, cycle if not + if (packobj%ibound(node) <= 0) cycle + ! + ! -- + ! + ! -- calculate the viscosity associcated with the boundary + viscmaw = calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, & + cviscref, ctemp, ivisc, a2, a3, a4, & + packobj%auxvar) + ! + ! -- fill lak relative viscosity into column 1 of viscratios + packobj%viscratios(1, n) = calc_vsc_ratio(viscref, viscmaw) + ! + ! -- fill gwf relative viscosity into column 2 of viscratios + packobj%viscratios(2, n) = calc_vsc_ratio(viscref, visc(node)) + end do + end select + ! + ! -- Return + return + end subroutine vsc_ad_maw + + !> @brief Apply viscosity to the conductance term + !! + !! When the viscosity package is active apply the viscosity ratio to the + !! active boundary package's conductance term. + !< + function update_bnd_cond(bndvisc, viscref, spcfdcond) result(updatedcond) + ! -- modules + ! -- dummy + real(DP), intent(in) :: viscref + real(DP), intent(in) :: bndvisc + real(DP), intent(in) :: spcfdcond + ! -- local + real(DP) :: vscratio + real(DP) :: updatedcond +! ------------------------------------------------------------------------------- + ! + vscratio = calc_vsc_ratio(viscref, bndvisc) + ! + ! -- calculate new conductance here + updatedcond = vscratio * spcfdcond + ! + ! -- Return + return + end function update_bnd_cond + + !> @brief calculate and return the viscosity ratio + !< + function calc_vsc_ratio(viscref, bndvisc) result(viscratio) + ! -- dummy + real(DP), intent(in) :: viscref + real(DP), intent(in) :: bndvisc + ! -- local + real(DP) :: viscratio +! ------------------------------------------------------------------------------- + ! + viscratio = viscref / bndvisc + ! + ! -- Return + return + end function calc_vsc_ratio + + !> @ brief Calculate the boundary viscosity + !! + !! Return the viscosity of the boundary package using one of + !! the options in the following order of priority: + !! 1. Assign as aux variable in column with name 'VISCOSITY' + !! 2. Calculate using viscosity equation and nviscspecies aux columns + !! 3. If neither of those, then assign as viscref !! + !< + function calc_bnd_viscosity(n, locvisc, locconc, viscref, dviscdc, cviscref, & + ctemp, ivisc, a2, a3, a4, auxvar) result(viscbnd) + ! -- modules + ! -- dummy + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: locvisc + real(DP), intent(in) :: a2, a3, a4 + integer(I4B), dimension(:), intent(in) :: ivisc + integer(I4B), dimension(:), intent(in) :: locconc + real(DP), intent(in) :: viscref + real(DP), dimension(:), intent(in) :: dviscdc + real(DP), dimension(:), intent(in) :: cviscref + real(DP), dimension(:), intent(inout) :: ctemp + real(DP), dimension(:, :), intent(in) :: auxvar + ! -- return + real(DP) :: viscbnd + ! -- local + integer(I4B) :: i +! ------------------------------------------------------------------------------ + ! + ! -- assign boundary viscosity based on one of three options + if (locvisc > 0) then + ! -- assign viscosity to an aux column named 'VISCOSITY' + viscbnd = auxvar(locvisc, n) + else if (locconc(1) > 0) then + ! -- calculate viscosity using one or more concentration auxcolumns + do i = 1, size(locconc) + ctemp(i) = DZERO + if (locconc(i) > 0) then + ctemp(i) = auxvar(locconc(i), n) + end if + end do + viscbnd = calc_visc(ivisc, viscref, dviscdc, cviscref, ctemp, a2, a3, a4) + else + ! -- neither of the above, so assign as viscref + viscbnd = viscref + end if + ! + ! -- return + return + end function calc_bnd_viscosity + + !> @brief Calculate the viscosity ratio + !! + !! Calculate the viscosity ratio applied to the hydraulic characteristic + !! provided by the user. The viscosity ratio is applicable only + !! when the hydraulic characteristic is specified as positive and will not + !! be applied when the hydchr is negative + !< + subroutine get_visc_ratio(this, n, m, gwhdn, gwhdm, viscratio) + ! -- modules + use ConstantsModule, only: DONE + ! -- dummy + class(GwfVscType) :: this + integer(I4B), intent(in) :: n, m + real(DP), intent(in) :: gwhdn, gwhdm + real(DP), intent(inout) :: viscratio + ! -- loca + integer(I4B) :: cellid +! ------------------------------------------------------------------------------ +! + viscratio = DONE + if (gwhdm > gwhdn) then + cellid = m + else if (gwhdn >= gwhdm) then + cellid = n + end if + call this%calc_q_visc(cellid, viscratio) + ! + ! -- return + return + end subroutine get_visc_ratio + + !> @brief Account for viscosity in the aquiferhorizontal flow barriers + !! + !! Will return the viscosity associated with the upgradient node (cell) + !! to the HFB package for adjusting the hydraulic characteristic (hydchr) + !! of the barrier + !< + subroutine calc_q_visc(this, cellid, viscratio) + ! -- dummy variables + class(GwfVscType) :: this + integer(I4B), intent(in) :: cellid + ! -- return + real(DP), intent(inout) :: viscratio + ! -- local + real(DP) :: visc +! ------------------------------------------------------------------------------ + ! + ! -- Retrieve viscosity for the passed node number + visc = this%visc(cellid) + ! + ! -- Calculate the viscosity ratio for the + viscratio = calc_vsc_ratio(this%viscref, visc) + ! + ! -- return + return + end subroutine calc_q_visc + + !> @brief Appled the viscosity ratio (mu_o/mu) to the hydraulic conductivity + !! + !! This routine called after updating the viscosity values using the latest + !! concentration and/or temperature values. The ratio mu_o/mu, reference + !! viscosity divided by the updated viscosity value, is multiplied by K + !! for each cell. + !< + subroutine update_k_with_vsc(this) + ! -- modules + ! -- dummy + class(GwfVscType) :: this + ! -- local + integer(I4B) :: n + real(DP) :: viscratio +! ------------------------------------------------------------------------------ + ! + ! -- For viscosity-based K's, apply change of K to K11 by starting with + ! user-specified K values and not the K's leftover from the last viscosity + ! update. + do n = 1, this%dis%nodes + call this%calc_q_visc(n, viscratio) + this%k11(n) = this%k11input(n) * viscratio + this%k22(n) = this%k22input(n) * viscratio + this%k33(n) = this%k33input(n) * viscratio + this%nodekchange(n) = 1 + end do + ! + ! -- Flag kchange + call this%vsc_set_changed_at(kper, kstp) + ! + ! -- return + return + end subroutine update_k_with_vsc + + !> @brief Mark K changes as having occurred at (kper, kstp) + !! + !! Procedure called by VSC code when K updated due to viscosity changes. + !! K values changed at (kper, kstp). + !! + !< + subroutine vsc_set_changed_at(this, kper, kstp) + ! -- dummy variables + class(GwfVscType) :: this + integer(I4B), intent(in) :: kper + integer(I4B), intent(in) :: kstp + ! + this%kchangeper = kper + this%kchangestp = kstp + ! + return + end subroutine vsc_set_changed_at + + !> @ brief Output viscosity package dependent-variable terms. + !! + !! Save calculated viscosity array to binary file + !! + !< + subroutine vsc_ot_dv(this, idvfl) + ! -- dummy + class(GwfVscType) :: this + integer(I4B), intent(in) :: idvfl + ! -- local + character(len=1) :: cdatafmp = ' ', editdesc = ' ' + integer(I4B) :: ibinun + integer(I4B) :: iprint + integer(I4B) :: nvaluesp + integer(I4B) :: nwidthp + real(DP) :: dinact +! ------------------------------------------------------------------------------ + ! + ! -- Set unit number for viscosity output + if (this%ioutvisc /= 0) then + ibinun = 1 + else + ibinun = 0 + end if + if (idvfl == 0) ibinun = 0 + ! + ! -- save viscosity array + if (ibinun /= 0) then + iprint = 0 + dinact = DHNOFLO + ! + ! -- write viscosity to binary file + if (this%ioutvisc /= 0) then + ibinun = this%ioutvisc + call this%dis%record_array(this%visc, this%iout, iprint, ibinun, & + ' VISCOSITY', cdatafmp, nvaluesp, & + nwidthp, editdesc, dinact) + end if + end if + ! + ! -- Return + return + end subroutine vsc_ot_dv + + !> @ brief Deallocate viscosity package memory + !! + !! Deallocate viscosity package scalars and arrays. + !! + !< + subroutine vsc_da(this) + ! -- modules + ! -- dummy + class(GwfVscType) :: this +! ------------------------------------------------------------------------------ + ! + ! -- Deallocate arrays if package was active + if (this%inunit > 0) then + call mem_deallocate(this%visc) + call mem_deallocate(this%ivisc) + call mem_deallocate(this%dviscdc) + call mem_deallocate(this%cviscref) + call mem_deallocate(this%ctemp) + deallocate (this%cmodelname) + deallocate (this%cauxspeciesname) + deallocate (this%modelconc) + end if + ! + ! -- Scalars + call mem_deallocate(this%thermivisc) + call mem_deallocate(this%idxtmpr) + call mem_deallocate(this%ioutvisc) + call mem_deallocate(this%ireadelev) + call mem_deallocate(this%iconcset) + call mem_deallocate(this%viscref) + call mem_deallocate(this%nviscspecies) + call mem_deallocate(this%a2) + call mem_deallocate(this%a3) + call mem_deallocate(this%a4) + ! + ! -- Nullify pointers to other package variables + nullify (this%k11) + nullify (this%k22) + nullify (this%k33) + nullify (this%k11input) + nullify (this%k22input) + nullify (this%k33input) + nullify (this%kchangeper) + nullify (this%kchangestp) + nullify (this%nodekchange) + ! + ! -- deallocate parent + call this%NumericalPackageType%da() + ! + ! -- Return + return + end subroutine vsc_da + + !> @ brief Read dimensions + !! + !! Read dimensions for the viscosity package + !! + !< + subroutine read_dimensions(this) + ! -- modules + ! -- dummy + class(GwfVscType), intent(inout) :: this + ! -- local + character(len=LINELENGTH) :: errmsg, keyword + integer(I4B) :: ierr + logical :: isfound, endOfBlock + ! -- format +! ------------------------------------------------------------------------------ + ! + ! -- get dimensions block + call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & + supportOpenClose=.true.) + ! + ! -- parse dimensions block if detected + if (isfound) then + write (this%iout, '(/1x,a)') 'Processing VSC DIMENSIONS block' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('NVISCSPECIES') + this%nviscspecies = this%parser%GetInteger() + write (this%iout, '(4x,a,i0)') 'NVISCSPECIES = ', this%nviscspecies + case default + write (errmsg, '(4x,a,a)') & + 'unknown VSC dimension: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end select + end do + write (this%iout, '(1x,a)') 'End of VSC DIMENSIONS block' + else + call store_error('Required VSC DIMENSIONS block not found.') + call this%parser%StoreErrorUnit() + end if + ! + ! -- check dimension + if (this%nviscspecies < 1) then + call store_error('NVISCSPECIES must be greater than zero.') + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine read_dimensions + + !> @ brief Read data for package + !! + !! Method to read data for the viscosity package. + !! + !< + subroutine read_packagedata(this) + ! -- modules + ! -- dummy + class(GwfVscType) :: this + ! -- local + character(len=LINELENGTH) :: errmsg + character(len=LINELENGTH) :: line + integer(I4B) :: ierr + integer(I4B) :: iviscspec + logical :: isfound, endOfBlock + logical :: blockrequired + integer(I4B), dimension(:), allocatable :: itemp + character(len=10) :: c10 + character(len=16) :: c16 + ! -- format + character(len=*), parameter :: fmterr = & + "('Invalid value for IRHOSPEC (',i0,') detected in VSC Package. & + &IRHOSPEC must be > 0 and <= NVISCSPECIES, and duplicate values & + &are not allowed.')" +! ------------------------------------------------------------------------------ + ! + ! -- initialize + allocate (itemp(this%nviscspecies)) + itemp(:) = 0 + ! + ! -- get packagedata block + blockrequired = .true. + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + blockRequired=blockRequired, & + supportOpenClose=.true.) + ! + ! -- parse packagedata block + if (isfound) then + write (this%iout, '(1x,a)') 'Procesing VSC PACKAGEDATA block' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + iviscspec = this%parser%GetInteger() + if (iviscspec < 1 .or. iviscspec > this%nviscspecies) then + write (errmsg, fmterr) iviscspec + call store_error(errmsg) + end if + if (itemp(iviscspec) /= 0) then + write (errmsg, fmterr) iviscspec + call store_error(errmsg) + end if + itemp(iviscspec) = 1 + ! + this%dviscdc(iviscspec) = this%parser%GetDouble() + this%cviscref(iviscspec) = this%parser%GetDouble() + call this%parser%GetStringCaps(this%cmodelname(iviscspec)) + call this%parser%GetStringCaps(this%cauxspeciesname(iviscspec)) + ! + if (this%cauxspeciesname(iviscspec) == this%name_temp_spec) then + if (this%idxtmpr > 0) then + write (errmsg, '(a)') 'More than one species in VSC input identified & + &as '//trim(this%name_temp_spec)//'. Only one species may be & + &designated to represent temperature.' + call store_error(errmsg) + else + this%idxtmpr = iviscspec + if (this%thermivisc == 2) then + this%ivisc(iviscspec) = 2 + end if + end if + end if + end do + else + call store_error('Required VSC PACKAGEDATA block not found.') + call this%parser%StoreErrorUnit() + end if + ! + ! -- Check for errors. + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- write packagedata information + write (this%iout, '(/,1x,a)') 'Summary of species information in VSC Package' + write (this%iout, '(1a11,5a17)') & + 'Species', 'DVISCDC', 'CVISCREF', 'Model', 'AUXSPECIESNAME' + do iviscspec = 1, this%nviscspecies + write (c10, '(i0)') iviscspec + line = ' '//adjustr(c10) + + write (c16, '(g15.6)') this%dviscdc(iviscspec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(g15.6)') this%cviscref(iviscspec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(a)') this%cmodelname(iviscspec) + line = trim(line)//' '//adjustr(c16) + write (c16, '(a)') this%cauxspeciesname(iviscspec) + line = trim(line)//' '//adjustr(c16) + write (this%iout, '(a)') trim(line) + end do + ! + ! -- deallocate + deallocate (itemp) + ! + write (this%iout, '(/,1x,a)') 'End of VSC PACKAGEDATA block' + ! + ! -- return + return + end subroutine read_packagedata + + !> @brief Sets package data instead of reading from file + !< + subroutine set_packagedata(this, input_data) + class(GwfVscType) :: this !< this vscoancy pkg + type(GwfVscInputDataType), intent(in) :: input_data !< the input data to be set + ! local + integer(I4B) :: ispec + + do ispec = 1, this%nviscspecies + this%dviscdc(ispec) = input_data%dviscdc(ispec) + this%cviscref(ispec) = input_data%cviscref(ispec) + this%cmodelname(ispec) = input_data%cmodelname(ispec) + this%cauxspeciesname(ispec) = input_data%cauxspeciesname(ispec) + end do + + end subroutine set_packagedata + + !> @brief Calculate fluid viscosity + !! + !! Calculates fluid viscosity based on concentration or + !! temperature + !! + !< + subroutine vsc_calcvisc(this) + ! -- dummy + class(GwfVscType) :: this + + ! -- local + integer(I4B) :: n + integer(I4B) :: i +! ------------------------------------------------------------------------------ + ! + ! -- Calculate the viscosity using the specified concentration and/or + ! temperature arrays + do n = 1, this%dis%nodes + do i = 1, this%nviscspecies + if (this%modelconc(i)%icbund(n) == 0) then + this%ctemp = DZERO + else + this%ctemp(i) = this%modelconc(i)%conc(n) + end if + end do + ! + this%visc(n) = calc_visc(this%ivisc, this%viscref, this%dviscdc, & + this%cviscref, this%ctemp, this%a2, & + this%a3, this%a4) + end do + ! + ! -- Return + return + end subroutine vsc_calcvisc + + !> @ brief Allocate scalars + !! + !! Allocate and initialize scalars for the VSC package. The base model + !! allocate scalars method is also called. + !! + !< + subroutine allocate_scalars(this) +! ****************************************************************************** +! allocate_scalars +! ****************************************************************************** +! +! SPECIFICATIONS: +! ------------------------------------------------------------------------------ + ! -- modules + use ConstantsModule, only: DZERO, DTEN, DEP3 + ! -- dummy + class(GwfVscType) :: this + ! -- local +! ------------------------------------------------------------------------------ + ! + ! -- allocate scalars in NumericalPackageType + call this%NumericalPackageType%allocate_scalars() + ! + ! -- Allocate + call mem_allocate(this%thermivisc, 'THERMIVISC', this%memoryPath) + call mem_allocate(this%idxtmpr, 'IDXTMPR', this%memoryPath) + call mem_allocate(this%ioutvisc, 'IOUTVISC', this%memoryPath) + call mem_allocate(this%ireadelev, 'IREADELEV', this%memoryPath) + call mem_allocate(this%iconcset, 'ICONCSET', this%memoryPath) + call mem_allocate(this%viscref, 'VISCREF', this%memoryPath) + call mem_allocate(this%a2, 'A2', this%memoryPath) + call mem_allocate(this%a3, 'A3', this%memoryPath) + call mem_allocate(this%a4, 'A4', this%memoryPath) + ! + call mem_allocate(this%nviscspecies, 'NVISCSPECIES', this%memoryPath) + ! + ! -- Initialize + this%thermivisc = 0 + this%idxtmpr = 0 + this%ioutvisc = 0 + this%ireadelev = 0 + this%iconcset = 0 + this%viscref = DEP3 + this%A2 = DTEN + this%A3 = 248.37_DP + this%A4 = 133.15_DP + ! + this%nviscspecies = 0 + ! + ! -- Return + return + end subroutine allocate_scalars + + !> @ brief Allocate arrays + !! + !! Allocate and initialize arrays for the VSC package. + !! + !< + subroutine allocate_arrays(this, nodes) + ! -- modules + ! -- dummy + class(GwfVscType) :: this + integer(I4B), intent(in) :: nodes + ! -- local + integer(I4B) :: i +! ------------------------------------------------------------------------------ + ! + ! -- Allocate + call mem_allocate(this%visc, nodes, 'VISC', this%memoryPath) + call mem_allocate(this%ivisc, this%nviscspecies, 'IVISC', this%memoryPath) + call mem_allocate(this%dviscdc, this%nviscspecies, 'DRHODC', & + this%memoryPath) + call mem_allocate(this%cviscref, this%nviscspecies, 'CRHOREF', & + this%memoryPath) + call mem_allocate(this%ctemp, this%nviscspecies, 'CTEMP', this%memoryPath) + allocate (this%cmodelname(this%nviscspecies)) + allocate (this%cauxspeciesname(this%nviscspecies)) + allocate (this%modelconc(this%nviscspecies)) + ! + ! -- Initialize + do i = 1, nodes + this%visc(i) = this%viscref + end do + ! + ! -- Initialize nviscspecies arrays + do i = 1, this%nviscspecies + this%ivisc(i) = 1 + this%dviscdc(i) = DZERO + this%cviscref(i) = DZERO + this%ctemp(i) = DZERO + this%cmodelname(i) = '' + this%cauxspeciesname(i) = '' + end do + ! + ! -- Return + return + end subroutine allocate_arrays + + !> @ brief Read Options block + !! + !! Reads the options block inside the VSC package. + !! + !< + subroutine read_options(this) + ! -- modules + use OpenSpecModule, only: access, form + use InputOutputModule, only: urword, getunit, urdaux, openfile + ! -- dummy + class(GwfVscType) :: this + ! -- local + character(len=LINELENGTH) :: warnmsg, errmsg, keyword, keyword2 + character(len=MAXCHARLEN) :: fname + integer(I4B) :: ierr + logical :: isfound, endOfBlock + ! -- formats + character(len=*), parameter :: fmtfileout = & + "(1x, 'VSC', 1x, a, 1x, 'Will be saved to file: ', & + &a, /4x, 'opened on unit: ', I7)" + character(len=*), parameter :: fmtlinear = & + "(/,1x,'Viscosity will vary linearly with temperature & + &change ')" + character(len=*), parameter :: fmtnonlinear = & + "(/,1x,'Viscosity will vary non-linearly with temperature & + &change ')" +! ------------------------------------------------------------------------------ + ! + ! -- get options block + call this%parser%GetBlock('OPTIONS', isfound, ierr, & + supportOpenClose=.true., blockRequired=.false.) + ! + ! -- parse options block if detected + if (isfound) then + write (this%iout, '(1x,a)') 'Processing VSC OPTIONS block' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('VISCREF') + this%viscref = this%parser%GetDouble() + write (this%iout, '(4x,a,1pg15.6)') & + 'Reference viscosity has been set to: ', & + this%viscref + case ('VISCOSITY') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ioutvisc = getunit() + call openfile(this%ioutvisc, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtfileout) & + 'VISCOSITY', fname, this%ioutvisc + else + errmsg = 'Optional VISCOSITY keyword must be '// & + 'followed by FILEOUT' + call store_error(errmsg) + end if + case ('TEMPERATURE_SPECIES_NAME') + call this%parser%GetStringCaps(this%name_temp_spec) + write (this%iout, '(4x, a)') 'Temperature species name set to: '// & + trim(this%name_temp_spec) + case ('THERMAL_FORMULATION') + call this%parser%GetStringCaps(keyword2) + if (trim(adjustl(keyword2)) == 'LINEAR') this%thermivisc = 1 + if (trim(adjustl(keyword2)) == 'NONLINEAR') this%thermivisc = 2 + select case (this%thermivisc) + case (1) + write (this%iout, fmtlinear) + case (2) + write (this%iout, fmtnonlinear) + end select + case ('THERMAL_A2') + this%a2 = this%parser%GetDouble() + if (this%thermivisc == 2) then + write (this%iout, '(4x,a,1pg15.6)') & + 'A2 in nonlinear viscosity formulation has been set to: ', & + this%a2 + else + write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A2 specified by user & + &in VSC Package input file. LINEAR viscosity ', 'formulation also & + &specified. THERMAL_A2 will not affect ', 'viscosity calculations.' + end if + case ('THERMAL_A3') + this%a3 = this%parser%GetDouble() + if (this%thermivisc == 2) then + write (this%iout, '(4x,a,1pg15.6)') & + 'A3 in nonlinear viscosity formulation has been set to: ', & + this%a3 + else + write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A3 specified by user & + &in VSC Package input file. LINEAR viscosity ', 'formulation also & + &specified. THERMAL_A3 will not affect ', 'viscosity calculations.' + end if + case ('THERMAL_A4') + this%a4 = this%parser%GetDouble() + if (this%thermivisc == 2) then + write (this%iout, '(4x,a,1pg15.6)') & + 'A4 in nonlinear viscosity formulation has been set to: ', & + this%a4 + else + write (this%iout, '(4x,a,/,4x,a,/,4x,a)') 'THERMAL_A4 specified by user & + &in VSC Package input file. LINEAR viscosity ', 'formulation also & + &specified. THERMAL_A4 will not affect ', 'viscosity calculations.' + end if + case default + write (errmsg, '(4x,a,a)') '**Error. Unknown VSC option: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end select + end do + ! + if (this%thermivisc == 1) then + if (this%a2 == 0.0) then + write (errmsg, '(a)') 'LINEAR option selected for varying & + &viscosity with temperature, but A1, a surrogate for & + &dVISC/dT, set equal to 0.0' + call store_error(errmsg) + end if + end if + if (this%thermivisc > 1) then + if (this%a2 == 0) then + write (warnmsg, '(a)') 'NONLINEAR option selected for & + &varying viscosity with temperature, but A2 set equal to & + &zero which may lead to unintended values for viscosity' + call store_warning(errmsg) + end if + if (this%a3 == 0) then + write (warnmsg, '(a)') 'NONLINEAR option selected for & + &varying viscosity with temperature,, but A3 set equal to & + &zero which may lead to unintended values for viscosity' + call store_warning(warnmsg) + end if + if (this%a4 == 0) then + write (warnmsg, '(a)') 'NONLINEAR option selected for & + &varying viscosity with temperature, BUT A4 SET EQUAL TO & + &zero which may lead to unintended values for viscosity' + call store_warning(warnmsg) + end if + end if + end if + ! + write (this%iout, '(/,1x,a)') 'end of VSC options block' + ! + ! -- Return + return + end subroutine read_options + + !> @brief Sets options as opposed to reading them from a file + !< + subroutine set_options(this, input_data) + class(GwfVscType) :: this + type(GwfVscInputDataType), intent(in) :: input_data !< the input data to be set + + this%viscref = input_data%viscref + ! + ! -- Return + return + end subroutine set_options + + !> @ brief Set pointers to concentration(s) + !! + !! Pass in a gwt model name, concentration array, and ibound, + !! and store a pointer to these in the VSC package so that + !! viscosity can be calculated from them. This routine is called + !! from the gwfgwt exchange in the exg_ar() method. + !! + !< + subroutine set_concentration_pointer(this, modelname, conc, icbund, istmpr) + ! -- modules + ! -- dummy + class(GwfVscType) :: this + character(len=LENMODELNAME), intent(in) :: modelname + real(DP), dimension(:), pointer :: conc + integer(I4B), dimension(:), pointer :: icbund + integer(I4B), optional, intent(in) :: istmpr + ! -- local + integer(I4B) :: i + logical :: found +! ------------------------------------------------------------------------------ + ! + this%iconcset = 1 + found = .false. + do i = 1, this%nviscspecies + if (this%cmodelname(i) == modelname) then + this%modelconc(i)%conc => conc + this%modelconc(i)%icbund => icbund + found = .true. + exit + end if + end do + ! + ! -- Return + return + end subroutine set_concentration_pointer + +end module GwfVscModule diff --git a/src/Model/GroundWaterFlow/gwf3wel8.f90 b/src/Model/GroundWaterFlow/gwf3wel8.f90 index bdd32ea0c83..008580a6475 100644 --- a/src/Model/GroundWaterFlow/gwf3wel8.f90 +++ b/src/Model/GroundWaterFlow/gwf3wel8.f90 @@ -16,12 +16,12 @@ module WelModule ! -- modules used by WelModule methods use KindModule, only: DP, I4B use ConstantsModule, only: DZERO, DEM1, DONE, LENFTYPE, DNODATA, MAXCHARLEN - use SimVariablesModule, only: errmsg - use SimModule, only: store_error + use SimVariablesModule, only: errmsg + use SimModule, only: store_error use MemoryHelperModule, only: create_mem_path use BndModule, only: BndType use ObsModule, only: DefaultObsIdProcessor - use SmoothingModule, only: sQSaturation, sQSaturationDerivative + use SmoothingModule, only: sQSaturation, sQSaturationDerivative use ObserveModule, only: ObserveType use TimeSeriesLinkModule, only: TimeSeriesLinkType, & GetTimeSeriesLinkFromList @@ -33,13 +33,13 @@ module WelModule private public :: wel_create ! - character(len=LENFTYPE) :: ftype = 'WEL' !< package ftype - character(len=16) :: text = ' WEL' !< package flow text string + character(len=LENFTYPE) :: ftype = 'WEL' !< package ftype + character(len=16) :: text = ' WEL' !< package flow text string ! type, extends(BndType) :: WelType - integer(I4B), pointer :: iflowred => null() !< flag indicating if the AUTO_FLOW_REDUCE option is active - real(DP), pointer :: flowred => null() !< AUTO_FLOW_REDUCE variable - integer(I4B), pointer :: ioutafrcsv => null() !< unit number for CSV output file containing wells with reduced puping rates + integer(I4B), pointer :: iflowred => null() !< flag indicating if the AUTO_FLOW_REDUCE option is active + real(DP), pointer :: flowred => null() !< AUTO_FLOW_REDUCE variable + integer(I4B), pointer :: ioutafrcsv => null() !< unit number for CSV output file containing wells with reduced puping rates contains procedure :: allocate_scalars => wel_allocate_scalars procedure :: bnd_options => wel_options @@ -67,526 +67,527 @@ module WelModule !! !< subroutine wel_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) - ! -- dummy variables - class(BndType), pointer :: packobj !< pointer to default package type - integer(I4B),intent(in) :: id !< package id - integer(I4B),intent(in) :: ibcnum !< boundary condition number - integer(I4B),intent(in) :: inunit !< unit number of WEL package input file - integer(I4B),intent(in) :: iout !< unit number of model listing file - character(len=*), intent(in) :: namemodel !< model name - character(len=*), intent(in) :: pakname !< package name - ! -- local variables - type(WelType), pointer :: welobj - ! - ! -- allocate the object and assign values to object variables - allocate(welobj) - packobj => welobj - ! - ! -- create name and memory path - call packobj%set_names(ibcnum, namemodel, pakname, ftype) - packobj%text = text - ! - ! -- allocate scalars - call welobj%allocate_scalars() - ! - ! -- initialize package - call packobj%pack_initialize() + ! -- dummy variables + class(BndType), pointer :: packobj !< pointer to default package type + integer(I4B), intent(in) :: id !< package id + integer(I4B), intent(in) :: ibcnum !< boundary condition number + integer(I4B), intent(in) :: inunit !< unit number of WEL package input file + integer(I4B), intent(in) :: iout !< unit number of model listing file + character(len=*), intent(in) :: namemodel !< model name + character(len=*), intent(in) :: pakname !< package name + ! -- local variables + type(WelType), pointer :: welobj + ! + ! -- allocate the object and assign values to object variables + allocate (welobj) + packobj => welobj + ! + ! -- create name and memory path + call packobj%set_names(ibcnum, namemodel, pakname, ftype) + packobj%text = text + ! + ! -- allocate scalars + call welobj%allocate_scalars() + ! + ! -- initialize package + call packobj%pack_initialize() - packobj%inunit=inunit - packobj%iout=iout - packobj%id=id - packobj%ibcnum = ibcnum - packobj%ncolbnd=1 - packobj%iscloc=1 - packobj%ictMemPath = create_mem_path(namemodel,'NPF') - ! - ! -- return - return - end subroutine wel_create + packobj%inunit = inunit + packobj%iout = iout + packobj%id = id + packobj%ibcnum = ibcnum + packobj%ncolbnd = 1 + packobj%iscloc = 1 + packobj%ictMemPath = create_mem_path(namemodel, 'NPF') + ! + ! -- return + return + end subroutine wel_create - !> @ brief Deallocate package memory + !> @ brief Deallocate package memory !! !! Deallocate WEL package scalars and arrays. !! - !< - subroutine wel_da(this) - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy variables - class(WelType) :: this !< WelType object - ! - ! -- Deallocate parent package - call this%BndType%bnd_da() - ! - ! -- scalars - call mem_deallocate(this%iflowred) - call mem_deallocate(this%flowred) - call mem_deallocate(this%ioutafrcsv) - ! - ! -- return - return - end subroutine wel_da + !< + subroutine wel_da(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy variables + class(WelType) :: this !< WelType object + ! + ! -- Deallocate parent package + call this%BndType%bnd_da() + ! + ! -- scalars + call mem_deallocate(this%iflowred) + call mem_deallocate(this%flowred) + call mem_deallocate(this%ioutafrcsv) + ! + ! -- return + return + end subroutine wel_da - !> @ brief Allocate scalars + !> @ brief Allocate scalars !! !! Allocate and initialize scalars for the WEL package. The base model !! allocate scalars method is also called. !! - !< - subroutine wel_allocate_scalars(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate - ! -- dummy variables - class(WelType) :: this !< WelType object - ! - ! -- call standard BndType allocate scalars - call this%BndType%allocate_scalars() - ! - ! -- allocate the object and assign values to object variables - call mem_allocate(this%iflowred, 'IFLOWRED', this%memoryPath) - call mem_allocate(this%flowred, 'FLOWRED', this%memoryPath) - call mem_allocate(this%ioutafrcsv, 'IOUTAFRCSV', this%memoryPath) - ! - ! -- Set values - this%iflowred = 0 - this%ioutafrcsv = 0 - this%flowred = DZERO - ! - ! -- return - return - end subroutine wel_allocate_scalars + !< + subroutine wel_allocate_scalars(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy variables + class(WelType) :: this !< WelType object + ! + ! -- call standard BndType allocate scalars + call this%BndType%allocate_scalars() + ! + ! -- allocate the object and assign values to object variables + call mem_allocate(this%iflowred, 'IFLOWRED', this%memoryPath) + call mem_allocate(this%flowred, 'FLOWRED', this%memoryPath) + call mem_allocate(this%ioutafrcsv, 'IOUTAFRCSV', this%memoryPath) + ! + ! -- Set values + this%iflowred = 0 + this%ioutafrcsv = 0 + this%flowred = DZERO + ! + ! -- return + return + end subroutine wel_allocate_scalars - !> @ brief Read additional options for package + !> @ brief Read additional options for package !! !! Read additional options for WEL package. !! - !< - subroutine wel_options(this, option, found) - ! -- modules - use InputOutputModule, only: urword - ! -- dummy variables - class(WelType), intent(inout) :: this !< WelType object - character(len=*), intent(inout) :: option !< option keyword string - logical, intent(inout) :: found !< boolean indicating if option found - ! -- local variables - real(DP) :: r - character(len=MAXCHARLEN) :: fname - character(len=MAXCHARLEN) :: keyword - ! -- formats - character(len=*),parameter :: fmtflowred = & - "(4x, 'AUTOMATIC FLOW REDUCTION OF WELLS IMPLEMENTED.')" - character(len=*),parameter :: fmtflowredv = & - "(4x, 'AUTOMATIC FLOW REDUCTION FRACTION (',g15.7,').')" - ! - ! -- Check for 'AUTO_FLOW_REDUCE' and set this%iflowred - select case (option) - case('AUTO_FLOW_REDUCE') - this%iflowred = 1 - r = this%parser%GetDouble() - if (r <= DZERO) then - r = DEM1 - else if (r > DONE) then - r = DONE - end if - this%flowred = r - ! - ! -- Write option and return with found set to true - if(this%iflowred > 0) & - write(this%iout, fmtflowred) - write(this%iout, fmtflowredv) this%flowred - found = .true. - case('AUTO_FLOW_REDUCE_CSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - call this%wel_afr_csv_init(fname) - else - call store_error('OPTIONAL AUTO_FLOW_REDUCE_CSV KEYWORD MUST BE & - &FOLLOWED BY FILEOUT') - end if - case('MOVER') - this%imover = 1 - write(this%iout, '(4x,A)') 'MOVER OPTION ENABLED' - found = .true. - case default - ! - ! -- No options found - found = .false. - end select - ! - ! -- return - return - end subroutine wel_options + !< + subroutine wel_options(this, option, found) + ! -- modules + use InputOutputModule, only: urword + ! -- dummy variables + class(WelType), intent(inout) :: this !< WelType object + character(len=*), intent(inout) :: option !< option keyword string + logical, intent(inout) :: found !< boolean indicating if option found + ! -- local variables + real(DP) :: r + character(len=MAXCHARLEN) :: fname + character(len=MAXCHARLEN) :: keyword + ! -- formats + character(len=*), parameter :: fmtflowred = & + &"(4x, 'AUTOMATIC FLOW REDUCTION OF WELLS IMPLEMENTED.')" + character(len=*), parameter :: fmtflowredv = & + &"(4x, 'AUTOMATIC FLOW REDUCTION FRACTION (',g15.7,').')" + ! + ! -- Check for 'AUTO_FLOW_REDUCE' and set this%iflowred + select case (option) + case ('AUTO_FLOW_REDUCE') + this%iflowred = 1 + r = this%parser%GetDouble() + if (r <= DZERO) then + r = DEM1 + else if (r > DONE) then + r = DONE + end if + this%flowred = r + ! + ! -- Write option and return with found set to true + if (this%iflowred > 0) & + write (this%iout, fmtflowred) + write (this%iout, fmtflowredv) this%flowred + found = .true. + case ('AUTO_FLOW_REDUCE_CSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + call this%wel_afr_csv_init(fname) + else + call store_error('OPTIONAL AUTO_FLOW_REDUCE_CSV KEYWORD MUST BE & + &FOLLOWED BY FILEOUT') + end if + case ('MOVER') + this%imover = 1 + write (this%iout, '(4x,A)') 'MOVER OPTION ENABLED' + found = .true. + case default + ! + ! -- No options found + found = .false. + end select + ! + ! -- return + return + end subroutine wel_options - !> @ brief Formulate the package hcof and rhs terms. + !> @ brief Formulate the package hcof and rhs terms. !! !! Formulate the hcof and rhs terms for the WEL package that will be !! added to the coefficient matrix and right-hand side vector. !! - !< - subroutine wel_cf(this, reset_mover) - ! -- dummy variables - class(WelType) :: this !< WelType object - logical, intent(in), optional :: reset_mover !< boolean for resetting mover - ! -- local variables - integer(I4B) :: i, node, ict - real(DP) :: qmult - real(DP) :: q - real(DP) :: tp - real(DP) :: bt - real(DP) :: thick - logical :: lrm - ! - ! -- Return if no wells - if(this%nbound == 0) return - ! - ! -- pakmvrobj cf - lrm = .true. - if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then - call this%pakmvrobj%cf() - endif - ! - ! -- Calculate hcof and rhs for each well entry - do i = 1, this%nbound - node = this%nodelist(i) - this%hcof(i) = DZERO - if(this%ibound(node) <= 0) then - this%rhs(i) = DZERO - cycle - end if - q = this%bound(1,i) - if (this%iflowred /= 0 .and. q < DZERO) then - ict = this%icelltype(node) - if (ict /= 0) then - tp = this%dis%top(node) - bt = this%dis%bot(node) - thick = tp - bt - tp = bt + this%flowred * thick - qmult = sQSaturation(tp, bt, this%xnew(node)) - q = q * qmult - endif + !< + subroutine wel_cf(this, reset_mover) + ! -- dummy variables + class(WelType) :: this !< WelType object + logical, intent(in), optional :: reset_mover !< boolean for resetting mover + ! -- local variables + integer(I4B) :: i, node, ict + real(DP) :: qmult + real(DP) :: q + real(DP) :: tp + real(DP) :: bt + real(DP) :: thick + logical :: lrm + ! + ! -- Return if no wells + if (this%nbound == 0) return + ! + ! -- pakmvrobj cf + lrm = .true. + if (present(reset_mover)) lrm = reset_mover + if (this%imover == 1 .and. lrm) then + call this%pakmvrobj%cf() + end if + ! + ! -- Calculate hcof and rhs for each well entry + do i = 1, this%nbound + node = this%nodelist(i) + this%hcof(i) = DZERO + if (this%ibound(node) <= 0) then + this%rhs(i) = DZERO + cycle + end if + q = this%bound(1, i) + if (this%iflowred /= 0 .and. q < DZERO) then + ict = this%icelltype(node) + if (ict /= 0) then + tp = this%dis%top(node) + bt = this%dis%bot(node) + thick = tp - bt + tp = bt + this%flowred * thick + qmult = sQSaturation(tp, bt, this%xnew(node)) + q = q * qmult end if - this%rhs(i) = -q - enddo - ! - return - end subroutine wel_cf + end if + this%rhs(i) = -q + end do + ! + return + end subroutine wel_cf - !> @ brief Copy hcof and rhs terms into solution. + !> @ brief Copy hcof and rhs terms into solution. !! - !! Add the hcof and rhs terms for the WEL package to the + !! Add the hcof and rhs terms for the WEL package to the !! coefficient matrix and right-hand side vector. !! - !< - subroutine wel_fc(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(WelType) :: this !< WelType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! -- local variables - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: ipos - ! - ! -- pakmvrobj fc - if(this%imover == 1) then - call this%pakmvrobj%fc() - endif - ! - ! -- Copy package rhs and hcof into solution rhs and amat - do i = 1, this%nbound - n = this%nodelist(i) - rhs(n) = rhs(n) + this%rhs(i) - ipos = ia(n) - amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) - ! - ! -- If mover is active and this well is discharging, - ! store available water (as positive value). - if(this%imover == 1 .and. this%rhs(i) > DZERO) then - call this%pakmvrobj%accumulate_qformvr(i, this%rhs(i)) - endif - enddo - ! - ! -- return - return - end subroutine wel_fc + !< + subroutine wel_fc(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(WelType) :: this !< WelType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! -- local variables + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: ipos + ! + ! -- pakmvrobj fc + if (this%imover == 1) then + call this%pakmvrobj%fc() + end if + ! + ! -- Copy package rhs and hcof into solution rhs and amat + do i = 1, this%nbound + n = this%nodelist(i) + rhs(n) = rhs(n) + this%rhs(i) + ipos = ia(n) + amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) + ! + ! -- If mover is active and this well is discharging, + ! store available water (as positive value). + if (this%imover == 1 .and. this%rhs(i) > DZERO) then + call this%pakmvrobj%accumulate_qformvr(i, this%rhs(i)) + end if + end do + ! + ! -- return + return + end subroutine wel_fc - !> @ brief Add Newton-Raphson terms for package into solution. + !> @ brief Add Newton-Raphson terms for package into solution. !! - !! Calculate and add the Newton-Raphson terms for the WEL package to the + !! Calculate and add the Newton-Raphson terms for the WEL package to the !! coefficient matrix and right-hand side vector. !! - !< - subroutine wel_fn(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(WelType) :: this !< WelType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! -- local variables - integer(I4B) :: i - integer(I4B) :: node - integer(I4B) :: ipos - integer(I4B) :: ict - real(DP) :: drterm - real(DP) :: q - real(DP) :: tp - real(DP) :: bt - real(DP) :: thick + !< + subroutine wel_fn(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(WelType) :: this !< WelType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! -- local variables + integer(I4B) :: i + integer(I4B) :: node + integer(I4B) :: ipos + integer(I4B) :: ict + real(DP) :: drterm + real(DP) :: q + real(DP) :: tp + real(DP) :: bt + real(DP) :: thick + ! + ! -- Copy package rhs and hcof into solution rhs and amat + do i = 1, this%nbound + node = this%nodelist(i) + ! + ! -- test if node is constant or inactive + if (this%ibound(node) <= 0) then + cycle + end if ! - ! -- Copy package rhs and hcof into solution rhs and amat - do i = 1, this%nbound - node = this%nodelist(i) - ! - ! -- test if node is constant or inactive - if(this%ibound(node) <= 0) then - cycle + ! -- well rate is possibly head dependent + ict = this%icelltype(node) + if (this%iflowred /= 0 .and. ict /= 0) then + ipos = ia(node) + q = -this%rhs(i) + if (q < DZERO) then + ! -- calculate derivative for well + tp = this%dis%top(node) + bt = this%dis%bot(node) + thick = tp - bt + tp = bt + this%flowred * thick + drterm = sQSaturationDerivative(tp, bt, this%xnew(node)) + drterm = drterm * this%bound(1, i) + !--fill amat and rhs with newton-raphson terms + amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + drterm + rhs(node) = rhs(node) + drterm * this%xnew(node) end if - ! - ! -- well rate is possibly head dependent - ict = this%icelltype(node) - if (this%iflowred /= 0 .and. ict /= 0) then - ipos = ia(node) - q = -this%rhs(i) - if (q < DZERO) then - ! -- calculate derivative for well - tp = this%dis%top(node) - bt = this%dis%bot(node) - thick = tp - bt - tp = bt + this%flowred * thick - drterm = sQSaturationDerivative(tp, bt, this%xnew(node)) - drterm = drterm * this%bound(1,i) - !--fill amat and rhs with newton-raphson terms - amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + drterm - rhs(node) = rhs(node) + drterm * this%xnew(node) - end if - end if - end do - ! - ! -- return - return - end subroutine wel_fn + end if + end do + ! + ! -- return + return + end subroutine wel_fn - !> @brief Initialize the auto flow reduce csv output file - subroutine wel_afr_csv_init(this, fname) - ! -- dummy variables - class(WelType), intent(inout) :: this !< WelType object - character(len=*), intent(in) :: fname - ! -- format - character(len=*),parameter :: fmtafrcsv = & - "(4x, 'AUTO FLOW REDUCE INFORMATION WILL BE SAVED TO FILE: ', a, /4x, & + !> @brief Initialize the auto flow reduce csv output file + subroutine wel_afr_csv_init(this, fname) + ! -- dummy variables + class(WelType), intent(inout) :: this !< WelType object + character(len=*), intent(in) :: fname + ! -- format + character(len=*), parameter :: fmtafrcsv = & + "(4x, 'AUTO FLOW REDUCE INFORMATION WILL BE SAVED TO FILE: ', a, /4x, & &'OPENED ON UNIT: ', I0)" - - this%ioutafrcsv = getunit() - call openfile(this%ioutafrcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtafrcsv) trim(adjustl(fname)), & - this%ioutafrcsv - write(this%ioutafrcsv, '(a)') & - 'time,period,step,boundnumber,cellnumber,rate-requested,rate-actual,wel-reduction' - return - end subroutine wel_afr_csv_init - - !> @brief Write out auto flow reductions only when & where they occur - subroutine wel_afr_csv_write(this) - ! -- modules - use TdisModule, only: totim, kstp, kper - ! -- dummy variables - class(WelType), intent(inout) :: this !< WelType object - ! -- local - integer(I4B) :: i - integer(I4B) :: nodereduced - integer(I4B) :: nodeuser - real(DP) :: v - ! -- format - do i = 1, this%nbound - nodereduced = this%nodelist(i) - ! - ! -- test if node is constant or inactive - if(this%ibound(nodereduced) <= 0) then - cycle - end if - v = this%bound(1,i) + this%rhs(i) - if (v < DZERO) then - nodeuser = this%dis%get_nodeuser(nodereduced) - write(this%ioutafrcsv,'(*(G0,:,","))') & - totim, kper, kstp, i, nodeuser, this%bound(1,i), this%simvals(i), v - end if - enddo - end subroutine wel_afr_csv_write - - !> @ brief Define the list label for the package + + this%ioutafrcsv = getunit() + call openfile(this%ioutafrcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtafrcsv) trim(adjustl(fname)), & + this%ioutafrcsv + write (this%ioutafrcsv, '(a)') & + 'time,period,step,boundnumber,cellnumber,rate-requested,& + &rate-actual,wel-reduction' + return + end subroutine wel_afr_csv_init + + !> @brief Write out auto flow reductions only when & where they occur + subroutine wel_afr_csv_write(this) + ! -- modules + use TdisModule, only: totim, kstp, kper + ! -- dummy variables + class(WelType), intent(inout) :: this !< WelType object + ! -- local + integer(I4B) :: i + integer(I4B) :: nodereduced + integer(I4B) :: nodeuser + real(DP) :: v + ! -- format + do i = 1, this%nbound + nodereduced = this%nodelist(i) + ! + ! -- test if node is constant or inactive + if (this%ibound(nodereduced) <= 0) then + cycle + end if + v = this%bound(1, i) + this%rhs(i) + if (v < DZERO) then + nodeuser = this%dis%get_nodeuser(nodereduced) + write (this%ioutafrcsv, '(*(G0,:,","))') & + totim, kper, kstp, i, nodeuser, this%bound(1, i), this%simvals(i), v + end if + end do + end subroutine wel_afr_csv_write + + !> @ brief Define the list label for the package !! !! Method defined the list label for the WEL package. The list label is !! the heading that is written to iout when PRINT_INPUT option is used. !! - !< - subroutine define_listlabel(this) - ! -- dummy variables - class(WelType), intent(inout) :: this !< WelType object - ! - ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if (this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' - else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - end if - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if (this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - end if - ! - ! -- return - return - end subroutine define_listlabel + !< + subroutine define_listlabel(this) + ! -- dummy variables + class(WelType), intent(inout) :: this !< WelType object + ! + ! -- create the header list label + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + else + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if + ! + ! -- return + return + end subroutine define_listlabel - ! -- Procedures related to observations + ! -- Procedures related to observations - !> @brief Determine if observations are supported. + !> @brief Determine if observations are supported. !! !! Function to determine if observations are supported by the WEL package. !! Observations are supported by the WEL package. !! !! @return wel_obs_supported boolean indicating if observations are supported !! - !< - logical function wel_obs_supported(this) - ! -- dummy variables - class(WelType) :: this !< WelType object - ! - ! -- set boolean - wel_obs_supported = .true. - ! - ! -- return - return - end function wel_obs_supported + !< + logical function wel_obs_supported(this) + ! -- dummy variables + class(WelType) :: this !< WelType object + ! + ! -- set boolean + wel_obs_supported = .true. + ! + ! -- return + return + end function wel_obs_supported - !> @brief Define the observation types available in the package + !> @brief Define the observation types available in the package !! !! Method to define the observation types available in the WEL package. !! - !< - subroutine wel_df_obs(this) - ! -- dummy variables - class(WelType) :: this !< WelType object - ! -- local variables - integer(I4B) :: indx - ! - ! -- initialize observations - call this%obs%StoreObsType('wel', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor - ! - ! -- Store obs type and assign procedure pointer - ! for to-mvr observation type. - call this%obs%StoreObsType('to-mvr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor - ! - ! -- Store obs type and assign procedure pointer - ! for wel-reduction observation type. - call this%obs%StoreObsType('wel-reduction', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor - ! - ! -- return - return - end subroutine wel_df_obs + !< + subroutine wel_df_obs(this) + ! -- dummy variables + class(WelType) :: this !< WelType object + ! -- local variables + integer(I4B) :: indx + ! + ! -- initialize observations + call this%obs%StoreObsType('wel', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor + ! + ! -- Store obs type and assign procedure pointer + ! for to-mvr observation type. + call this%obs%StoreObsType('to-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor + ! + ! -- Store obs type and assign procedure pointer + ! for wel-reduction observation type. + call this%obs%StoreObsType('wel-reduction', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor + ! + ! -- return + return + end subroutine wel_df_obs - !> @brief Save observations for the package + !> @brief Save observations for the package !! !! Method to save simulated values for the WEL package. !! - !< - subroutine wel_bd_obs(this) - ! -- dummy variables - class(WelType) :: this !< WelType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: jj - real(DP) :: v - type(ObserveType), pointer :: obsrv => null() - ! - ! -- clear the observations - call this%obs%obs_bd_clear() - ! - ! -- Save simulated values for all of package's observations. - do i = 1, this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv - if (obsrv%BndFound) then - do n = 1, obsrv%indxbnds_count - v = DNODATA - jj = obsrv%indxbnds(n) - select case (obsrv%ObsTypeId) - case ('TO-MVR') - if (this%imover == 1) then - v = this%pakmvrobj%get_qtomvr(jj) - if (v > DZERO) then - v = -v - end if - end if - case ('WEL') - v = this%simvals(jj) - case('WEL-REDUCTION') - if (this%iflowred > 0) then - v = this%bound(1,jj) + this%rhs(jj) + !< + subroutine wel_bd_obs(this) + ! -- dummy variables + class(WelType) :: this !< WelType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: jj + real(DP) :: v + type(ObserveType), pointer :: obsrv => null() + ! + ! -- clear the observations + call this%obs%obs_bd_clear() + ! + ! -- Save simulated values for all of package's observations. + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv + if (obsrv%BndFound) then + do n = 1, obsrv%indxbnds_count + v = DNODATA + jj = obsrv%indxbnds(n) + select case (obsrv%ObsTypeId) + case ('TO-MVR') + if (this%imover == 1) then + v = this%pakmvrobj%get_qtomvr(jj) + if (v > DZERO) then + v = -v end if - case default - errmsg = 'Unrecognized observation type: ' // trim(obsrv%ObsTypeId) - call store_error(errmsg) - end select - call this%obs%SaveOneSimval(obsrv, v) - end do - else - call this%obs%SaveOneSimval(obsrv, DNODATA) - endif - end do - ! - ! -- Write the auto flow reduce csv file entries for this step - if (this%ioutafrcsv > 0) then - call this%wel_afr_csv_write() + end if + case ('WEL') + v = this%simvals(jj) + case ('WEL-REDUCTION') + if (this%iflowred > 0) then + v = this%bound(1, jj) + this%rhs(jj) + end if + case default + errmsg = 'Unrecognized observation type: '//trim(obsrv%ObsTypeId) + call store_error(errmsg) + end select + call this%obs%SaveOneSimval(obsrv, v) + end do + else + call this%obs%SaveOneSimval(obsrv, DNODATA) end if - ! - ! -- return - return - end subroutine wel_bd_obs + end do + ! + ! -- Write the auto flow reduce csv file entries for this step + if (this%ioutafrcsv > 0) then + call this%wel_afr_csv_write() + end if + ! + ! -- return + return + end subroutine wel_bd_obs - ! -- Procedure related to time series + ! -- Procedure related to time series - !> @brief Assign time series links for the package + !> @brief Assign time series links for the package !! !! Assign the time series links for the WEL package. Only !! the Q variable can be defined with time series. !! - !< - subroutine wel_rp_ts(this) - ! -- dummy variables - class(WelType), intent(inout) :: this !< WelType object - ! -- local variables - integer(I4B) :: i, nlinks - type(TimeSeriesLinkType), pointer :: tslink => null() - ! - ! -- set up the time series links - nlinks = this%TsManager%boundtslinks%Count() - do i = 1, nlinks - tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) - if (associated(tslink)) then - if (tslink%JCol==1) then - tslink%Text = 'Q' - end if + !< + subroutine wel_rp_ts(this) + ! -- dummy variables + class(WelType), intent(inout) :: this !< WelType object + ! -- local variables + integer(I4B) :: i, nlinks + type(TimeSeriesLinkType), pointer :: tslink => null() + ! + ! -- set up the time series links + nlinks = this%TsManager%boundtslinks%Count() + do i = 1, nlinks + tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) + if (associated(tslink)) then + if (tslink%JCol == 1) then + tslink%Text = 'Q' end if - end do - ! - ! -- return - return - end subroutine wel_rp_ts + end if + end do + ! + ! -- return + return + end subroutine wel_rp_ts end module WelModule diff --git a/src/Model/GroundWaterTransport/gwt1.f90 b/src/Model/GroundWaterTransport/gwt1.f90 index 27430779cb9..9b6c1bf91e7 100644 --- a/src/Model/GroundWaterTransport/gwt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1.f90 @@ -1,31 +1,31 @@ ! Groundwater Transport (GWT) Model ! The following are additional features/checks to add -! * Add check that discretization is the same between both models -! * Program GWT-GWT exchange transport (awaiting implementation of interface model) +! * Add check that discretization is the same between both models ! * Consider implementation of steady-state transport (affects MST, IST) ! * Check and handle pore space discrepancy between flow and transport (porosity vs specific yield) ! * UZT may not have the required porosity term - + module GwtModule - use KindModule, only: DP, I4B - use InputOutputModule, only: ParseLine, upcase - use ConstantsModule, only: LENFTYPE, DZERO, LENPAKLOC - use VersionModule, only: write_listfile_header - use NumericalModelModule, only: NumericalModelType - use BaseModelModule, only: BaseModelType - use BndModule, only: BndType, AddBndToList, GetBndFromList - use GwtIcModule, only: GwtIcType - use GwtFmiModule, only: GwtFmiType - use GwtAdvModule, only: GwtAdvType - use GwtDspModule, only: GwtDspType - use GwtSsmModule, only: GwtSsmType - use GwtMvtModule, only: GwtMvtType - use GwtMstModule, only: GwtMstType - use GwtOcModule, only: GwtOcType - use GwtObsModule, only: GwtObsType - use BudgetModule, only: BudgetType - + use KindModule, only: DP, I4B + use InputOutputModule, only: ParseLine, upcase + use ConstantsModule, only: LENFTYPE, DZERO, LENPAKLOC + use VersionModule, only: write_listfile_header + use NumericalModelModule, only: NumericalModelType + use TransportModelModule, only: TransportModelType + use BaseModelModule, only: BaseModelType + use BndModule, only: BndType, AddBndToList, GetBndFromList + use GwtIcModule, only: GwtIcType + use GwtFmiModule, only: GwtFmiType + use GwtAdvModule, only: GwtAdvType + use GwtDspModule, only: GwtDspType + use GwtSsmModule, only: GwtSsmType + use GwtMvtModule, only: GwtMvtType + use GwtMstModule, only: GwtMstType + use GwtOcModule, only: GwtOcType + use GwtObsModule, only: GwtObsType + use BudgetModule, only: BudgetType + implicit none private @@ -33,45 +33,45 @@ module GwtModule public :: GwtModelType public :: CastAsGwtModel - type, extends(NumericalModelType) :: GwtModelType - - type(GwtIcType), pointer :: ic => null() ! initial conditions package - type(GwtFmiType), pointer :: fmi => null() ! flow model interface - type(GwtMstType), pointer :: mst => null() ! mass storage and transfer package - type(GwtAdvType), pointer :: adv => null() ! advection package - type(GwtDspType), pointer :: dsp => null() ! dispersion package - type(GwtSsmType), pointer :: ssm => null() ! source sink mixing package - type(GwtMvtType), pointer :: mvt => null() ! mover transport package - type(GwtOcType), pointer :: oc => null() ! output control package - type(GwtObsType), pointer :: obs => null() ! observation package - type(BudgetType), pointer :: budget => null() ! budget object - integer(I4B), pointer :: inic => null() ! unit number IC - integer(I4B), pointer :: infmi => null() ! unit number FMI - integer(I4B), pointer :: inmvt => null() ! unit number MVT - integer(I4B), pointer :: inmst => null() ! unit number MST - integer(I4B), pointer :: inadv => null() ! unit number ADV - integer(I4B), pointer :: indsp => null() ! unit number DSP - integer(I4B), pointer :: inssm => null() ! unit number SSM - integer(I4B), pointer :: inoc => null() ! unit number OC - integer(I4B), pointer :: inobs => null() ! unit number OBS - + type, extends(TransportModelType) :: GwtModelType + + type(GwtIcType), pointer :: ic => null() ! initial conditions package + type(GwtFmiType), pointer :: fmi => null() ! flow model interface + type(GwtMstType), pointer :: mst => null() ! mass storage and transfer package + type(GwtAdvType), pointer :: adv => null() ! advection package + type(GwtDspType), pointer :: dsp => null() ! dispersion package + type(GwtSsmType), pointer :: ssm => null() ! source sink mixing package + type(GwtMvtType), pointer :: mvt => null() ! mover transport package + type(GwtOcType), pointer :: oc => null() ! output control package + type(GwtObsType), pointer :: obs => null() ! observation package + type(BudgetType), pointer :: budget => null() ! budget object + integer(I4B), pointer :: inic => null() ! unit number IC + integer(I4B), pointer :: infmi => null() ! unit number FMI + integer(I4B), pointer :: inmvt => null() ! unit number MVT + integer(I4B), pointer :: inmst => null() ! unit number MST + integer(I4B), pointer :: inadv => null() ! unit number ADV + integer(I4B), pointer :: indsp => null() ! unit number DSP + integer(I4B), pointer :: inssm => null() ! unit number SSM + integer(I4B), pointer :: inoc => null() ! unit number OC + integer(I4B), pointer :: inobs => null() ! unit number OBS + contains - - procedure :: model_df => gwt_df - procedure :: model_ac => gwt_ac - procedure :: model_mc => gwt_mc - procedure :: model_ar => gwt_ar - procedure :: model_rp => gwt_rp - procedure :: model_ad => gwt_ad - procedure :: model_cf => gwt_cf - procedure :: model_fc => gwt_fc - procedure :: model_cc => gwt_cc - procedure :: model_cq => gwt_cq - procedure :: model_bd => gwt_bd - procedure :: model_ot => gwt_ot - procedure :: model_da => gwt_da - procedure :: model_bdentry => gwt_bdentry - + + procedure :: model_df => gwt_df + procedure :: model_ac => gwt_ac + procedure :: model_mc => gwt_mc + procedure :: model_ar => gwt_ar + procedure :: model_rp => gwt_rp + procedure :: model_ad => gwt_ad + procedure :: model_cf => gwt_cf + procedure :: model_fc => gwt_fc + procedure :: model_cc => gwt_cc + procedure :: model_cq => gwt_cq + procedure :: model_bd => gwt_bd + procedure :: model_ot => gwt_ot + procedure :: model_da => gwt_da + procedure :: model_bdentry => gwt_bdentry + procedure :: allocate_scalars procedure, private :: package_create procedure, private :: ftype_check @@ -81,21 +81,21 @@ module GwtModule procedure, private :: gwt_ot_dv procedure, private :: gwt_ot_bdsummary procedure, private :: gwt_ot_obs - + end type GwtModelType ! -- Module variables constant for simulation - integer(I4B), parameter :: NIUNIT=100 + integer(I4B), parameter :: NIUNIT = 100 character(len=LENFTYPE), dimension(NIUNIT) :: cunit - data cunit/ 'DIS6 ', 'DISV6', 'DISU6', 'IC6 ', 'MST6 ', & ! 5 - 'ADV6 ', 'DSP6 ', 'SSM6 ', ' ', 'CNC6 ', & ! 10 - 'OC6 ', 'OBS6 ', 'FMI6 ', 'SRC6 ', 'IST6 ', & ! 15 - 'LKT6 ', 'SFT6 ', 'MWT6 ', 'UZT6 ', 'MVT6 ', & ! 20 - 'API6 ', ' ', ' ', ' ', ' ', & ! 25 - 75 * ' '/ - - contains - + data cunit/'DIS6 ', 'DISV6', 'DISU6', 'IC6 ', 'MST6 ', & ! 5 + &'ADV6 ', 'DSP6 ', 'SSM6 ', ' ', 'CNC6 ', & ! 10 + &'OC6 ', 'OBS6 ', 'FMI6 ', 'SRC6 ', 'IST6 ', & ! 15 + &'LKT6 ', 'SFT6 ', 'MWT6 ', 'UZT6 ', 'MVT6 ', & ! 20 + &'API6 ', ' ', ' ', ' ', ' ', & ! 25 + &75*' '/ + +contains + subroutine gwt_cr(filename, id, modelname) ! ****************************************************************************** ! gwt_cr -- Create a new groundwater transport model object @@ -104,45 +104,45 @@ subroutine gwt_cr(filename, id, modelname) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ListsModule, only: basemodellist - use BaseModelModule, only: AddBaseModelToList - use SimModule, only: store_error, count_errors - use ConstantsModule, only: LINELENGTH, LENPACKAGENAME + use ListsModule, only: basemodellist + use BaseModelModule, only: AddBaseModelToList + use SimModule, only: store_error, count_errors + use ConstantsModule, only: LINELENGTH, LENPACKAGENAME use CompilerVersion - use MemoryManagerModule, only: mem_allocate - use MemoryHelperModule, only: create_mem_path - use GwfDisModule, only: dis_cr - use GwfDisvModule, only: disv_cr - use GwfDisuModule, only: disu_cr - use GwtIcModule, only: ic_cr - use GwtFmiModule, only: fmi_cr - use GwtMstModule, only: mst_cr - use GwtAdvModule, only: adv_cr - use GwtDspModule, only: dsp_cr - use GwtSsmModule, only: ssm_cr - use GwtMvtModule, only: mvt_cr - use GwtOcModule, only: oc_cr - use GwtObsModule, only: gwt_obs_cr - use BudgetModule, only: budget_cr - use NameFileModule, only: NameFileType + use MemoryManagerModule, only: mem_allocate + use MemoryHelperModule, only: create_mem_path + use GwfDisModule, only: dis_cr + use GwfDisvModule, only: disv_cr + use GwfDisuModule, only: disu_cr + use GwtIcModule, only: ic_cr + use GwtFmiModule, only: fmi_cr + use GwtMstModule, only: mst_cr + use GwtAdvModule, only: adv_cr + use GwtDspModule, only: dsp_cr + use GwtSsmModule, only: ssm_cr + use GwtMvtModule, only: mvt_cr + use GwtOcModule, only: oc_cr + use GwtObsModule, only: gwt_obs_cr + use BudgetModule, only: budget_cr + use NameFileModule, only: NameFileType ! -- dummy - character(len=*), intent(in) :: filename - integer(I4B), intent(in) :: id - character(len=*), intent(in) :: modelname + character(len=*), intent(in) :: filename + integer(I4B), intent(in) :: id + character(len=*), intent(in) :: modelname ! -- local integer(I4B) :: indis, indis6, indisu6, indisv6 integer(I4B) :: ipakid, i, j, iu, ipaknum character(len=LINELENGTH) :: errmsg character(len=LENPACKAGENAME) :: pakname type(NameFileType) :: namefile_obj - type(GwtModelType), pointer :: this - class(BaseModelType), pointer :: model + type(GwtModelType), pointer :: this + class(BaseModelType), pointer :: model integer(I4B) :: nwords character(len=LINELENGTH), allocatable, dimension(:) :: words ! ------------------------------------------------------------------------------ ! ! -- Allocate a new GWT Model (this) and add it to basemodellist - allocate(this) + allocate (this) ! ! -- Set this before any allocs in the memory manager can be done this%memoryPath = create_mem_path(modelname) @@ -170,32 +170,32 @@ subroutine gwt_cr(filename, id, modelname) ! ! -- if (size(namefile_obj%opts) > 0) then - write(this%iout, '(1x,a)') 'NAMEFILE OPTIONS:' + write (this%iout, '(1x,a)') 'NAMEFILE OPTIONS:' end if ! ! -- parse options in the gwt name file do i = 1, size(namefile_obj%opts) call ParseLine(namefile_obj%opts(i), nwords, words) call upcase(words(1)) - select case(words(1)) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'STRESS PACKAGE INPUT WILL BE PRINTED '// & - 'FOR ALL MODEL STRESS PACKAGES' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') 'PACKAGE FLOWS WILL BE PRINTED '// & - 'FOR ALL MODEL PACKAGES' - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, '(4x,a)') & - 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL' - case default - write(errmsg,'(4x,a,a,a,a)') & - 'UNKNOWN GWT NAMEFILE (', & - trim(adjustl(this%filename)), ') OPTION: ', & - trim(adjustl(namefile_obj%opts(i))) - call store_error(errmsg, terminate=.TRUE.) + select case (words(1)) + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') 'STRESS PACKAGE INPUT WILL BE PRINTED '// & + 'FOR ALL MODEL STRESS PACKAGES' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') 'PACKAGE FLOWS WILL BE PRINTED '// & + 'FOR ALL MODEL PACKAGES' + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, '(4x,a)') & + 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL' + case default + write (errmsg, '(4x,a,a,a,a)') & + 'UNKNOWN GWT NAMEFILE (', & + trim(adjustl(this%filename)), ') OPTION: ', & + trim(adjustl(namefile_obj%opts(i))) + call store_error(errmsg, terminate=.TRUE.) end select end do ! @@ -207,32 +207,32 @@ subroutine gwt_cr(filename, id, modelname) indisu6 = 0 indisv6 = 0 call namefile_obj%get_unitnumber('DIS6', indis6, 1) - if(indis6 > 0) indis = indis6 - if(indis <= 0) call namefile_obj%get_unitnumber('DISU6', indisu6, 1) - if(indisu6 > 0) indis = indisu6 - if(indis <= 0) call namefile_obj%get_unitnumber('DISV6', indisv6, 1) - if(indisv6 > 0) indis = indisv6 - call namefile_obj%get_unitnumber('IC6', this%inic, 1) + if (indis6 > 0) indis = indis6 + if (indis <= 0) call namefile_obj%get_unitnumber('DISU6', indisu6, 1) + if (indisu6 > 0) indis = indisu6 + if (indis <= 0) call namefile_obj%get_unitnumber('DISV6', indisv6, 1) + if (indisv6 > 0) indis = indisv6 + call namefile_obj%get_unitnumber('IC6', this%inic, 1) call namefile_obj%get_unitnumber('FMI6', this%infmi, 1) call namefile_obj%get_unitnumber('MVT6', this%inmvt, 1) call namefile_obj%get_unitnumber('MST6', this%inmst, 1) call namefile_obj%get_unitnumber('ADV6', this%inadv, 1) call namefile_obj%get_unitnumber('DSP6', this%indsp, 1) call namefile_obj%get_unitnumber('SSM6', this%inssm, 1) - call namefile_obj%get_unitnumber('OC6', this%inoc, 1) + call namefile_obj%get_unitnumber('OC6', this%inoc, 1) call namefile_obj%get_unitnumber('OBS6', this%inobs, 1) ! ! -- Check to make sure that required ftype's have been specified call this%ftype_check(namefile_obj, indis) ! ! -- Create discretization object - if(indis6 > 0) then + if (indis6 > 0) then call dis_cr(this%dis, this%name, indis, this%iout) - elseif(indisu6 > 0) then + elseif (indisu6 > 0) then call disu_cr(this%dis, this%name, indis, this%iout) - elseif(indisv6 > 0) then + elseif (indisv6 > 0) then call disv_cr(this%dis, this%name, indis, this%iout) - endif + end if ! ! -- Create utility objects call budget_cr(this%budget, this%name) @@ -255,12 +255,12 @@ subroutine gwt_cr(filename, id, modelname) do j = 1, namefile_obj%get_nval_for_row(i) iu = namefile_obj%get_unitnumber_rowcol(i, j) call namefile_obj%get_pakname(i, j, pakname) - call this%package_create(cunit(i), ipakid, ipaknum, pakname, iu, & - this%iout) + call this%package_create(cunit(i), ipakid, ipaknum, pakname, iu, & + this%iout) ipaknum = ipaknum + 1 ipakid = ipakid + 1 - enddo - enddo + end do + end do ! ! -- return return @@ -296,8 +296,8 @@ subroutine gwt_df(this) ! -- Assign or point model members to dis members this%neq = this%dis%nodes this%nja = this%dis%nja - this%ia => this%dis%con%ia - this%ja => this%dis%con%ja + this%ia => this%dis%con%ia + this%ja => this%dis%con%ja ! ! -- Allocate model arrays, now that neq and nja are assigned call this%allocate_arrays() @@ -308,7 +308,7 @@ subroutine gwt_df(this) call packobj%bnd_df(this%neq, this%dis) packobj%TsManager%iout = this%iout packobj%TasManager%iout = this%iout - enddo + end do ! ! -- Store information needed for observations call this%obs%obs_df(this%iout, this%name, 'GWT', this%dis) @@ -343,7 +343,7 @@ subroutine gwt_ac(this, sparse) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ac(this%moffset, sparse) - enddo + end do ! ! -- return return @@ -372,10 +372,10 @@ subroutine gwt_mc(this, iasln, jasln) if (this%indsp > 0) call this%dsp%dsp_mc(this%moffset, iasln, jasln) ! ! -- Map any package connections - do ip=1,this%bndlist%Count() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_mc(this%moffset, iasln, jasln) - enddo + end do ! ! -- return return @@ -402,7 +402,7 @@ subroutine gwt_ar(this) ! -- Allocate and read modules attached to model call this%fmi%fmi_ar(this%ibound) if (this%inmvt > 0) call this%mvt%mvt_ar() - if (this%inic > 0) call this%ic%ic_ar(this%x) + if (this%inic > 0) call this%ic%ic_ar(this%x) if (this%inmst > 0) call this%mst%mst_ar(this%dis, this%ibound) if (this%inadv > 0) call this%adv%adv_ar(this%dis, this%ibound) if (this%indsp > 0) call this%dsp%dsp_ar(this%ibound, this%mst%porosity) @@ -417,13 +417,13 @@ subroutine gwt_ar(this) call this%budget%set_ibudcsv(this%oc%ibudcsv) ! ! -- Package input files now open, so allocate and read - do ip=1,this%bndlist%Count() + do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) - call packobj%set_pointers(this%dis%nodes, this%ibound, this%x, & + call packobj%set_pointers(this%dis%nodes, this%ibound, this%x, & this%xold, this%flowja) ! -- Read and allocate package call packobj%bnd_ar() - enddo + end do ! ! -- return return @@ -454,18 +454,18 @@ subroutine gwt_rp(this) if (.not. readnewdata) return ! ! -- Read and prepare - if(this%inoc > 0) call this%oc%oc_rp() - if(this%inssm > 0) call this%ssm%ssm_rp() + if (this%inoc > 0) call this%oc%oc_rp() + if (this%inssm > 0) call this%ssm%ssm_rp() do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_rp() call packobj%bnd_rp_obs() - enddo + end do ! ! -- Return return end subroutine gwt_rp - + subroutine gwt_ad(this) ! ****************************************************************************** ! gwt_ad -- GroundWater Transport Model Time Step Advance @@ -496,13 +496,13 @@ subroutine gwt_ad(this) else this%xold(n) = this%x(n) end if - enddo + end do else ! ! -- copy xold into x if this time step is a redo do n = 1, this%dis%nodes this%x(n) = this%xold(n) - enddo + end do end if ! ! -- Advance fmi @@ -510,15 +510,15 @@ subroutine gwt_ad(this) ! ! -- Advance !if(this%inmst > 0) call this%mst%mst_ad() - if(this%indsp > 0) call this%dsp%dsp_ad() - if(this%inssm > 0) call this%ssm%ssm_ad() + if (this%indsp > 0) call this%dsp%dsp_ad() + if (this%inssm > 0) call this%ssm%ssm_ad() do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ad() if (isimcheck > 0) then call packobj%bnd_ck() end if - enddo + end do ! ! -- Push simulated values to preceding time/subtime step call this%obs%obs_ad() @@ -537,7 +537,7 @@ subroutine gwt_cf(this, kiter) ! -- modules ! -- dummy class(GwtModelType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter ! -- local class(BndType), pointer :: packobj integer(I4B) :: ip @@ -547,7 +547,7 @@ subroutine gwt_cf(this, kiter) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_cf() - enddo + end do ! ! -- return return @@ -573,32 +573,32 @@ subroutine gwt_fc(this, kiter, amatsln, njasln, inwtflag) ! ------------------------------------------------------------------------------ ! ! -- call fc routines - call this%fmi%fmi_fc(this%dis%nodes, this%xold, this%nja, njasln, & + call this%fmi%fmi_fc(this%dis%nodes, this%xold, this%nja, njasln, & amatsln, this%idxglo, this%rhs) if (this%inmvt > 0) then call this%mvt%mvt_fc(this%x, this%x) end if - if(this%inmst > 0) then - call this%mst%mst_fc(this%dis%nodes, this%xold, this%nja, njasln, & + if (this%inmst > 0) then + call this%mst%mst_fc(this%dis%nodes, this%xold, this%nja, njasln, & amatsln, this%idxglo, this%x, this%rhs, kiter) - endif - if(this%inadv > 0) then - call this%adv%adv_fc(this%dis%nodes, amatsln, this%idxglo, this%x, & + end if + if (this%inadv > 0) then + call this%adv%adv_fc(this%dis%nodes, amatsln, this%idxglo, this%x, & this%rhs) - endif - if(this%indsp > 0) then - call this%dsp%dsp_fc(kiter, this%dis%nodes, this%nja, njasln, amatsln, & + end if + if (this%indsp > 0) then + call this%dsp%dsp_fc(kiter, this%dis%nodes, this%nja, njasln, amatsln, & this%idxglo, this%rhs, this%x) - endif - if(this%inssm > 0) then + end if + if (this%inssm > 0) then call this%ssm%ssm_fc(amatsln, this%idxglo, this%rhs) - endif + end if ! ! -- packages do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_fc(this%rhs, this%ia, this%idxglo, amatsln) - enddo + end do ! ! -- return return @@ -614,10 +614,10 @@ subroutine gwt_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! ------------------------------------------------------------------------------ ! -- dummy class(GwtModelType) :: this - integer(I4B),intent(in) :: innertot - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: iend - integer(I4B),intent(in) :: icnvgmod + integer(I4B), intent(in) :: innertot + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: iend + integer(I4B), intent(in) :: icnvgmod character(len=LENPAKLOC), intent(inout) :: cpak integer(I4B), intent(inout) :: ipak real(DP), intent(inout) :: dpak @@ -639,7 +639,7 @@ subroutine gwt_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) ! -- return return end subroutine gwt_cc - + subroutine gwt_cq(this, icnvg, isuppress_output) ! ****************************************************************************** ! gwt_cq --Groundwater transport model calculate flow @@ -667,13 +667,13 @@ subroutine gwt_cq(this, icnvg, isuppress_output) ! its flow to this diagonal position. do i = 1, this%nja this%flowja(i) = DZERO - enddo - if(this%inadv > 0) call this%adv%adv_cq(this%x, this%flowja) - if(this%indsp > 0) call this%dsp%dsp_cq(this%x, this%flowja) - if(this%inmst > 0) call this%mst%mst_cq(this%dis%nodes, this%x, this%xold, & - this%flowja) - if(this%inssm > 0) call this%ssm%ssm_cq(this%flowja) - if(this%infmi > 0) call this%fmi%fmi_cq(this%x, this%flowja) + end do + if (this%inadv > 0) call this%adv%adv_cq(this%x, this%flowja) + if (this%indsp > 0) call this%dsp%dsp_cq(this%x, this%flowja) + if (this%inmst > 0) call this%mst%mst_cq(this%dis%nodes, this%x, this%xold, & + this%flowja) + if (this%inssm > 0) call this%ssm%ssm_cq(this%flowja) + if (this%infmi > 0) call this%fmi%fmi_cq(this%x, this%flowja) ! ! -- Go through packages and call cq routines. cf() routines are called ! first to regenerate non-linear terms to be consistent with the final @@ -682,7 +682,7 @@ subroutine gwt_cq(this, icnvg, isuppress_output) packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_cf(reset_mover=.false.) call packobj%bnd_cq(this%x, this%flowja) - enddo + end do ! ! -- Finalize calculation of flowja by adding face flows to the diagonal. ! This results in the flow residual being stored in the diagonal @@ -709,7 +709,7 @@ subroutine gwt_bd(this, icnvg, isuppress_output) integer(I4B), intent(in) :: isuppress_output ! -- local integer(I4B) :: ip - class(BndType),pointer :: packobj + class(BndType), pointer :: packobj ! ------------------------------------------------------------------------------ ! ! -- Save the solution convergence flag @@ -720,14 +720,14 @@ subroutine gwt_bd(this, icnvg, isuppress_output) ! should be added here to this%budget. In a subsequent exchange call, ! exchange flows might also be added. call this%budget%reset() - if(this%inmst > 0) call this%mst%mst_bd(isuppress_output, this%budget) - if(this%inssm > 0) call this%ssm%ssm_bd(isuppress_output, this%budget) - if(this%infmi > 0) call this%fmi%fmi_bd(isuppress_output, this%budget) - if(this%inmvt > 0) call this%mvt%mvt_bd(this%x, this%x) + if (this%inmst > 0) call this%mst%mst_bd(isuppress_output, this%budget) + if (this%inssm > 0) call this%ssm%ssm_bd(isuppress_output, this%budget) + if (this%infmi > 0) call this%fmi%fmi_bd(isuppress_output, this%budget) + if (this%inmvt > 0) call this%mvt%mvt_bd(this%x, this%x) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_bd(this%budget) - enddo + end do ! ! -- Return @@ -753,7 +753,7 @@ subroutine gwt_ot(this) integer(I4B) :: ibudfl integer(I4B) :: ipflag ! -- formats - character(len=*),parameter :: fmtnocnvg = & + character(len=*), parameter :: fmtnocnvg = & "(1X,/9X,'****FAILED TO MEET SOLVER CONVERGENCE CRITERIA IN TIME STEP ', & &I0,' OF STRESS PERIOD ',I0,'****')" ! ------------------------------------------------------------------------------ @@ -763,10 +763,10 @@ subroutine gwt_ot(this) idvprint = 0 icbcfl = 0 ibudfl = 0 - if(this%oc%oc_save('CONCENTRATION')) idvsave = 1 - if(this%oc%oc_print('CONCENTRATION')) idvprint = 1 - if(this%oc%oc_save('BUDGET')) icbcfl = 1 - if(this%oc%oc_print('BUDGET')) ibudfl = 1 + if (this%oc%oc_save('CONCENTRATION')) idvsave = 1 + if (this%oc%oc_print('CONCENTRATION')) idvprint = 1 + if (this%oc%oc_save('BUDGET')) icbcfl = 1 + if (this%oc%oc_print('BUDGET')) ibudfl = 1 icbcun = this%oc%oc_save_unit('BUDGET') ! ! -- Override ibudfl and idvprint flags for nonconvergence @@ -776,47 +776,47 @@ subroutine gwt_ot(this) ! ! Calculate and save observations call this%gwt_ot_obs() - ! + ! ! Save and print flows call this%gwt_ot_flow(icbcfl, ibudfl, icbcun) - ! + ! ! Save and print dependent variables call this%gwt_ot_dv(idvsave, idvprint, ipflag) - ! + ! ! Print budget summaries call this%gwt_ot_bdsummary(ibudfl, ipflag) ! ! -- Timing Output; if any dependendent variables or budgets ! are printed, then ipflag is set to 1. - if(ipflag == 1) call tdis_ot(this%iout) + if (ipflag == 1) call tdis_ot(this%iout) ! ! -- Write non-convergence message - if(this%icnvg == 0) then - write(this%iout, fmtnocnvg) kstp, kper - endif + if (this%icnvg == 0) then + write (this%iout, fmtnocnvg) kstp, kper + end if ! ! -- Return return end subroutine gwt_ot - + subroutine gwt_ot_obs(this) class(GwtModelType) :: this class(BndType), pointer :: packobj integer(I4B) :: ip - + ! -- Calculate and save observations call this%obs%obs_bd() call this%obs%obs_ot() - + ! -- Calculate and save package obserations do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_bd_obs() call packobj%bnd_ot_obs() end do - + end subroutine gwt_ot_obs - + subroutine gwt_ot_flow(this, icbcfl, ibudfl, icbcun) class(GwtModelType) :: this integer(I4B), intent(in) :: icbcfl @@ -827,20 +827,22 @@ subroutine gwt_ot_flow(this, icbcfl, ibudfl, icbcun) ! -- Save GWT flows call this%gwt_ot_flowja(this%nja, this%flowja, icbcfl, icbcun) - if(this%inmst > 0) call this%mst%mst_ot_flow(icbcfl, icbcun) - if(this%infmi > 0) call this%fmi%fmi_ot_flow(icbcfl, icbcun) - if(this%inssm > 0) call this%ssm%ssm_ot_flow(icbcfl=icbcfl, ibudfl=0, icbcun=icbcun) + if (this%inmst > 0) call this%mst%mst_ot_flow(icbcfl, icbcun) + if (this%infmi > 0) call this%fmi%fmi_ot_flow(icbcfl, icbcun) + if (this%inssm > 0) then + call this%ssm%ssm_ot_flow(icbcfl=icbcfl, ibudfl=0, icbcun=icbcun) + end if do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_model_flows(icbcfl=icbcfl, ibudfl=0, icbcun=icbcun) end do - + ! -- Save advanced package flows do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_package_flows(icbcfl=icbcfl, ibudfl=0) end do - if(this%inmvt > 0) then + if (this%inmvt > 0) then call this%mvt%mvt_ot_saveflow(icbcfl, ibudfl) end if @@ -848,23 +850,25 @@ subroutine gwt_ot_flow(this, icbcfl, ibudfl, icbcun) ! no need to print flowja ! no need to print mst ! no need to print fmi - if(this%inssm > 0) call this%ssm%ssm_ot_flow(icbcfl=icbcfl, ibudfl=ibudfl, icbcun=0) + if (this%inssm > 0) then + call this%ssm%ssm_ot_flow(icbcfl=icbcfl, ibudfl=ibudfl, icbcun=0) + end if do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_model_flows(icbcfl=icbcfl, ibudfl=ibudfl, icbcun=0) end do - + ! -- Print advanced package flows do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_package_flows(icbcfl=0, ibudfl=ibudfl) end do - if(this%inmvt > 0) then + if (this%inmvt > 0) then call this%mvt%mvt_ot_printflow(icbcfl, ibudfl) end if - + end subroutine gwt_ot_flow - + subroutine gwt_ot_flowja(this, nja, flowja, icbcfl, icbcun) ! ****************************************************************************** ! gwt_ot_flowja -- Write intercell flows @@ -874,8 +878,8 @@ subroutine gwt_ot_flowja(this, nja, flowja, icbcfl, icbcun) ! ------------------------------------------------------------------------------ ! -- dummy class(GwtModelType) :: this - integer(I4B),intent(in) :: nja - real(DP),dimension(nja),intent(in) :: flowja + integer(I4B), intent(in) :: nja + real(DP), dimension(nja), intent(in) :: flowja integer(I4B), intent(in) :: icbcfl integer(I4B), intent(in) :: icbcun ! -- local @@ -884,19 +888,19 @@ subroutine gwt_ot_flowja(this, nja, flowja, icbcfl, icbcun) ! ------------------------------------------------------------------------------ ! ! -- Set unit number for binary output - if(this%ipakcb < 0) then + if (this%ipakcb < 0) then ibinun = icbcun - elseif(this%ipakcb == 0) then + elseif (this%ipakcb == 0) then ibinun = 0 else ibinun = this%ipakcb - endif - if(icbcfl == 0) ibinun = 0 + end if + if (icbcfl == 0) ibinun = 0 ! ! -- Write the face flows if requested - if(ibinun /= 0) then + if (ibinun /= 0) then call this%dis%record_connection_array(flowja, ibinun, this%iout) - endif + end if ! ! -- Return return @@ -909,18 +913,18 @@ subroutine gwt_ot_dv(this, idvsave, idvprint, ipflag) integer(I4B), intent(inout) :: ipflag class(BndType), pointer :: packobj integer(I4B) :: ip - + ! -- Print advanced package dependent variables do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_dv(idvsave, idvprint) end do - + ! -- save head and print head call this%oc%oc_ot(ipflag) - + end subroutine gwt_ot_dv - + subroutine gwt_ot_bdsummary(this, ibudfl, ipflag) use TdisModule, only: kstp, kper, totim class(GwtModelType) :: this @@ -934,24 +938,24 @@ subroutine gwt_ot_bdsummary(this, ibudfl, ipflag) do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_ot_bdsummary(kstp, kper, this%iout, ibudfl) - enddo - + end do + ! -- mover budget summary - if(this%inmvt > 0) then + if (this%inmvt > 0) then call this%mvt%mvt_ot_bdsummary(ibudfl) end if - + ! -- model budget summary if (ibudfl /= 0) then ipflag = 1 call this%budget%budget_ot(kstp, kper, this%iout) end if - + ! -- Write to budget csv call this%budget%writecsv(totim) - + end subroutine gwt_ot_bdsummary - + subroutine gwt_da(this) ! ****************************************************************************** ! gwt_da -- Deallocate @@ -965,7 +969,7 @@ subroutine gwt_da(this) class(GwtModelType) :: this ! -- local integer(I4B) :: ip - class(BndType),pointer :: packobj + class(BndType), pointer :: packobj ! ------------------------------------------------------------------------------ ! ! -- Internal flow packages deallocate @@ -982,24 +986,24 @@ subroutine gwt_da(this) call this%obs%obs_da() ! ! -- Internal package objects - deallocate(this%dis) - deallocate(this%ic) - deallocate(this%fmi) - deallocate(this%adv) - deallocate(this%dsp) - deallocate(this%ssm) - deallocate(this%mst) - deallocate(this%mvt) - deallocate(this%budget) - deallocate(this%oc) - deallocate(this%obs) + deallocate (this%dis) + deallocate (this%ic) + deallocate (this%fmi) + deallocate (this%adv) + deallocate (this%dsp) + deallocate (this%ssm) + deallocate (this%mst) + deallocate (this%mvt) + deallocate (this%budget) + deallocate (this%oc) + deallocate (this%obs) ! ! -- Boundary packages do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) call packobj%bnd_da() - deallocate(packobj) - enddo + deallocate (packobj) + end do ! ! -- Scalars call mem_deallocate(this%inic) @@ -1030,7 +1034,7 @@ end subroutine gwt_da subroutine gwt_bdentry(this, budterm, budtxt, rowlabel) ! -- modules use ConstantsModule, only: LENBUDTXT - use TdisModule, only:delt + use TdisModule, only: delt ! -- dummy class(GwtModelType) :: this real(DP), dimension(:, :), intent(in) :: budterm @@ -1044,18 +1048,15 @@ subroutine gwt_bdentry(this, budterm, budtxt, rowlabel) return end subroutine gwt_bdentry - function gwt_get_iasym(this) result (iasym) -! ****************************************************************************** -! gwt_get_iasym -- return 1 if any package causes the matrix to be asymmetric. -! Otherwise return 0. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ + !> @brief return 1 if any package causes the matrix to be asymmetric. + !! Otherwise return 0. + !< + function gwt_get_iasym(this) result(iasym) class(GwtModelType) :: this ! -- local integer(I4B) :: iasym -! ------------------------------------------------------------------------------ + integer(I4B) :: ip + class(BndType), pointer :: packobj ! ! -- Start by setting iasym to zero iasym = 0 @@ -1063,7 +1064,18 @@ function gwt_get_iasym(this) result (iasym) ! -- ADV if (this%inadv > 0) then if (this%adv%iasym /= 0) iasym = 1 - endif + end if + ! + ! -- DSP + if (this%indsp > 0) then + if (this%dsp%ixt3d /= 0) iasym = 1 + end if + ! + ! -- Check for any packages that introduce matrix asymmetry + do ip = 1, this%bndlist%Count() + packobj => GetBndFromList(this%bndlist, ip) + if (packobj%iasym /= 0) iasym = 1 + end do ! ! -- return return @@ -1080,38 +1092,38 @@ subroutine allocate_scalars(this, modelname) use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwtModelType) :: this - character(len=*), intent(in) :: modelname + character(len=*), intent(in) :: modelname ! ------------------------------------------------------------------------------ ! ! -- allocate members from parent class call this%NumericalModelType%allocate_scalars(modelname) ! ! -- allocate members that are part of model class - call mem_allocate(this%inic , 'INIC', this%memoryPath) + call mem_allocate(this%inic, 'INIC', this%memoryPath) call mem_allocate(this%infmi, 'INFMI', this%memoryPath) call mem_allocate(this%inmvt, 'INMVT', this%memoryPath) call mem_allocate(this%inmst, 'INMST', this%memoryPath) call mem_allocate(this%inadv, 'INADV', this%memoryPath) call mem_allocate(this%indsp, 'INDSP', this%memoryPath) call mem_allocate(this%inssm, 'INSSM', this%memoryPath) - call mem_allocate(this%inoc, 'INOC ', this%memoryPath) + call mem_allocate(this%inoc, 'INOC ', this%memoryPath) call mem_allocate(this%inobs, 'INOBS', this%memoryPath) ! - this%inic = 0 + this%inic = 0 this%infmi = 0 this%inmvt = 0 this%inmst = 0 this%inadv = 0 this%indsp = 0 this%inssm = 0 - this%inoc = 0 + this%inoc = 0 this%inobs = 0 ! ! -- return return end subroutine allocate_scalars - subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & + subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & iout) ! ****************************************************************************** ! package_create -- Create boundary condition packages for this model @@ -1132,13 +1144,13 @@ subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & use ApiModule, only: api_create ! -- dummy class(GwtModelType) :: this - character(len=*),intent(in) :: filtyp + character(len=*), intent(in) :: filtyp character(len=LINELENGTH) :: errmsg - integer(I4B),intent(in) :: ipakid - integer(I4B),intent(in) :: ipaknum + integer(I4B), intent(in) :: ipakid + integer(I4B), intent(in) :: ipaknum character(len=*), intent(in) :: pakname - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout ! -- local class(BndType), pointer :: packobj class(BndType), pointer :: packobj2 @@ -1146,44 +1158,44 @@ subroutine package_create(this, filtyp, ipakid, ipaknum, pakname, inunit, & ! ------------------------------------------------------------------------------ ! ! -- This part creates the package object - select case(filtyp) - case('CNC6') + select case (filtyp) + case ('CNC6') call cnc_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('SRC6') + case ('SRC6') call src_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) - case('LKT6') - call lkt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & + case ('LKT6') + call lkt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & pakname, this%fmi) - case('SFT6') - call sft_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & + case ('SFT6') + call sft_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & pakname, this%fmi) - case('MWT6') - call mwt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & + case ('MWT6') + call mwt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & pakname, this%fmi) - case('UZT6') - call uzt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & + case ('UZT6') + call uzt_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & pakname, this%fmi) - case('IST6') - call ist_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & + case ('IST6') + call ist_create(packobj, ipakid, ipaknum, inunit, iout, this%name, & pakname, this%fmi, this%mst) - case('API6') + case ('API6') call api_create(packobj, ipakid, ipaknum, inunit, iout, this%name, pakname) case default - write(errmsg, *) 'Invalid package type: ', filtyp + write (errmsg, *) 'Invalid package type: ', filtyp call store_error(errmsg, terminate=.TRUE.) end select ! ! -- Packages is the bndlist that is associated with the parent model ! -- The following statement puts a pointer to this package in the ipakid ! -- position of packages. - do ip = 1, this%bndlist%Count() - packobj2 => GetBndFromList(this%bndlist, ip) - if(packobj2%packName == pakname) then - write(errmsg, '(a,a)') 'Cannot create package. Package name ' // & - 'already exists: ', trim(pakname) - call store_error(errmsg, terminate=.TRUE.) - endif - enddo + do ip = 1, this%bndlist%Count() + packobj2 => GetBndFromList(this%bndlist, ip) + if (packobj2%packName == pakname) then + write (errmsg, '(a,a)') 'Cannot create package. Package name '// & + 'already exists: ', trim(pakname) + call store_error(errmsg, terminate=.TRUE.) + end if + end do call AddBndToList(this%bndlist, packobj) ! ! -- return @@ -1198,9 +1210,9 @@ subroutine ftype_check(this, namefile_obj, indis) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, count_errors - use NameFileModule, only: NameFileType + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error, count_errors + use NameFileModule, only: NameFileType ! -- dummy class(GwtModelType) :: this type(NameFileType), intent(in) :: namefile_obj @@ -1208,49 +1220,50 @@ subroutine ftype_check(this, namefile_obj, indis) ! -- local character(len=LINELENGTH) :: errmsg integer(I4B) :: i, iu - character(len=LENFTYPE), dimension(10) :: nodupftype = & - (/'DIS6 ', 'DISU6', 'DISV6', 'IC6 ', 'MST6 ', 'ADV6 ', 'DSP6 ', & - 'SSM6 ', 'OC6 ', 'OBS6 '/) + character(len=LENFTYPE), dimension(10) :: nodupftype = & + &(/'DIS6 ', 'DISU6', 'DISV6', 'IC6 ', 'MST6 ', 'ADV6 ', 'DSP6 ', & + &'SSM6 ', 'OC6 ', 'OBS6 '/) ! ------------------------------------------------------------------------------ ! ! -- Check for IC6, DIS(u), and MST. Stop if not present. - if(this%inic == 0) then - write(errmsg, '(1x,a)') 'ERROR. INITIAL CONDITIONS (IC6) PACKAGE NOT SPECIFIED.' + if (this%inic == 0) then + write (errmsg, '(1x,a)') & + 'ERROR. INITIAL CONDITIONS (IC6) PACKAGE NOT SPECIFIED.' call store_error(errmsg) - endif - if(indis == 0) then - write(errmsg, '(1x,a)') & + end if + if (indis == 0) then + write (errmsg, '(1x,a)') & 'ERROR. DISCRETIZATION (DIS6 or DISU6) PACKAGE NOT SPECIFIED.' call store_error(errmsg) - endif - if(this%inmst == 0) then - write(errmsg, '(1x,a)') 'ERROR. MASS STORAGE AND TRANSFER (MST6) & + end if + if (this%inmst == 0) then + write (errmsg, '(1x,a)') 'ERROR. MASS STORAGE AND TRANSFER (MST6) & &PACKAGE NOT SPECIFIED.' call store_error(errmsg) - endif - if(count_errors() > 0) then - write(errmsg,'(1x,a)') 'ERROR. REQUIRED PACKAGE(S) NOT SPECIFIED.' + end if + if (count_errors() > 0) then + write (errmsg, '(1x,a)') 'ERROR. REQUIRED PACKAGE(S) NOT SPECIFIED.' call store_error(errmsg) - endif + end if ! ! -- Check to make sure that some GWT packages are not specified more ! than once do i = 1, size(nodupftype) call namefile_obj%get_unitnumber(trim(nodupftype(i)), iu, 0) if (iu > 0) then - write(errmsg,'(1x, a, a, a)') & - 'DUPLICATE ENTRIES FOR FTYPE ', trim(nodupftype(i)), & + write (errmsg, '(1x, a, a, a)') & + 'DUPLICATE ENTRIES FOR FTYPE ', trim(nodupftype(i)), & ' NOT ALLOWED FOR GWT MODEL.' call store_error(errmsg) - endif - enddo + end if + end do ! ! -- Stop if errors - if(count_errors() > 0) then - write(errmsg, '(a, a)') 'ERROR OCCURRED WHILE READING FILE: ', & + if (count_errors() > 0) then + write (errmsg, '(a, a)') 'ERROR OCCURRED WHILE READING FILE: ', & trim(namefile_obj%filename) call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- return return @@ -1258,16 +1271,16 @@ end subroutine ftype_check !> @brief Cast to GwtModelType function CastAsGwtModel(model) result(gwtmodel) - class(*), pointer :: model !< The object to be cast + class(*), pointer :: model !< The object to be cast class(GwtModelType), pointer :: gwtmodel !< The GWT model - + gwtmodel => null() if (.not. associated(model)) return - select type(model) + select type (model) type is (GwtModelType) gwtmodel => model end select - + end function CastAsGwtModel - + end module GwtModule diff --git a/src/Model/GroundWaterTransport/gwt1adv1.f90 b/src/Model/GroundWaterTransport/gwt1adv1.f90 index 9ade154fac6..3612b99f2dd 100644 --- a/src/Model/GroundWaterTransport/gwt1adv1.f90 +++ b/src/Model/GroundWaterTransport/gwt1adv1.f90 @@ -1,11 +1,11 @@ module GwtAdvModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: DONE, DZERO, DHALF, DTWO + + use KindModule, only: DP, I4B + use ConstantsModule, only: DONE, DZERO, DHALF, DTWO use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use GwtFmiModule, only: GwtFmiType - use GwtAdvOptionsModule, only: GwtAdvOptionsType + use BaseDisModule, only: DisBaseType + use GwtFmiModule, only: GwtFmiType + use GwtAdvOptionsModule, only: GwtAdvOptionsType implicit none private @@ -13,29 +13,29 @@ module GwtAdvModule public :: adv_cr type, extends(NumericalPackageType) :: GwtAdvType - - integer(I4B), pointer :: iadvwt => null() !< advection scheme (0 up, 1 central, 2 tvd) - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object - + + integer(I4B), pointer :: iadvwt => null() !< advection scheme (0 up, 1 central, 2 tvd) + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object + contains - + procedure :: adv_df procedure :: adv_ar procedure :: adv_fc procedure :: adv_cq procedure :: adv_da - + procedure :: allocate_scalars procedure, private :: read_options procedure, private :: advqtvd procedure, private :: advtvd_bd procedure :: adv_weight procedure :: advtvd - + end type GwtAdvType - - contains + +contains subroutine adv_cr(advobj, name_model, inunit, iout, fmi) ! ****************************************************************************** @@ -53,7 +53,7 @@ subroutine adv_cr(advobj, name_model, inunit, iout, fmi) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(advobj) + allocate (advobj) ! ! -- create name and memory path call advobj%set_names(1, name_model, 'ADV', 'ADV') @@ -74,19 +74,19 @@ subroutine adv_df(this, adv_options) class(GwtAdvType) :: this type(GwtAdvOptionsType), optional, intent(in) :: adv_options !< the optional options, for when not constructing from file ! local - character(len=*), parameter :: fmtadv = & - "(1x,/1x,'ADV-- ADVECTION PACKAGE, VERSION 1, 8/25/2017', & + character(len=*), parameter :: fmtadv = & + "(1x,/1x,'ADV-- ADVECTION PACKAGE, VERSION 1, 8/25/2017', & &' INPUT READ FROM UNIT ', i0, //)" ! ! -- Read or set advection options - if (.not. present(adv_options)) then + if (.not. present(adv_options)) then ! ! -- Initialize block parser (adv has no define, so it's ! not done until here) call this%parser%Initialize(this%inunit, this%iout) ! ! --print a message identifying the advection package. - write(this%iout, fmtadv) this%inunit + write (this%iout, fmtadv) this%inunit ! ! --read options from file call this%read_options() @@ -112,14 +112,11 @@ subroutine adv_ar(this, dis, ibound) integer(I4B), dimension(:), pointer, contiguous :: ibound ! -- local ! -- formats -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! ! -- adv pointers to arguments that were passed in - this%dis => dis - this%ibound => ibound - ! - ! -- Allocate arrays (not needed for adv) - !call this%allocate_arrays(dis%nodes) + this%dis => dis + this%ibound => ibound ! ! -- Return return @@ -145,7 +142,7 @@ subroutine adv_fc(this, nodes, amatsln, idxglo, cnew, rhs) real(DP) :: omega, qnm ! ------------------------------------------------------------------------------ ! - ! -- Calculate advection terms and add to solution rhs and hcof. qnm + ! -- Calculate advection terms and add to solution rhs and hcof. qnm ! is the volumetric flow rate and has dimensions of L^/T. do n = 1, nodes if (this%ibound(n) == 0) cycle @@ -158,21 +155,21 @@ subroutine adv_fc(this, nodes, amatsln, idxglo, cnew, rhs) omega = this%adv_weight(this%iadvwt, ipos, n, m, qnm) amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + qnm * (DONE - omega) amatsln(idxglo(idiag)) = amatsln(idxglo(idiag)) + qnm * omega - enddo - enddo + end do + end do ! ! -- TVD if (this%iadvwt == 2) then do n = 1, nodes - if(this%ibound(n) == 0) cycle + if (this%ibound(n) == 0) cycle call this%advtvd(n, cnew, rhs) - enddo - endif + end do + end if ! ! -- Return return end subroutine adv_fc - + subroutine advtvd(this, n, cnew, rhs) ! ****************************************************************************** ! advtvd -- Calculate TVD @@ -181,7 +178,7 @@ subroutine advtvd(this, n, cnew, rhs) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - ! -- dummy + ! -- dummy class(GwtAdvType) :: this integer(I4B), intent(in) :: n real(DP), dimension(:), intent(in) :: cnew @@ -199,8 +196,8 @@ subroutine advtvd(this, n, cnew, rhs) qtvd = this%advqtvd(n, m, ipos, cnew) rhs(n) = rhs(n) - qtvd rhs(m) = rhs(m) + qtvd - endif - enddo + end if + end do ! ! -- Return return @@ -217,7 +214,7 @@ function advqtvd(this, n, m, iposnm, cnew) result(qtvd) use ConstantsModule, only: DPREC ! -- return real(DP) :: qtvd - ! -- dummy + ! -- dummy class(GwtAdvType) :: this integer(I4B), intent(in) :: n integer(I4B), intent(in) :: m @@ -242,7 +239,7 @@ function advqtvd(this, n, m, iposnm, cnew) result(qtvd) else iup = n idn = m - endif + end if elupdn = this%dis%con%cl1(isympos) + this%dis%con%cl2(isympos) ! ! -- Find second node upstream to iup @@ -257,22 +254,22 @@ function advqtvd(this, n, m, iposnm, cnew) result(qtvd) qmax = qupj i2up = j elup2up = this%dis%con%cl1(isympos) + this%dis%con%cl2(isympos) - endif - enddo + end if + end do ! ! -- Calculate flux limiting term if (i2up > 0) then smooth = DZERO cdiff = ABS(cnew(idn) - cnew(iup)) if (cdiff > DPREC) then - smooth = (cnew(iup) - cnew(i2up)) / elup2up * & + smooth = (cnew(iup) - cnew(i2up)) / elup2up * & elupdn / (cnew(idn) - cnew(iup)) - endif + end if if (smooth > DZERO) then alimiter = DTWO * smooth / (DONE + smooth) qtvd = DHALF * alimiter * qnm * (cnew(idn) - cnew(iup)) - endif - endif + end if + end if ! ! -- Return return @@ -307,10 +304,10 @@ subroutine adv_cq(this, cnew, flowja) if (this%ibound(m) == 0) cycle qnm = this%fmi%gwfflowja(ipos) omega = this%adv_weight(this%iadvwt, ipos, n, m, qnm) - flowja(ipos) = flowja(ipos) + qnm * omega * cnew(n) + & - qnm * (DONE - omega) * cnew(m) - enddo - enddo + flowja(ipos) = flowja(ipos) + qnm * omega * cnew(n) + & + qnm * (DONE - omega) * cnew(m) + end do + end do ! ! -- TVD if (this%iadvwt == 2) call this%advtvd_bd(cnew, flowja) @@ -318,7 +315,7 @@ subroutine adv_cq(this, cnew, flowja) ! -- Return return end subroutine adv_cq - + subroutine advtvd_bd(this, cnew, flowja) ! ****************************************************************************** ! advtvd_bd -- Add TVD contribution to flowja @@ -327,7 +324,7 @@ subroutine advtvd_bd(this, cnew, flowja) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - ! -- dummy + ! -- dummy class(GwtAdvType) :: this real(DP), dimension(:), intent(in) :: cnew real(DP), dimension(:), intent(inout) :: flowja @@ -345,9 +342,9 @@ subroutine advtvd_bd(this, cnew, flowja) qnm = this%fmi%gwfflowja(ipos) qtvd = this%advqtvd(n, m, ipos, cnew) flowja(ipos) = flowja(ipos) + qtvd - endif - enddo - enddo + end if + end do + end do ! ! -- Return return @@ -367,8 +364,8 @@ subroutine adv_da(this) ! ------------------------------------------------------------------------------ ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then - endif + if (this%inunit > 0) then + end if ! ! -- nullify pointers this%ibound => null() @@ -421,8 +418,8 @@ subroutine read_options(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error ! -- dummy class(GwtAdvType) :: this ! -- local @@ -430,8 +427,8 @@ subroutine read_options(this) integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*), parameter :: fmtiadvwt = & - "(4x,'ADVECTION WEIGHTING SCHEME HAS BEEN SET TO: ', a)" + character(len=*), parameter :: fmtiadvwt = & + &"(4x,'ADVECTION WEIGHTING SCHEME HAS BEEN SET TO: ', a)" ! ------------------------------------------------------------------------------ ! ! -- get options block @@ -440,46 +437,40 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING ADVECTION OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING ADVECTION OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SCHEME') - call this%parser%GetStringCaps(keyword) - select case (keyword) - case('UPSTREAM') - this%iadvwt = 0 - this%iasym = 1 - write(this%iout, fmtiadvwt) 'UPSTREAM' - case ('CENTRAL') - this%iadvwt = 1 - write(this%iout, fmtiadvwt) 'CENTRAL' - case('TVD') - this%iadvwt = 2 - write(this%iout, fmtiadvwt) 'TVD' - case default - write(errmsg,'(4x, a, a)') & - 'ERROR. UNKNOWN SCHEME: ', trim(keyword) - call store_error(errmsg) - write(errmsg,'(4x, a, a)') & - 'SCHEME MUST BE "UPSTREAM", "CENTRAL" OR "TVD"' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select + case ('SCHEME') + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('UPSTREAM') + this%iadvwt = 0 + write (this%iout, fmtiadvwt) 'UPSTREAM' + case ('CENTRAL') + this%iadvwt = 1 + write (this%iout, fmtiadvwt) 'CENTRAL' + case ('TVD') + this%iadvwt = 2 + write (this%iout, fmtiadvwt) 'TVD' case default - write(errmsg,'(4x,a,a)')'Unknown ADVECTION option: ', & - trim(keyword) - call store_error(errmsg, terminate=.TRUE.) + write (errmsg, '(4x, a, a)') & + 'ERROR. UNKNOWN SCHEME: ', trim(keyword) + call store_error(errmsg) + write (errmsg, '(4x, a, a)') & + 'SCHEME MUST BE "UPSTREAM", "CENTRAL" OR "TVD"' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end select + case default + write (errmsg, '(4x,a,a)') 'Unknown ADVECTION option: ', & + trim(keyword) + call store_error(errmsg, terminate=.TRUE.) end select end do - if (this%iadvwt /= 1) then - this%iasym = 1 - write(this%iout,'(1x,a)')'SELECTED ADVECTION SCHEME RESULTS IN AN & - &ASYMMETRIC MATRIX.' - endif - write(this%iout,'(1x,a)')'END OF ADVECTION OPTIONS' + write (this%iout, '(1x,a)') 'END OF ADVECTION OPTIONS' end if ! ! -- Return @@ -505,8 +496,8 @@ function adv_weight(this, iadvwt, ipos, n, m, qnm) result(omega) ! -- local real(DP) :: lnm, lmn ! ------------------------------------------------------------------------------ - select case(iadvwt) - case(1) + select case (iadvwt) + case (1) ! -- calculate weight based on distances between nodes and the shared ! face of the connection if (this%dis%con%ihc(this%dis%con%jas(ipos)) == 0) then @@ -517,21 +508,19 @@ function adv_weight(this, iadvwt, ipos, n, m, qnm) result(omega) ! -- horizontal connection lnm = this%dis%con%cl1(this%dis%con%jas(ipos)) lmn = this%dis%con%cl2(this%dis%con%jas(ipos)) - endif + end if omega = lmn / (lnm + lmn) - case(0, 2) + case (0, 2) ! -- use upstream weighting for upstream and tvd schemes - if(qnm > DZERO) then + if (qnm > DZERO) then omega = DZERO else omega = DONE - endif + end if end select ! ! -- return return end function adv_weight - - -end module GwtAdvModule \ No newline at end of file +end module GwtAdvModule diff --git a/src/Model/GroundWaterTransport/gwt1apt1.f90 b/src/Model/GroundWaterTransport/gwt1apt1.f90 index f51ac8f02fb..a9db2eb3a1e 100644 --- a/src/Model/GroundWaterTransport/gwt1apt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1apt1.f90 @@ -1,7 +1,7 @@ ! -- Advanced Package Transport Module ! -- This module contains most of the routines for simulating transport -! -- through the advanced packages. -! -- Future work: +! -- through the advanced packages. +! -- Future work: ! * support decay, sorption ! * dispersion in SFT and UZT? ! @@ -22,7 +22,7 @@ ! EXT-INFLOW idxbudiflw EXT-INFLOW q * ciflw ! WITHDRAWAL idxbudwdrl WITHDRAWAL q * cfeat ! EXT-OUTFLOW idxbudoutf EXT-OUTFLOW q * cfeat - + ! -- terms from a flow file that should be skipped ! CONSTANT none none none ! AUXILIARY none none none @@ -36,84 +36,88 @@ module GwtAptModule use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: DZERO, DONE, DEP20, LENFTYPE, LINELENGTH, & - LENBOUNDNAME, LENPACKAGENAME, NAMEDBOUNDFLAG, & - DNODATA, TABLEFT, TABCENTER, TABRIGHT, & - TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & + use ConstantsModule, only: DZERO, DONE, DEP20, LENFTYPE, LINELENGTH, & + LENBOUNDNAME, LENPACKAGENAME, NAMEDBOUNDFLAG, & + DNODATA, TABLEFT, TABCENTER, TABRIGHT, & + TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & LENAUXNAME use SimModule, only: store_error, store_error_unit, count_errors use SimVariablesModule, only: errmsg use BndModule, only: BndType use GwtFmiModule, only: GwtFmiType use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr + use BudgetTermModule, only: BudgetTermType use TableModule, only: TableType, table_cr use ObserveModule, only: ObserveType use InputOutputModule, only: extract_idnum_or_bndname use BaseDisModule, only: DisBaseType - + implicit none - - public GwtAptType, apt_process_obsID - + + public :: GwtAptType + public :: apt_process_obsID + public :: apt_process_obsID12 + character(len=LENFTYPE) :: ftype = 'APT' - character(len=16) :: text = ' APT' - + character(len=16) :: text = ' APT' + type, extends(BndType) :: GwtAptType - - character(len=LENPACKAGENAME) :: flowpackagename = '' !< name of corresponding flow package - character(len=8), dimension(:), pointer, contiguous :: status => null() !< active, inactive, constant - character(len=LENAUXNAME) :: cauxfpconc = '' !< name of aux column in flow package auxvar array for concentration - integer(I4B), pointer :: iauxfpconc => null() !< column in flow package bound array to insert concs - integer(I4B), pointer :: imatrows => null() !< if active, add new rows to matrix - integer(I4B), pointer :: iprconc => null() !< print conc to listing file - integer(I4B), pointer :: iconcout => null() !< unit number for conc output file - integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file - integer(I4B), pointer :: ncv => null() !< number of control volumes - integer(I4B), pointer :: igwfaptpak => null() !< package number of corresponding this package - real(DP), dimension(:), pointer, contiguous :: strt => null() !< starting feature concentration - integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !< map position in global rhs and x array of pack entry - integer(I4B), dimension(:), pointer, contiguous :: idxpakdiag => null() !< map diag position of feature in global amat - integer(I4B), dimension(:), pointer, contiguous :: idxdglo => null() !< map position in global array of package diagonal row entries - integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !< map position in global array of package off diagonal row entries - integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !< map position in global array of package diagonal entries to model rows - integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !< map position in global array of package off diagonal entries to model rows - integer(I4B), dimension(:), pointer, contiguous :: idxfjfdglo => null() !< map diagonal feature to feature in global amat - integer(I4B), dimension(:), pointer, contiguous :: idxfjfoffdglo => null() !< map off diagonal feature to feature in global amat - integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< package ibound - real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !< feature concentration for current time step - real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !< feature concentration from previous time step - real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< temporary storage array - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: featname => null() - real(DP), dimension(:), pointer, contiguous :: concfeat => null() !< concentration of the feature - real(DP), dimension(:,:), pointer, contiguous :: lauxvar => null() !< auxiliary variable - type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object - real(DP), dimension(:), pointer, contiguous :: qsto => null() !< mass flux due to storage change - real(DP), dimension(:), pointer, contiguous :: ccterm => null() !< mass flux required to maintain constant concentration - integer(I4B), pointer :: idxbudfjf => null() !< index of flow ja face in flowbudptr - integer(I4B), pointer :: idxbudgwf => null() !< index of gwf terms in flowbudptr - integer(I4B), pointer :: idxbudsto => null() !< index of storage terms in flowbudptr - integer(I4B), pointer :: idxbudtmvr => null() !< index of to mover terms in flowbudptr - integer(I4B), pointer :: idxbudfmvr => null() !< index of from mover terms in flowbudptr - integer(I4B), pointer :: idxbudaux => null() !< index of auxiliary terms in flowbudptr - integer(I4B), dimension(:), pointer, contiguous :: idxbudssm => null() !< flag that flowbudptr%buditem is a general solute source/sink - integer(I4B), pointer :: nconcbudssm => null() !< number of concbudssm terms (columns) - real(DP), dimension(:, : ), pointer, contiguous :: concbudssm => null() !< user specified concentrations for flow terms - real(DP), dimension(:), pointer, contiguous :: qmfrommvr => null() !< a mass flow coming from the mover that needs to be added + + character(len=LENPACKAGENAME) :: flowpackagename = '' !< name of corresponding flow package + character(len=8), & + dimension(:), pointer, contiguous :: status => null() !< active, inactive, constant + character(len=LENAUXNAME) :: cauxfpconc = '' !< name of aux column in flow package auxvar array for concentration + integer(I4B), pointer :: iauxfpconc => null() !< column in flow package bound array to insert concs + integer(I4B), pointer :: imatrows => null() !< if active, add new rows to matrix + integer(I4B), pointer :: iprconc => null() !< print conc to listing file + integer(I4B), pointer :: iconcout => null() !< unit number for conc output file + integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + integer(I4B), pointer :: ncv => null() !< number of control volumes + integer(I4B), pointer :: igwfaptpak => null() !< package number of corresponding this package + real(DP), dimension(:), pointer, contiguous :: strt => null() !< starting feature concentration + integer(I4B), dimension(:), pointer, contiguous :: idxlocnode => null() !< map position in global rhs and x array of pack entry + integer(I4B), dimension(:), pointer, contiguous :: idxpakdiag => null() !< map diag position of feature in global amat + integer(I4B), dimension(:), pointer, contiguous :: idxdglo => null() !< map position in global array of package diagonal row entries + integer(I4B), dimension(:), pointer, contiguous :: idxoffdglo => null() !< map position in global array of package off diagonal row entries + integer(I4B), dimension(:), pointer, contiguous :: idxsymdglo => null() !< map position in global array of package diagonal entries to model rows + integer(I4B), dimension(:), pointer, contiguous :: idxsymoffdglo => null() !< map position in global array of package off diagonal entries to model rows + integer(I4B), dimension(:), pointer, contiguous :: idxfjfdglo => null() !< map diagonal feature to feature in global amat + integer(I4B), dimension(:), pointer, contiguous :: idxfjfoffdglo => null() !< map off diagonal feature to feature in global amat + integer(I4B), dimension(:), pointer, contiguous :: iboundpak => null() !< package ibound + real(DP), dimension(:), pointer, contiguous :: xnewpak => null() !< feature concentration for current time step + real(DP), dimension(:), pointer, contiguous :: xoldpak => null() !< feature concentration from previous time step + real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< temporary storage array + character(len=LENBOUNDNAME), & + dimension(:), pointer, contiguous :: featname => null() + real(DP), dimension(:), pointer, contiguous :: concfeat => null() !< concentration of the feature + real(DP), dimension(:, :), pointer, contiguous :: lauxvar => null() !< auxiliary variable + type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object + real(DP), dimension(:), pointer, contiguous :: qsto => null() !< mass flux due to storage change + real(DP), dimension(:), pointer, contiguous :: ccterm => null() !< mass flux required to maintain constant concentration + integer(I4B), pointer :: idxbudfjf => null() !< index of flow ja face in flowbudptr + integer(I4B), pointer :: idxbudgwf => null() !< index of gwf terms in flowbudptr + integer(I4B), pointer :: idxbudsto => null() !< index of storage terms in flowbudptr + integer(I4B), pointer :: idxbudtmvr => null() !< index of to mover terms in flowbudptr + integer(I4B), pointer :: idxbudfmvr => null() !< index of from mover terms in flowbudptr + integer(I4B), pointer :: idxbudaux => null() !< index of auxiliary terms in flowbudptr + integer(I4B), dimension(:), pointer, contiguous :: idxbudssm => null() !< flag that flowbudptr%buditem is a general solute source/sink + integer(I4B), pointer :: nconcbudssm => null() !< number of concbudssm terms (columns) + real(DP), dimension(:, :), pointer, contiguous :: concbudssm => null() !< user specified concentrations for flow terms + real(DP), dimension(:), pointer, contiguous :: qmfrommvr => null() !< a mass flow coming from the mover that needs to be added ! ! -- pointer to flow package boundary - type(BndType), pointer :: flowpackagebnd => null() + type(BndType), pointer :: flowpackagebnd => null() ! ! -- budget objects - type(BudgetObjectType), pointer :: budobj => null() !< apt solute budget object - type(BudgetObjectType), pointer :: flowbudptr => null() !< GWF flow budget object + type(BudgetObjectType), pointer :: budobj => null() !< apt solute budget object + type(BudgetObjectType), pointer :: flowbudptr => null() !< GWF flow budget object ! ! -- table objects type(TableType), pointer :: dvtab => null() - + contains - + procedure :: set_pointers => apt_set_pointers procedure :: bnd_ac => apt_ac procedure :: bnd_mc => apt_mc @@ -136,6 +140,7 @@ module GwtAptModule procedure :: bnd_ot_bdsummary => apt_ot_bdsummary procedure :: bnd_da => apt_da procedure :: allocate_scalars + procedure :: apt_allocate_index_arrays procedure :: apt_allocate_arrays procedure :: find_apt_package procedure :: apt_solve @@ -149,7 +154,11 @@ module GwtAptModule procedure :: bnd_obs_supported => apt_obs_supported procedure :: bnd_df_obs => apt_df_obs procedure :: pak_df_obs + procedure :: pak_rp_obs procedure :: bnd_rp_obs => apt_rp_obs + procedure :: rp_obs_byfeature + procedure :: rp_obs_budterm + procedure :: rp_obs_flowjaface procedure :: bnd_bd_obs => apt_bd_obs procedure :: pak_bd_obs procedure :: get_volumes @@ -163,11 +172,11 @@ module GwtAptModule procedure, private :: apt_fjf_term procedure, private :: apt_copy2flowp procedure, private :: apt_setup_tableobj - + end type GwtAptType - contains - +contains + subroutine apt_ac(this, moffset, sparse) ! ****************************************************************************** ! bnd_ac -- Add package connection to matrix @@ -178,7 +187,7 @@ subroutine apt_ac(this, moffset, sparse) use MemoryManagerModule, only: mem_setptr use SparseModule, only: sparsematrix ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this integer(I4B), intent(in) :: moffset type(sparsematrix), intent(inout) :: sparse ! -- local @@ -232,7 +241,7 @@ subroutine apt_mc(this, moffset, iasln, jasln) ! ------------------------------------------------------------------------------ use SparseModule, only: sparsematrix ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this integer(I4B), intent(in) :: moffset integer(I4B), dimension(:), intent(in) :: iasln integer(I4B), dimension(:), intent(in) :: jasln @@ -243,21 +252,11 @@ subroutine apt_mc(this, moffset, iasln, jasln) ! ------------------------------------------------------------------------------ ! ! + ! -- allocate memory for index arrays + call this%apt_allocate_index_arrays() + ! + ! -- store index positions if (this%imatrows /= 0) then - ! - ! -- allocate pointers to global matrix - allocate(this%idxlocnode(this%ncv)) - allocate(this%idxpakdiag(this%ncv)) - allocate(this%idxdglo(this%maxbound)) - allocate(this%idxoffdglo(this%maxbound)) - allocate(this%idxsymdglo(this%maxbound)) - allocate(this%idxsymoffdglo(this%maxbound)) - n = 0 - if (this%idxbudfjf /= 0) then - n = this%flowbudptr%budterm(this%idxbudfjf)%maxlist - end if - allocate(this%idxfjfdglo(n)) - allocate(this%idxfjfoffdglo(n)) ! ! -- Find the position of each connection in the global ia, ja structure ! and store them in idxglo. idxglo allows this model to insert or @@ -274,12 +273,12 @@ subroutine apt_mc(this, moffset, iasln, jasln) iglo = moffset + this%dis%nodes + this%ioffset + n jglo = j + moffset searchloop: do jj = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(jj)) then + if (jglo == jasln(jj)) then this%idxdglo(ipos) = iasln(iglo) this%idxoffdglo(ipos) = jj exit searchloop - endif - enddo searchloop + end if + end do searchloop end do ! ! -- apt contributions to gwf portion of global matrix @@ -289,12 +288,12 @@ subroutine apt_mc(this, moffset, iasln, jasln) iglo = j + moffset jglo = moffset + this%dis%nodes + this%ioffset + n symsearchloop: do jj = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(jj)) then + if (jglo == jasln(jj)) then this%idxsymdglo(ipos) = iasln(iglo) this%idxsymoffdglo(ipos) = jj exit symsearchloop - endif - enddo symsearchloop + end if + end do symsearchloop end do ! ! -- apt-apt contributions to gwf portion of global matrix @@ -305,24 +304,15 @@ subroutine apt_mc(this, moffset, iasln, jasln) iglo = moffset + this%dis%nodes + this%ioffset + n jglo = moffset + this%dis%nodes + this%ioffset + j fjfsearchloop: do jj = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(jj)) then + if (jglo == jasln(jj)) then this%idxfjfdglo(ipos) = iasln(iglo) this%idxfjfoffdglo(ipos) = jj exit fjfsearchloop - endif - enddo fjfsearchloop + end if + end do fjfsearchloop end do end if - else - allocate(this%idxlocnode(0)) - allocate(this%idxpakdiag(0)) - allocate(this%idxdglo(0)) - allocate(this%idxoffdglo(0)) - allocate(this%idxsymdglo(0)) - allocate(this%idxsymoffdglo(0)) - allocate(this%idxfjfdglo(0)) - allocate(this%idxfjfoffdglo(0)) - endif + end if ! ! -- return return @@ -342,16 +332,16 @@ subroutine apt_ar(this) integer(I4B) :: j logical :: found ! -- formats - character(len=*), parameter :: fmtapt = & - "(1x,/1x,'APT -- ADVANCED PACKAGE TRANSPORT, VERSION 1, 3/5/2020', & + character(len=*), parameter :: fmtapt = & + "(1x,/1x,'APT -- ADVANCED PACKAGE TRANSPORT, VERSION 1, 3/5/2020', & &' INPUT READ FROM UNIT ', i0, //)" ! ------------------------------------------------------------------------------ ! - ! -- Get obs setup + ! -- Get obs setup call this%obs%obs_ar() ! ! --print a message identifying the apt package. - write(this%iout, fmtapt) this%inunit + write (this%iout, fmtapt) this%inunit ! ! -- Allocate arrays call this%apt_allocate_arrays() @@ -359,7 +349,7 @@ subroutine apt_ar(this) ! -- read optional initial package parameters call this%read_initial_attr() ! - ! -- Find the package index in the GWF model or GWF budget file + ! -- Find the package index in the GWF model or GWF budget file ! for the corresponding apt flow package call this%fmi%get_package_index(this%flowpackagename, this%igwfaptpak) ! @@ -371,7 +361,7 @@ subroutine apt_ar(this) this%fmi%datp(this%igwfaptpak)%qmfrommvr => this%qmfrommvr ! ! -- If there is an associated flow package and the user wishes to put - ! simulated concentrations into a aux variable column, then find + ! simulated concentrations into a aux variable column, then find ! the column number. if (associated(this%flowpackagebnd)) then if (this%cauxfpconc /= '') then @@ -384,9 +374,9 @@ subroutine apt_ar(this) end if end do if (this%iauxfpconc == 0) then - errmsg = 'COULD NOT FIND AUXILIARY VARIABLE ' // & - trim(adjustl(this%cauxfpconc)) // ' IN FLOW PACKAGE ' // & - trim(adjustl(this%flowpackagename)) + errmsg = 'COULD NOT FIND AUXILIARY VARIABLE '// & + trim(adjustl(this%cauxfpconc))//' IN FLOW PACKAGE '// & + trim(adjustl(this%flowpackagename)) call store_error(errmsg) call this%parser%StoreErrorUnit() else @@ -422,10 +412,10 @@ subroutine apt_rp(this) integer(I4B) :: itemno integer(I4B) :: igwfnode ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Error. Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" ! ------------------------------------------------------------------------------ ! ! -- set nbound to maxbound @@ -433,15 +423,16 @@ subroutine apt_rp(this) ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -454,23 +445,23 @@ subroutine apt_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg) call this%parser%StoreErrorUnit() end if - endif + end if end if ! ! -- Read data if ionper == kper - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- setup table for period data if (this%iprpak /= 0) then ! ! -- reset the input table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper call table_cr(this%inputtab, this%packName, title) call this%inputtab%table_df(1, 4, this%iout, finalize=.FALSE.) text = 'NUMBER' @@ -478,7 +469,7 @@ subroutine apt_rp(this) text = 'KEYWORD' call this%inputtab%initialize_column(text, 20, alignment=TABLEFT) do n = 1, 2 - write(text, '(a,1x,i6)') 'VALUE', n + write (text, '(a,1x,i6)') 'VALUE', n call this%inputtab%initialize_column(text, 15, alignment=TABCENTER) end do end if @@ -504,11 +495,11 @@ subroutine apt_rp(this) if (this%iprpak /= 0) then call this%inputtab%finalize_table() end if - ! - ! -- using stress period data from the previous stress period + ! + ! -- using stress period data from the previous stress period else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + write (this%iout, fmtlsp) trim(this%filtyp) + end if ! ! -- write summary of stress period error messages ierr = count_errors() @@ -537,7 +528,7 @@ subroutine apt_set_stressperiod(this, itemno) ! -- module use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this integer(I4B), intent(in) :: itemno ! -- local character(len=LINELENGTH) :: text @@ -555,68 +546,69 @@ subroutine apt_set_stressperiod(this, itemno) ! STATUS ! CONCENTRATION ! WITHDRAWAL - ! AUXILIARY + ! AUXILIARY ! ! -- read line call this%parser%GetStringCaps(keyword) select case (keyword) - case ('STATUS') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetStringCaps(text) - this%status(itemno) = text(1:8) - if (text == 'CONSTANT') then - this%iboundpak(itemno) = -1 - else if (text == 'INACTIVE') then - this%iboundpak(itemno) = 0 - else if (text == 'ACTIVE') then - this%iboundpak(itemno) = 1 - else - write(errmsg,'(a,a)') & - 'Unknown ' // trim(this%text)//' status keyword: ', text // '.' - call store_error(errmsg) - end if - case ('CONCENTRATION') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if + case ('STATUS') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetStringCaps(text) + this%status(itemno) = text(1:8) + if (text == 'CONSTANT') then + this%iboundpak(itemno) = -1 + else if (text == 'INACTIVE') then + this%iboundpak(itemno) = 0 + else if (text == 'ACTIVE') then + this%iboundpak(itemno) = 1 + else + write (errmsg, '(a,a)') & + 'Unknown '//trim(this%text)//' status keyword: ', text//'.' + call store_error(errmsg) + end if + case ('CONCENTRATION') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 ! For feature concentration + bndElem => this%concfeat(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'CONCENTRATION') + case ('AUXILIARY') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetStringCaps(caux) + do jj = 1, this%naux + if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle call this%parser%GetString(text) - jj = 1 ! For feature concentration - bndElem => this%concfeat(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'CONCENTRATION') - case ('AUXILIARY') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetStringCaps(caux) - do jj = 1, this%naux - if (trim(adjustl(caux)) /= trim(adjustl(this%auxname(jj)))) cycle - call this%parser%GetString(text) - ii = itemno - bndElem => this%lauxvar(jj, ii) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, & - this%packName, 'AUX', this%tsManager, & - this%iprpak, this%auxname(jj)) - exit - end do - case default - ! - ! -- call the specific package to look for stress period data - call this%pak_set_stressperiod(itemno, keyword, found) - ! - ! -- terminate with error if data not valid - if (.not. found) then - write(errmsg,'(2a)') & - 'Unknown ' // trim(adjustl(this%text)) // ' data keyword: ', & - trim(keyword) // '.' - call store_error(errmsg) - end if + ii = itemno + bndElem => this%lauxvar(jj, ii) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & + this%auxname(jj)) + exit + end do + case default + ! + ! -- call the specific package to look for stress period data + call this%pak_set_stressperiod(itemno, keyword, found) + ! + ! -- terminate with error if data not valid + if (.not. found) then + write (errmsg, '(2a)') & + 'Unknown '//trim(adjustl(this%text))//' data keyword: ', & + trim(keyword)//'.' + call store_error(errmsg) + end if end select ! ! -- terminate if any errors were detected @@ -637,7 +629,7 @@ subroutine pak_set_stressperiod(this, itemno, keyword, found) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this integer(I4B), intent(in) :: itemno character(len=*), intent(in) :: keyword logical, intent(inout) :: found @@ -663,14 +655,14 @@ function apt_check_valid(this, itemno) result(ierr) ! -- return integer(I4B) :: ierr ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this integer(I4B), intent(in) :: itemno ! -- local ! -- formats ! ------------------------------------------------------------------------------ ierr = 0 if (itemno < 1 .or. itemno > this%ncv) then - write(errmsg,'(4x,a,1x,i6,1x,a,1x,i6)') & + write (errmsg, '(4x,a,1x,i6,1x,a,1x,i6)') & '****ERROR. FEATURENO ', itemno, 'MUST BE > 0 and <= ', this%ncv call store_error(errmsg) ierr = 1 @@ -739,17 +731,17 @@ subroutine apt_ad(this) ! -- return return end subroutine apt_ad - + !> @ brief Formulate the package hcof and rhs terms. !! - !! For the APT Package, the sole purpose here is to + !! For the APT Package, the sole purpose here is to !! reset the qmfrommvr term. !! !< subroutine apt_cf(this, reset_mover) ! -- modules - class(GwtAptType) :: this !< GwtAptType object - logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover + class(GwtAptType) :: this !< GwtAptType object + logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover ! -- local integer(I4B) :: i logical :: lrm @@ -859,7 +851,7 @@ subroutine apt_fc_expanded(this, rhs, ia, idxglo, amatsln) ! ------------------------------------------------------------------------------ ! ! -- call the specific method for the advanced transport package, such as - ! what would be overridden by + ! what would be overridden by ! GwtLktType, GwtSftType, GwtMwtType, GwtUztType ! This routine will add terms for rainfall, runoff, or other terms ! specific to the package @@ -867,7 +859,7 @@ subroutine apt_fc_expanded(this, rhs, ia, idxglo, amatsln) ! ! -- mass storage in features do n = 1, this%ncv - cold = this%xoldpak(n) + cold = this%xoldpak(n) iloc = this%idxlocnode(n) iposd = this%idxpakdiag(n) call this%apt_stor_term(n, n1, n2, rrate, rhsval, hcofval) @@ -918,7 +910,7 @@ subroutine apt_fc_expanded(this, rhs, ia, idxglo, amatsln) ipossymoffd = this%idxsymoffdglo(j) amatsln(ipossymd) = amatsln(ipossymd) - (DONE - omega) * qbnd amatsln(ipossymoffd) = amatsln(ipossymoffd) - omega * qbnd - end if + end if end do ! ! -- go through each apt-apt connection @@ -996,10 +988,10 @@ subroutine apt_cfupdate(this) qbnd = this%flowbudptr%budterm(this%idxbudgwf)%flow(j) omega = DZERO if (qbnd < DZERO) omega = DONE - this%hcof(j) = - (DONE - omega) * qbnd + this%hcof(j) = -(DONE - omega) * qbnd this%rhs(j) = omega * qbnd * this%xnewpak(n) - endif - end do + end if + end do ! ! -- Return return @@ -1023,7 +1015,7 @@ subroutine apt_cq(this, x, flowja, iadv) real(DP) :: rrate ! ------------------------------------------------------------------------------ ! - ! -- Solve the feature concentrations again or update the feature hcof + ! -- Solve the feature concentrations again or update the feature hcof ! and rhs terms if (this%imatrows == 0) then call this%apt_solve() @@ -1062,10 +1054,10 @@ subroutine apt_ot_package_flows(this, icbcfl, ibudfl) ! ! -- write the flows from the budobj ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & pertim, totim, this%iout) @@ -1075,7 +1067,7 @@ subroutine apt_ot_package_flows(this, icbcfl, ibudfl) if (ibudfl /= 0 .and. this%iprflow /= 0) then call this%budobj%write_flowtable(this%dis, kstp, kper) end if - + end subroutine apt_ot_package_flows subroutine apt_ot_dv(this, idvsave, idvprint) @@ -1091,10 +1083,10 @@ subroutine apt_ot_dv(this, idvsave, idvprint) ! ! -- set unit number for binary dependent variable output ibinun = 0 - if(this%iconcout /= 0) then + if (this%iconcout /= 0) then ibinun = this%iconcout end if - if(idvsave == 0) ibinun = 0 + if (idvsave == 0) ibinun = 0 ! ! -- write binary output if (ibinun > 0) then @@ -1105,57 +1097,55 @@ subroutine apt_ot_dv(this, idvsave, idvprint) end if this%dbuff(n) = c end do - call ulasav(this%dbuff, ' CONCENTRATION', kstp, kper, pertim, totim, & + call ulasav(this%dbuff, ' CONCENTRATION', kstp, kper, pertim, totim, & this%ncv, 1, 1, ibinun) end if - ! - ! -- write apt conc table - if (idvprint /= 0 .and. this%iprconc /= 0) then + ! + ! -- write apt conc table + if (idvprint /= 0 .and. this%iprconc /= 0) then ! ! -- set table kstp and kper call this%dvtab%set_kstpkper(kstp, kper) ! ! -- fill concentration data do n = 1, this%ncv - if(this%inamedbound==1) then + if (this%inamedbound == 1) then call this%dvtab%add_term(this%featname(n)) end if call this%dvtab%add_term(n) call this%dvtab%add_term(this%xnewpak(n)) end do - end if - + end if + end subroutine apt_ot_dv - + subroutine apt_ot_bdsummary(this, kstp, kper, iout, ibudfl) ! -- module use TdisModule, only: totim ! -- dummy - class(GwtAptType) :: this !< GwtAptType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + class(GwtAptType) :: this !< GwtAptType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written ! call this%budobj%write_budtable(kstp, kper, iout, ibudfl, totim) ! ! -- return return end subroutine apt_ot_bdsummary - + + !> @ brief Allocate scalars + !! + !! Allocate scalar variables for this package + !! + !< subroutine allocate_scalars(this) -! ****************************************************************************** -! allocate_scalars -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwtAptType) :: this ! -- local -! ------------------------------------------------------------------------------ ! ! -- allocate scalars in NumericalPackageType call this%BndType%allocate_scalars() @@ -1176,7 +1166,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%idxbudfmvr, 'IDXBUDFMVR', this%memoryPath) call mem_allocate(this%idxbudaux, 'IDXBUDAUX', this%memoryPath) call mem_allocate(this%nconcbudssm, 'NCONCBUDSSM', this%memoryPath) - ! + ! ! -- Initialize this%iauxfpconc = 0 this%imatrows = 1 @@ -1194,28 +1184,89 @@ subroutine allocate_scalars(this) this%idxbudaux = 0 this%nconcbudssm = 0 ! + ! -- set this package as causing asymmetric matrix terms + this%iasym = 1 + ! ! -- Return return end subroutine allocate_scalars + !> @ brief Allocate index arrays + !! + !! Allocate arrays that map to locations in the + !! numerical solution + !! + !< + subroutine apt_allocate_index_arrays(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy + class(GwtAptType), intent(inout) :: this + ! -- local + integer(I4B) :: n + + if (this%imatrows /= 0) then + ! + ! -- count number of flow-ja-face connections + n = 0 + if (this%idxbudfjf /= 0) then + n = this%flowbudptr%budterm(this%idxbudfjf)%maxlist + end if + ! + ! -- allocate pointers to global matrix + call mem_allocate(this%idxlocnode, this%ncv, 'IDXLOCNODE', & + this%memoryPath) + call mem_allocate(this%idxpakdiag, this%ncv, 'IDXPAKDIAG', & + this%memoryPath) + call mem_allocate(this%idxdglo, this%maxbound, 'IDXGLO', & + this%memoryPath) + call mem_allocate(this%idxoffdglo, this%maxbound, 'IDXOFFDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymdglo, this%maxbound, 'IDXSYMDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymoffdglo, this%maxbound, 'IDXSYMOFFDGLO', & + this%memoryPath) + call mem_allocate(this%idxfjfdglo, n, 'IDXFJFDGLO', & + this%memoryPath) + call mem_allocate(this%idxfjfoffdglo, n, 'IDXFJFOFFDGLO', & + this%memoryPath) + else + call mem_allocate(this%idxlocnode, 0, 'IDXLOCNODE', & + this%memoryPath) + call mem_allocate(this%idxpakdiag, 0, 'IDXPAKDIAG', & + this%memoryPath) + call mem_allocate(this%idxdglo, 0, 'IDXGLO', & + this%memoryPath) + call mem_allocate(this%idxoffdglo, 0, 'IDXOFFDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymdglo, 0, 'IDXSYMDGLO', & + this%memoryPath) + call mem_allocate(this%idxsymoffdglo, 0, 'IDXSYMOFFDGLO', & + this%memoryPath) + call mem_allocate(this%idxfjfdglo, 0, 'IDXFJFDGLO', & + this%memoryPath) + call mem_allocate(this%idxfjfoffdglo, 0, 'IDXFJFOFFDGLO', & + this%memoryPath) + end if + return + end subroutine apt_allocate_index_arrays + + !> @ brief Allocate arrays + !! + !! Allocate package arrays + !! + !< subroutine apt_allocate_arrays(this) -! ****************************************************************************** -! allocate_arrays -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy class(GwtAptType), intent(inout) :: this ! -- local integer(I4B) :: n -! ------------------------------------------------------------------------------ ! ! -- call standard BndType allocate scalars call this%BndType%allocate_arrays() - ! + ! ! -- Allocate ! ! -- allocate and initialize dbuff @@ -1229,7 +1280,7 @@ subroutine apt_allocate_arrays(this) end if ! ! -- allocate character array for status - allocate(this%status(this%ncv)) + allocate (this%status(this%ncv)) ! ! -- time series call mem_allocate(this%concfeat, this%ncv, 'CONCFEAT', this%memoryPath) @@ -1240,7 +1291,7 @@ subroutine apt_allocate_arrays(this) ! ! -- concentration for budget terms call mem_allocate(this%concbudssm, this%nconcbudssm, this%ncv, & - 'CONCBUDSSM', this%memoryPath) + 'CONCBUDSSM', this%memoryPath) ! ! -- mass added from the mover transport package call mem_allocate(this%qmfrommvr, this%ncv, 'QMFROMMVR', this%memoryPath) @@ -1258,20 +1309,18 @@ subroutine apt_allocate_arrays(this) ! -- Return return end subroutine apt_allocate_arrays - + + !> @ brief Deallocate memory + !! + !! Deallocate memory associated with this package + !! + !< subroutine apt_da(this) -! ****************************************************************************** -! apt_da -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy class(GwtAptType) :: this ! -- local -! ------------------------------------------------------------------------------ ! ! -- deallocate arrays call mem_deallocate(this%dbuff) @@ -1287,30 +1336,30 @@ subroutine apt_da(this) call mem_deallocate(this%concbudssm) call mem_deallocate(this%concfeat) call mem_deallocate(this%qmfrommvr) - deallocate(this%status) - deallocate(this%featname) + deallocate (this%status) + deallocate (this%featname) ! ! -- budobj call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- conc table if (this%iprconc > 0) then call this%dvtab%table_da() - deallocate(this%dvtab) - nullify(this%dvtab) + deallocate (this%dvtab) + nullify (this%dvtab) end if ! ! -- index pointers - deallocate(this%idxlocnode) - deallocate(this%idxpakdiag) - deallocate(this%idxdglo) - deallocate(this%idxoffdglo) - deallocate(this%idxsymdglo) - deallocate(this%idxsymoffdglo) - deallocate(this%idxfjfdglo) - deallocate(this%idxfjfoffdglo) + call mem_deallocate(this%idxlocnode) + call mem_deallocate(this%idxpakdiag) + call mem_deallocate(this%idxdglo) + call mem_deallocate(this%idxoffdglo) + call mem_deallocate(this%idxsymdglo) + call mem_deallocate(this%idxsymoffdglo) + call mem_deallocate(this%idxfjfdglo) + call mem_deallocate(this%idxfjfoffdglo) ! ! -- deallocate scalars call mem_deallocate(this%iauxfpconc) @@ -1353,13 +1402,13 @@ subroutine find_apt_package(this) ! ! -- this routine should never be called call store_error('Program error: pak_solve not implemented.', & - terminate=.TRUE.) + terminate=.TRUE.) ! ! -- Return return end subroutine find_apt_package - subroutine apt_options(this, option, found) + subroutine apt_options(this, option, found) ! ****************************************************************************** ! apt_options -- set options specific to GwtAptType ! @@ -1373,86 +1422,84 @@ subroutine apt_options(this, option, found) use InputOutputModule, only: urword, getunit, openfile ! -- dummy class(GwtAptType), intent(inout) :: this - character(len=*), intent(inout) :: option - logical, intent(inout) :: found + character(len=*), intent(inout) :: option + logical, intent(inout) :: found ! -- local character(len=MAXCHARLEN) :: fname, keyword ! -- formats - character(len=*),parameter :: fmtaptbin = & - "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I0)" + character(len=*), parameter :: fmtaptbin = & + "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, & + &/4x, 'OPENED ON UNIT: ', I0)" ! ------------------------------------------------------------------------------ ! + found = .true. select case (option) - case ('FLOW_PACKAGE_NAME') - call this%parser%GetStringCaps(this%flowpackagename) - write(this%iout,'(4x,a)') & - 'THIS '//trim(adjustl(this%text))//' PACKAGE CORRESPONDS TO A GWF & - &PACKAGE WITH THE NAME '//trim(adjustl(this%flowpackagename)) - found = .true. - case ('FLOW_PACKAGE_AUXILIARY_NAME') - call this%parser%GetStringCaps(this%cauxfpconc) - write(this%iout,'(4x,a)') & - 'SIMULATED CONCENTRATIONS WILL BE COPIED INTO THE FLOW PACKAGE & - &AUXILIARY VARIABLE WITH THE NAME ' //trim(adjustl(this%cauxfpconc)) - found = .true. - case ('DEV_NONEXPANDING_MATRIX') - ! -- use an iterative solution where concentration is not solved - ! as part of the matrix. It is instead solved separately with a - ! general mixing equation and then added to the RHS of the GWT - ! equations - call this%parser%DevOpt() - this%imatrows = 0 - write(this%iout,'(4x,a)') & - trim(adjustl(this%text))//' WILL NOT ADD ADDITIONAL ROWS TO THE A MATRIX.' - found = .true. - case ('PRINT_CONCENTRATION') - this%iprconc = 1 - write(this%iout,'(4x,a)') trim(adjustl(this%text))// & - ' CONCENTRATIONS WILL BE PRINTED TO LISTING FILE.' - found = .true. - case('CONCENTRATION') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%iconcout = getunit() - call openfile(this%iconcout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE') - write(this%iout,fmtaptbin) trim(adjustl(this%text)), 'CONCENTRATION', & - trim(fname), this%iconcout - found = .true. - else - call store_error('OPTIONAL CONCENTRATION KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE') - write(this%iout,fmtaptbin) trim(adjustl(this%text)), 'BUDGET', & - trim(fname), this%ibudgetout - found = .true. - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtaptbin) trim(adjustl(this%text)), 'BUDGET CSV', & - trim(fname), this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case default - ! - ! -- No options found - found = .false. + case ('FLOW_PACKAGE_NAME') + call this%parser%GetStringCaps(this%flowpackagename) + write (this%iout, '(4x,a)') & + 'THIS '//trim(adjustl(this%text))//' PACKAGE CORRESPONDS TO A GWF & + &PACKAGE WITH THE NAME '//trim(adjustl(this%flowpackagename)) + case ('FLOW_PACKAGE_AUXILIARY_NAME') + call this%parser%GetStringCaps(this%cauxfpconc) + write (this%iout, '(4x,a)') & + 'SIMULATED CONCENTRATIONS WILL BE COPIED INTO THE FLOW PACKAGE & + &AUXILIARY VARIABLE WITH THE NAME '//trim(adjustl(this%cauxfpconc)) + case ('DEV_NONEXPANDING_MATRIX') + ! -- use an iterative solution where concentration is not solved + ! as part of the matrix. It is instead solved separately with a + ! general mixing equation and then added to the RHS of the GWT + ! equations + call this%parser%DevOpt() + this%imatrows = 0 + write (this%iout, '(4x,a)') & + trim(adjustl(this%text))// & + ' WILL NOT ADD ADDITIONAL ROWS TO THE A MATRIX.' + case ('PRINT_CONCENTRATION') + this%iprconc = 1 + write (this%iout, '(4x,a)') trim(adjustl(this%text))// & + ' CONCENTRATIONS WILL BE PRINTED TO LISTING FILE.' + case ('CONCENTRATION') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%iconcout = getunit() + call openfile(this%iconcout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtaptbin) & + trim(adjustl(this%text)), 'CONCENTRATION', trim(fname), this%iconcout + else + call store_error('OPTIONAL CONCENTRATION KEYWORD MUST & + &BE FOLLOWED BY FILEOUT') + end if + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtaptbin) trim(adjustl(this%text)), 'BUDGET', & + trim(fname), this%ibudgetout + else + call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtaptbin) trim(adjustl(this%text)), 'BUDGET CSV', & + trim(fname), this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case default + ! + ! -- No options found + found = .false. end select ! ! -- return @@ -1467,7 +1514,7 @@ subroutine apt_read_dimensions(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this ! -- local integer(I4B) :: ierr ! -- format @@ -1476,36 +1523,36 @@ subroutine apt_read_dimensions(this) ! -- Set a pointer to the GWF LAK Package budobj if (this%flowpackagename == '') then this%flowpackagename = this%packName - write(this%iout,'(4x,a)') & + write (this%iout, '(4x,a)') & 'THE FLOW PACKAGE NAME FOR '//trim(adjustl(this%text))//' WAS NOT & &SPECIFIED. SETTING FLOW PACKAGE NAME TO '// & &trim(adjustl(this%flowpackagename)) - + end if call this%find_apt_package() ! - ! -- Set dimensions from the GWF LAK package + ! -- Set dimensions from the GWF advanced package this%ncv = this%flowbudptr%ncv this%maxbound = this%flowbudptr%budterm(this%idxbudgwf)%maxlist this%nbound = this%maxbound - write(this%iout, '(a, a)') 'SETTING DIMENSIONS FOR PACKAGE ', this%packName - write(this%iout,'(2x,a,i0)')'NUMBER OF CONTROL VOLUMES = ', this%ncv - write(this%iout,'(2x,a,i0)')'MAXBOUND = ', this%maxbound - write(this%iout,'(2x,a,i0)')'NBOUND = ', this%nbound + write (this%iout, '(a, a)') 'SETTING DIMENSIONS FOR PACKAGE ', this%packName + write (this%iout, '(2x,a,i0)') 'NUMBER OF CONTROL VOLUMES = ', this%ncv + write (this%iout, '(2x,a,i0)') 'MAXBOUND = ', this%maxbound + write (this%iout, '(2x,a,i0)') 'NBOUND = ', this%nbound if (this%imatrows /= 0) then this%npakeq = this%ncv - write(this%iout,'(2x,a)') trim(adjustl(this%text)) // & + write (this%iout, '(2x,a)') trim(adjustl(this%text))// & ' SOLVED AS PART OF GWT MATRIX EQUATIONS' else - write(this%iout,'(2x,a)') trim(adjustl(this%text)) // & + write (this%iout, '(2x,a)') trim(adjustl(this%text))// & ' SOLVED SEPARATELY FROM GWT MATRIX EQUATIONS ' end if - write(this%iout, '(a, //)') 'DONE SETTING DIMENSIONS FOR ' // & + write (this%iout, '(a, //)') 'DONE SETTING DIMENSIONS FOR '// & trim(adjustl(this%text)) ! ! -- Check for errors if (this%ncv < 0) then - write(errmsg, '(1x,a)') & + write (errmsg, '(1x,a)') & 'ERROR: NUMBER OF CONTROL VOLUMES COULD NOT BE DETERMINED CORRECTLY.' call store_error(errmsg) end if @@ -1544,7 +1591,7 @@ subroutine apt_read_cvs(this) use MemoryManagerModule, only: mem_allocate use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: text character(len=LENBOUNDNAME) :: bndName, bndNameTemp @@ -1567,7 +1614,8 @@ subroutine apt_read_cvs(this) ! ! -- allocate apt data call mem_allocate(this%strt, this%ncv, 'STRT', this%memoryPath) - call mem_allocate(this%lauxvar, this%naux, this%ncv, 'LAUXVAR', this%memoryPath) + call mem_allocate(this%lauxvar, this%naux, this%ncv, 'LAUXVAR', & + this%memoryPath) ! ! -- lake boundary and concentrations if (this%imatrows == 0) then @@ -1577,7 +1625,7 @@ subroutine apt_read_cvs(this) call mem_allocate(this%xoldpak, this%ncv, 'XOLDPAK', this%memoryPath) ! ! -- allocate character storage not managed by the memory manager - allocate(this%featname(this%ncv)) ! ditch after boundnames allocated?? + allocate (this%featname(this%ncv)) ! ditch after boundnames allocated?? !allocate(this%status(this%ncv)) ! do n = 1, this%ncv @@ -1592,21 +1640,22 @@ subroutine apt_read_cvs(this) ! ! -- allocate local storage for aux variables if (this%naux > 0) then - allocate(caux(this%naux)) + allocate (caux(this%naux)) end if ! ! -- allocate and initialize temporary variables - allocate(nboundchk(this%ncv)) + allocate (nboundchk(this%ncv)) do n = 1, this%ncv nboundchk(n) = 0 end do ! ! -- get packagedata block - call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, supportOpenClose=.true.) + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + supportOpenClose=.true.) ! ! -- parse locations block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & ' PACKAGEDATA' nlak = 0 nconn = 0 @@ -1616,12 +1665,12 @@ subroutine apt_read_cvs(this) n = this%parser%GetInteger() if (n < 1 .or. n > this%ncv) then - write(errmsg,'(4x,a,1x,i6)') & + write (errmsg, '(4x,a,1x,i6)') & '****ERROR. itemno MUST BE > 0 and <= ', this%ncv call store_error(errmsg) cycle end if - + ! -- increment nboundchk nboundchk(n) = nboundchk(n) + 1 @@ -1634,15 +1683,15 @@ subroutine apt_read_cvs(this) end do ! -- set default bndName - write (cno,'(i9.9)') n - bndName = 'Feature' // cno + write (cno, '(i9.9)') n + bndName = 'Feature'//cno ! -- featname if (this%inamedbound /= 0) then call this%parser%GetStringCaps(bndNameTemp) if (bndNameTemp /= '') then bndName = bndNameTemp - endif + end if end if this%featname(n) = bndName @@ -1652,27 +1701,29 @@ subroutine apt_read_cvs(this) text = caux(jj) ii = n bndElem => this%lauxvar(jj, ii) - call read_value_or_time_series_adv(text, ii, jj, bndElem, this%packName, & - 'AUX', this%tsManager, this%iprpak, & + call read_value_or_time_series_adv(text, ii, jj, bndElem, & + this%packName, 'AUX', & + this%tsManager, this%iprpak, & this%auxname(jj)) end do - + nlak = nlak + 1 end do ! ! -- check for duplicate or missing lakes do n = 1, this%ncv if (nboundchk(n) == 0) then - write(errmsg,'(a,1x,i0)') 'ERROR. NO DATA SPECIFIED FOR FEATURE', n + write (errmsg, '(a,1x,i0)') 'ERROR. NO DATA SPECIFIED FOR FEATURE', n call store_error(errmsg) else if (nboundchk(n) > 1) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'ERROR. DATA FOR FEATURE', n, 'SPECIFIED', nboundchk(n), 'TIMES' call store_error(errmsg) end if end do - write(this%iout,'(1x,a)')'END OF '//trim(adjustl(this%text))//' PACKAGEDATA' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' PACKAGEDATA' else call store_error('ERROR. REQUIRED PACKAGEDATA BLOCK NOT FOUND.') end if @@ -1684,16 +1735,16 @@ subroutine apt_read_cvs(this) ! ! -- deallocate local storage for aux variables if (this%naux > 0) then - deallocate(caux) + deallocate (caux) end if ! ! -- deallocate local storage for nboundchk - deallocate(nboundchk) + deallocate (nboundchk) ! ! -- return return end subroutine apt_read_cvs - + subroutine apt_read_initial_attr(this) ! ****************************************************************************** ! apt_read_initial_attr -- Read the initial parameters for this package @@ -1704,7 +1755,7 @@ subroutine apt_read_initial_attr(this) use ConstantsModule, only: LINELENGTH use BudgetModule, only: budget_cr ! -- dummy - class(GwtAptType),intent(inout) :: this + class(GwtAptType), intent(inout) :: this ! -- local !character(len=LINELENGTH) :: text integer(I4B) :: j, n @@ -1749,15 +1800,15 @@ subroutine apt_read_initial_attr(this) !call read_single_value_or_time_series(text, & ! this%stage(n)%value, & ! this%stage(n)%name, & - ! endtim, & + ! endtim, & ! this%name, 'BND', this%TsManager, & ! this%iprpak, n, jj, 'STAGE', & ! this%featname(n), this%inunit) ! -- todo: read aux - + ! -- todo: read boundname - + end do ! ! -- initialize status (iboundpak) of lakes to active @@ -1779,6 +1830,9 @@ subroutine apt_read_initial_attr(this) end do end if ! + ! -- copy boundname into boundname_cst + call this%copy_boundname() + ! ! -- return return end subroutine apt_read_initial_attr @@ -1829,7 +1883,7 @@ subroutine apt_solve(this) end do end if ! - ! -- go through each gwf connection and accumulate + ! -- go through each gwf connection and accumulate ! total mass in dbuff mass do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j) @@ -1848,7 +1902,7 @@ subroutine apt_solve(this) this%dbuff(n) = this%dbuff(n) + c1 end do ! - ! -- go through each lak-lak connection and accumulate + ! -- go through each lak-lak connection and accumulate ! total mass in dbuff mass if (this%idxbudfjf /= 0) then do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist @@ -1867,7 +1921,7 @@ subroutine apt_solve(this) this%dbuff(n) = this%dbuff(n) - rhsval ! ! -- Now to calculate c, need to divide dbuff by hcofval - c1 = - this%dbuff(n) / hcofval + c1 = -this%dbuff(n) / hcofval if (this%iboundpak(n) > 0) then this%xnewpak(n) = c1 end if @@ -1876,7 +1930,7 @@ subroutine apt_solve(this) ! -- Return return end subroutine apt_solve - + subroutine pak_solve(this) ! ****************************************************************************** ! pak_solve -- must be overridden @@ -1896,7 +1950,7 @@ subroutine pak_solve(this) ! -- Return return end subroutine pak_solve - + subroutine apt_accumulate_ccterm(this, ilak, rrate, ccratin, ccratout) ! ****************************************************************************** ! apt_accumulate_ccterm -- Accumulate constant concentration terms for budget. @@ -1947,21 +2001,21 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -2000,7 +2054,7 @@ subroutine apt_set_pointers(this, neq, ibound, xnew, xold, flowja) ! ! -- return end subroutine apt_set_pointers - + subroutine get_volumes(this, icv, vnew, vold, delt) ! ****************************************************************************** ! get_volumes -- return the feature new volume and old volume @@ -2030,7 +2084,7 @@ subroutine get_volumes(this, icv, vnew, vold, delt) ! -- Return return end subroutine get_volumes - + function pak_get_nbudterms(this) result(nbudterms) ! ****************************************************************************** ! pak_get_nbudterms -- function to return the number of budget terms just for @@ -2049,10 +2103,10 @@ function pak_get_nbudterms(this) result(nbudterms) ! ! -- this routine should never be called call store_error('Program error: pak_get_nbudterms not implemented.', & - terminate=.TRUE.) + terminate=.TRUE.) nbudterms = 0 end function pak_get_nbudterms - + subroutine apt_setup_budobj(this) ! ****************************************************************************** ! apt_setup_budobj -- Set up the budget object that stores all the lake flows @@ -2082,7 +2136,7 @@ subroutine apt_setup_budobj(this) nlen = this%flowbudptr%budterm(this%idxbudfjf)%maxlist end if ! - ! -- Determine the number of lake budget terms. These are fixed for + ! -- Determine the number of lake budget terms. These are fixed for ! the simulation and cannot change ! -- the first 3 is for GWF, STORAGE, and CONSTANT nbudterm = 3 @@ -2101,7 +2155,7 @@ subroutine apt_setup_budobj(this) ! -- set up budobj call budgetobject_cr(this%budobj, this%packName) call this%budobj%budgetobject_df(this%ncv, nbudterm, 0, 0, & - bddim_opt='M') + bddim_opt='M', ibudcsv=this%ibudcsv) idx = 0 ! ! -- Go through and set up each budget term @@ -2126,10 +2180,10 @@ subroutine apt_setup_budobj(this) n1 = this%flowbudptr%budterm(this%idxbudfjf)%id1(n) n2 = this%flowbudptr%budterm(this%idxbudfjf)%id2(n) call this%budobj%budterm(idx)%update_term(n1, n2, q) - end do + end do end if ! - ! -- + ! -- text = ' GWF' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudgwf)%maxlist @@ -2152,7 +2206,7 @@ subroutine apt_setup_budobj(this) ! -- Reserve space for the package specific terms call this%pak_setup_budobj(idx) ! - ! -- + ! -- text = ' STORAGE' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudsto)%maxlist @@ -2167,7 +2221,7 @@ subroutine apt_setup_budobj(this) naux, auxtxt) if (this%idxbudtmvr /= 0) then ! - ! -- + ! -- text = ' TO-MVR' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudtmvr)%maxlist @@ -2183,7 +2237,7 @@ subroutine apt_setup_budobj(this) end if if (this%idxbudfmvr /= 0) then ! - ! -- + ! -- text = ' FROM-MVR' idx = idx + 1 maxlist = this%ncv @@ -2197,7 +2251,7 @@ subroutine apt_setup_budobj(this) naux) end if ! - ! -- + ! -- text = ' CONSTANT' idx = idx + 1 maxlist = this%ncv @@ -2209,13 +2263,13 @@ subroutine apt_setup_budobj(this) this%packName, & maxlist, .false., .false., & naux) - + ! - ! -- + ! -- naux = this%naux if (naux > 0) then ! - ! -- + ! -- text = ' AUXILIARY' idx = idx + 1 maxlist = this%ncv @@ -2297,7 +2351,6 @@ subroutine apt_fill_budobj(this, x) this%ccterm(n1) = DZERO end do - ! -- FLOW JA FACE nlen = 0 if (this%idxbudfjf /= 0) then @@ -2312,10 +2365,9 @@ subroutine apt_fill_budobj(this, x) call this%apt_fjf_term(j, n1, n2, q) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) - end do + end do end if - ! -- GWF (LEAKAGE) idx = idx + 1 call this%budobj%budterm(idx)%reset(this%maxbound) @@ -2325,21 +2377,19 @@ subroutine apt_fill_budobj(this, x) if (this%iboundpak(n1) /= 0) then igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(j) q = this%hcof(j) * x(igwfnode) - this%rhs(j) - q = -q ! flip sign so relative to lake + q = -q ! flip sign so relative to advanced package feature end if call this%budobj%budterm(idx)%update_term(n1, igwfnode, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - ! -- individual package terms call this%pak_fill_budobj(idx, x, ccratin, ccratout) - ! -- STORAGE idx = idx + 1 call this%budobj%budterm(idx)%reset(this%ncv) - allocate(auxvartmp(1)) + allocate (auxvartmp(1)) do n1 = 1, this%ncv call this%get_volumes(n1, v1, v0, delt) auxvartmp(1) = v1 * this%xnewpak(n1) @@ -2347,9 +2397,8 @@ subroutine apt_fill_budobj(this, x) call this%budobj%budterm(idx)%update_term(n1, n1, q, auxvartmp) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - deallocate(auxvartmp) - - + deallocate (auxvartmp) + ! -- TO MOVER if (this%idxbudtmvr /= 0) then idx = idx + 1 @@ -2361,7 +2410,7 @@ subroutine apt_fill_budobj(this, x) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- FROM MOVER if (this%idxbudfmvr /= 0) then idx = idx + 1 @@ -2373,7 +2422,7 @@ subroutine apt_fill_budobj(this, x) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- CONSTANT FLOW idx = idx + 1 call this%budobj%budterm(idx)%reset(this%ncv) @@ -2381,12 +2430,12 @@ subroutine apt_fill_budobj(this, x) q = this%ccterm(n1) call this%budobj%budterm(idx)%update_term(n1, n1, q) end do - + ! -- AUXILIARY VARIABLES naux = this%naux if (naux > 0) then idx = idx + 1 - allocate(auxvartmp(naux)) + allocate (auxvartmp(naux)) call this%budobj%budterm(idx)%reset(this%ncv) do n1 = 1, this%ncv q = DZERO @@ -2395,7 +2444,7 @@ subroutine apt_fill_budobj(this, x) end do call this%budobj%budterm(idx)%update_term(n1, n1, q, auxvartmp) end do - deallocate(auxvartmp) + deallocate (auxvartmp) end if ! ! --Terms are filled, now accumulate them for this time step @@ -2424,8 +2473,8 @@ subroutine pak_fill_budobj(this, idx, x, ccratin, ccratout) ! ----------------------------------------------------------------------------- ! ! -- this routine should never be called - call store_error('Program error: pak_fill_budobj not implemented.', & - terminate=.TRUE.) + call store_error('Program error: pak_fill_budobj not implemented.', & + terminate=.TRUE.) ! ! -- return return @@ -2447,7 +2496,7 @@ subroutine apt_stor_term(this, ientry, n1, n2, rrate, & n2 = ientry call this%get_volumes(n1, v1, v0, delt) c0 = this%xoldpak(n1) - c1 = this%xnewpak(n1) + c1 = this%xnewpak(n1) if (present(rrate)) rrate = -c1 * v1 / delt + c0 * v0 / delt if (present(rhsval)) rhsval = -c0 * v0 / delt if (present(hcofval)) hcofval = -v1 / delt @@ -2455,7 +2504,7 @@ subroutine apt_stor_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine apt_stor_term - + subroutine apt_tmvr_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) class(GwtAptType) :: this @@ -2478,7 +2527,7 @@ subroutine apt_tmvr_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine apt_tmvr_term - + subroutine apt_fjf_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) class(GwtAptType) :: this @@ -2505,7 +2554,7 @@ subroutine apt_fjf_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine apt_fjf_term - + subroutine apt_copy2flowp(this) ! ****************************************************************************** ! apt_copy2flowp -- copy concentrations into flow package aux variable @@ -2535,7 +2584,7 @@ subroutine apt_copy2flowp(this) ! -- return return end subroutine apt_copy2flowp - + logical function apt_obs_supported(this) ! ****************************************************************************** ! apt_obs_supported -- obs are supported? @@ -2556,7 +2605,7 @@ logical function apt_obs_supported(this) ! -- return return end function apt_obs_supported - + subroutine apt_df_obs(this) ! ****************************************************************************** ! apt_df_obs -- obs are supported? @@ -2570,50 +2619,14 @@ subroutine apt_df_obs(this) ! -- dummy class(GwtAptType) :: this ! -- local - integer(I4B) :: indx -! ------------------------------------------------------------------------------ - ! - ! -- Store obs type and assign procedure pointer - ! for concentration observation type. - call this%obs%StoreObsType('concentration', .false., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for flow between lakes. - call this%obs%StoreObsType('flow-ja-face', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for from-mvr observation type. - call this%obs%StoreObsType('from-mvr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for observation type: lkt, sft, mwt, uzt. - call this%obs%StoreObsType(trim(adjustl(this%text)), .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for to-mvr observation type. - call this%obs%StoreObsType('to-mvr', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for storage observation type. - call this%obs%StoreObsType('storage', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID - ! - ! -- Store obs type and assign procedure pointer - ! for constant observation type. - call this%obs%StoreObsType('constant', .true., indx) - this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID +! ------------------------------------------------------------------------------ ! ! -- call additional specific observations for lkt, sft, mwt, and uzt call this%pak_df_obs() ! return end subroutine apt_df_obs - + subroutine pak_df_obs(this) ! ****************************************************************************** ! pak_df_obs -- obs are supported? @@ -2635,186 +2648,303 @@ subroutine pak_df_obs(this) ! return end subroutine pak_df_obs - -subroutine apt_rp_obs(this) + + !> @brief Process package specific obs + !! + !! Method to process specific observations for this package. + !! + !< + subroutine pak_rp_obs(this, obsrv, found) + ! -- dummy + class(GwtAptType), intent(inout) :: this !< package class + type(ObserveType), intent(inout) :: obsrv !< observation object + logical, intent(inout) :: found !< indicate whether observation was found + ! -- local + ! + ! -- this routine should never be called + call store_error('Program error: pak_rp_obs not implemented.', & + terminate=.TRUE.) + ! + return + end subroutine pak_rp_obs + + !> @brief Prepare observation + !! + !! Find the indices for this observation assuming + !! they are indexed by feature number + !! + !< + subroutine rp_obs_byfeature(this, obsrv) + class(GwtAptType), intent(inout) :: this !< object + type(ObserveType), intent(inout) :: obsrv !< observation + integer(I4B) :: nn1 + integer(I4B) :: j + logical :: jfound + character(len=*), parameter :: fmterr = & + "('Boundary ', a, ' for observation ', a, & + &' is invalid in package ', a)" + nn1 = obsrv%NodeNumber + if (nn1 == NAMEDBOUNDFLAG) then + jfound = .false. + do j = 1, this%ncv + if (this%featname(j) == obsrv%FeatureName) then + jfound = .true. + call obsrv%AddObsIndex(j) + end if + end do + if (.not. jfound) then + write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), & + trim(this%packName) + call store_error(errmsg) + end if + else + ! + ! -- ensure nn1 is > 0 and < ncv + if (nn1 < 0 .or. nn1 > this%ncv) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' was assigned ID = ', nn1, & + '. ID must be >= 1 and <= ', this%ncv, '.' + call store_error(errmsg) + end if + call obsrv%AddObsIndex(nn1) + end if + return + end subroutine rp_obs_byfeature + + !> @brief Prepare observation + !! + !! Find the indices for this observation assuming + !! they are first indexed by feature number and + !! secondly by a connection number + !! + !< + subroutine rp_obs_budterm(this, obsrv, budterm) + class(GwtAptType), intent(inout) :: this !< object + type(ObserveType), intent(inout) :: obsrv !< observation + type(BudgetTermType), intent(in) :: budterm !< budget term + integer(I4B) :: nn1 + integer(I4B) :: iconn + integer(I4B) :: icv + integer(I4B) :: idx + integer(I4B) :: j + logical :: jfound + character(len=*), parameter :: fmterr = & + "('Boundary ', a, ' for observation ', a, & + &' is invalid in package ', a)" + nn1 = obsrv%NodeNumber + if (nn1 == NAMEDBOUNDFLAG) then + jfound = .false. + do j = 1, budterm%nlist + icv = budterm%id1(j) + if (this%featname(icv) == obsrv%FeatureName) then + jfound = .true. + call obsrv%AddObsIndex(j) + end if + end do + if (.not. jfound) then + write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), & + trim(this%packName) + call store_error(errmsg) + end if + else + ! + ! -- ensure nn1 is > 0 and < ncv + if (nn1 < 0 .or. nn1 > this%ncv) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' was assigned ID = ', nn1, & + '. ID must be >= 1 and <= ', this%ncv, '.' + call store_error(errmsg) + end if + iconn = obsrv%NodeNumber2 + do j = 1, budterm%nlist + if (budterm%id1(j) == nn1) then + ! -- Look for the first occurrence of nn1, then set indxbnds + ! to the iconn record after that + idx = j + iconn - 1 + call obsrv%AddObsIndex(idx) + exit + end if + end do + if (idx < 1 .or. idx > budterm%nlist) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' specifies iconn = ', iconn, & + ', but this is not a valid connection for ID ', nn1, '.' + call store_error(errmsg) + else if (budterm%id1(idx) /= nn1) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' specifies iconn = ', iconn, & + ', but this is not a valid connection for ID ', nn1, '.' + call store_error(errmsg) + end if + end if + return + end subroutine rp_obs_budterm + + !> @brief Prepare observation + !! + !! Find the indices for this observation assuming + !! they are first indexed by a feature number and + !! secondly by a second feature number + !! + !< + subroutine rp_obs_flowjaface(this, obsrv, budterm) + class(GwtAptType), intent(inout) :: this !< object + type(ObserveType), intent(inout) :: obsrv !< observation + type(BudgetTermType), intent(in) :: budterm !< budget term + integer(I4B) :: nn1 + integer(I4B) :: nn2 + integer(I4B) :: icv + integer(I4B) :: j + logical :: jfound + character(len=*), parameter :: fmterr = & + "('Boundary ', a, ' for observation ', a, & + &' is invalid in package ', a)" + nn1 = obsrv%NodeNumber + if (nn1 == NAMEDBOUNDFLAG) then + jfound = .false. + do j = 1, budterm%nlist + icv = budterm%id1(j) + if (this%featname(icv) == obsrv%FeatureName) then + jfound = .true. + call obsrv%AddObsIndex(j) + end if + end do + if (.not. jfound) then + write (errmsg, fmterr) trim(obsrv%FeatureName), trim(obsrv%Name), & + trim(this%packName) + call store_error(errmsg) + end if + else + ! + ! -- ensure nn1 is > 0 and < ncv + if (nn1 < 0 .or. nn1 > this%ncv) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' was assigned ID = ', nn1, & + '. ID must be >= 1 and <= ', this%ncv, '.' + call store_error(errmsg) + end if + nn2 = obsrv%NodeNumber2 + ! + ! -- ensure nn2 is > 0 and < ncv + if (nn2 < 0 .or. nn2 > this%ncv) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), ' was assigned ID2 = ', nn2, & + '. ID must be >= 1 and <= ', this%ncv, '.' + call store_error(errmsg) + end if + ! -- Look for nn1 and nn2 in id1 and id2 + jfound = .false. + do j = 1, budterm%nlist + if (budterm%id1(j) == nn1 .and. budterm%id2(j) == nn2) then + call obsrv%AddObsIndex(j) + jfound = .true. + end if + end do + if (.not. jfound) then + write (errmsg, '(7a, i0, a, i0, a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), & + ' specifies a connection between feature ', nn1, & + ' feature ', nn2, ', but these features are not connected.' + call store_error(errmsg) + end if + end if + return + end subroutine rp_obs_flowjaface + + subroutine apt_rp_obs(this) ! ****************************************************************************** -! apt_rp_obs -- +! apt_rp_obs -- ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules + use TdisModule, only: kper ! -- dummy class(GwtAptType), intent(inout) :: this ! -- local integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: n - integer(I4B) :: nn1 - integer(I4B) :: nn2 - integer(I4B) :: idx - integer(I4B) :: ntmvr - character(len=LENBOUNDNAME) :: bname - logical :: jfound + logical :: found class(ObserveType), pointer :: obsrv => null() ! ------------------------------------------------------------------------------ - ! -- formats -10 format('Boundary "',a,'" for observation "',a, & - '" is invalid in package "',a,'"') ! - do i = 1, this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv - ! - ! -- indxbnds needs to be reset each stress period because - ! list of boundaries can change each stress period. - call obsrv%ResetObsIndex() - ! - ! -- get node number 1 - nn1 = obsrv%NodeNumber - if (nn1 == NAMEDBOUNDFLAG) then - bname = obsrv%FeatureName - if (bname /= '') then - ! -- Observation is based on a boundary name. - ! Iterate through all features (lak/maw/sfr/uzf) to identify and - ! store corresponding index in bound array. - jfound = .false. - if (obsrv%ObsTypeId == trim(adjustl(this%text))) then - do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist - n = this%flowbudptr%budterm(this%idxbudgwf)%id1(j) - if (this%boundname(n) == bname) then - jfound = .true. - call obsrv%AddObsIndex(j) - end if - end do - else if (obsrv%ObsTypeId=='FLOW-JA-FACE') then - do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist - n = this%flowbudptr%budterm(this%idxbudfjf)%id1(j) - if (this%featname(n) == bname) then - jfound = .true. - call obsrv%AddObsIndex(j) - end if - end do - else - do j = 1, this%ncv - if (this%featname(j) == bname) then - jfound = .true. - call obsrv%AddObsIndex(j) - end if - end do - end if - if (.not. jfound) then - write(errmsg,10) trim(bname), trim(obsrv%Name), trim(this%packName) + if (kper == 1) then + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv + select case (obsrv%ObsTypeId) + case ('CONCENTRATION') + call this%rp_obs_byfeature(obsrv) + ! + ! -- catch non-cumulative observation assigned to observation defined + ! by a boundname that is assigned to more than one element + if (obsrv%indxbnds_count > 1) then + write (errmsg, '(a, a, a)') & + 'CONCENTRATION for observation', trim(adjustl(obsrv%Name)), & + ' must be assigned to a feature with a unique boundname.' call store_error(errmsg) end if - end if - else - if (obsrv%indxbnds_count == 0) then - if (obsrv%ObsTypeId == trim(adjustl(this%text))) then - nn2 = obsrv%NodeNumber2 - ! -- Look for the first occurrence of nn1, then set indxbnds - ! to the nn2 record after that - do j = 1, this%flowbudptr%budterm(this%idxbudgwf)%nlist - if (this%flowbudptr%budterm(this%idxbudgwf)%id1(j) == nn1) then - idx = j + nn2 - 1 - call obsrv%AddObsIndex(idx) - exit - end if - end do - if (this%flowbudptr%budterm(this%idxbudgwf)%id1(idx) /= nn1) then - write (errmsg, '(4x,a,1x,a,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'ERROR:', trim(adjustl(obsrv%ObsTypeId)), & - ' connection number =', nn2, & - '(does not correspond to control volume ', nn1, ')' - call store_error(errmsg) - end if - else if (obsrv%ObsTypeId=='FLOW-JA-FACE') then - nn2 = obsrv%NodeNumber2 - ! -- Look for the first occurrence of nn1, then set indxbnds - ! to the nn2 record after that - idx = 0 - do j = 1, this%flowbudptr%budterm(this%idxbudfjf)%nlist - if (this%flowbudptr%budterm(this%idxbudfjf)%id1(j) == nn1 .and. & - this%flowbudptr%budterm(this%idxbudfjf)%id2(j) == nn2) then - idx = j - call obsrv%AddObsIndex(idx) - exit - end if - end do - if (idx == 0) then - write (errmsg, '(4x,a,1x,a,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'ERROR:', trim(adjustl(obsrv%ObsTypeId)), & - ' lake number =', nn1, & - '(is not connected to lake ', nn2, ')' - call store_error(errmsg) - end if + case ('LKT', 'SFT', 'MWT', 'UZT') + call this%rp_obs_budterm(obsrv, & + this%flowbudptr%budterm(this%idxbudgwf)) + case ('FLOW-JA-FACE') + if (this%idxbudfjf > 0) then + call this%rp_obs_flowjaface(obsrv, & + this%flowbudptr%budterm(this%idxbudfjf)) else - call obsrv%AddObsIndex(nn1) - end if - else - errmsg = 'Programming error in apt_rp_obs' - call store_error(errmsg) - endif - end if - ! - ! -- catch non-cumulative observation assigned to observation defined - ! by a boundname that is assigned to more than one element - if (obsrv%ObsTypeId == 'CONCENTRATION') then - if (obsrv%indxbnds_count > 1) then - write (errmsg, '(4x,a,4(1x,a))') & - 'ERROR:', trim(adjustl(obsrv%ObsTypeId)), & - 'for observation', trim(adjustl(obsrv%Name)), & - ' must be assigned to a feature with a unique boundname.' - call store_error(errmsg) - end if - end if - ! - ! -- check that index values are valid - if (obsrv%ObsTypeId=='TO-MVR' .or. & - obsrv%ObsTypeId=='EXT-OUTFLOW') then - ntmvr = this%flowbudptr%budterm(this%idxbudtmvr)%nlist - do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) - if (nn1 < 1 .or. nn1 > ntmvr) then - write(errmsg, '(a, a, i0, a, i0, a)') & - trim(adjustl(obsrv%ObsTypeId)), & - ' must be > 0 or <= ', ntmvr, & - '. (specified value is ', nn1, ').' + write (errmsg, '(7a)') & + 'Observation ', trim(obsrv%Name), ' of type ', & + trim(adjustl(obsrv%ObsTypeId)), ' in package ', & + trim(this%packName), & + ' cannot be processed because there are no flow connections.' call store_error(errmsg) end if - end do - else if (obsrv%ObsTypeId == trim(adjustl(this%text)) .or. & - obsrv%ObsTypeId == 'FLOW-JA-FACE') then - do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) - if (nn1 < 1 .or. nn1 > this%maxbound) then - write (errmsg, '(4x,a,1x,a,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'ERROR:', trim(adjustl(obsrv%ObsTypeId)), & - ' connection number must be > 0 and <=', this%maxbound, & - '(specified value is ', nn1, ')' - call store_error(errmsg) - end if - end do - else - do j = 1, obsrv%indxbnds_count - nn1 = obsrv%indxbnds(j) - if (nn1 < 1 .or. nn1 > this%ncv) then - write (errmsg, '(4x,a,1x,a,1x,a,1x,i0,1x,a,1x,i0,1x,a)') & - 'ERROR:', trim(adjustl(obsrv%ObsTypeId)), & - ' control volume must be > 0 and <=', this%ncv, & - '(specified value is ', nn1, ')' - call store_error(errmsg) + case ('STORAGE') + call this%rp_obs_byfeature(obsrv) + case ('CONSTANT') + call this%rp_obs_byfeature(obsrv) + case ('FROM-MVR') + call this%rp_obs_byfeature(obsrv) + case default + ! + ! -- check the child package for any specific obs + found = .false. + call this%pak_rp_obs(obsrv, found) + ! + ! -- if none found then terminate with an error + if (.not. found) then + errmsg = 'Unrecognized observation type "'// & + trim(obsrv%ObsTypeId)//'" for '// & + trim(adjustl(this%text))//' package '// & + trim(this%packName) + call store_error(errmsg, terminate=.TRUE.) end if - end do + end select + + end do + ! + ! -- check for errors + if (count_errors() > 0) then + call store_error_unit(this%obs%inunitobs) end if - end do - ! - ! -- check for errors - if (count_errors() > 0) then - call store_error_unit(this%obs%inunitobs) end if ! return end subroutine apt_rp_obs - + subroutine apt_bd_obs(this) ! ****************************************************************************** ! apt_bd_obs -- Calculate observations common to SFT/LKT/MWT/UZT @@ -2823,6 +2953,7 @@ subroutine apt_bd_obs(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules ! -- dummy class(GwtAptType) :: this ! -- local @@ -2847,55 +2978,55 @@ subroutine apt_bd_obs(this) v = DNODATA jj = obsrv%indxbnds(j) select case (obsrv%ObsTypeId) - case ('CONCENTRATION') - if (this%iboundpak(jj) /= 0) then - v = this%xnewpak(jj) - end if - case ('LKT', 'SFT', 'MWT', 'UZT') - n = this%flowbudptr%budterm(this%idxbudgwf)%id1(jj) - if (this%iboundpak(n) /= 0) then - igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(jj) - v = this%hcof(jj) * this%xnew(igwfnode) - this%rhs(jj) - v = -v - end if - case ('FLOW-JA-FACE') - n = this%flowbudptr%budterm(this%idxbudgwf)%id1(jj) + case ('CONCENTRATION') + if (this%iboundpak(jj) /= 0) then + v = this%xnewpak(jj) + end if + case ('LKT', 'SFT', 'MWT', 'UZT') + n = this%flowbudptr%budterm(this%idxbudgwf)%id1(jj) + if (this%iboundpak(n) /= 0) then + igwfnode = this%flowbudptr%budterm(this%idxbudgwf)%id2(jj) + v = this%hcof(jj) * this%xnew(igwfnode) - this%rhs(jj) + v = -v + end if + case ('FLOW-JA-FACE') + n = this%flowbudptr%budterm(this%idxbudfjf)%id1(jj) + if (this%iboundpak(n) /= 0) then + call this%apt_fjf_term(jj, n1, n2, v) + end if + case ('STORAGE') + if (this%iboundpak(jj) /= 0) then + v = this%qsto(jj) + end if + case ('CONSTANT') + if (this%iboundpak(jj) /= 0) then + v = this%ccterm(jj) + end if + case ('FROM-MVR') + if (this%iboundpak(jj) /= 0 .and. this%idxbudfmvr > 0) then + v = this%qmfrommvr(jj) + end if + case ('TO-MVR') + if (this%idxbudtmvr > 0) then + n = this%flowbudptr%budterm(this%idxbudtmvr)%id1(jj) if (this%iboundpak(n) /= 0) then - call this%apt_fjf_term(jj, n1, n2, v) - end if - case ('STORAGE') - if (this%iboundpak(jj) /= 0) then - v = this%qsto(jj) - end if - case ('CONSTANT') - if (this%iboundpak(jj) /= 0) then - v = this%ccterm(jj) - end if - case ('FROM-MVR') - if (this%iboundpak(jj) /= 0 .and. this%idxbudfmvr > 0) then - v = this%qmfrommvr(jj) - end if - case ('TO-MVR') - if (this%idxbudtmvr > 0) then - n = this%flowbudptr%budterm(this%idxbudtmvr)%id1(jj) - if (this%iboundpak(n) /= 0) then - call this%apt_tmvr_term(jj, n1, n2, v) - end if - end if - case default - found = .false. - ! - ! -- check the child package for any specific obs - call this%pak_bd_obs(obsrv%ObsTypeId, jj, v, found) - ! - ! -- if none found then terminate with an error - if (.not. found) then - errmsg = 'Unrecognized observation type "' // & - trim(obsrv%ObsTypeId) // '" for ' // & - trim(adjustl(this%text)) // ' package ' // & - trim(this%packName) - call store_error(errmsg, terminate=.TRUE.) + call this%apt_tmvr_term(jj, n1, n2, v) end if + end if + case default + found = .false. + ! + ! -- check the child package for any specific obs + call this%pak_bd_obs(obsrv%ObsTypeId, jj, v, found) + ! + ! -- if none found then terminate with an error + if (.not. found) then + errmsg = 'Unrecognized observation type "'// & + trim(obsrv%ObsTypeId)//'" for '// & + trim(adjustl(this%text))//' package '// & + trim(this%packName) + call store_error(errmsg, terminate=.TRUE.) + end if end select call this%obs%SaveOneSimval(obsrv, v) end do @@ -2912,7 +3043,7 @@ end subroutine apt_bd_obs subroutine pak_bd_obs(this, obstypeid, jj, v, found) ! ****************************************************************************** -! pak_bd_obs -- +! pak_bd_obs -- ! -- check for observations in concrete packages. ! ****************************************************************************** ! @@ -2933,66 +3064,111 @@ subroutine pak_bd_obs(this, obstypeid, jj, v, found) return end subroutine pak_bd_obs + !> @brief Process observation IDs for a package + !! + !! Method to process observation ID strings for an APT package. + !! This processor is only for observation types that support ID1 + !! and not ID2. + !! + !< subroutine apt_process_obsID(obsrv, dis, inunitobs, iout) -! ****************************************************************************** -! apt_process_obsID -- -! -- This procedure is pointed to by ObsDataType%ProcesssIdPtr. It processes -! the ID string of an observation definition for LAK package observations. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - ! -- modules - ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout - ! -- local - integer(I4B) :: nn1, nn2 - integer(I4B) :: icol, istart, istop + ! -- dummy variables + type(ObserveType), intent(inout) :: obsrv !< Observation object + class(DisBaseType), intent(in) :: dis !< Discretization object + integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file + integer(I4B), intent(in) :: iout !< model listing file unit number + ! -- local variables + integer(I4B) :: nn1 + integer(I4B) :: icol + integer(I4B) :: istart + integer(I4B) :: istop character(len=LINELENGTH) :: strng character(len=LENBOUNDNAME) :: bndname - ! -- formats -! ------------------------------------------------------------------------------ ! + ! -- initialize local variables strng = obsrv%IDstring - ! -- Extract lake number from strng and store it. + ! + ! -- Extract reach number from strng and store it. ! If 1st item is not an integer(I4B), it should be a - ! lake name--deal with it. + ! boundary name--deal with it. icol = 1 - ! -- get number or boundary name + ! + ! -- get reach number or boundary name call extract_idnum_or_bndname(strng, icol, istart, istop, nn1, bndname) if (nn1 == NAMEDBOUNDFLAG) then obsrv%FeatureName = bndname - else - if (obsrv%ObsTypeId == 'LKT' .or. & - obsrv%ObsTypeId == 'SFT' .or. & - obsrv%ObsTypeId == 'MWT' .or. & - obsrv%ObsTypeId == 'UZT' .or. & - obsrv%ObsTypeId == 'FLOW-JA-FACE') then - call extract_idnum_or_bndname(strng, icol, istart, istop, nn2, bndname) - if (nn2 == NAMEDBOUNDFLAG) then - obsrv%FeatureName = bndname - ! -- reset nn1 - nn1 = nn2 - else - obsrv%NodeNumber2 = nn2 - end if - !! -- store connection number (NodeNumber2) - !obsrv%NodeNumber2 = nn2 - endif - endif - ! -- store lake number (NodeNumber) + end if + ! + ! -- store reach number (NodeNumber) obsrv%NodeNumber = nn1 ! + ! -- store NodeNumber2 as 1 so that this can be used + ! as the iconn value for SFT. This works for SFT + ! because there is only one reach per GWT connection. + obsrv%NodeNumber2 = 1 + ! + ! -- return return end subroutine apt_process_obsID - + + !> @brief Process observation IDs for a package + !! + !! Method to process observation ID strings for an APT package. + !! This processor is for the case where if ID1 is an integer + !! then ID2 must be provided. + !! + !< + subroutine apt_process_obsID12(obsrv, dis, inunitobs, iout) + ! -- dummy variables + type(ObserveType), intent(inout) :: obsrv !< Observation object + class(DisBaseType), intent(in) :: dis !< Discretization object + integer(I4B), intent(in) :: inunitobs !< file unit number for the package observation file + integer(I4B), intent(in) :: iout !< model listing file unit number + ! -- local variables + integer(I4B) :: nn1 + integer(I4B) :: iconn + integer(I4B) :: icol + integer(I4B) :: istart + integer(I4B) :: istop + character(len=LINELENGTH) :: strng + character(len=LENBOUNDNAME) :: bndname + ! + ! -- initialize local variables + strng = obsrv%IDstring + ! + ! -- Extract reach number from strng and store it. + ! If 1st item is not an integer(I4B), it should be a + ! boundary name--deal with it. + icol = 1 + ! + ! -- get reach number or boundary name + call extract_idnum_or_bndname(strng, icol, istart, istop, nn1, bndname) + if (nn1 == NAMEDBOUNDFLAG) then + obsrv%FeatureName = bndname + else + call extract_idnum_or_bndname(strng, icol, istart, istop, iconn, bndname) + if (len_trim(bndName) < 1 .and. iconn < 0) then + write (errmsg, '(a,1x,a,a,1x,a,1x,a)') & + 'For observation type', trim(adjustl(obsrv%ObsTypeId)), & + ', ID given as an integer and not as boundname,', & + 'but ID2 is missing. Either change ID to valid', & + 'boundname or supply valid entry for ID2.' + call store_error(errmsg) + end if + obsrv%NodeNumber2 = iconn + end if + ! + ! -- store reach number (NodeNumber) + obsrv%NodeNumber = nn1 + ! + ! -- return + return + end subroutine apt_process_obsID12 + subroutine apt_setup_tableobj(this) ! ****************************************************************************** -! apt_setup_tableobj -- Set up the table object that is used to write the apt -! conc data. The terms listed here must correspond in +! apt_setup_tableobj -- Set up the table object that is used to write the apt +! conc data. The terms listed here must correspond in ! in the apt_ot method. ! ****************************************************************************** ! @@ -3005,7 +3181,7 @@ subroutine apt_setup_tableobj(this) ! -- local integer(I4B) :: nterms character(len=LINELENGTH) :: title - character(len=LINELENGTH) :: text + character(len=LINELENGTH) :: text_temp ! ------------------------------------------------------------------------------ ! ! -- setup well head table @@ -3016,31 +3192,32 @@ subroutine apt_setup_tableobj(this) if (this%inamedbound == 1) nterms = nterms + 1 ! ! -- set up table title - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(adjustl(this%packName)) //') CONCENTRATION FOR EACH CONTROL VOLUME' + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(adjustl(this%packName))// & + ') CONCENTRATION FOR EACH CONTROL VOLUME' ! ! -- set up dv tableobj call table_cr(this%dvtab, this%packName, title) - call this%dvtab%table_df(this%ncv, nterms, this%iout, & + call this%dvtab%table_df(this%ncv, nterms, this%iout, & transient=.TRUE.) ! ! -- Go through and set up table budget term if (this%inamedbound == 1) then - text = 'NAME' - call this%dvtab%initialize_column(text, 20, alignment=TABLEFT) + text_temp = 'NAME' + call this%dvtab%initialize_column(text_temp, 20, alignment=TABLEFT) end if ! ! -- feature number - text = 'NUMBER' - call this%dvtab%initialize_column(text, 10, alignment=TABCENTER) + text_temp = 'NUMBER' + call this%dvtab%initialize_column(text_temp, 10, alignment=TABCENTER) ! ! -- feature conc - text = 'CONC' - call this%dvtab%initialize_column(text, 12, alignment=TABCENTER) + text_temp = 'CONC' + call this%dvtab%initialize_column(text_temp, 12, alignment=TABCENTER) end if ! ! -- return return end subroutine apt_setup_tableobj -end module GwtAptModule \ No newline at end of file +end module GwtAptModule diff --git a/src/Model/GroundWaterTransport/gwt1cnc1.f90 b/src/Model/GroundWaterTransport/gwt1cnc1.f90 index 5ef0f25e7d5..28f6a3d4814 100644 --- a/src/Model/GroundWaterTransport/gwt1cnc1.f90 +++ b/src/Model/GroundWaterTransport/gwt1cnc1.f90 @@ -1,11 +1,11 @@ module GwtCncModule ! - use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DONE, NAMEDBOUNDFLAG, LENFTYPE, & - LENPACKAGENAME - use ObsModule, only: DefaultObsIdProcessor - use BndModule, only: BndType - use ObserveModule, only: ObserveType + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, DONE, NAMEDBOUNDFLAG, LENFTYPE, & + LENPACKAGENAME + use ObsModule, only: DefaultObsIdProcessor + use BndModule, only: BndType + use ObserveModule, only: ObserveType use TimeSeriesLinkModule, only: TimeSeriesLinkType, & GetTimeSeriesLinkFromList ! @@ -14,13 +14,13 @@ module GwtCncModule private public :: cnc_create ! - character(len=LENFTYPE) :: ftype = 'CNC' - character(len=LENPACKAGENAME) :: text = ' CNC' + character(len=LENFTYPE) :: ftype = 'CNC' + character(len=LENPACKAGENAME) :: text = ' CNC' ! type, extends(BndType) :: GwtCncType - real(DP), dimension(:), pointer, contiguous :: ratecncin => null() !simulated flows into constant conc (excluding other concs) - real(DP), dimension(:), pointer, contiguous :: ratecncout => null() !simulated flows out of constant conc (excluding to other concs) - contains + real(DP), dimension(:), pointer, contiguous :: ratecncin => null() !simulated flows into constant conc (excluding other concs) + real(DP), dimension(:), pointer, contiguous :: ratecncout => null() !simulated flows out of constant conc (excluding to other concs) + contains procedure :: bnd_rp => cnc_rp procedure :: bnd_ad => cnc_ad procedure :: bnd_ck => cnc_ck @@ -50,10 +50,10 @@ subroutine cnc_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -61,7 +61,7 @@ subroutine cnc_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(cncobj) + allocate (cncobj) packobj => cncobj ! ! -- create name and memory path @@ -108,7 +108,8 @@ subroutine cnc_allocate_arrays(this, nodelist, auxvar) ! ! -- allocate ratecncex call mem_allocate(this%ratecncin, this%maxbound, 'RATECNCIN', this%memoryPath) - call mem_allocate(this%ratecncout, this%maxbound, 'RATECNCOUT', this%memoryPath) + call mem_allocate(this%ratecncout, this%maxbound, 'RATECNCOUT', & + this%memoryPath) do i = 1, this%maxbound this%ratecncin(i) = DZERO this%ratecncout(i) = DZERO @@ -117,7 +118,7 @@ subroutine cnc_allocate_arrays(this, nodelist, auxvar) ! -- return return end subroutine cnc_allocate_arrays - + subroutine cnc_rp(this) ! ****************************************************************************** ! cnc_rp -- Read and prepare @@ -133,33 +134,33 @@ subroutine cnc_rp(this) ! ------------------------------------------------------------------------------ ! ! -- Reset previous CNCs to active cell - do i=1,this%nbound - node = this%nodelist(i) - this%ibound(node) = this%ibcnum - enddo + do i = 1, this%nbound + node = this%nodelist(i) + this%ibound(node) = this%ibcnum + end do ! ! -- Call the parent class read and prepare call this%BndType%bnd_rp() ! ! -- Set ibound to -(ibcnum + 1) for constant concentration cells ierr = 0 - do i=1,this%nbound + do i = 1, this%nbound node = this%nodelist(i) ibd = this%ibound(node) - if(ibd < 0) then + if (ibd < 0) then call this%dis%noder_to_string(node, nodestr) call store_error('Error. Cell is already a constant concentration: ' & - // trim(adjustl(nodestr))) + //trim(adjustl(nodestr))) ierr = ierr + 1 else this%ibound(node) = -this%ibcnum - endif - enddo + end if + end do ! ! -- Stop if errors detected - if(ierr > 0) then + if (ierr > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -190,7 +191,7 @@ subroutine cnc_ad(this) cb = this%bound(1, i) this%xnew(node) = cb this%xold(node) = this%xnew(node) - enddo + end do ! ! -- For each observation, push simulated value and corresponding ! simulation time from "current" to "preceding" and reset @@ -212,7 +213,7 @@ subroutine cnc_ck(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(GwtCncType),intent(inout) :: this + class(GwtCncType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: errmsg character(len=30) :: nodestr @@ -220,18 +221,18 @@ subroutine cnc_ck(this) integer(I4B) :: node ! -- formats character(len=*), parameter :: fmtcncerr = & - "('CNC BOUNDARY ',i0,' CONC (',g0,') IS LESS THAN ZERO FOR CELL', a)" + &"('CNC BOUNDARY ',i0,' CONC (',g0,') IS LESS THAN ZERO FOR CELL', a)" ! ------------------------------------------------------------------------------ ! ! -- check stress period data do i = 1, this%nbound - node = this%nodelist(i) - ! -- accumulate errors - if (this%bound(1,i) < DZERO) then - call this%dis%noder_to_string(node, nodestr) - write(errmsg, fmt=fmtcncerr) i, this%bound(1,i), trim(nodestr) - call store_error(errmsg) - end if + node = this%nodelist(i) + ! -- accumulate errors + if (this%bound(1, i) < DZERO) then + call this%dis%noder_to_string(node, nodestr) + write (errmsg, fmt=fmtcncerr) i, this%bound(1, i), trim(nodestr) + call store_error(errmsg) + end if end do ! ! -- write summary of cnc package error messages @@ -288,7 +289,7 @@ subroutine cnc_cq(this, x, flowja, iadv) ! ------------------------------------------------------------------------------ ! ! -- If no boundaries, skip flow calculations. - if(this%nbound > 0) then + if (this%nbound > 0) then ! ! -- Loop through each boundary calculating flow. do i = 1, this%nbound @@ -300,7 +301,7 @@ subroutine cnc_cq(this, x, flowja, iadv) ! ! -- Calculate the flow rate into the cell. do ipos = this%dis%con%ia(node) + 1, & - this%dis%con%ia(node + 1) - 1 + this%dis%con%ia(node + 1) - 1 q = flowja(ipos) rate = rate - q ! -- only accumulate chin and chout for active @@ -315,7 +316,7 @@ subroutine cnc_cq(this, x, flowja, iadv) end if end do ! - ! -- For CNC, store total flow in rhs so it is available for other + ! -- For CNC, store total flow in rhs so it is available for other ! calculations this%rhs(i) = -rate this%hcof(i) = DZERO @@ -347,7 +348,7 @@ subroutine cnc_bd(this, model_budget) isuppress_output = 0 call rate_accumulator(this%ratecncin(1:this%nbound), ratin, dum) call rate_accumulator(this%ratecncout(1:this%nbound), ratout, dum) - call model_budget%addentry(ratin, ratout, delt, this%text, & + call model_budget%addentry(ratin, ratout, delt, this%text, & isuppress_output, this%packName) end subroutine cnc_bd @@ -387,21 +388,21 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'CONCENTRATION' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'CONCENTRATION' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -470,15 +471,15 @@ subroutine cnc_rp_ts(this) ! ------------------------------------------------------------------------------ ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then select case (tslink%JCol) case (1) tslink%Text = 'CONCENTRATION' end select - endif - enddo + end if + end do ! ! -- return return diff --git a/src/Model/GroundWaterTransport/gwt1dsp.f90 b/src/Model/GroundWaterTransport/gwt1dsp.f90 index d2a8fdd6d47..8419a508de0 100644 --- a/src/Model/GroundWaterTransport/gwt1dsp.f90 +++ b/src/Model/GroundWaterTransport/gwt1dsp.f90 @@ -1,13 +1,12 @@ module GwtDspModule - use KindModule, only: DP, I4B - use ConstantsModule, only: DONE, DZERO, DHALF, DPI + use KindModule, only: DP, I4B + use ConstantsModule, only: DONE, DZERO, DHALF, DPI use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use GwtFmiModule, only: GwtFmiType - use Xt3dModule, only: Xt3dType, xt3d_cr - use GwtDspOptionsModule, only: GwtDspOptionsType - use GwtDspGridDataModule, only: GwtDspGridDataType + use BaseDisModule, only: DisBaseType + use GwtFmiModule, only: GwtFmiType + use Xt3dModule, only: Xt3dType, xt3d_cr + use GwtDspOptionsModule, only: GwtDspOptionsType implicit none private @@ -15,35 +14,42 @@ module GwtDspModule public :: dsp_cr type, extends(NumericalPackageType) :: GwtDspType - - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() ! pointer to GWT model ibound - type(GwtFmiType), pointer :: fmi => null() ! pointer to GWT fmi object - real(DP), dimension(:), pointer, contiguous :: porosity => null() ! pointer to GWT storage porosity - real(DP), dimension(:), pointer, contiguous :: diffc => null() ! molecular diffusion coefficient for each cell - real(DP), dimension(:), pointer, contiguous :: alh => null() ! longitudinal horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: alv => null() ! longitudinal vertical dispersivity - real(DP), dimension(:), pointer, contiguous :: ath1 => null() ! transverse horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: ath2 => null() ! transverse horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: atv => null() ! transverse vertical dispersivity - integer(I4B), pointer :: idiffc => null() ! flag indicating diffusion is active - integer(I4B), pointer :: idisp => null() ! flag indicating mechanical dispersion is active - integer(I4B), pointer :: ixt3d => null() ! flag indicating xt3d is active - type(Xt3dType), pointer :: xt3d => null() ! xt3d object - real(DP), dimension(:), pointer, contiguous :: dispcoef => null() ! disp coefficient (only if xt3d not active) - integer(I4B), pointer :: id22 => null() ! flag indicating d22 is available - integer(I4B), pointer :: id33 => null() ! flag indicating d33 is available - real(DP), dimension(:), pointer, contiguous :: d11 => null() ! dispersion coefficient - real(DP), dimension(:), pointer, contiguous :: d22 => null() ! dispersion coefficient - real(DP), dimension(:), pointer, contiguous :: d33 => null() ! dispersion coefficient - real(DP), dimension(:), pointer, contiguous :: angle1 => null() ! rotation angle 1 - real(DP), dimension(:), pointer, contiguous :: angle2 => null() ! rotation angle 2 - real(DP), dimension(:), pointer, contiguous :: angle3 => null() ! rotation angle 3 - integer(I4B), pointer :: iangle1 => null() ! flag indicating angle1 is available - integer(I4B), pointer :: iangle2 => null() ! flag indicating angle2 is available - integer(I4B), pointer :: iangle3 => null() ! flag indicating angle3 is available - + + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() ! pointer to GWT model ibound + type(GwtFmiType), pointer :: fmi => null() ! pointer to GWT fmi object + real(DP), dimension(:), pointer, contiguous :: porosity => null() ! pointer to GWT storage porosity + real(DP), dimension(:), pointer, contiguous :: diffc => null() ! molecular diffusion coefficient for each cell + real(DP), dimension(:), pointer, contiguous :: alh => null() ! longitudinal horizontal dispersivity + real(DP), dimension(:), pointer, contiguous :: alv => null() ! longitudinal vertical dispersivity + real(DP), dimension(:), pointer, contiguous :: ath1 => null() ! transverse horizontal dispersivity + real(DP), dimension(:), pointer, contiguous :: ath2 => null() ! transverse horizontal dispersivity + real(DP), dimension(:), pointer, contiguous :: atv => null() ! transverse vertical dispersivity + integer(I4B), pointer :: idiffc => null() ! flag indicating diffusion is active + integer(I4B), pointer :: idisp => null() ! flag indicating mechanical dispersion is active + integer(I4B), pointer :: ialh => null() ! longitudinal horizontal dispersivity data flag + integer(I4B), pointer :: ialv => null() ! longitudinal vertical dispersivity data flag + integer(I4B), pointer :: iath1 => null() ! transverse horizontal dispersivity data flag + integer(I4B), pointer :: iath2 => null() ! transverse horizontal dispersivity data flag + integer(I4B), pointer :: iatv => null() ! transverse vertical dispersivity data flag + integer(I4B), pointer :: ixt3doff => null() ! xt3d off flag, xt3d is set inactive if 1 + integer(I4B), pointer :: ixt3drhs => null() ! xt3d rhs flag, xt3d rhs is set active if 1 + integer(I4B), pointer :: ixt3d => null() ! flag indicating xt3d is active + type(Xt3dType), pointer :: xt3d => null() ! xt3d object + real(DP), dimension(:), pointer, contiguous :: dispcoef => null() ! disp coefficient (only if xt3d not active) + integer(I4B), pointer :: id22 => null() ! flag indicating d22 is available + integer(I4B), pointer :: id33 => null() ! flag indicating d33 is available + real(DP), dimension(:), pointer, contiguous :: d11 => null() ! dispersion coefficient + real(DP), dimension(:), pointer, contiguous :: d22 => null() ! dispersion coefficient + real(DP), dimension(:), pointer, contiguous :: d33 => null() ! dispersion coefficient + real(DP), dimension(:), pointer, contiguous :: angle1 => null() ! rotation angle 1 + real(DP), dimension(:), pointer, contiguous :: angle2 => null() ! rotation angle 2 + real(DP), dimension(:), pointer, contiguous :: angle3 => null() ! rotation angle 3 + integer(I4B), pointer :: iangle1 => null() ! flag indicating angle1 is available + integer(I4B), pointer :: iangle2 => null() ! flag indicating angle2 is available + integer(I4B), pointer :: iangle3 => null() ! flag indicating angle3 is available + contains - + procedure :: dsp_df procedure :: dsp_ac procedure :: dsp_mc @@ -54,16 +60,17 @@ module GwtDspModule procedure :: dsp_da procedure :: allocate_scalars procedure :: allocate_arrays - procedure, private :: read_options - procedure, private :: read_data - procedure, private :: set_data + procedure, private :: source_options + procedure, private :: source_griddata + procedure, private :: log_options + procedure, private :: log_griddata procedure, private :: calcdispellipse procedure, private :: calcdispcoef - + end type GwtDspType - - contains - + +contains + subroutine dsp_cr(dspobj, name_model, inunit, iout, fmi) ! ****************************************************************************** ! dsp_cr -- Create a new DSP object @@ -71,16 +78,23 @@ subroutine dsp_cr(dspobj, name_model, inunit, iout, fmi) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ + ! -- modules + use IdmMf6FileLoaderModule, only: input_load + use ConstantsModule, only: LENPACKAGETYPE ! -- dummy type(GwtDspType), pointer :: dspobj character(len=*), intent(in) :: name_model integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout type(GwtFmiType), intent(in), target :: fmi + ! -- formats + character(len=*), parameter :: fmtdsp = & + "(1x,/1x,'DSP-- DISPERSION PACKAGE, VERSION 1, 1/24/2018', & + &' INPUT READ FROM UNIT ', i0, //)" ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(dspobj) + allocate (dspobj) ! ! -- create name and memory path call dspobj%set_names(1, name_model, 'DSP', 'DSP') @@ -93,13 +107,30 @@ subroutine dsp_cr(dspobj, name_model, inunit, iout, fmi) dspobj%iout = iout dspobj%fmi => fmi ! + ! -- Check if input file is open + if (dspobj%inunit > 0) then + ! + ! -- Print a message identifying the dispersion package. + if (dspobj%iout > 0) then + write (dspobj%iout, fmtdsp) dspobj%inunit + end if + ! + ! -- Initialize block parser + call dspobj%parser%Initialize(dspobj%inunit, dspobj%iout) + ! + ! -- Use the input data model routines to load the input data + ! into memory + call input_load(dspobj%parser, 'DSP6', 'GWT', 'DSP', dspobj%name_model, & + 'DSP', [character(len=LENPACKAGETYPE) ::], iout) + end if + ! ! -- Return return end subroutine dsp_cr subroutine dsp_df(this, dis, dspOptions) ! ****************************************************************************** -! dsp_df -- Allocate and Read +! dsp_df -- Define ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -111,10 +142,6 @@ subroutine dsp_df(this, dis, dspOptions) type(GwtDspOptionsType), optional, intent(in) :: dspOptions !< the optional DSP options, used when not !! creating DSP from file ! -- local - ! -- formats - character(len=*), parameter :: fmtdsp = & - "(1x,/1x,'DSP-- DISPERSION PACKAGE, VERSION 1, 1/24/2018', & - &' INPUT READ FROM UNIT ', i0, //)" ! ------------------------------------------------------------------------------ ! ! -- Store pointer to dis @@ -127,20 +154,26 @@ subroutine dsp_df(this, dis, dspOptions) ! -- Read dispersion options if (present(dspOptions)) then this%ixt3d = dspOptions%ixt3d - else ! - ! -- Initialize block parser - call this%parser%Initialize(this%inunit, this%iout) - call this%read_options() + ! -- Allocate only, grid data will not be read from file + call this%allocate_arrays(this%dis%nodes) + else + ! + ! -- Source options + call this%source_options() + call this%allocate_arrays(this%dis%nodes) + ! + ! -- Source dispersion data + call this%source_griddata() end if ! ! -- xt3d create - if(this%ixt3d > 0) then - call xt3d_cr(this%xt3d, this%name_model, this%inunit, this%iout, & + if (this%ixt3d > 0) then + call xt3d_cr(this%xt3d, this%name_model, this%inunit, this%iout, & ldispopt=.true.) this%xt3d%ixt3d = this%ixt3d call this%xt3d%xt3d_df(dis) - endif + end if ! ! -- Return return @@ -188,13 +221,13 @@ subroutine dsp_mc(this, moffset, iasln, jasln) ! ------------------------------------------------------------------------------ ! ! -- Call xt3d map connections - if(this%ixt3d > 0) call this%xt3d%xt3d_mc(moffset, iasln, jasln) + if (this%ixt3d > 0) call this%xt3d%xt3d_mc(moffset, iasln, jasln) ! ! -- Return return end subroutine dsp_mc - subroutine dsp_ar(this, ibound, porosity, grid_data) + subroutine dsp_ar(this, ibound, porosity) ! ****************************************************************************** ! dsp_ar -- Allocate and Read ! ****************************************************************************** @@ -206,35 +239,17 @@ subroutine dsp_ar(this, ibound, porosity, grid_data) class(GwtDspType) :: this integer(I4B), dimension(:), pointer, contiguous :: ibound real(DP), dimension(:), pointer, contiguous :: porosity - type(GwtDspGridDataType), optional, intent(in) :: grid_data !< optional data structure with DSP grid data, - !! to create the package without input file ! -- local ! -- formats - character(len=*), parameter :: fmtdsp = & - "(1x,/1x,'DSP-- DISPERSION PACKAGE, VERSION 1, 1/24/2018', & + character(len=*), parameter :: fmtdsp = & + "(1x,/1x,'DSP-- DISPERSION PACKAGE, VERSION 1, 1/24/2018', & &' INPUT READ FROM UNIT ', i0, //)" ! ------------------------------------------------------------------------------ ! ! -- dsp pointers to arguments that were passed in - this%ibound => ibound + this%ibound => ibound this%porosity => porosity ! - ! -- Print a message identifying the dispersion package. - if (this%iout > 0) then - write(this%iout, fmtdsp) this%inunit - end if - ! - ! -- Allocate arrays - call this%allocate_arrays(this%dis%nodes) - ! - if (present(grid_data)) then - ! -- Set dispersion data - call this%set_data(grid_data) - else - ! -- Read dispersion data - call this%read_data() - end if - ! ! -- Return return end subroutine dsp_ar @@ -257,11 +272,13 @@ subroutine dsp_ad(this) ! TODO: might consider adding a new mf6 level set pointers method, and ! doing this stuff there instead of in the time step loop. if (kstp * kper == 1) then - if(this%ixt3d > 0) call this%xt3d%xt3d_ar(this%fmi%ibdgwfsat0, & - this%d11, this%id33, this%d33, this%fmi%gwfsat, this%id22, this%d22, & - this%iangle1, this%iangle2, this%iangle3, & - this%angle1, this%angle2, this%angle3) - endif + if (this%ixt3d > 0) then + call this%xt3d%xt3d_ar(this%fmi%ibdgwfsat0, this%d11, this%id33, & + this%d33, this%fmi%gwfsat, this%id22, this%d22, & + this%iangle1, this%iangle2, this%iangle3, & + this%angle1, this%angle2, this%angle3) + end if + end if ! ! -- Fill d11, d22, d33, angle1, angle2, angle3 using specific discharge call this%calcdispellipse() @@ -272,7 +289,7 @@ subroutine dsp_ad(this) call this%calcdispcoef() else if (this%ixt3d > 0) then call this%xt3d%xt3d_fcpc(this%dis%nodes, .false.) - endif + end if end if ! ! -- Return @@ -290,29 +307,29 @@ subroutine dsp_fc(this, kiter, nodes, nja, njasln, amatsln, idxglo, rhs, cnew) ! -- dummy class(GwtDspType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: nodes - integer(I4B),intent(in) :: nja - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amatsln - integer(I4B),intent(in),dimension(nja) :: idxglo - real(DP),intent(inout),dimension(nodes) :: rhs - real(DP),intent(inout),dimension(nodes) :: cnew + integer(I4B), intent(in) :: nodes + integer(I4B), intent(in) :: nja + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amatsln + integer(I4B), intent(in), dimension(nja) :: idxglo + real(DP), intent(inout), dimension(nodes) :: rhs + real(DP), intent(inout), dimension(nodes) :: cnew ! -- local integer(I4B) :: n, m, idiag, idiagm, ipos, isympos, isymcon real(DP) :: dnm ! ------------------------------------------------------------------------------ ! - if(this%ixt3d > 0) then + if (this%ixt3d > 0) then call this%xt3d%xt3d_fc(kiter, njasln, amatsln, idxglo, rhs, cnew) else do n = 1, nodes - if(this%fmi%ibdgwfsat0(n) == 0) cycle + if (this%fmi%ibdgwfsat0(n) == 0) cycle idiag = this%dis%con%ia(n) do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 if (this%dis%con%mask(ipos) == 0) cycle m = this%dis%con%ja(ipos) if (m < n) cycle - if(this%fmi%ibdgwfsat0(m) == 0) cycle + if (this%fmi%ibdgwfsat0(m) == 0) cycle isympos = this%dis%con%jas(ipos) dnm = this%dispcoef(isympos) ! @@ -325,14 +342,14 @@ subroutine dsp_fc(this, kiter, nodes, nja, njasln, amatsln, idxglo, rhs, cnew) isymcon = this%dis%con%isym(ipos) amatsln(idxglo(isymcon)) = amatsln(idxglo(isymcon)) + dnm amatsln(idxglo(idiagm)) = amatsln(idxglo(idiagm)) - dnm - enddo - enddo - endif + end do + end do + end if ! ! -- Return return end subroutine dsp_fc - + subroutine dsp_cq(this, cnew, flowja) ! ****************************************************************************** ! dsp_cq -- Calculate dispersion contribution to flowja @@ -351,25 +368,25 @@ subroutine dsp_cq(this, cnew, flowja) ! ------------------------------------------------------------------------------ ! ! -- Calculate dispersion and add to flowja - if(this%ixt3d > 0) then + if (this%ixt3d > 0) then call this%xt3d%xt3d_flowja(cnew, flowja) else do n = 1, this%dis%nodes - if(this%fmi%ibdgwfsat0(n) == 0) cycle + if (this%fmi%ibdgwfsat0(n) == 0) cycle do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 m = this%dis%con%ja(ipos) - if(this%fmi%ibdgwfsat0(m) == 0) cycle + if (this%fmi%ibdgwfsat0(m) == 0) cycle isympos = this%dis%con%jas(ipos) dnm = this%dispcoef(isympos) flowja(ipos) = flowja(ipos) + dnm * (cnew(m) - cnew(n)) - enddo - enddo - endif + end do + end do + end if ! ! -- Return return end subroutine dsp_cq - + subroutine allocate_scalars(this) ! ****************************************************************************** ! allocate_scalars @@ -391,6 +408,13 @@ subroutine allocate_scalars(this) ! -- Allocate call mem_allocate(this%idiffc, 'IDIFFC', this%memoryPath) call mem_allocate(this%idisp, 'IDISP', this%memoryPath) + call mem_allocate(this%ialh, 'IALH', this%memoryPath) + call mem_allocate(this%ialv, 'IALV', this%memoryPath) + call mem_allocate(this%iath1, 'IATH1', this%memoryPath) + call mem_allocate(this%iath2, 'IATH2', this%memoryPath) + call mem_allocate(this%iatv, 'IATV', this%memoryPath) + call mem_allocate(this%ixt3doff, 'IXT3DOFF', this%memoryPath) + call mem_allocate(this%ixt3drhs, 'IXT3DRHS', this%memoryPath) call mem_allocate(this%ixt3d, 'IXT3D', this%memoryPath) call mem_allocate(this%id22, 'ID22', this%memoryPath) call mem_allocate(this%id33, 'ID33', this%memoryPath) @@ -401,6 +425,13 @@ subroutine allocate_scalars(this) ! -- Initialize this%idiffc = 0 this%idisp = 0 + this%ialh = 0 + this%ialv = 0 + this%iath1 = 0 + this%iath2 = 0 + this%iatv = 0 + this%ixt3doff = 0 + this%ixt3drhs = 0 this%ixt3d = 0 this%id22 = 1 this%id33 = 1 @@ -429,12 +460,12 @@ subroutine allocate_arrays(this, nodes) ! ------------------------------------------------------------------------------ ! ! -- Allocate - call mem_allocate(this%alh, 0, 'ALH', trim(this%memoryPath)) - call mem_allocate(this%alv, 0, 'ALV', trim(this%memoryPath)) - call mem_allocate(this%ath1, 0, 'ATH1', trim(this%memoryPath)) - call mem_allocate(this%ath2, 0, 'ATH2', trim(this%memoryPath)) - call mem_allocate(this%atv, 0, 'ATV', trim(this%memoryPath)) - call mem_allocate(this%diffc, 0, 'DIFFC', trim(this%memoryPath)) + call mem_allocate(this%alh, nodes, 'ALH', trim(this%memoryPath)) + call mem_allocate(this%alv, nodes, 'ALV', trim(this%memoryPath)) + call mem_allocate(this%ath1, nodes, 'ATH1', trim(this%memoryPath)) + call mem_allocate(this%ath2, nodes, 'ATH2', trim(this%memoryPath)) + call mem_allocate(this%atv, nodes, 'ATV', trim(this%memoryPath)) + call mem_allocate(this%diffc, nodes, 'DIFFC', trim(this%memoryPath)) call mem_allocate(this%d11, nodes, 'D11', trim(this%memoryPath)) call mem_allocate(this%d22, nodes, 'D22', trim(this%memoryPath)) call mem_allocate(this%d33, nodes, 'D33', trim(this%memoryPath)) @@ -444,11 +475,11 @@ subroutine allocate_arrays(this, nodes) ! ! -- Allocate dispersion coefficient array if xt3d not in use if (this%ixt3d == 0) then - call mem_allocate(this%dispcoef, this%dis%njas, 'DISPCOEF', & - trim(this%memoryPath)) + call mem_allocate(this%dispcoef, this%dis%njas, 'DISPCOEF', & + trim(this%memoryPath)) else call mem_allocate(this%dispcoef, 0, 'DISPCOEF', trim(this%memoryPath)) - endif + end if ! ! -- Return return @@ -463,10 +494,15 @@ subroutine dsp_da(this) ! ------------------------------------------------------------------------------ ! -- modules use MemoryManagerModule, only: mem_deallocate + use MemoryManagerExtModule, only: memorylist_remove + use SimVariablesModule, only: idm_context ! -- dummy class(GwtDspType) :: this ! -- local ! ------------------------------------------------------------------------------ + ! + ! -- Deallocate input memory + call memorylist_remove(this%name_model, 'DSP', idm_context) ! ! -- deallocate arrays if (this%inunit /= 0) then @@ -487,11 +523,18 @@ subroutine dsp_da(this) end if ! ! -- deallocate objects - if (this%ixt3d > 0) deallocate(this%xt3d) + if (this%ixt3d > 0) deallocate (this%xt3d) ! ! -- deallocate scalars call mem_deallocate(this%idiffc) call mem_deallocate(this%idisp) + call mem_deallocate(this%ialh) + call mem_deallocate(this%ialv) + call mem_deallocate(this%iath1) + call mem_deallocate(this%iath2) + call mem_deallocate(this%iatv) + call mem_deallocate(this%ixt3doff) + call mem_deallocate(this%ixt3drhs) call mem_deallocate(this%ixt3d) call mem_deallocate(this%id22) call mem_deallocate(this%id33) @@ -506,239 +549,192 @@ subroutine dsp_da(this) return end subroutine dsp_da - subroutine read_options(this) + !> @brief Write user options to list file + !< + subroutine log_options(this, found) + use GwtDspInputModule, only: GwtDspParamFoundType + class(GwTDspType) :: this + type(GwtDspParamFoundType), intent(in) :: found + + write (this%iout, '(1x,a)') 'Setting DSP Options' + write (this%iout, '(4x,a,i0)') 'XT3D formulation [0=INACTIVE, 1=ACTIVE, & + &3=ACTIVE RHS] set to: ', this%ixt3d + write (this%iout, '(1x,a,/)') 'End Setting DSP Options' + end subroutine log_options + + subroutine source_options(this) ! ****************************************************************************** -! read_options -- Allocate and Read +! source_options -- update simulation mempath options ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error + !use KindModule, only: LGP + use MemoryHelperModule, only: create_mem_path + use MemoryTypeModule, only: MemoryType + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use ConstantsModule, only: LENMEMPATH + use GwtDspInputModule, only: GwtDspParamFoundType ! -- dummy class(GwtDspType) :: this - ! -- local - character(len=LINELENGTH) :: errmsg, keyword - integer(I4B) :: ierr - logical :: isfound, endOfBlock - ! -- formats + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + type(GwtDspParamFoundType) :: found ! ------------------------------------------------------------------------------ ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, blockRequired=.false., & - supportOpenClose=.true.) - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING DISPERSION OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('XT3D_OFF') - this%ixt3d = 0 - write(this%iout, '(4x,a)') & - 'XT3D FORMULATION HAS BEEN SHUT OFF.' - case ('XT3D_RHS') - this%ixt3d = 2 - write(this%iout, '(4x,a)') & - 'XT3D RIGHT-HAND SIDE FORMULATION IS SELECTED.' - case default - write(errmsg,'(4x,a,a)')'UNKNOWN DISPERSION OPTION: ', & - trim(keyword) - call store_error(errmsg, terminate=.TRUE.) - end select - end do - write(this%iout,'(1x,a)')'END OF DISPERSION OPTIONS' + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DSP', idm_context) + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%ixt3doff, 'XT3D_OFF', idmMemoryPath, found%xt3d_off) + call mem_set_value(this%ixt3drhs, 'XT3D_RHS', idmMemoryPath, found%xt3d_rhs) + ! + ! -- set xt3d state flag + if (found%xt3d_off) this%ixt3d = 0 + if (found%xt3d_rhs) this%ixt3d = 2 + ! + ! -- log options + if (this%iout > 0) then + call this%log_options(found) end if ! ! -- Return return - end subroutine read_options + end subroutine source_options + + !> @brief Write dimensions to list file + !< + subroutine log_griddata(this, found) + use GwtDspInputModule, only: GwtDspParamFoundType + class(GwtDspType) :: this + type(GwtDspParamFoundType), intent(in) :: found - subroutine read_data(this) + write (this%iout, '(1x,a)') 'Setting DSP Griddata' + + if (found%diffc) then + write (this%iout, '(4x,a)') 'DIFFC set from input file' + end if + + if (found%alh) then + write (this%iout, '(4x,a)') 'ALH set from input file' + end if + + if (found%alv) then + write (this%iout, '(4x,a)') 'ALV set from input file' + end if + + if (found%ath1) then + write (this%iout, '(4x,a)') 'ATH1 set from input file' + end if + + if (found%ath2) then + write (this%iout, '(4x,a)') 'ATH2 set from input file' + end if + + if (found%atv) then + write (this%iout, '(4x,a)') 'ATV set from input file' + end if + + write (this%iout, '(1x,a,/)') 'End Setting DSP Griddata' + + end subroutine log_griddata + + subroutine source_griddata(this) ! ****************************************************************************** -! read_data -- read the dispersion data +! source_griddata -- update dsp simulation data from input mempath ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, count_errors - use MemoryManagerModule, only: mem_reallocate, mem_copyptr, mem_reassignptr + ! -- modules + use SimModule, only: count_errors, store_error + use MemoryHelperModule, only: create_mem_path + use MemoryManagerModule, only: mem_reallocate, mem_reassignptr + use MemoryManagerExtModule, only: mem_set_value + use SimVariablesModule, only: idm_context + use ConstantsModule, only: LENMEMPATH, LINELENGTH + use GwtDspInputModule, only: GwtDspParamFoundType ! -- dummy class(GwtDsptype) :: this - ! -- local - character(len=LINELENGTH) :: errmsg, keyword - character(len=:), allocatable :: line - integer(I4B) :: istart, istop, lloc, ierr - logical :: isfound, endOfBlock - logical, dimension(6) :: lname - character(len=24), dimension(6) :: aname + ! -- locals + character(len=LENMEMPATH) :: idmMemoryPath + character(len=LINELENGTH) :: errmsg + type(GwtDspParamFoundType) :: found + integer(I4B), dimension(:), pointer, contiguous :: map ! -- formats - ! -- data - data aname(1) /' DIFFUSION COEFFICIENT'/ - data aname(2) /' ALH'/ - data aname(3) /' ALV'/ - data aname(4) /' ATH1'/ - data aname(5) /' ATH2'/ - data aname(6) /' ATV'/ ! ------------------------------------------------------------------------------ ! - ! -- initialize - lname(:) = .false. - isfound = .false. - ! - ! -- get griddata block - call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - call this%parser%GetRemainingLine(line) - lloc = 1 - select case (keyword) - case ('DIFFC') - call mem_reallocate(this%diffc, this%dis%nodes, 'DIFFC', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%diffc, & - aname(1)) - lname(1) = .true. - case ('ALH') - call mem_reallocate(this%alh, this%dis%nodes, 'ALH', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%alh, & - aname(2)) - lname(2) = .true. - case ('ALV') - call mem_reallocate(this%alv, this%dis%nodes, 'ALV', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%alv, & - aname(3)) - lname(3) = .true. - case ('ATH1') - call mem_reallocate(this%ath1, this%dis%nodes, 'ATH1', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%ath1, & - aname(4)) - lname(4) = .true. - case ('ATH2') - call mem_reallocate(this%ath2, this%dis%nodes, 'ATH2', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%ath2, & - aname(5)) - lname(5) = .true. - case ('ATV') - call mem_reallocate(this%atv, this%dis%nodes, 'ATV', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%atv, & - aname(6)) - lname(6) = .true. - case default - write(errmsg,'(4x,a,a)') 'Unknown GRIDDATA tag: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end select - end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' - else - write(errmsg,'(1x,a)') 'Required GRIDDATA block not found.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() + ! -- set memory path + idmMemoryPath = create_mem_path(this%name_model, 'DSP', idm_context) + ! + ! -- set map + map => null() + if (this%dis%nodes < this%dis%nodesuser) map => this%dis%nodeuser + ! + ! -- update defaults with idm sourced values + call mem_set_value(this%diffc, 'DIFFC', idmMemoryPath, map, found%diffc) + call mem_set_value(this%alh, 'ALH', idmMemoryPath, map, found%alh) + call mem_set_value(this%alv, 'ALV', idmMemoryPath, map, found%alv) + call mem_set_value(this%ath1, 'ATH1', idmMemoryPath, map, found%ath1) + call mem_set_value(this%ath2, 'ATH2', idmMemoryPath, map, found%ath2) + call mem_set_value(this%atv, 'ATV', idmMemoryPath, map, found%atv) + ! + ! -- set active flags + if (found%diffc) this%idiffc = 1 + if (found%alh) this%ialh = 1 + if (found%alv) this%ialv = 1 + if (found%ath1) this%iath1 = 1 + if (found%ath2) this%iath2 = 1 + if (found%atv) this%iatv = 1 + ! + ! -- reallocate diffc if not found + if (.not. found%diffc) then + call mem_reallocate(this%diffc, 0, 'DIFFC', trim(this%memoryPath)) end if ! - if(lname(1)) this%idiffc = 1 - if(lname(2)) this%idisp = this%idisp + 1 - if(lname(3)) this%idisp = this%idisp + 1 - if(lname(4)) this%idisp = this%idisp + 1 - if(lname(5)) this%idisp = this%idisp + 1 - ! - ! -- if dispersivities are specified, then both alh and ath1 must be included - if(this%idisp > 0) then - ! - ! -- make sure alh was specified - if (.not. lname(2)) then - write(errmsg,'(1x,a)') 'IF DISPERSIVITIES ARE SPECIFIED THEN ALH IS REQUIRED.' + ! -- set this%idisp flag + if (found%alh) this%idisp = this%idisp + 1 + if (found%alv) this%idisp = this%idisp + 1 + if (found%ath1) this%idisp = this%idisp + 1 + if (found%ath2) this%idisp = this%idisp + 1 + ! + ! -- manage dispersion arrays + if (this%idisp > 0) then + if (.not. (found%alh .and. found%ath1)) then + write (errmsg, '(1x,a)') & + 'if dispersivities are specified then ALH and ATH1 are required.' call store_error(errmsg) - endif - ! - ! -- make sure ath1 was specified - if (.not. lname(4)) then - write(errmsg,'(1x,a)') 'IF DISPERSIVITIES ARE SPECIFIED THEN ATH1 IS REQUIRED.' - call store_error(errmsg) - endif - ! + end if ! -- If alv not specified then point it to alh - if(.not. lname(3)) then - call mem_reassignptr(this%alv, 'ALV', trim(this%memoryPath), & - 'ALH', trim(this%memoryPath)) - endif - ! - ! -- If ath2 not specified then assign it to ath1 - if (.not. lname(5)) then - call mem_reassignptr(this%ath2, 'ATH2', trim(this%memoryPath), & - 'ATH1', trim(this%memoryPath)) - endif - ! - ! -- If atv not specified then assign it to ath2 - if (.not. lname(6)) then - call mem_reassignptr(this%atv, 'ATV', trim(this%memoryPath), & - 'ATH2', trim(this%memoryPath)) - endif - endif - ! - ! -- terminate if errors - if(count_errors() > 0) then - call this%parser%StoreErrorUnit() - endif + if (.not. found%alv) & + call mem_reassignptr(this%alv, 'ALV', trim(this%memoryPath), & + 'ALH', trim(this%memoryPath)) + ! -- If ath2 not specified then point it to ath1 + if (.not. found%ath2) & + call mem_reassignptr(this%ath2, 'ATH2', trim(this%memoryPath), & + 'ATH1', trim(this%memoryPath)) + ! -- If atv not specified then point it to ath2 + if (.not. found%atv) & + call mem_reassignptr(this%atv, 'ATV', trim(this%memoryPath), & + 'ATH2', trim(this%memoryPath)) + else + call mem_reallocate(this%alh, 0, 'ALH', trim(this%memoryPath)) + call mem_reallocate(this%alv, 0, 'ALV', trim(this%memoryPath)) + call mem_reallocate(this%ath1, 0, 'ATH1', trim(this%memoryPath)) + call mem_reallocate(this%ath2, 0, 'ATH2', trim(this%memoryPath)) + call mem_reallocate(this%atv, 0, 'ATV', trim(this%memoryPath)) + end if + ! + ! -- log griddata + if (this%iout > 0) then + call this%log_griddata(found) + end if ! ! -- Return return - end subroutine read_data - - - !< @brief Set the grid data to the package - !< - subroutine set_data(this, grid_data) - use MemoryManagerModule, only: mem_reallocate - class(GwtDspType) :: this !< this DSP package - type(GwtDspGridDataType), intent(in) :: grid_data !< the data structure with DSP grid data - ! local - integer(I4B) :: i - - call mem_reallocate(this%diffc, this%dis%nodes, 'DIFFC', & - trim(this%memoryPath)) - call mem_reallocate(this%alh, this%dis%nodes, 'ALH', & - trim(this%memoryPath)) - call mem_reallocate(this%alv, this%dis%nodes, 'ALV', & - trim(this%memoryPath)) - call mem_reallocate(this%ath1, this%dis%nodes, 'ATH1', & - trim(this%memoryPath)) - call mem_reallocate(this%ath2, this%dis%nodes, 'ATH2', & - trim(this%memoryPath)) - call mem_reallocate(this%atv, this%dis%nodes, 'ATV', & - trim(this%memoryPath)) - - do i = 1, this%dis%nodes - this%diffc(i) = grid_data%diffc(i) - this%alh(i) = grid_data%alh(i) - this%alv(i) = grid_data%alv(i) - this%ath1(i) = grid_data%ath1(i) - this%ath2(i) = grid_data%ath2(i) - this%atv(i) = grid_data%atv(i) - end do - - end subroutine + end subroutine source_griddata subroutine calcdispellipse(this) ! ****************************************************************************** @@ -770,7 +766,7 @@ subroutine calcdispellipse(this) this%angle1(n) = DZERO this%angle2(n) = DZERO this%angle3(n) = DZERO - if(this%fmi%ibdgwfsat0(n) == 0) cycle + if (this%fmi%ibdgwfsat0(n) == 0) cycle ! ! -- specific discharge qx = DZERO @@ -780,7 +776,7 @@ subroutine calcdispellipse(this) qx = this%fmi%gwfspdis(1, n) qy = this%fmi%gwfspdis(2, n) qz = this%fmi%gwfspdis(3, n) - q = qx ** 2 + qy ** 2 + qz ** 2 + q = qx**2 + qy**2 + qz**2 if (q > DZERO) q = sqrt(q) ! ! -- dispersion coefficients @@ -795,22 +791,22 @@ subroutine calcdispellipse(this) ath1 = this%ath1(n) ath2 = this%ath2(n) atv = this%atv(n) - endif + end if dstar = DZERO if (this%idiffc > 0) then dstar = this%diffc(n) * this%porosity(n) - endif + end if ! ! -- Calculate the longitudal and transverse dispersivities al = DZERO at1 = DZERO at2 = DZERO if (q > DZERO) then - qzoqsquared = (qz / q) ** 2 + qzoqsquared = (qz / q)**2 al = alh * (DONE - qzoqsquared) + alv * qzoqsquared at1 = ath1 * (DONE - qzoqsquared) + atv * qzoqsquared at2 = ath2 * (DONE - qzoqsquared) + atv * qzoqsquared - endif + end if ! ! -- Calculate and save the diagonal components of the dispersion tensor this%d11(n) = al * q + dstar @@ -839,7 +835,7 @@ subroutine calcdispellipse(this) a = qx / a else a = DZERO - endif + end if ! ! -- acos(1) not defined, so set to zero if necessary if (a <= -DONE) then @@ -848,10 +844,10 @@ subroutine calcdispellipse(this) this%angle1(n) = DZERO else this%angle1(n) = acos(a) - endif + end if ! - endif - enddo + end if + end do ! ! -- Return return @@ -885,7 +881,7 @@ subroutine calcdispcoef(this) ! -- Proces connections nodes = size(this%d11) do n = 1, nodes - if(this%fmi%ibdgwfsat0(n) == 0) cycle + if (this%fmi%ibdgwfsat0(n) == 0) cycle idiag = this%dis%con%ia(n) do ipos = this%dis%con%ia(n) + 1, this%dis%con%ia(n + 1) - 1 ! @@ -896,7 +892,7 @@ subroutine calcdispcoef(this) if (m < n) cycle isympos = this%dis%con%jas(ipos) this%dispcoef(isympos) = DZERO - if(this%fmi%ibdgwfsat0(m) == 0) cycle + if (this%fmi%ibdgwfsat0(m) == 0) cycle ! ! -- cell dimensions hwva = this%dis%con%hwva(isympos) @@ -916,16 +912,16 @@ subroutine calcdispcoef(this) ! normal to the shared n-m face and for cell m in the direction ! normal to the shared n-m face. call this%dis%connection_normal(n, m, ihc, vg1, vg2, vg3, ipos) - dn = hyeff_calc(this%d11(n), this%d22(n), this%d33(n), & - this%angle1(n), this%angle2(n), this%angle3(n), & + dn = hyeff_calc(this%d11(n), this%d22(n), this%d33(n), & + this%angle1(n), this%angle2(n), this%angle3(n), & vg1, vg2, vg3, iavgmeth) - dm = hyeff_calc(this%d11(m), this%d22(m), this%d33(m), & - this%angle1(m), this%angle2(m), this%angle3(m), & + dm = hyeff_calc(this%d11(m), this%d22(m), this%d33(m), & + this%angle1(m), this%angle2(m), this%angle3(m), & vg1, vg2, vg3, iavgmeth) ! ! -- Calculate dispersion conductance based on NPF subroutines and the ! effective dispersion coefficients dn and dm. - if(ihc == 0) then + if (ihc == 0) then clnm = satn * (topn - botn) * DHALF clmn = satm * (topm - botm) * DHALF anm = hwva @@ -935,18 +931,18 @@ subroutine calcdispcoef(this) anm = DZERO else if (n > m .and. satn < DONE) then anm = DZERO - endif + end if ! ! -- m is convertible and unsaturated if (satm == DZERO) then anm = DZERO else if (m > n .and. satm < DONE) then anm = DZERO - endif + end if ! ! -- amn is the same as anm for vertical flow amn = anm - ! + ! else ! ! -- horizontal conductance @@ -971,7 +967,7 @@ subroutine calcdispcoef(this) if (satn == DZERO .or. satm == DZERO) then anm = DZERO amn = DZERO - endif + end if ! end if ! @@ -990,11 +986,11 @@ subroutine calcdispcoef(this) ! -- Assign the calculated dispersion conductance this%dispcoef(isympos) = cond ! - enddo - enddo + end do + end do ! ! -- Return return end subroutine calcdispcoef - + end module GwtDspModule diff --git a/src/Model/GroundWaterTransport/gwt1dspidm.f90 b/src/Model/GroundWaterTransport/gwt1dspidm.f90 new file mode 100644 index 00000000000..323346d5d56 --- /dev/null +++ b/src/Model/GroundWaterTransport/gwt1dspidm.f90 @@ -0,0 +1,183 @@ +module GwtDspInputModule + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + private + public gwt_dsp_param_definitions + public gwt_dsp_aggregate_definitions + public gwt_dsp_block_definitions + public GwtDspParamFoundType + + type GwtDspParamFoundType + logical :: xt3d_off = .false. + logical :: xt3d_rhs = .false. + logical :: diffc = .false. + logical :: alh = .false. + logical :: alv = .false. + logical :: ath1 = .false. + logical :: ath2 = .false. + logical :: atv = .false. + end type GwtDspParamFoundType + + type(InputParamDefinitionType), parameter :: & + gwtdsp_xt3d_off = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'OPTIONS', & ! block + 'XT3D_OFF', & ! tag name + 'XT3D_OFF', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_xt3d_rhs = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'OPTIONS', & ! block + 'XT3D_RHS', & ! tag name + 'XT3D_RHS', & ! fortran variable + 'KEYWORD', & ! type + '', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .false. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_diffc = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'DIFFC', & ! tag name + 'DIFFC', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_alh = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'ALH', & ! tag name + 'ALH', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_alv = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'ALV', & ! tag name + 'ALV', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_ath1 = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'ATH1', & ! tag name + 'ATH1', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_ath2 = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'ATH2', & ! tag name + 'ATH2', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwtdsp_atv = InputParamDefinitionType & + ( & + 'GWT', & ! component + 'DSP', & ! subcomponent + 'GRIDDATA', & ! block + 'ATV', & ! tag name + 'ATV', & ! fortran variable + 'DOUBLE1D', & ! type + 'NODES', & ! shape + .false., & ! required + .false., & ! multi-record + .false., & ! preserve case + .true. & ! layered + ) + + type(InputParamDefinitionType), parameter :: & + gwt_dsp_param_definitions(*) = & + [ & + gwtdsp_xt3d_off, & + gwtdsp_xt3d_rhs, & + gwtdsp_diffc, & + gwtdsp_alh, & + gwtdsp_alv, & + gwtdsp_ath1, & + gwtdsp_ath2, & + gwtdsp_atv & + ] + + type(InputParamDefinitionType), parameter :: & + gwt_dsp_aggregate_definitions(*) = & + [ & + InputParamDefinitionType :: & + ] + + type(InputBlockDefinitionType), parameter :: & + gwt_dsp_block_definitions(*) = & + [ & + InputBlockDefinitionType( & + 'OPTIONS', & ! blockname + .false., & ! required + .false. & ! aggregate + ), & + InputBlockDefinitionType( & + 'GRIDDATA', & ! blockname + .false., & ! required + .false. & ! aggregate + ) & + ] + +end module GwtDspInputModule diff --git a/src/Model/GroundWaterTransport/gwt1fmi1.f90 b/src/Model/GroundWaterTransport/gwt1fmi1.f90 index d9f2951bd06..908a21f8be8 100644 --- a/src/Model/GroundWaterTransport/gwt1fmi1.f90 +++ b/src/Model/GroundWaterTransport/gwt1fmi1.f90 @@ -1,17 +1,17 @@ module GwtFmiModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: DONE, DZERO, DHALF, LINELENGTH, LENBUDTXT, & - LENPACKAGENAME - use SimModule, only: store_error, store_error_unit - use SimVariablesModule, only: errmsg + + use KindModule, only: DP, I4B + use ConstantsModule, only: DONE, DZERO, DHALF, LINELENGTH, LENBUDTXT, & + LENPACKAGENAME + use SimModule, only: store_error, store_error_unit + use SimVariablesModule, only: errmsg use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use ListModule, only: ListType + use BaseDisModule, only: DisBaseType + use ListModule, only: ListType use BudgetFileReaderModule, only: BudgetFileReaderType - use HeadFileReaderModule, only: HeadFileReaderType - use PackageBudgetModule, only: PackageBudgetType - use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr_bfr + use HeadFileReaderModule, only: HeadFileReaderType + use PackageBudgetModule, only: PackageBudgetType + use BudgetObjectModule, only: BudgetObjectType, budgetobject_cr_bfr implicit none private @@ -20,49 +20,50 @@ module GwtFmiModule integer(I4B), parameter :: NBDITEMS = 2 character(len=LENBUDTXT), dimension(NBDITEMS) :: budtxt - data budtxt / ' FLOW-ERROR', ' FLOW-CORRECTION' / - + data budtxt/' FLOW-ERROR', ' FLOW-CORRECTION'/ + type :: DataAdvancedPackageType real(DP), dimension(:), contiguous, pointer :: concpack => null() real(DP), dimension(:), contiguous, pointer :: qmfrommvr => null() end type - + type :: BudObjPtrArray type(BudgetObjectType), pointer :: ptr - end type BudObjPtrArray - + end type BudObjPtrArray + type, extends(NumericalPackageType) :: GwtFmiType - - logical, pointer :: flows_from_file => null() !< if .false., then flows come from GWF through GWF-GWT exg - integer(I4B), dimension(:), pointer, contiguous :: iatp => null() !< advanced transport package applied to gwfpackages - type(ListType), pointer :: gwfbndlist => null() !< list of gwf stress packages - integer(I4B), pointer :: iflowsupdated => null() !< flows were updated for this time step - integer(I4B), pointer :: iflowerr => null() !< add the flow error correction - real(DP), dimension(:), pointer, contiguous :: flowcorrect => null() !< mass flow correction - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to GWT ibound - real(DP), dimension(:), pointer, contiguous :: gwfflowja => null() !< pointer to the GWF flowja array - real(DP), dimension(:, :), pointer, contiguous :: gwfspdis => null() !< pointer to npf specific discharge array - real(DP), dimension(:), pointer, contiguous :: gwfhead => null() !< pointer to the GWF head array - real(DP), dimension(:), pointer, contiguous :: gwfsat => null() !< pointer to the GWF saturation array - integer(I4B), dimension(:), pointer, contiguous :: ibdgwfsat0 => null() !< mark cells with saturation = 0 to exclude from dispersion - real(DP), dimension(:), pointer, contiguous :: gwfstrgss => null() !< pointer to flow model QSTOSS - real(DP), dimension(:), pointer, contiguous :: gwfstrgsy => null() !< pointer to flow model QSTOSY - integer(I4B), pointer :: igwfstrgss => null() !< indicates if gwfstrgss is available - integer(I4B), pointer :: igwfstrgsy => null() !< indicates if gwfstrgsy is available - integer(I4B), pointer :: iubud => null() !< unit number GWF budget file - integer(I4B), pointer :: iuhds => null() !< unit number GWF head file - integer(I4B), pointer :: iumvr => null() !< unit number GWF mover budget file - integer(I4B), pointer :: nflowpack => null() !< number of GWF flow packages - integer(I4B), dimension(:), pointer, contiguous :: igwfmvrterm => null() !< flag to indicate that gwf package is a mover term - type(BudgetFileReaderType) :: bfr !< budget file reader - type(HeadFileReaderType) :: hfr !< head file reader - type(PackageBudgetType), dimension(:), allocatable :: gwfpackages !< used to get flows between a package and gwf - type(BudgetObjectType), pointer :: mvrbudobj => null() !< pointer to the mover budget budget object - type(DataAdvancedPackageType), dimension(:), pointer, contiguous :: datp => null() - character(len=16), dimension(:), allocatable :: flowpacknamearray !< array of boundary package names (e.g. LAK-1, SFR-3, etc.) - type(BudObjPtrArray), dimension(:), allocatable :: aptbudobj !< flow budget objects for the advanced packages + + logical, pointer :: flows_from_file => null() !< if .false., then flows come from GWF through GWF-GWT exg + integer(I4B), dimension(:), pointer, contiguous :: iatp => null() !< advanced transport package applied to gwfpackages + type(ListType), pointer :: gwfbndlist => null() !< list of gwf stress packages + integer(I4B), pointer :: iflowsupdated => null() !< flows were updated for this time step + integer(I4B), pointer :: iflowerr => null() !< add the flow error correction + real(DP), dimension(:), pointer, contiguous :: flowcorrect => null() !< mass flow correction + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to GWT ibound + real(DP), dimension(:), pointer, contiguous :: gwfflowja => null() !< pointer to the GWF flowja array + real(DP), dimension(:, :), pointer, contiguous :: gwfspdis => null() !< pointer to npf specific discharge array + real(DP), dimension(:), pointer, contiguous :: gwfhead => null() !< pointer to the GWF head array + real(DP), dimension(:), pointer, contiguous :: gwfsat => null() !< pointer to the GWF saturation array + integer(I4B), dimension(:), pointer, contiguous :: ibdgwfsat0 => null() !< mark cells with saturation = 0 to exclude from dispersion + real(DP), dimension(:), pointer, contiguous :: gwfstrgss => null() !< pointer to flow model QSTOSS + real(DP), dimension(:), pointer, contiguous :: gwfstrgsy => null() !< pointer to flow model QSTOSY + integer(I4B), pointer :: igwfstrgss => null() !< indicates if gwfstrgss is available + integer(I4B), pointer :: igwfstrgsy => null() !< indicates if gwfstrgsy is available + integer(I4B), pointer :: iubud => null() !< unit number GWF budget file + integer(I4B), pointer :: iuhds => null() !< unit number GWF head file + integer(I4B), pointer :: iumvr => null() !< unit number GWF mover budget file + integer(I4B), pointer :: nflowpack => null() !< number of GWF flow packages + integer(I4B), dimension(:), pointer, contiguous :: igwfmvrterm => null() !< flag to indicate that gwf package is a mover term + type(BudgetFileReaderType) :: bfr !< budget file reader + type(HeadFileReaderType) :: hfr !< head file reader + type(PackageBudgetType), dimension(:), allocatable :: gwfpackages !< used to get flows between a package and gwf + type(BudgetObjectType), pointer :: mvrbudobj => null() !< pointer to the mover budget budget object + type(DataAdvancedPackageType), & + dimension(:), pointer, contiguous :: datp => null() + character(len=16), dimension(:), allocatable :: flowpacknamearray !< array of boundary package names (e.g. LAK-1, SFR-3, etc.) + type(BudObjPtrArray), dimension(:), allocatable :: aptbudobj !< flow budget objects for the advanced packages contains - + procedure :: fmi_df procedure :: fmi_ar procedure :: fmi_rp @@ -89,11 +90,11 @@ module GwtFmiModule procedure :: deallocate_gwfpackages procedure :: get_package_index procedure :: set_aptbudobj_pointer - + end type GwtFmiType - contains - +contains + subroutine fmi_cr(fmiobj, name_model, inunit, iout) ! ****************************************************************************** ! fmi_cr -- Create a new FMI object @@ -109,7 +110,7 @@ subroutine fmi_cr(fmiobj, name_model, inunit, iout) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(fmiobj) + allocate (fmiobj) ! ! -- create name and memory path call fmiobj%set_names(1, name_model, 'FMI', 'FMI') @@ -147,26 +148,26 @@ subroutine fmi_df(this, dis, inssm) integer(I4B), intent(in) :: inssm ! -- local ! -- formats - character(len=*), parameter :: fmtfmi = & - "(1x,/1x,'FMI -- FLOW MODEL INTERFACE, VERSION 1, 8/29/2017', & + character(len=*), parameter :: fmtfmi = & + "(1x,/1x,'FMI -- FLOW MODEL INTERFACE, VERSION 1, 8/29/2017', & &' INPUT READ FROM UNIT ', i0, //)" - character(len=*), parameter :: fmtfmi0 = & - "(1x,/1x,'FMI -- FLOW MODEL INTERFACE, VERSION 1, 8/29/2017')" + character(len=*), parameter :: fmtfmi0 = & + &"(1x,/1x,'FMI -- FLOW MODEL INTERFACE, VERSION 1, 8/29/2017')" ! ------------------------------------------------------------------------------ ! ! --print a message identifying the FMI package. if (this%iout > 0) then if (this%inunit /= 0) then - write(this%iout, fmtfmi) this%inunit + write (this%iout, fmtfmi) this%inunit else - write(this%iout, fmtfmi0) + write (this%iout, fmtfmi0) if (this%flows_from_file) then - write(this%iout, '(a)') ' FLOWS ARE ASSUMED TO BE ZERO.' + write (this%iout, '(a)') ' FLOWS ARE ASSUMED TO BE ZERO.' else - write(this%iout, '(a)') ' FLOWS PROVIDED BY A GWF MODEL IN THIS & + write (this%iout, '(a)') ' FLOWS PROVIDED BY A GWF MODEL IN THIS & &SIMULATION' - endif - endif + end if + end if end if ! ! -- store pointers to arguments that were passed in @@ -194,13 +195,13 @@ subroutine fmi_df(this, dis, inssm) call store_error('FLOW MODEL HAS BOUNDARY PACKAGES, BUT THERE & &IS NO SSM PACKAGE. THE SSM PACKAGE MUST BE ACTIVATED.', & terminate=.TRUE.) - endif - endif + end if + end if ! ! -- Return return end subroutine fmi_df - + subroutine fmi_ar(this, ibound) ! ****************************************************************************** ! fmi_ar -- Allocate and Read @@ -218,7 +219,7 @@ subroutine fmi_ar(this, ibound) ! ------------------------------------------------------------------------------ ! ! -- store pointers to arguments that were passed in - this%ibound => ibound + this%ibound => ibound ! ! -- Allocate arrays call this%allocate_arrays(this%dis%nodes) @@ -226,7 +227,7 @@ subroutine fmi_ar(this, ibound) ! -- Return return end subroutine fmi_ar - + subroutine fmi_rp(this, inmvr) ! ****************************************************************************** ! fmi_rp -- Read and prepare @@ -244,16 +245,16 @@ subroutine fmi_rp(this, inmvr) ! ------------------------------------------------------------------------------ ! ! --Check to make sure MVT Package is active if mvr flows are available. - ! This cannot be checked until RP because exchange doesn't set a pointer + ! This cannot be checked until RP because exchange doesn't set a pointer ! to mvrbudobj until exg_ar(). if (kper * kstp == 1) then if (associated(this%mvrbudobj) .and. inmvr == 0) then - write(errmsg,'(4x,a)') 'GWF WATER MOVER IS ACTIVE BUT THE GWT MVT & + write (errmsg, '(4x,a)') 'GWF WATER MOVER IS ACTIVE BUT THE GWT MVT & &PACKAGE HAS NOT BEEN SPECIFIED. ACTIVATE GWT MVT PACKAGE.' call store_error(errmsg, terminate=.TRUE.) end if if (.not. associated(this%mvrbudobj) .and. inmvr > 0) then - write(errmsg,'(4x,a)') 'GWF WATER MOVER TERMS ARE NOT AVAILABLE & + write (errmsg, '(4x,a)') 'GWF WATER MOVER TERMS ARE NOT AVAILABLE & &BUT THE GWT MVT PACKAGE HAS BEEN ACTIVATED. GWF-GWT EXCHANGE & &OR SPECIFY GWFMOVER IN FMI PACKAGEDATA.' call store_error(errmsg, terminate=.TRUE.) @@ -263,7 +264,7 @@ subroutine fmi_rp(this, inmvr) ! -- Return return end subroutine fmi_rp - + subroutine fmi_ad(this, cnew) ! ****************************************************************************** ! fmi_ad -- advance @@ -281,7 +282,7 @@ subroutine fmi_ad(this, cnew) integer(I4B) :: m integer(I4B) :: ipos real(DP) :: crewet, tflow, flownm - character (len=15) :: nodestr + character(len=15) :: nodestr character(len=*), parameter :: fmtdry = & &"(/1X,'WARNING: DRY CELL ENCOUNTERED AT ',a,'; RESET AS INACTIVE & &WITH DRY CONCENTRATION = ', G13.5)" @@ -298,12 +299,12 @@ subroutine fmi_ad(this, cnew) ! -- If reading flows from a budget file, read the next set of records if (this%iubud /= 0) then call this%advance_bfr() - endif + end if ! ! -- If reading heads from a head file, read the next set of records if (this%iuhds /= 0) then call this%advance_hfr() - endif + end if ! ! -- If mover flows are being read from file, read the next set of records if (this%iumvr /= 0) then @@ -320,7 +321,7 @@ subroutine fmi_ad(this, cnew) ! -- if flow cell is dry, then set gwt%ibound = 0 and conc to dry do n = 1, this%dis%nodes ! - ! -- Calculate the ibound-like array that has 0 if saturation + ! -- Calculate the ibound-like array that has 0 if saturation ! is zero and 1 otherwise if (this%gwfsat(n) > DZERO) then this%ibdgwfsat0(n) = 1 @@ -335,9 +336,9 @@ subroutine fmi_ad(this, cnew) this%ibound(n) = 0 cnew(n) = DHDRY call this%dis%noder_to_string(n, nodestr) - write(this%iout, fmtdry) trim(nodestr), DHDRY - endif - endif + write (this%iout, fmtdry) trim(nodestr), DHDRY + end if + end if ! ! -- Convert dry transport cell to active if flow has rewet if (cnew(n) == DHDRY) then @@ -353,28 +354,28 @@ subroutine fmi_ad(this, cnew) if (this%ibound(m) /= 0) then crewet = crewet + cnew(m) * flownm tflow = tflow + this%gwfflowja(ipos) - endif - endif - enddo + end if + end if + end do if (tflow > DZERO) then crewet = crewet / tflow else crewet = DZERO - endif + end if ! ! -- cell is now wet this%ibound(n) = 1 cnew(n) = crewet call this%dis%noder_to_string(n, nodestr) - write(this%iout, fmtrewet) trim(nodestr), crewet - endif - endif - enddo + write (this%iout, fmtrewet) trim(nodestr), crewet + end if + end if + end do ! ! -- Return return end subroutine fmi_ad - + subroutine fmi_fc(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs) ! ****************************************************************************** ! fmi_fc -- Calculate coefficients and fill amat and rhs @@ -406,13 +407,13 @@ subroutine fmi_fc(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs) idiag = idxglo(this%dis%con%ia(n)) ipos = this%dis%con%ia(n) amatsln(idiag) = amatsln(idiag) - this%gwfflowja(ipos) - enddo + end do end if ! ! -- Return return end subroutine fmi_fc - + subroutine fmi_cq(this, cnew, flowja) ! ****************************************************************************** ! fmi_cq -- Calculate flow correction @@ -443,13 +444,13 @@ subroutine fmi_cq(this, cnew, flowja) end if this%flowcorrect(n) = rate flowja(idiag) = flowja(idiag) + rate - enddo + end do end if ! ! -- Return return end subroutine fmi_cq - + subroutine fmi_bd(this, isuppress_output, model_budget) ! ****************************************************************************** ! mst_bd -- Calculate budget terms @@ -478,7 +479,7 @@ subroutine fmi_bd(this, isuppress_output, model_budget) ! -- Return return end subroutine fmi_bd - + subroutine fmi_ot_flow(this, icbcfl, icbcun) ! ****************************************************************************** ! fmi_ot_flow -- Save budget terms @@ -493,33 +494,33 @@ subroutine fmi_ot_flow(this, icbcfl, icbcun) ! -- local integer(I4B) :: ibinun integer(I4B) :: iprint, nvaluesp, nwidthp - character(len=1) :: cdatafmp=' ', editdesc=' ' + character(len=1) :: cdatafmp = ' ', editdesc = ' ' real(DP) :: dinact ! ------------------------------------------------------------------------------ ! ! -- Set unit number for binary output - if(this%ipakcb < 0) then + if (this%ipakcb < 0) then ibinun = icbcun - elseif(this%ipakcb == 0) then + elseif (this%ipakcb == 0) then ibinun = 0 else ibinun = this%ipakcb - endif - if(icbcfl == 0) ibinun = 0 + end if + if (icbcfl == 0) ibinun = 0 ! ! -- Do not save flow corrections if not active - if(this%iflowerr == 0) ibinun = 0 + if (this%iflowerr == 0) ibinun = 0 ! ! -- Record the storage rates if requested - if(ibinun /= 0) then + if (ibinun /= 0) then iprint = 0 dinact = DZERO ! ! -- flow correction call this%dis%record_array(this%flowcorrect, this%iout, iprint, -ibinun, & - budtxt(2), cdatafmp, nvaluesp, & + budtxt(2), cdatafmp, nvaluesp, & nwidthp, editdesc, dinact) - endif + end if ! ! -- Return return @@ -544,25 +545,27 @@ subroutine fmi_da(this) ! ! -- deallocate fmi arrays if (associated(this%datp)) then - deallocate(this%datp) - deallocate(this%gwfpackages) - deallocate(this%flowpacknamearray) + deallocate (this%datp) + deallocate (this%gwfpackages) + deallocate (this%flowpacknamearray) call mem_deallocate(this%iatp) call mem_deallocate(this%igwfmvrterm) end if - deallocate(this%aptbudobj) + deallocate (this%aptbudobj) call mem_deallocate(this%flowcorrect) call mem_deallocate(this%ibdgwfsat0) if (this%flows_from_file) then - call mem_deallocate(this%gwfflowja) - call mem_deallocate(this%gwfsat) - call mem_deallocate(this%gwfhead) call mem_deallocate(this%gwfstrgss) call mem_deallocate(this%gwfstrgsy) - call mem_deallocate(this%gwfspdis) end if ! + ! -- special treatment, these could be from mem_checkin + call mem_deallocate(this%gwfhead, 'GWFHEAD', this%memoryPath) + call mem_deallocate(this%gwfsat, 'GWFSAT', this%memoryPath) + call mem_deallocate(this%gwfspdis, 'GWFSPDIS', this%memoryPath) + call mem_deallocate(this%gwfflowja, 'GWFFLOWJA', this%memoryPath) + ! ! -- deallocate scalars call mem_deallocate(this%flows_from_file) call mem_deallocate(this%iflowsupdated) @@ -580,7 +583,7 @@ subroutine fmi_da(this) ! -- Return return end subroutine fmi_da - + subroutine allocate_scalars(this) ! ****************************************************************************** ! allocate_scalars @@ -611,7 +614,7 @@ subroutine allocate_scalars(this) ! ! -- Although not a scalar, allocate the advanced package transport ! budget object to zero so that it can be dynamically resized later - allocate(this%aptbudobj(0)) + allocate (this%aptbudobj(0)) ! ! -- Initialize this%flows_from_file = .true. @@ -653,7 +656,7 @@ subroutine allocate_arrays(this, nodes) end if do n = 1, size(this%flowcorrect) this%flowcorrect(n) = DZERO - enddo + end do ! ! -- Allocate ibdgwfsat0, which is an indicator array marking cells with ! saturation greater than 0.0 with a value of 1 @@ -665,7 +668,8 @@ subroutine allocate_arrays(this, nodes) ! -- Allocate differently depending on whether or not flows are ! being read from a file. if (this%flows_from_file) then - call mem_allocate(this%gwfflowja, this%dis%con%nja, 'GWFFLOWJA', this%memoryPath) + call mem_allocate(this%gwfflowja, this%dis%con%nja, 'GWFFLOWJA', & + this%memoryPath) call mem_allocate(this%gwfsat, nodes, 'GWFSAT', this%memoryPath) call mem_allocate(this%gwfhead, nodes, 'GWFHEAD', this%memoryPath) call mem_allocate(this%gwfspdis, 3, nodes, 'GWFSPDIS', this%memoryPath) @@ -704,7 +708,7 @@ subroutine allocate_arrays(this, nodes) ! -- Return return end subroutine allocate_arrays - + function gwfsatold(this, n, delt) result(satold) ! ****************************************************************************** ! gwfsatold -- calculate the groundwater cell head saturation for the end of @@ -737,7 +741,7 @@ function gwfsatold(this, n, delt) result(satold) ! -- Return return end function gwfsatold - + subroutine read_options(this) ! ****************************************************************************** ! read_options -- Read Options @@ -756,11 +760,11 @@ subroutine read_options(this) character(len=LINELENGTH) :: keyword integer(I4B) :: ierr logical :: isfound, endOfBlock - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO AND FLOW IMBALANCE CORRECTION ACTIVE.')" - character(len=*), parameter :: fmtifc = & - "(4x,'MASS WILL BE ADDED OR REMOVED TO COMPENSATE FOR FLOW IMBALANCE.')" + character(len=*), parameter :: fmtisvflow = & + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO AND FLOW IMBALANCE CORRECTION ACTIVE.')" + character(len=*), parameter :: fmtifc = & + &"(4x,'MASS WILL BE ADDED OR REMOVED TO COMPENSATE FOR FLOW IMBALANCE.')" ! ------------------------------------------------------------------------------ ! ! -- get options block @@ -769,26 +773,26 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING FMI OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING FMI OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtisvflow) - case ('FLOW_IMBALANCE_CORRECTION') - write(this%iout, fmtifc) - this%iflowerr = 1 - case default - write(errmsg,'(4x,a,a)')'***ERROR. UNKNOWN FMI OPTION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtisvflow) + case ('FLOW_IMBALANCE_CORRECTION') + write (this%iout, fmtifc) + this%iflowerr = 1 + case default + write (errmsg, '(4x,a,a)') '***ERROR. UNKNOWN FMI OPTION: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)') 'END OF FMI OPTIONS' + write (this%iout, '(1x,a)') 'END OF FMI OPTIONS' end if ! ! -- return @@ -829,109 +833,109 @@ subroutine read_packagedata(this) blockrequired = .true. ! ! -- get options block - call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & - blockRequired=blockRequired, & + call this%parser%GetBlock('PACKAGEDATA', isfound, ierr, & + blockRequired=blockRequired, & supportOpenClose=.true.) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING FMI PACKAGEDATA' + write (this%iout, '(1x,a)') 'PROCESSING FMI PACKAGEDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('GWFBUDGET') - call this%parser%GetStringCaps(keyword) - if(keyword /= 'FILEIN') then - call store_error('GWFBUDGET KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - inunit = getunit() - inquire(file=trim(fname), exist=exist) - if (.not. exist) then - call store_error('Could not find file '//trim(fname)) - call this%parser%StoreErrorUnit() - end if - call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & - ACCESS, 'UNKNOWN') - this%iubud = inunit - call this%initialize_bfr() - case ('GWFHEAD') - call this%parser%GetStringCaps(keyword) - if(keyword /= 'FILEIN') then - call store_error('GWFHEAD KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - inquire(file=trim(fname), exist=exist) - if (.not. exist) then - call store_error('Could not find file '//trim(fname)) - call this%parser%StoreErrorUnit() - end if - inunit = getunit() - call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & - ACCESS, 'UNKNOWN') - this%iuhds = inunit - call this%initialize_hfr() - case ('GWFMOVER') - call this%parser%GetStringCaps(keyword) - if(keyword /= 'FILEIN') then - call store_error('GWFMOVER KEYWORD MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - inunit = getunit() - call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & - ACCESS, 'UNKNOWN') - this%iumvr = inunit - call budgetobject_cr_bfr(this%mvrbudobj, 'MVT', this%iumvr, & - this%iout) - call this%mvrbudobj%fill_from_bfr(this%dis, this%iout) - case default - ! - ! --expand the size of aptbudobj, which stores a pointer to the budobj - allocate(tmpbudobj(iapt)) - do i = 1, size(this%aptbudobj) - tmpbudobj(i)%ptr => this%aptbudobj(i)%ptr - end do - deallocate(this%aptbudobj) - allocate(this%aptbudobj(iapt + 1)) - do i = 1, size(tmpbudobj) - this%aptbudobj(i)%ptr => tmpbudobj(i)%ptr - end do - deallocate(tmpbudobj) - ! - ! -- Open the budget file and start filling it - iapt = iapt + 1 - pname = keyword(1:LENPACKAGENAME) - call this%parser%GetStringCaps(keyword) - if(keyword /= 'FILEIN') then - call store_error('PACKAGE NAME MUST BE FOLLOWED BY ' // & - '"FILEIN" then by filename.') - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - inunit = getunit() - call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & - ACCESS, 'UNKNOWN') - call budgetobject_cr_bfr(budobjptr, pname, inunit, & - this%iout, colconv2=['GWF ']) - call budobjptr%fill_from_bfr(this%dis, this%iout) - this%aptbudobj(iapt)%ptr => budobjptr + case ('GWFBUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword /= 'FILEIN') then + call store_error('GWFBUDGET KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') + call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + inunit = getunit() + inquire (file=trim(fname), exist=exist) + if (.not. exist) then + call store_error('Could not find file '//trim(fname)) + call this%parser%StoreErrorUnit() + end if + call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & + ACCESS, 'UNKNOWN') + this%iubud = inunit + call this%initialize_bfr() + case ('GWFHEAD') + call this%parser%GetStringCaps(keyword) + if (keyword /= 'FILEIN') then + call store_error('GWFHEAD KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') + call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + inquire (file=trim(fname), exist=exist) + if (.not. exist) then + call store_error('Could not find file '//trim(fname)) + call this%parser%StoreErrorUnit() + end if + inunit = getunit() + call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & + ACCESS, 'UNKNOWN') + this%iuhds = inunit + call this%initialize_hfr() + case ('GWFMOVER') + call this%parser%GetStringCaps(keyword) + if (keyword /= 'FILEIN') then + call store_error('GWFMOVER KEYWORD MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') + call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + inunit = getunit() + call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & + ACCESS, 'UNKNOWN') + this%iumvr = inunit + call budgetobject_cr_bfr(this%mvrbudobj, 'MVT', this%iumvr, & + this%iout) + call this%mvrbudobj%fill_from_bfr(this%dis, this%iout) + case default + ! + ! --expand the size of aptbudobj, which stores a pointer to the budobj + allocate (tmpbudobj(iapt)) + do i = 1, size(this%aptbudobj) + tmpbudobj(i)%ptr => this%aptbudobj(i)%ptr + end do + deallocate (this%aptbudobj) + allocate (this%aptbudobj(iapt + 1)) + do i = 1, size(tmpbudobj) + this%aptbudobj(i)%ptr => tmpbudobj(i)%ptr + end do + deallocate (tmpbudobj) + ! + ! -- Open the budget file and start filling it + iapt = iapt + 1 + pname = keyword(1:LENPACKAGENAME) + call this%parser%GetStringCaps(keyword) + if (keyword /= 'FILEIN') then + call store_error('PACKAGE NAME MUST BE FOLLOWED BY '// & + '"FILEIN" then by filename.') + call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + inunit = getunit() + call openfile(inunit, this%iout, fname, 'DATA(BINARY)', FORM, & + ACCESS, 'UNKNOWN') + call budgetobject_cr_bfr(budobjptr, pname, inunit, & + this%iout, colconv2=['GWF ']) + call budobjptr%fill_from_bfr(this%dis, this%iout) + this%aptbudobj(iapt)%ptr => budobjptr end select end do - write(this%iout,'(1x,a)') 'END OF FMI PACKAGEDATA' + write (this%iout, '(1x,a)') 'END OF FMI PACKAGEDATA' end if ! ! -- return return end subroutine read_packagedata - + subroutine set_aptbudobj_pointer(this, name, budobjptr) ! ****************************************************************************** ! set_aptbudobj_pointer -- an advanced transport can pass in a name and a @@ -982,7 +986,7 @@ subroutine initialize_bfr(this) ! -- todo: need to run through the budget terms ! and do some checking end subroutine initialize_bfr - + subroutine advance_bfr(this) ! ****************************************************************************** ! advance_bfr -- advance the budget file reader by reading the next chunk @@ -1003,10 +1007,10 @@ subroutine advance_bfr(this) integer(I4B) :: ip, i logical :: readnext ! -- format - character(len=*), parameter :: fmtkstpkper = & - "(1x,/1x,'FMI READING BUDGET TERMS FOR KSTP ', i0, ' KPER ', i0)" + character(len=*), parameter :: fmtkstpkper = & + &"(1x,/1x,'FMI READING BUDGET TERMS FOR KSTP ', i0, ' KPER ', i0)" character(len=*), parameter :: fmtbudkstpkper = & - "(1x,/1x, 'FMI SETTING BUDGET TERMS FOR KSTP ', i0, ' AND KPER ', & + "(1x,/1x, 'FMI SETTING BUDGET TERMS FOR KSTP ', i0, ' AND KPER ', & &i0, ' TO BUDGET FILE TERMS FROM KSTP ', i0, ' AND KPER ', i0)" ! ------------------------------------------------------------------------------ ! @@ -1023,19 +1027,19 @@ subroutine advance_bfr(this) readnext = .false. end if else if (this%bfr%endoffile) then - write(errmsg,'(4x,a)') 'REACHED END OF GWF BUDGET & + write (errmsg, '(4x,a)') 'REACHED END OF GWF BUDGET & &FILE BEFORE READING SUFFICIENT BUDGET INFORMATION FOR THIS & &GWT SIMULATION.' call store_error(errmsg) call store_error_unit(this%iubud) - end if + end if end if ! ! -- Read the next record if (readnext) then ! ! -- Write the current time step and stress period - write(this%iout, fmtkstpkper) kstp, kper + write (this%iout, fmtkstpkper) kstp, kper ! ! -- loop through the budget terms for this stress period ! i is the counter for gwf flow packages @@ -1043,95 +1047,95 @@ subroutine advance_bfr(this) do n = 1, this%bfr%nbudterms call this%bfr%read_record(success, this%iout) if (.not. success) then - write(errmsg,'(4x,a)') 'GWF BUDGET READ NOT SUCCESSFUL' + write (errmsg, '(4x,a)') 'GWF BUDGET READ NOT SUCCESSFUL' call store_error(errmsg) call store_error_unit(this%iubud) - endif + end if ! ! -- Ensure kper is same between model and budget file if (kper /= this%bfr%kper) then - write(errmsg,'(4x,a)') 'PERIOD NUMBER IN BUDGET FILE & + write (errmsg, '(4x,a)') 'PERIOD NUMBER IN BUDGET FILE & &DOES NOT MATCH PERIOD NUMBER IN TRANSPORT MODEL. IF THERE & &IS MORE THAN ONE TIME STEP IN THE BUDGET FILE FOR A GIVEN STRESS & &PERIOD, BUDGET FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS & &ONE-FOR-ONE IN THAT STRESS PERIOD.' call store_error(errmsg) call store_error_unit(this%iubud) - endif + end if ! ! -- if budget file kstp > 1, then kstp must match if (this%bfr%kstp > 1 .and. (kstp /= this%bfr%kstp)) then - write(errmsg,'(4x,a)') 'TIME STEP NUMBER IN BUDGET FILE & + write (errmsg, '(4x,a)') 'TIME STEP NUMBER IN BUDGET FILE & &DOES NOT MATCH TIME STEP NUMBER IN TRANSPORT MODEL. IF THERE & &IS MORE THAN ONE TIME STEP IN THE BUDGET FILE FOR A GIVEN STRESS & &PERIOD, BUDGET FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS & &ONE-FOR-ONE IN THAT STRESS PERIOD.' call store_error(errmsg) call store_error_unit(this%iubud) - endif + end if ! ! -- parse based on the type of data, and compress all user node ! numbers into reduced node numbers - select case(trim(adjustl(this%bfr%budtxt))) - case('FLOW-JA-FACE') - ! - ! -- bfr%flowja contains only reduced connections so there is - ! a one-to-one match with this%gwfflowja - do ipos = 1, size(this%bfr%flowja) - this%gwfflowja(ipos) = this%bfr%flowja(ipos) - end do - case('DATA-SPDIS') - do i = 1, this%bfr%nlist - nu = this%bfr%nodesrc(i) - nr = this%dis%get_nodenumber(nu, 0) - if (nr <= 0) cycle - this%gwfspdis(1, nr) = this%bfr%auxvar(1, i) - this%gwfspdis(2, nr) = this%bfr%auxvar(2, i) - this%gwfspdis(3, nr) = this%bfr%auxvar(3, i) - end do - case('DATA-SAT') - do i = 1, this%bfr%nlist - nu = this%bfr%nodesrc(i) - nr = this%dis%get_nodenumber(nu, 0) - if (nr <= 0) cycle - this%gwfsat(nr) = this%bfr%auxvar(1, i) - end do - case('STO-SS') - do nu = 1, this%dis%nodesuser - nr = this%dis%get_nodenumber(nu, 0) - if (nr <= 0) cycle - this%gwfstrgss(nr) = this%bfr%flow(nu) - end do - case('STO-SY') - do nu = 1, this%dis%nodesuser - nr = this%dis%get_nodenumber(nu, 0) - if (nr <= 0) cycle - this%gwfstrgsy(nr) = this%bfr%flow(nu) - end do - case default - call this%gwfpackages(ip)%copy_values( & - this%bfr%nlist, & - this%bfr%nodesrc, & - this%bfr%flow, & - this%bfr%auxvar) - do i = 1, this%gwfpackages(ip)%nbound - nu = this%gwfpackages(ip)%nodelist(i) - nr = this%dis%get_nodenumber(nu, 0) - this%gwfpackages(ip)%nodelist(i) = nr - end do - ip = ip + 1 + select case (trim(adjustl(this%bfr%budtxt))) + case ('FLOW-JA-FACE') + ! + ! -- bfr%flowja contains only reduced connections so there is + ! a one-to-one match with this%gwfflowja + do ipos = 1, size(this%bfr%flowja) + this%gwfflowja(ipos) = this%bfr%flowja(ipos) + end do + case ('DATA-SPDIS') + do i = 1, this%bfr%nlist + nu = this%bfr%nodesrc(i) + nr = this%dis%get_nodenumber(nu, 0) + if (nr <= 0) cycle + this%gwfspdis(1, nr) = this%bfr%auxvar(1, i) + this%gwfspdis(2, nr) = this%bfr%auxvar(2, i) + this%gwfspdis(3, nr) = this%bfr%auxvar(3, i) + end do + case ('DATA-SAT') + do i = 1, this%bfr%nlist + nu = this%bfr%nodesrc(i) + nr = this%dis%get_nodenumber(nu, 0) + if (nr <= 0) cycle + this%gwfsat(nr) = this%bfr%auxvar(1, i) + end do + case ('STO-SS') + do nu = 1, this%dis%nodesuser + nr = this%dis%get_nodenumber(nu, 0) + if (nr <= 0) cycle + this%gwfstrgss(nr) = this%bfr%flow(nu) + end do + case ('STO-SY') + do nu = 1, this%dis%nodesuser + nr = this%dis%get_nodenumber(nu, 0) + if (nr <= 0) cycle + this%gwfstrgsy(nr) = this%bfr%flow(nu) + end do + case default + call this%gwfpackages(ip)%copy_values( & + this%bfr%nlist, & + this%bfr%nodesrc, & + this%bfr%flow, & + this%bfr%auxvar) + do i = 1, this%gwfpackages(ip)%nbound + nu = this%gwfpackages(ip)%nodelist(i) + nr = this%dis%get_nodenumber(nu, 0) + this%gwfpackages(ip)%nodelist(i) = nr + end do + ip = ip + 1 end select end do else ! ! -- write message to indicate that flows are being reused - write(this%iout, fmtbudkstpkper) kstp, kper, this%bfr%kstp, this%bfr%kper + write (this%iout, fmtbudkstpkper) kstp, kper, this%bfr%kstp, this%bfr%kper ! ! -- set the flag to indicate that flows were not updated this%iflowsupdated = 0 - endif + end if end subroutine advance_bfr - + subroutine finalize_bfr(this) ! ****************************************************************************** ! finalize_bfr -- finalize the budget file reader @@ -1148,7 +1152,7 @@ subroutine finalize_bfr(this) call this%bfr%finalize() ! end subroutine finalize_bfr - + subroutine initialize_hfr(this) ! ****************************************************************************** ! initialize_hfr -- initalize the head file reader @@ -1167,7 +1171,7 @@ subroutine initialize_hfr(this) ! -- todo: need to run through the head terms ! and do some checking end subroutine initialize_hfr - + subroutine advance_hfr(this) ! ****************************************************************************** ! advance_hfr -- advance the head file reader @@ -1183,10 +1187,10 @@ subroutine advance_hfr(this) real(DP) :: val logical :: readnext logical :: success - character(len=*), parameter :: fmtkstpkper = & - "(1x,/1x,'FMI READING HEAD FOR KSTP ', i0, ' KPER ', i0)" + character(len=*), parameter :: fmtkstpkper = & + &"(1x,/1x,'FMI READING HEAD FOR KSTP ', i0, ' KPER ', i0)" character(len=*), parameter :: fmthdskstpkper = & - "(1x,/1x, 'FMI SETTING HEAD FOR KSTP ', i0, ' AND KPER ', & + "(1x,/1x, 'FMI SETTING HEAD FOR KSTP ', i0, ' AND KPER ', & &i0, ' TO BINARY FILE HEADS FROM KSTP ', i0, ' AND KPER ', i0)" ! ------------------------------------------------------------------------------ ! @@ -1203,19 +1207,19 @@ subroutine advance_hfr(this) readnext = .false. end if else if (this%hfr%endoffile) then - write(errmsg,'(4x,a)') 'REACHED END OF GWF HEAD & + write (errmsg, '(4x,a)') 'REACHED END OF GWF HEAD & &FILE BEFORE READING SUFFICIENT HEAD INFORMATION FOR THIS & &GWT SIMULATION.' call store_error(errmsg) call store_error_unit(this%iuhds) - end if + end if end if ! ! -- Read the next record if (readnext) then ! ! -- write to list file that heads are being read - write(this%iout, fmtkstpkper) kstp, kper + write (this%iout, fmtkstpkper) kstp, kper ! ! -- loop through the layered heads for this time step do ilay = 1, this%hfr%nlay @@ -1223,32 +1227,32 @@ subroutine advance_hfr(this) ! -- read next head chunk call this%hfr%read_record(success, this%iout) if (.not. success) then - write(errmsg,'(4x,a)') 'GWF HEAD READ NOT SUCCESSFUL' + write (errmsg, '(4x,a)') 'GWF HEAD READ NOT SUCCESSFUL' call store_error(errmsg) call store_error_unit(this%iuhds) - endif + end if ! ! -- Ensure kper is same between model and head file if (kper /= this%hfr%kper) then - write(errmsg,'(4x,a)') 'PERIOD NUMBER IN HEAD FILE & + write (errmsg, '(4x,a)') 'PERIOD NUMBER IN HEAD FILE & &DOES NOT MATCH PERIOD NUMBER IN TRANSPORT MODEL. IF THERE & &IS MORE THAN ONE TIME STEP IN THE HEAD FILE FOR A GIVEN STRESS & &PERIOD, HEAD FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS & &ONE-FOR-ONE IN THAT STRESS PERIOD.' call store_error(errmsg) call store_error_unit(this%iuhds) - endif + end if ! ! -- if head file kstp > 1, then kstp must match if (this%hfr%kstp > 1 .and. (kstp /= this%hfr%kstp)) then - write(errmsg,'(4x,a)') 'TIME STEP NUMBER IN HEAD FILE & + write (errmsg, '(4x,a)') 'TIME STEP NUMBER IN HEAD FILE & &DOES NOT MATCH TIME STEP NUMBER IN TRANSPORT MODEL. IF THERE & &IS MORE THAN ONE TIME STEP IN THE HEAD FILE FOR A GIVEN STRESS & &PERIOD, HEAD FILE TIME STEPS MUST MATCH GWT MODEL TIME STEPS & &ONE-FOR-ONE IN THAT STRESS PERIOD.' call store_error(errmsg) call store_error_unit(this%iuhds) - endif + end if ! ! -- fill the head array for this layer and ! compress into reduced form @@ -1258,13 +1262,13 @@ subroutine advance_hfr(this) nr = this%dis%get_nodenumber(nu, 0) val = this%hfr%head(i) if (nr > 0) this%gwfhead(nr) = val - enddo + end do end do else - write(this%iout, fmthdskstpkper) kstp, kper, this%hfr%kstp, this%hfr%kper - endif + write (this%iout, fmthdskstpkper) kstp, kper, this%hfr%kstp, this%hfr%kper + end if end subroutine advance_hfr - + subroutine finalize_hfr(this) ! ****************************************************************************** ! finalize_hfr -- finalize the head file reader @@ -1278,10 +1282,10 @@ subroutine finalize_hfr(this) ! ------------------------------------------------------------------------------ ! ! -- Finalize the head file reader - close(this%iuhds) + close (this%iuhds) ! end subroutine finalize_hfr - + subroutine initialize_gwfterms_from_bfr(this) ! ****************************************************************************** ! initialize_gwfterms_from_bfr -- initalize terms and figure out how many @@ -1308,7 +1312,7 @@ subroutine initialize_gwfterms_from_bfr(this) ! ------------------------------------------------------------------------------ ! ! -- Calculate the number of gwf flow packages - allocate(imap(this%bfr%nbudterms)) + allocate (imap(this%bfr%nbudterms)) imap(:) = 0 nflowpack = 0 found_flowja = .false. @@ -1317,7 +1321,7 @@ subroutine initialize_gwfterms_from_bfr(this) found_stoss = .false. found_stosy = .false. do i = 1, this%bfr%nbudterms - select case(trim(adjustl(this%bfr%budtxtarray(i)))) + select case (trim(adjustl(this%bfr%budtxtarray(i)))) case ('FLOW-JA-FACE') found_flowja = .true. case ('DATA-SPDIS') @@ -1363,19 +1367,19 @@ subroutine initialize_gwfterms_from_bfr(this) ! ! -- Error if specific discharge, saturation or flowja not found if (.not. found_dataspdis) then - write(errmsg, '(4x,a)') 'SPECIFIC DISCHARGE NOT FOUND IN & + write (errmsg, '(4x,a)') 'SPECIFIC DISCHARGE NOT FOUND IN & &BUDGET FILE. SAVE_SPECIFIC_DISCHARGE AND & &SAVE_FLOWS MUST BE ACTIVATED IN THE NPF PACKAGE.' call store_error(errmsg) end if if (.not. found_datasat) then - write(errmsg, '(4x,a)') 'SATURATION NOT FOUND IN & + write (errmsg, '(4x,a)') 'SATURATION NOT FOUND IN & &BUDGET FILE. SAVE_SATURATION AND & &SAVE_FLOWS MUST BE ACTIVATED IN THE NPF PACKAGE.' call store_error(errmsg) end if if (.not. found_flowja) then - write(errmsg, '(4x,a)') 'FLOWJA NOT FOUND IN & + write (errmsg, '(4x,a)') 'FLOWJA NOT FOUND IN & &BUDGET FILE. SAVE_FLOWS MUST & &BE ACTIVATED IN THE NPF PACKAGE.' call store_error(errmsg) @@ -1387,7 +1391,7 @@ subroutine initialize_gwfterms_from_bfr(this) ! -- return return end subroutine initialize_gwfterms_from_bfr - + subroutine initialize_gwfterms_from_gwfbndlist(this) ! ****************************************************************************** ! initialize_gwfterms_from_gwfbndlist -- flows are coming from a gwf-gwt @@ -1407,7 +1411,7 @@ subroutine initialize_gwfterms_from_gwfbndlist(this) integer(I4B) :: imover integer(I4B) :: ntomvr integer(I4B) :: iterm - character (len=LENPACKAGENAME) :: budtxt + character(len=LENPACKAGENAME) :: budtxt class(BndType), pointer :: packobj => null() ! ------------------------------------------------------------------------------ ! @@ -1427,7 +1431,7 @@ subroutine initialize_gwfterms_from_gwfbndlist(this) end if end do ! - ! -- Allocate arrays in fmi of size ngwfterms, which is the number of + ! -- Allocate arrays in fmi of size ngwfterms, which is the number of ! packages plus the number of packages with mover terms. ngwfterms = ngwfpack + ntomvr call this%allocate_gwfpackages(ngwfterms) @@ -1441,6 +1445,8 @@ subroutine initialize_gwfterms_from_gwfbndlist(this) budtxt = adjustl(packobj%text) call this%gwfpackages(iterm)%set_name(packobj%packName, budtxt) this%flowpacknamearray(iterm) = packobj%packName + call this%gwfpackages(iterm)%set_auxname(packobj%naux, & + packobj%auxname) iterm = iterm + 1 ! ! -- if this package has a mover associated with it, then add another @@ -1448,19 +1454,21 @@ subroutine initialize_gwfterms_from_gwfbndlist(this) imover = packobj%imover if (packobj%isadvpak /= 0) imover = 0 if (imover /= 0) then - budtxt = trim(adjustl(packobj%text)) // '-TO-MVR' + budtxt = trim(adjustl(packobj%text))//'-TO-MVR' call this%gwfpackages(iterm)%set_name(packobj%packName, budtxt) this%flowpacknamearray(iterm) = packobj%packName + call this%gwfpackages(iterm)%set_auxname(packobj%naux, & + packobj%auxname) this%igwfmvrterm(iterm) = 1 iterm = iterm + 1 end if end do return end subroutine initialize_gwfterms_from_gwfbndlist - + subroutine allocate_gwfpackages(this, ngwfterms) ! ****************************************************************************** -! allocate_gwfpackages -- gwfpackages is an array of PackageBudget objects. +! allocate_gwfpackages -- gwfpackages is an array of PackageBudget objects. ! This routine allocates gwfpackages to the proper size and initializes some ! member variables. ! ****************************************************************************** @@ -1479,9 +1487,9 @@ subroutine allocate_gwfpackages(this, ngwfterms) ! ------------------------------------------------------------------------------ ! ! -- direct allocate - allocate(this%gwfpackages(ngwfterms)) - allocate(this%flowpacknamearray(ngwfterms)) - allocate(this%datp(ngwfterms)) + allocate (this%gwfpackages(ngwfterms)) + allocate (this%flowpacknamearray(ngwfterms)) + allocate (this%datp(ngwfterms)) ! ! -- mem_allocate call mem_allocate(this%iatp, ngwfterms, 'IATP', this%memoryPath) @@ -1494,16 +1502,16 @@ subroutine allocate_gwfpackages(this, ngwfterms) this%igwfmvrterm(n) = 0 this%flowpacknamearray(n) = '' ! - ! -- Create a mempath for each individual flow package data set + ! -- Create a mempath for each individual flow package data set ! of the form, MODELNAME/FMI-FTn - write(memPath, '(a, i0)') trim(this%memoryPath) // '-FT', n + write (memPath, '(a, i0)') trim(this%memoryPath)//'-FT', n call this%gwfpackages(n)%initialize(memPath) end do ! ! -- return return end subroutine allocate_gwfpackages - + subroutine deallocate_gwfpackages(this) ! ****************************************************************************** ! deallocate_gwfpackages -- memory in the gwfpackages array @@ -1526,7 +1534,7 @@ subroutine deallocate_gwfpackages(this) ! -- return return end subroutine deallocate_gwfpackages - + subroutine get_package_index(this, name, idx) ! ****************************************************************************** ! get_package_index -- find the package index for package called name @@ -1558,5 +1566,5 @@ subroutine get_package_index(this, name, idx) ! -- return return end subroutine get_package_index - + end module GwtFmiModule diff --git a/src/Model/GroundWaterTransport/gwt1ic1.f90 b/src/Model/GroundWaterTransport/gwt1ic1.f90 index c6aa511e37d..b89d932e5bd 100644 --- a/src/Model/GroundWaterTransport/gwt1ic1.f90 +++ b/src/Model/GroundWaterTransport/gwt1ic1.f90 @@ -1,9 +1,9 @@ module GwtIcModule - - use KindModule, only: DP, I4B - use GwfIcModule, only: GwfIcType - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType + + use KindModule, only: DP, I4B + use GwfIcModule, only: GwfIcType + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType implicit none private @@ -16,7 +16,7 @@ module GwtIcModule procedure :: read_data end type GwtIcType - contains +contains subroutine ic_cr(ic, name_model, inunit, iout, dis) ! ****************************************************************************** @@ -34,7 +34,7 @@ subroutine ic_cr(ic, name_model, inunit, iout, dis) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(ic) + allocate (ic) ! ! -- create name and memory path call ic%set_names(1, name_model, 'IC', 'IC') @@ -63,8 +63,8 @@ subroutine read_data(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error ! -- dummy class(GwtIcType) :: this ! -- local @@ -81,8 +81,8 @@ subroutine read_data(this) ! ! -- get griddata block call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING GRIDDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -90,18 +90,18 @@ subroutine read_data(this) call this%parser%GetRemainingLine(line) lloc = 1 select case (keyword) - case ('STRT') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, this%strt, & - aname(1)) - case default - write(errmsg,'(4x,a,a)')'ERROR. UNKNOWN GRIDDATA TAG: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('STRT') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%strt, & + aname(1)) + case default + write (errmsg, '(4x,a,a)') 'ERROR. UNKNOWN GRIDDATA TAG: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' + write (this%iout, '(1x,a)') 'END PROCESSING GRIDDATA' else call store_error('ERROR. REQUIRED GRIDDATA BLOCK NOT FOUND.') call this%parser%StoreErrorUnit() @@ -110,7 +110,5 @@ subroutine read_data(this) ! -- Return return end subroutine read_data - - + end module GwtIcModule - \ No newline at end of file diff --git a/src/Model/GroundWaterTransport/gwt1ist1.f90 b/src/Model/GroundWaterTransport/gwt1ist1.f90 index 83e0e9daea4..c19cb08a653 100644 --- a/src/Model/GroundWaterTransport/gwt1ist1.f90 +++ b/src/Model/GroundWaterTransport/gwt1ist1.f90 @@ -1,6 +1,6 @@ !> -- @ brief Immobile Storage and Transfer (IST) Module !! -!! The GwtIstModule is contains the GwtIstType, which is the +!! The GwtIstModule is contains the GwtIstType, which is the !! derived type responsible for adding the effects of an !! immobile domain. In addition to representing transfer !! of mass between the mobile and immobile domain, the IST @@ -13,69 +13,69 @@ !< module GwtIstModule - use KindModule, only: DP, I4B - use ConstantsModule, only: DONE, DZERO, LENFTYPE, & - LENPACKAGENAME, & - LENBUDTXT, DHNOFLO - use BndModule, only: BndType - use BudgetModule, only: BudgetType - use GwtFmiModule, only: GwtFmiType - use GwtMstModule, only: GwtMstType, get_zero_order_decay - use OutputControlDataModule, only: OutputControlDataType + use KindModule, only: DP, I4B + use ConstantsModule, only: DONE, DZERO, LENFTYPE, & + LENPACKAGENAME, & + LENBUDTXT, DHNOFLO + use BndModule, only: BndType + use BudgetModule, only: BudgetType + use GwtFmiModule, only: GwtFmiType + use GwtMstModule, only: GwtMstType, get_zero_order_decay + use OutputControlDataModule, only: OutputControlDataType ! implicit none ! private public :: ist_create ! - character(len=LENFTYPE) :: ftype = 'IST' - character(len=LENPACKAGENAME) :: text = ' IMMOBILE DOMAIN' + character(len=LENFTYPE) :: ftype = 'IST' + character(len=LENPACKAGENAME) :: text = ' IMMOBILE DOMAIN' integer(I4B), parameter :: NBDITEMS = 5 character(len=LENBUDTXT), dimension(NBDITEMS) :: budtxt - data budtxt / ' STORAGE-AQUEOUS', ' STORAGE-SORBED', & - ' DECAY-AQUEOUS', ' DECAY-SORBED', & - ' MOBILE-DOMAIN' / + data budtxt/' STORAGE-AQUEOUS', ' STORAGE-SORBED', & + ' DECAY-AQUEOUS', ' DECAY-SORBED', & + ' MOBILE-DOMAIN'/ !> @ brief Immobile storage and transfer !! !! Data and methods for handling the effects of an !! immobile domain. Note that there can be as many of these !! domains as necessary. Each immobile domain represents - !! changes in immobile solute storage, decay of dissolved - !! immobile solute mass, sorption within the immobile domain, + !! changes in immobile solute storage, decay of dissolved + !! immobile solute mass, sorption within the immobile domain, !! and decay of immobile domain sorbed mass. The immobile !! domain also includes exchange with the mobile domain. !< type, extends(BndType) :: GwtIstType - - type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object - type(GwtMstType), pointer :: mst => null() !< pointer to mst object - - integer(I4B), pointer :: icimout => null() !< unit number for binary cim output - integer(I4B), pointer :: ibudgetout => null() !< binary budget output file - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file - integer(I4B), pointer :: idcy => null() !< order of decay rate (0:none, 1:first, 2:zero) - integer(I4B), pointer :: isrb => null() !< sorption active flag (0:off, 1:on) - integer(I4B), pointer :: kiter => null() !< picard iteration counter - real(DP), dimension(:), pointer, contiguous :: cim => null() !< concentration for immobile domain - real(DP), dimension(:), pointer, contiguous :: cimnew => null() !< immobile concentration at end of current time step - real(DP), dimension(:), pointer, contiguous :: cimold => null() !< immobile concentration at end of last time step - real(DP), dimension(:), pointer, contiguous :: zetaim => null() !< mass transfer rate to immobile domain - real(DP), dimension(:), pointer, contiguous :: thetaim => null() !< porosity of the immobile domain - real(DP), dimension(:), pointer, contiguous :: bulk_density => null() !< bulk density - real(DP), dimension(:), pointer, contiguous :: distcoef => null() !< distribution coefficient - real(DP), dimension(:), pointer, contiguous :: decay => null() !< first or zero order rate constant for liquid - real(DP), dimension(:), pointer, contiguous :: decaylast => null() !< decay rate used for last iteration (needed for zero order decay) - real(DP), dimension(:), pointer, contiguous :: decayslast => null() !< sorbed decay rate used for last iteration (needed for zero order decay) - real(DP), dimension(:), pointer, contiguous :: decay_sorbed => null() !< first or zero order rate constant for sorbed mass - real(DP), dimension(:), pointer, contiguous :: strg => null() !< mass transfer rate - real(DP), dimension(2, NBDITEMS) :: budterm !< immmobile domain mass summaries - - type(BudgetType), pointer :: budget => null() !< budget object - type(OutputControlDataType), pointer :: ocd => null() !< output control object for cim - + + type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object + type(GwtMstType), pointer :: mst => null() !< pointer to mst object + + integer(I4B), pointer :: icimout => null() !< unit number for binary cim output + integer(I4B), pointer :: ibudgetout => null() !< binary budget output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + integer(I4B), pointer :: idcy => null() !< order of decay rate (0:none, 1:first, 2:zero) + integer(I4B), pointer :: isrb => null() !< sorption active flag (0:off, 1:on); only linear is supported in ist + integer(I4B), pointer :: kiter => null() !< picard iteration counter + real(DP), dimension(:), pointer, contiguous :: cim => null() !< concentration for immobile domain + real(DP), dimension(:), pointer, contiguous :: cimnew => null() !< immobile concentration at end of current time step + real(DP), dimension(:), pointer, contiguous :: cimold => null() !< immobile concentration at end of last time step + real(DP), dimension(:), pointer, contiguous :: zetaim => null() !< mass transfer rate to immobile domain + real(DP), dimension(:), pointer, contiguous :: thetaim => null() !< porosity of the immobile domain + real(DP), dimension(:), pointer, contiguous :: bulk_density => null() !< bulk density + real(DP), dimension(:), pointer, contiguous :: distcoef => null() !< distribution coefficient + real(DP), dimension(:), pointer, contiguous :: decay => null() !< first or zero order rate constant for liquid + real(DP), dimension(:), pointer, contiguous :: decaylast => null() !< decay rate used for last iteration (needed for zero order decay) + real(DP), dimension(:), pointer, contiguous :: decayslast => null() !< sorbed decay rate used for last iteration (needed for zero order decay) + real(DP), dimension(:), pointer, contiguous :: decay_sorbed => null() !< first or zero order rate constant for sorbed mass + real(DP), dimension(:), pointer, contiguous :: strg => null() !< mass transfer rate + real(DP), dimension(2, NBDITEMS) :: budterm !< immmobile domain mass summaries + + type(BudgetType), pointer :: budget => null() !< budget object + type(OutputControlDataType), pointer :: ocd => null() !< output control object for cim + contains - + procedure :: bnd_ar => ist_ar procedure :: bnd_rp => ist_rp procedure :: bnd_ad => ist_ad @@ -91,11 +91,11 @@ module GwtIstModule procedure :: read_options procedure, private :: ist_allocate_arrays procedure, private :: read_data - + end type GwtIstType - - contains - + +contains + !> @ brief Create a new package object !! !! Create a new IST object @@ -104,20 +104,20 @@ module GwtIstModule subroutine ist_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & fmi, mst) ! -- dummy - class(BndType), pointer :: packobj !< BndType pointer that will point to new IST Package - integer(I4B),intent(in) :: id !< name of the model - integer(I4B),intent(in) :: ibcnum !< consecutive package number - integer(I4B),intent(in) :: inunit !< unit number of package input file - integer(I4B),intent(in) :: iout !< unit number of model listing file - character(len=*), intent(in) :: namemodel !< name of the model - character(len=*), intent(in) :: pakname !< name of the package + class(BndType), pointer :: packobj !< BndType pointer that will point to new IST Package + integer(I4B), intent(in) :: id !< name of the model + integer(I4B), intent(in) :: ibcnum !< consecutive package number + integer(I4B), intent(in) :: inunit !< unit number of package input file + integer(I4B), intent(in) :: iout !< unit number of model listing file + character(len=*), intent(in) :: namemodel !< name of the model + character(len=*), intent(in) :: pakname !< name of the package ! -- local type(GwtIstType), pointer :: istobj type(GwtFmiType), pointer :: fmi type(GwtMstType), pointer :: mst ! ! -- allocate the object and assign values to object variables - allocate(istobj) + allocate (istobj) packobj => istobj ! ! -- create name and memory path @@ -156,16 +156,16 @@ subroutine ist_ar(this) use SimModule, only: store_error, count_errors use BudgetModule, only: budget_cr ! -- dummy - class(GwtIstType), intent(inout) :: this !< GwtIstType object + class(GwtIstType), intent(inout) :: this !< GwtIstType object ! -- local integer(I4B) :: n ! -- formats - character(len=*), parameter :: fmtist = & - "(1x,/1x,'IST -- IMMOBILE DOMAIN STORAGE AND TRANSFER PACKAGE, ', & + character(len=*), parameter :: fmtist = & + "(1x,/1x,'IST -- IMMOBILE DOMAIN STORAGE AND TRANSFER PACKAGE, ', & &'VERSION 1, 12/24/2018 INPUT READ FROM UNIT ', i0, //)" ! ! --print a message identifying the immobile domain package. - write(this%iout, fmtist) this%inunit + write (this%iout, fmtist) this%inunit ! ! -- Read immobile domain options call this%read_options() @@ -173,11 +173,11 @@ subroutine ist_ar(this) ! -- Allocate arrays call this%ist_allocate_arrays() ! - ! -- Now that arrays are allocated, check in the cimnew array to + ! -- Now that arrays are allocated, check in the cimnew array to ! the output control manager for subsequent printing/saving - call this%ocd%init_dbl('CIM', this%cimnew, this%dis, 'PRINT LAST ', & - 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & - this%iout, DHNOFLO) + call this%ocd%init_dbl('CIM', this%cimnew, this%dis, 'PRINT LAST ', & + 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & + this%iout, DHNOFLO) ! ! -- read the data block call this%read_data() @@ -195,16 +195,19 @@ subroutine ist_ar(this) call this%budget%budget_df(NBDITEMS, 'MASS', 'M', bdzone=this%packName) call this%budget%set_ibudcsv(this%ibudcsv) ! - ! -- Perform a check to ensure that sorption and decay are set + ! -- Perform a check to ensure that sorption and decay are set ! consistently between the MST and IST packages. if (this%idcy /= this%mst%idcy) then - call store_error('DECAY MUST BE ACTIVATED CONSISTENTLY BETWEEN THE & - &MST AND IST PACKAGES. TURN DECAY ON OR OFF FOR BOTH PACKAGES.') - endif + call store_error('DECAY must be activated consistently between the & + &MST and IST Packages. Activate or deactivate DECAY for both & + &Packages.') + end if if (this%isrb /= this%mst%isrb) then - call store_error('SORPTION MUST BE ACTIVATED CONSISTENTLY BETWEEN THE & - &MST AND IST PACKAGES. TURN SORPTION ON OR OFF FOR BOTH PACKAGES.') - endif + call store_error('Sorption is active for the IST Package but it is not & + &compatible with the sorption option selected for the MST Package. & + &If sorption is active for the IST Package, then SORPTION LINEAR must & + &be specified in the options block of the MST Package.') + end if if (count_errors() > 0) then call this%parser%StoreErrorUnit() end if @@ -212,7 +215,7 @@ subroutine ist_ar(this) ! -- Return return end subroutine ist_ar - + !> @ brief Read and prepare method for package !! !! Method to read and prepare package data @@ -220,7 +223,7 @@ end subroutine ist_ar !< subroutine ist_rp(this) ! -- dummy - class(GwtIstType), intent(inout) :: this !< GwtIstType object + class(GwtIstType), intent(inout) :: this !< GwtIstType object ! -- local ! -- format ! @@ -238,7 +241,7 @@ subroutine ist_ad(this) ! -- modules use SimVariablesModule, only: iFailedStepRetry ! -- dummy variables - class(GwtIstType) :: this !< GwtIstType object + class(GwtIstType) :: this !< GwtIstType object ! -- local variables integer(I4B) :: n ! @@ -272,11 +275,11 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtIstType) :: this !< GwtIstType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + class(GwtIstType) :: this !< GwtIstType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix ! -- local integer(I4B) :: n, idiag real(DP) :: tled @@ -307,7 +310,7 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) do n = 1, this%dis%nodes ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- calculate new and old water volumes vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -316,7 +319,7 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) thetaim = this%thetaim(n) idiag = ia(n) ! - ! -- set exchange coefficient + ! -- set exchange coefficient zetaim = this%zetaim(n) ! ! -- Set thetamfrac and thetaimfrac @@ -334,8 +337,8 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) ! -- setup decay variables if (this%idcy == 1) lambda1im = this%decay(n) if (this%idcy == 2) then - gamma1im = get_zero_order_decay(this%decay(n), this%decaylast(n), & - this%kiter, this%cimold(n), & + gamma1im = get_zero_order_decay(this%decay(n), this%decaylast(n), & + this%kiter, this%cimold(n), & this%cimnew(n), delt) this%decaylast(n) = gamma1im end if @@ -348,17 +351,17 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) if (this%idcy == 2) then cimsrbold = this%cimold(n) * kd cimsrbnew = this%cimnew(n) * kd - gamma2im = get_zero_order_decay(this%decay_sorbed(n), & - this%decayslast(n), & - this%kiter, cimsrbold, & + gamma2im = get_zero_order_decay(this%decay_sorbed(n), & + this%decayslast(n), & + this%kiter, cimsrbold, & cimsrbnew, delt) this%decayslast(n) = gamma2im end if end if ! ! -- calculate the terms and then get the hcof and rhs contributions - call get_ddterm(thetaim, vcell, delt, swtpdt, & - thetaimfrac, rhob, kd, lambda1im, lambda2im, & + call get_ddterm(thetaim, vcell, delt, swtpdt, & + thetaimfrac, rhob, kd, lambda1im, lambda2im, & gamma1im, gamma2im, zetaim, ddterm, f) cimold = this%cimold(n) call get_hcofrhs(ddterm, f, cimold, hhcof, rrhs) @@ -367,15 +370,15 @@ subroutine ist_fc(this, rhs, ia, idxglo, amatsln) amatsln(idxglo(idiag)) = amatsln(idxglo(idiag)) + hhcof rhs(n) = rhs(n) + rrhs ! - enddo + end do ! ! -- Return return end subroutine ist_fc - + !> @ brief Calculate package flows. !! - !! Calculate the flow between connected package control volumes. + !! Calculate the flow between connected package control volumes. !! !< subroutine ist_cq(this, x, flowja, iadv) @@ -383,10 +386,10 @@ subroutine ist_cq(this, x, flowja, iadv) use TdisModule, only: delt use ConstantsModule, only: DZERO ! -- dummy - class(GwtIstType), intent(inout) :: this !< GwtIstType object - real(DP), dimension(:), intent(in) :: x !< current dependent-variable value - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes - integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package + class(GwtIstType), intent(inout) :: this !< GwtIstType object + real(DP), dimension(:), intent(in) :: x !< current dependent-variable value + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package ! -- local integer(I4B) :: idiag integer(I4B) :: n @@ -413,7 +416,7 @@ subroutine ist_cq(this, x, flowja, iadv) ! -- formats ! ! -- initialize - this%budterm(:, :) = DZERO + this%budterm(:, :) = DZERO ! ! -- Calculate immobile domain transfer rate do n = 1, this%dis%nodes @@ -421,7 +424,7 @@ subroutine ist_cq(this, x, flowja, iadv) ! -- skip if transport inactive rate = DZERO cimnew = DZERO - if(this%ibound(n) > 0) then + if (this%ibound(n) > 0) then ! ! -- calculate new and old water volumes vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -429,7 +432,7 @@ subroutine ist_cq(this, x, flowja, iadv) swt = this%fmi%gwfsatold(n, delt) thetaim = this%thetaim(n) ! - ! -- set exchange coefficient + ! -- set exchange coefficient zetaim = this%zetaim(n) ! ! -- Set thetamfrac and thetaimfrac @@ -458,16 +461,16 @@ subroutine ist_cq(this, x, flowja, iadv) if (this%idcy == 2) then cimsrbold = this%cimold(n) * kd cimsrbnew = this%cimnew(n) * kd - gamma2im = get_zero_order_decay(this%decay_sorbed(n), & - this%decayslast(n), & - 0, cimsrbold, & + gamma2im = get_zero_order_decay(this%decay_sorbed(n), & + this%decayslast(n), & + 0, cimsrbold, & cimsrbnew, delt) end if end if ! ! -- calculate the terms and then get the hcof and rhs contributions - call get_ddterm(thetaim, vcell, delt, swtpdt, & - thetaimfrac, rhob, kd, lambda1im, lambda2im, & + call get_ddterm(thetaim, vcell, delt, swtpdt, & + thetaimfrac, rhob, kd, lambda1im, lambda2im, & gamma1im, gamma2im, zetaim, ddterm, f) cimold = this%cimold(n) call get_hcofrhs(ddterm, f, cimold, hhcof, rrhs) @@ -479,7 +482,7 @@ subroutine ist_cq(this, x, flowja, iadv) cimnew = get_ddconc(ddterm, f, cimold, x(n)) ! ! -- accumulate the budget terms - call accumulate_budterm(this%budterm, ddterm, cimnew, cimold, x(n), & + call accumulate_budterm(this%budterm, ddterm, cimnew, cimold, x(n), & this%idcy) end if ! @@ -491,14 +494,14 @@ subroutine ist_cq(this, x, flowja, iadv) ! -- store immobile domain concentration this%cimnew(n) = cimnew ! - enddo + end do return end subroutine ist_cq !> @ brief Add package flows to model budget. !! - !! Add the flow between IST package and the model (ratin and ratout) to the - !! model budget. + !! Add the flow between IST package and the model (ratin and ratout) to the + !! model budget. !! !< subroutine ist_bd(this, model_budget) @@ -506,34 +509,34 @@ subroutine ist_bd(this, model_budget) use TdisModule, only: delt use BudgetModule, only: BudgetType, rate_accumulator ! -- dummy - class(GwtIstType) :: this !< GwtIstType object - type(BudgetType), intent(inout) :: model_budget !< model budget object + class(GwtIstType) :: this !< GwtIstType object + type(BudgetType), intent(inout) :: model_budget !< model budget object ! -- local real(DP) :: ratin real(DP) :: ratout integer(I4B) :: isuppress_output isuppress_output = 0 call rate_accumulator(this%strg(:), ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%text, & + call model_budget%addentry(ratin, ratout, delt, this%text, & isuppress_output, this%packName) return end subroutine ist_bd !> @ brief Output model flow terms. !! - !! Output flow terms between the IST package and model to a binary file and/or - !! print flows to the model listing file. + !! Output flow terms between the IST package and model to a binary file and/or + !! print flows to the model listing file. !! !< subroutine ist_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) ! -- modules use ConstantsModule, only: DZERO ! -- dummy - class(GwtIstType) :: this !< GwtIstType object - integer(I4B), intent(in) :: icbcfl !< flag for cell-by-cell output - integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved - integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell output - integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping vector + class(GwtIstType) :: this !< GwtIstType object + integer(I4B), intent(in) :: icbcfl !< flag for cell-by-cell output + integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved + integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell output + integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping vector ! -- loca integer(I4B) :: n integer(I4B) :: ibinun @@ -542,32 +545,33 @@ subroutine ist_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) real(DP) :: rate ! ! -- Set unit number for binary output - if(this%ipakcb < 0) then + if (this%ipakcb < 0) then ibinun = icbcun - elseif(this%ipakcb == 0) then + elseif (this%ipakcb == 0) then ibinun = 0 else ibinun = this%ipakcb - endif - if(icbcfl == 0) ibinun = 0 + end if + if (icbcfl == 0) ibinun = 0 ! ! -- Record the storage rate if requested ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun /= 0) then + if (ibinun /= 0) then nbound = this%dis%nodes naux = 0 - call this%dis%record_srcdst_list_header(this%text, this%name_model, & - this%name_model, this%name_model, this%packName, naux, & - this%auxname, ibinun, nbound, this%iout) - endif + call this%dis%record_srcdst_list_header(this%text, this%name_model, & + this%name_model, this%name_model, & + this%packName, naux, this%auxname, & + ibinun, nbound, this%iout) + end if ! ! -- Calculate immobile domain rhs and hcof do n = 1, this%dis%nodes ! ! -- skip if transport inactive rate = DZERO - if(this%ibound(n) > 0) then + if (this%ibound(n) > 0) then ! ! -- set rate from this%strg rate = this%strg(n) @@ -575,28 +579,28 @@ subroutine ist_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) ! ! -- If saving cell-by-cell flows in list, write flow if (ibinun /= 0) then - call this%dis%record_mf6_list_entry(ibinun, n, n, rate, & - naux, this%auxvar(:,n), & - olconv=.TRUE., & + call this%dis%record_mf6_list_entry(ibinun, n, n, rate, & + naux, this%auxvar(:, n), & + olconv=.TRUE., & olconv2=.TRUE.) end if ! - enddo + end do ! ! -- Return return end subroutine ist_ot_model_flows - + !> @ brief Output immobile domain concentration. !! !< subroutine ist_ot_dv(this, idvsave, idvprint) ! -- modules use TdisModule, only: kstp, endofperiod - ! -- dummy variables - class(GwtIstType) :: this !< BndType object - integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output - integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file + ! -- dummy variables + class(GwtIstType) :: this !< BndType object + integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output + integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file ! -- local integer(I4B) :: ipflg integer(I4B) :: ibinun @@ -606,22 +610,22 @@ subroutine ist_ot_dv(this, idvsave, idvprint) ! for it. ipflg = 0 ibinun = 1 - if(idvsave == 0) ibinun = 0 + if (idvsave == 0) ibinun = 0 if (ibinun /= 0) then - call this%ocd%ocd_ot(ipflg, kstp, endofperiod, this%iout, & + call this%ocd%ocd_ot(ipflg, kstp, endofperiod, this%iout, & iprint_opt=0, isav_opt=ibinun) - endif + end if ! ! -- Print immobile domain concentrations to listing file if (idvprint /= 0) then - call this%ocd%ocd_ot(ipflg, kstp, endofperiod, this%iout, & + call this%ocd%ocd_ot(ipflg, kstp, endofperiod, this%iout, & iprint_opt=idvprint, isav_opt=0) - endif + end if end subroutine ist_ot_dv - + !> @ brief Output IST package budget summary. !! - !! Output advanced boundary package budget summary. This method only needs + !! Output advanced boundary package budget summary. This method only needs !! to be overridden for advanced packages that save budget summaries !! to the model listing file. !! @@ -630,11 +634,11 @@ subroutine ist_ot_bdsummary(this, kstp, kper, iout, ibudfl) ! -- modules use TdisModule, only: delt, totim ! -- dummy variables - class(GwtIstType) :: this !< GwtIstType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + class(GwtIstType) :: this !< GwtIstType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written ! -- local integer(I4B) :: isuppress_output = 0 ! @@ -651,20 +655,20 @@ subroutine ist_ot_bdsummary(this, kstp, kper, iout, ibudfl) call this%budget%writecsv(totim) return end subroutine ist_ot_bdsummary - + !> @ brief Deallocate package memory !! - !! Deallocate package scalars and arrays. + !! Deallocate package scalars and arrays. !! !< subroutine ist_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(GwtIstType) :: this !< GwtIstType object + class(GwtIstType) :: this !< GwtIstType object ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then call mem_deallocate(this%icimout) call mem_deallocate(this%ibudgetout) call mem_deallocate(this%ibudcsv) @@ -685,15 +689,15 @@ subroutine ist_da(this) call mem_deallocate(this%strg) this%fmi => null() this%mst => null() - endif + end if ! ! -- Scalars ! ! -- Objects call this%budget%budget_da() - deallocate(this%budget) + deallocate (this%budget) call this%ocd%ocd_da() - deallocate(this%ocd) + deallocate (this%ocd) ! ! -- deallocate parent call this%BndType%bnd_da() @@ -704,7 +708,7 @@ end subroutine ist_da !> @ brief Allocate package scalars !! - !! Allocate and initialize package scalars. + !! Allocate and initialize package scalars. !! !< subroutine allocate_scalars(this) @@ -712,7 +716,7 @@ subroutine allocate_scalars(this) use MemoryManagerModule, only: mem_allocate, mem_setptr use OutputControlDataModule, only: ocd_cr ! -- dummy - class(GwtIstType) :: this !< GwtIstType object + class(GwtIstType) :: this !< GwtIstType object ! -- local ! ! -- call standard BndType allocate scalars @@ -744,14 +748,14 @@ end subroutine allocate_scalars !> @ brief Allocate package arrays !! - !! Allocate and initialize package arrays. + !! Allocate and initialize package arrays. !! !< subroutine ist_allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy - class(GwtIstType), intent(inout) :: this !< GwtIstType object + class(GwtIstType), intent(inout) :: this !< GwtIstType object ! -- local integer(I4B) :: n ! @@ -768,25 +772,25 @@ subroutine ist_allocate_arrays(this) call mem_allocate(this%thetaim, this%dis%nodes, 'THETAIM', this%memoryPath) if (this%isrb == 0) then call mem_allocate(this%bulk_density, 1, 'BULK_DENSITY', this%memoryPath) - call mem_allocate(this%distcoef, 1, 'DISTCOEF', this%memoryPath) + call mem_allocate(this%distcoef, 1, 'DISTCOEF', this%memoryPath) else - call mem_allocate(this%bulk_density, this%dis%nodes, 'BULK_DENSITY', & + call mem_allocate(this%bulk_density, this%dis%nodes, 'BULK_DENSITY', & this%memoryPath) - call mem_allocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & + call mem_allocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & this%memoryPath) - endif + end if if (this%idcy == 0) then call mem_allocate(this%decay, 1, 'DECAY', this%memoryPath) call mem_allocate(this%decaylast, 1, 'DECAYLAST', this%memoryPath) else call mem_allocate(this%decay, this%dis%nodes, 'DECAY', this%memoryPath) - call mem_allocate(this%decaylast, this%dis%nodes, 'DECAYLAST', & + call mem_allocate(this%decaylast, this%dis%nodes, 'DECAYLAST', & this%memoryPath) - endif + end if if (this%isrb == 0 .and. this%idcy == 0) then call mem_allocate(this%decayslast, 1, 'DECAYSLAST', this%memoryPath) else - call mem_allocate(this%decayslast, this%dis%nodes, 'DECAYSLAST', & + call mem_allocate(this%decayslast, this%dis%nodes, 'DECAYSLAST', & this%memoryPath) end if call mem_allocate(this%decay_sorbed, 1, 'DECAY_SORBED', this%memoryPath) @@ -799,14 +803,14 @@ subroutine ist_allocate_arrays(this) this%cimold(n) = DZERO this%zetaim(n) = DZERO this%thetaim(n) = DZERO - enddo + end do do n = 1, size(this%decay) this%decay(n) = DZERO this%decaylast(n) = DZERO - enddo + end do do n = 1, size(this%decayslast) this%decayslast(n) = DZERO - enddo + end do ! ! -- Set pointers this%ocd%dis => this%dis @@ -822,12 +826,12 @@ end subroutine ist_allocate_arrays !< subroutine read_options(this) ! -- modules - use ConstantsModule, only: LINELENGTH, MNORMAL - use SimModule, only: store_error - use OpenSpecModule, only: access, form + use ConstantsModule, only: LINELENGTH, MNORMAL + use SimModule, only: store_error + use OpenSpecModule, only: access, form use InputOutputModule, only: getunit, openfile ! -- dummy - class(GwtIstType), intent(inout) :: this !< GwtIstType object + class(GwtIstType), intent(inout) :: this !< GwtIstType object ! -- local character(len=LINELENGTH) :: errmsg, keyword character(len=LINELENGTH) :: fname @@ -836,17 +840,18 @@ subroutine read_options(this) logical :: isfound, endOfBlock logical :: found ! -- formats - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtisrb = & - "(4x,'LINEAR SORPTION IS SELECTED. ')" - character(len=*), parameter :: fmtidcy1 = & - "(4x,'FIRST-ORDER DECAY IS ACTIVE. ')" - character(len=*), parameter :: fmtidcy2 = & - "(4x,'ZERO-ORDER DECAY IS ACTIVE. ')" - character(len=*),parameter :: fmtistbin = & - "(4x, 'IST ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I0)" + character(len=*), parameter :: fmtisvflow = & + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" + character(len=*), parameter :: fmtisrb = & + &"(4x,'LINEAR SORPTION IS SELECTED. ')" + character(len=*), parameter :: fmtidcy1 = & + &"(4x,'FIRST-ORDER DECAY IS ACTIVE. ')" + character(len=*), parameter :: fmtidcy2 = & + &"(4x,'ZERO-ORDER DECAY IS ACTIVE. ')" + character(len=*), parameter :: fmtistbin = & + "(4x, 'IST ', 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, & + &/4x, 'OPENED ON UNIT: ', I0)" ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, blockRequired=.false., & @@ -854,60 +859,61 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)') 'PROCESSING IMMOBILE STORAGE AND TRANSFER & + write (this%iout, '(1x,a)') 'PROCESSING IMMOBILE STORAGE AND TRANSFER & &OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtisvflow) - case('CIM') - call this%parser%GetRemainingLine(keyword2) - call this%ocd%set_option(keyword2, this%inunit, this%iout) - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE', mode_opt=MNORMAL) - write(this%iout,fmtistbin) 'BUDGET', fname, this%ibudgetout - found = .true. - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtistbin) 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case ('SORBTION', 'SORPTION') - this%isrb = 1 - write(this%iout, fmtisrb) - case ('FIRST_ORDER_DECAY') - this%idcy = 1 - write(this%iout, fmtidcy1) - case ('ZERO_ORDER_DECAY') - this%idcy = 2 - write(this%iout, fmtidcy2) - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN IST OPTION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtisvflow) + case ('CIM') + call this%parser%GetRemainingLine(keyword2) + call this%ocd%set_option(keyword2, this%inunit, this%iout) + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE', mode_opt=MNORMAL) + write (this%iout, fmtistbin) 'BUDGET', fname, this%ibudgetout + found = .true. + else + call store_error('OPTIONAL BUDGET KEYWORD MUST & + &BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtistbin) 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case ('SORBTION', 'SORPTION') + this%isrb = 1 + write (this%iout, fmtisrb) + case ('FIRST_ORDER_DECAY') + this%idcy = 1 + write (this%iout, fmtidcy1) + case ('ZERO_ORDER_DECAY') + this%idcy = 2 + write (this%iout, fmtidcy2) + case default + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN IST OPTION: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)') 'END OF IMMOBILE STORAGE AND TRANSFER & + write (this%iout, '(1x,a)') 'END OF IMMOBILE STORAGE AND TRANSFER & &OPTIONS' end if ! @@ -922,7 +928,7 @@ end subroutine read_options !< subroutine ist_read_dimensions(this) ! -- dummy - class(GwtIstType),intent(inout) :: this !< GwtIstType object + class(GwtIstType), intent(inout) :: this !< GwtIstType object ! -- local ! -- format ! @@ -937,11 +943,11 @@ end subroutine ist_read_dimensions !< subroutine read_data(this) ! -- modules - use ConstantsModule, only: LINELENGTH - use SimModule, only: store_error, count_errors + use ConstantsModule, only: LINELENGTH + use SimModule, only: store_error, count_errors use MemoryManagerModule, only: mem_reallocate, mem_reassignptr ! -- dummy - class(GwtIstType) :: this !< GwtIstType object + class(GwtIstType) :: this !< GwtIstType object ! -- local character(len=LINELENGTH) :: errmsg, keyword character(len=:), allocatable :: line @@ -951,13 +957,13 @@ subroutine read_data(this) character(len=24), dimension(7) :: aname ! -- formats ! -- data - data aname(1) /' BULK DENSITY'/ - data aname(2) /'DISTRIBUTION COEFFICIENT'/ - data aname(3) /' DECAY RATE'/ - data aname(4) /' DECAY SORBED RATE'/ - data aname(5) /' INITIAL IMMOBILE CONC'/ - data aname(6) /' FIRST ORDER TRANS RATE'/ - data aname(7) /'IMMOBILE DOMAIN POROSITY'/ + data aname(1)/' BULK DENSITY'/ + data aname(2)/'DISTRIBUTION COEFFICIENT'/ + data aname(3)/' DECAY RATE'/ + data aname(4)/' DECAY SORBED RATE'/ + data aname(5)/' INITIAL IMMOBILE CONC'/ + data aname(6)/' FIRST ORDER TRANS RATE'/ + data aname(7)/'IMMOBILE DOMAIN POROSITY'/ ! ! -- initialize isfound = .false. @@ -965,8 +971,8 @@ subroutine read_data(this) ! ! -- get griddata block call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING GRIDDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -974,61 +980,61 @@ subroutine read_data(this) call this%parser%GetRemainingLine(line) lloc = 1 select case (keyword) - case ('BULK_DENSITY') - if (this%isrb == 0) & - call mem_reallocate(this%bulk_density, this%dis%nodes, & - 'BULK_DENSITY', trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, & - this%bulk_density, aname(1)) - lname(1) = .true. - case ('DISTCOEF') - if (this%isrb == 0) & - call mem_reallocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & + case ('BULK_DENSITY') + if (this%isrb == 0) & + call mem_reallocate(this%bulk_density, this%dis%nodes, & + 'BULK_DENSITY', trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, & + this%bulk_density, aname(1)) + lname(1) = .true. + case ('DISTCOEF') + if (this%isrb == 0) & + call mem_reallocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & + trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%distcoef, & + aname(2)) + lname(2) = .true. + case ('DECAY') + if (this%idcy == 0) & + call mem_reallocate(this%decay, this%dis%nodes, 'DECAY', & trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%distcoef, & - aname(2)) - lname(2) = .true. - case ('DECAY') - if (this%idcy == 0) & - call mem_reallocate(this%decay, this%dis%nodes, 'DECAY', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%decay, & - aname(3)) - lname(3) = .true. - case ('DECAY_SORBED') - call mem_reallocate(this%decay_sorbed, this%dis%nodes, & - 'DECAY_SORBED', trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, & - this%decay_sorbed, aname(4)) - lname(4) = .true. - case ('CIM') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%cim, & - aname(5)) - lname(5) = .true. - case ('ZETAIM') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%zetaim, & - aname(6)) - lname(6) = .true. - case ('THETAIM') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%thetaim, & - aname(7)) - lname(7) = .true. - case default - write(errmsg,'(4x,a,a)') 'Unknown GRIDDATA tag: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%decay, & + aname(3)) + lname(3) = .true. + case ('DECAY_SORBED') + call mem_reallocate(this%decay_sorbed, this%dis%nodes, & + 'DECAY_SORBED', trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, & + this%decay_sorbed, aname(4)) + lname(4) = .true. + case ('CIM') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%cim, & + aname(5)) + lname(5) = .true. + case ('ZETAIM') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%zetaim, & + aname(6)) + lname(6) = .true. + case ('THETAIM') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%thetaim, & + aname(7)) + lname(7) = .true. + case default + write (errmsg, '(4x,a,a)') 'Unknown GRIDDATA tag: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END PROCESSING GRIDDATA' + write (this%iout, '(1x,a)') 'END PROCESSING GRIDDATA' else - write(errmsg,'(1x,a)')'Required GRIDDATA block not found.' + write (errmsg, '(1x,a)') 'Required GRIDDATA block not found.' call store_error(errmsg) call this%parser%StoreErrorUnit() end if @@ -1036,86 +1042,86 @@ subroutine read_data(this) ! -- Check for required sorption variables if (this%isrb > 0) then if (.not. lname(1)) then - write(errmsg, '(1x,a)') 'ERROR. SORPTION IS ACTIVE BUT BULK_DENSITY & + write (errmsg, '(1x,a)') 'ERROR. SORPTION IS ACTIVE BUT BULK_DENSITY & &NOT SPECIFIED. BULK_DENSITY MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (.not. lname(2)) then - write(errmsg, '(1x,a)') 'ERROR. SORPTION IS ACTIVE BUT DISTRIBUTION & + write (errmsg, '(1x,a)') 'ERROR. SORPTION IS ACTIVE BUT DISTRIBUTION & &COEFFICIENT NOT SPECIFIED. DISTCOEF MUST BE SPECIFIED IN & &GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if else if (lname(1)) then - write(this%iout, '(1x,a)') 'WARNING. SORPTION IS NOT ACTIVE BUT & + write (this%iout, '(1x,a)') 'WARNING. SORPTION IS NOT ACTIVE BUT & &BULK_DENSITY WAS SPECIFIED. BULK_DENSITY WILL HAVE NO AFFECT ON & &SIMULATION RESULTS.' - endif + end if if (lname(2)) then - write(this%iout, '(1x,a)') 'WARNING. SORPTION IS NOT ACTIVE BUT & + write (this%iout, '(1x,a)') 'WARNING. SORPTION IS NOT ACTIVE BUT & &DISTRIBUTION COEFFICIENT WAS SPECIFIED. DISTCOEF WILL HAVE & &NO AFFECT ON SIMULATION RESULTS.' - endif - endif + end if + end if ! ! -- Check for required decay/production rate coefficients if (this%idcy > 0) then if (.not. lname(3)) then - write(errmsg, '(1x,a)') 'ERROR. FIRST OR ZERO ORDER DECAY IS & + write (errmsg, '(1x,a)') 'ERROR. FIRST OR ZERO ORDER DECAY IS & &ACTIVE BUT THE FIRST RATE COEFFICIENT IS NOT SPECIFIED. & &DECAY MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (.not. lname(4)) then ! ! -- If DECAY_SORBED not specified and sorption is active, then set ! decay_sorbed equal to decay if (this%isrb > 0) then - write(errmsg, '(a)') 'DECAY_SORBED not provided in GRIDDATA & + write (errmsg, '(a)') 'DECAY_SORBED not provided in GRIDDATA & &block but decay and sorption are active. Specify DECAY_SORBED & &in GRIDDATA block.' call store_error(errmsg) - endif - endif + end if + end if else if (lname(3)) then - write(this%iout, '(1x,a)') 'WARNING. FIRST OR ZERO ORER DECAY & + write (this%iout, '(1x,a)') 'WARNING. FIRST OR ZERO ORER DECAY & &IS NOT ACTIVE BUT DECAY WAS SPECIFIED. DECAY WILL & &HAVE NO AFFECT ON SIMULATION RESULTS.' - endif + end if if (lname(4)) then - write(this%iout, '(1x,a)') 'WARNING. FIRST OR ZERO ORER DECAY & + write (this%iout, '(1x,a)') 'WARNING. FIRST OR ZERO ORER DECAY & &IS NOT ACTIVE BUT DECAY_SORBED MUST WAS SPECIFIED. & &DECAY_SORBED MUST WILL HAVE NO AFFECT ON SIMULATION & &RESULTS.' - endif - endif + end if + end if ! ! -- Check for required dual domain arrays or warn if they are specified ! but won't be used. if (.not. lname(5)) then - write(this%iout, '(1x,a)') 'WARNING. DUAL DOMAIN IS ACTIVE BUT & + write (this%iout, '(1x,a)') 'WARNING. DUAL DOMAIN IS ACTIVE BUT & &INITIAL IMMOBILE DOMAIN CONCENTRATION WAS NOT SPECIFIED. & &SETTING CIM TO ZERO.' - endif + end if if (.not. lname(6)) then - write(errmsg, '(1x,a)') 'DUAL DOMAIN IS ACTIVE BUT DUAL & + write (errmsg, '(1x,a)') 'DUAL DOMAIN IS ACTIVE BUT DUAL & &DOMAIN MASS TRANSFER RATE (ZETAIM) WAS NOT SPECIFIED. ZETAIM & &MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (.not. lname(7)) then - write(errmsg, '(1x,a)') 'DUAL DOMAIN IS ACTIVE BUT & + write (errmsg, '(1x,a)') 'DUAL DOMAIN IS ACTIVE BUT & &IMMOBILE DOMAIN POROSITY (THETAIM) WAS NOT SPECIFIED. THETAIM & &MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if ! ! -- terminate if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return @@ -1129,31 +1135,31 @@ end subroutine read_data !! for the immobile domain. !! !< - subroutine get_ddterm(thetaim, vcell, delt, swtpdt, & - thetaimfrac, rhob, kd, lambda1im, lambda2im, & + subroutine get_ddterm(thetaim, vcell, delt, swtpdt, & + thetaimfrac, rhob, kd, lambda1im, lambda2im, & gamma1im, gamma2im, zetaim, ddterm, f) ! -- dummy - real(DP), intent(in) :: thetaim !< immobile domain porosity - real(DP), intent(in) :: vcell !< volume of cell - real(DP), intent(in) :: delt !< length of time step - real(DP), intent(in) :: swtpdt !< cell saturation at end of time step - real(DP), intent(in) :: thetaimfrac !< fraction of total porosity this is immobile - real(DP), intent(in) :: rhob !< bulk density - real(DP), intent(in) :: kd !< distribution coefficient for linear isotherm - real(DP), intent(in) :: lambda1im !< first-order decay rate in aqueous phase - real(DP), intent(in) :: lambda2im !< first-order decay rate in sorbed phase - real(DP), intent(in) :: gamma1im !< zero-order decay rate in aqueous phase - real(DP), intent(in) :: gamma2im !< zero-order decay rate in sorbed phase - real(DP), intent(in) :: zetaim !< transfer coefficient between mobile and immobile domains - real(DP), dimension(:), intent(inout) :: ddterm !< nine terms comprising the balance equation of the immobile domain - real(DP), intent(inout) :: f !< the f term used to calculate the immobile domain concentration + real(DP), intent(in) :: thetaim !< immobile domain porosity + real(DP), intent(in) :: vcell !< volume of cell + real(DP), intent(in) :: delt !< length of time step + real(DP), intent(in) :: swtpdt !< cell saturation at end of time step + real(DP), intent(in) :: thetaimfrac !< fraction of total porosity this is immobile + real(DP), intent(in) :: rhob !< bulk density + real(DP), intent(in) :: kd !< distribution coefficient for linear isotherm + real(DP), intent(in) :: lambda1im !< first-order decay rate in aqueous phase + real(DP), intent(in) :: lambda2im !< first-order decay rate in sorbed phase + real(DP), intent(in) :: gamma1im !< zero-order decay rate in aqueous phase + real(DP), intent(in) :: gamma2im !< zero-order decay rate in sorbed phase + real(DP), intent(in) :: zetaim !< transfer coefficient between mobile and immobile domains + real(DP), dimension(:), intent(inout) :: ddterm !< nine terms comprising the balance equation of the immobile domain + real(DP), intent(inout) :: f !< the f term used to calculate the immobile domain concentration ! -- local real(DP) :: tled ! ! -- initialize tled = DONE / delt ! - ! -- Calculate terms. These terms correspond to the concentration + ! -- Calculate terms. These terms correspond to the concentration ! coefficients in equation 7-4 of the GWT model report ddterm(1) = thetaim * vcell * tled ddterm(2) = thetaim * vcell * tled @@ -1180,14 +1186,14 @@ end subroutine get_ddterm !< subroutine get_hcofrhs(ddterm, f, cimold, hcof, rhs) ! -- dummy - real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain - real(DP), intent(in) :: f !< the f term used to calculate the immobile domain concentration - real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step - real(DP), intent(inout) :: hcof !< calculated contribution for the a-matrix diagonal position - real(DP), intent(inout) :: rhs !< calculated contribution for the solution right-hand side + real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain + real(DP), intent(in) :: f !< the f term used to calculate the immobile domain concentration + real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step + real(DP), intent(inout) :: hcof !< calculated contribution for the a-matrix diagonal position + real(DP), intent(inout) :: rhs !< calculated contribution for the solution right-hand side ! ! -- calculate hcof - hcof = ddterm(9) ** 2 / f - ddterm(9) + hcof = ddterm(9)**2 / f - ddterm(9) ! ! -- calculate rhs, and switch the sign because this term needs to ! be moved to the left hand side @@ -1204,25 +1210,25 @@ end subroutine get_hcofrhs !! This function calculates the concentration of the immobile domain. !! !< - function get_ddconc(ddterm, f, cimold, cnew) result (cimnew) + function get_ddconc(ddterm, f, cimold, cnew) result(cimnew) ! -- dummy - real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain - real(DP), intent(in) :: f !< the f term used to calculate the immobile domain concentration - real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step - real(DP), intent(in) :: cnew !< concentration of the mobile domain at the end of the time step + real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain + real(DP), intent(in) :: f !< the f term used to calculate the immobile domain concentration + real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step + real(DP), intent(in) :: cnew !< concentration of the mobile domain at the end of the time step ! -- result - real(DP) :: cimnew !< calculated concentration of the immobile domain + real(DP) :: cimnew !< calculated concentration of the immobile domain ! -- local ! ! -- calculate ddconc - cimnew = (ddterm(2) + ddterm(4)) * cimold + ddterm(9) * cnew - ddterm(7) & + cimnew = (ddterm(2) + ddterm(4)) * cimold + ddterm(9) * cnew - ddterm(7) & - ddterm(8) cimnew = cimnew / f ! ! -- Return return end function get_ddconc - + !> @ brief Calculate the immobile domain budget terms !! !! This subroutine calculates and accumulates the immobile domain @@ -1232,64 +1238,64 @@ end function get_ddconc subroutine accumulate_budterm(budterm, ddterm, cimnew, cimold, cnew, idcy) ! -- modules ! -- dummy - real(DP), dimension(:, :), intent(inout) :: budterm !< - real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain - real(DP), intent(in) :: cimnew !< immobile domain concenration at the end of this time step - real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step - real(DP), intent(in) :: cnew !< mobile domain concentration at the end of this time step - integer(I4B), intent(in) :: idcy !< order of decay rate (0:none, 1:first, 2:zero) + real(DP), dimension(:, :), intent(inout) :: budterm !< + real(DP), dimension(:), intent(in) :: ddterm !< terms comprising the balance equation of the immobile domain + real(DP), intent(in) :: cimnew !< immobile domain concenration at the end of this time step + real(DP), intent(in) :: cimold !< immobile domain concentration at end of last time step + real(DP), intent(in) :: cnew !< mobile domain concentration at the end of this time step + integer(I4B), intent(in) :: idcy !< order of decay rate (0:none, 1:first, 2:zero) ! -- local real(DP) :: rate integer(I4B) :: i ! ! -- calculate STORAGE-AQUEOUS i = 1 - rate = - ddterm(1) * cimnew + ddterm(2) * cimold + rate = -ddterm(1) * cimnew + ddterm(2) * cimold if (rate > DZERO) then budterm(1, i) = budterm(1, i) + rate else budterm(2, i) = budterm(2, i) - rate - endif + end if ! ! -- calculate STORAGE-SORBED i = 2 - rate = - ddterm(3) * cimnew + ddterm(4) * cimold + rate = -ddterm(3) * cimnew + ddterm(4) * cimold if (rate > DZERO) then budterm(1, i) = budterm(1, i) + rate else budterm(2, i) = budterm(2, i) - rate - endif + end if ! ! -- calculate DECAY-AQUEOUS i = 3 rate = DZERO if (idcy == 1) then - rate = - ddterm(5) * cimnew + rate = -ddterm(5) * cimnew else if (idcy == 2) then - rate = - ddterm(7) + rate = -ddterm(7) else rate = DZERO - endif + end if if (rate > DZERO) then budterm(1, i) = budterm(1, i) + rate else budterm(2, i) = budterm(2, i) - rate - endif + end if ! ! -- calculate DECAY-SORBED i = 4 if (idcy == 1) then - rate = - ddterm(6) * cimnew + rate = -ddterm(6) * cimnew else if (idcy == 2) then - rate = - ddterm(8) + rate = -ddterm(8) else rate = DZERO - endif + end if if (rate > DZERO) then budterm(1, i) = budterm(1, i) + rate else budterm(2, i) = budterm(2, i) - rate - endif + end if ! ! -- calculate MOBILE-DOMAIN i = 5 @@ -1298,11 +1304,11 @@ subroutine accumulate_budterm(budterm, ddterm, cimnew, cimold, cnew, idcy) budterm(1, i) = budterm(1, i) + rate else budterm(2, i) = budterm(2, i) - rate - endif + end if ! ! ! -- Return return end subroutine accumulate_budterm -end module GwtIstModule \ No newline at end of file +end module GwtIstModule diff --git a/src/Model/GroundWaterTransport/gwt1lkt1.f90 b/src/Model/GroundWaterTransport/gwt1lkt1.f90 index 3092980ec05..cf6e7c0e223 100644 --- a/src/Model/GroundWaterTransport/gwt1lkt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1lkt1.f90 @@ -5,7 +5,7 @@ ! ! LAK flows (lakbudptr) index var LKT term Transport Type !--------------------------------------------------------------------------------- - + ! -- terms from LAK that will be handled by parent APT Package ! FLOW-JA-FACE idxbudfjf FLOW-JA-FACE cv2cv ! GWF (aux FLOW-AREA) idxbudgwf GWF cv2gwf @@ -20,7 +20,7 @@ ! EXT-INFLOW idxbudiflw EXT-INFLOW q * ciflw ! WITHDRAWAL idxbudwdrl WITHDRAWAL q * cfeat ! EXT-OUTFLOW idxbudoutf EXT-OUTFLOW q * cfeat - + ! -- terms from a flow file that should be skipped ! CONSTANT none none none ! AUXILIARY none none none @@ -39,32 +39,34 @@ module GwtLktModule use BndModule, only: BndType, GetBndFromList use GwtFmiModule, only: GwtFmiType use LakModule, only: LakType - use GwtAptModule, only: GwtAptType - + use ObserveModule, only: ObserveType + use GwtAptModule, only: GwtAptType, apt_process_obsID, & + apt_process_obsID12 + implicit none - + public lkt_create - + character(len=*), parameter :: ftype = 'LKT' character(len=*), parameter :: flowtype = 'LAK' - character(len=16) :: text = ' LKT' - + character(len=16) :: text = ' LKT' + type, extends(GwtAptType) :: GwtLktType - - integer(I4B), pointer :: idxbudrain => null() ! index of rainfall terms in flowbudptr - integer(I4B), pointer :: idxbudevap => null() ! index of evaporation terms in flowbudptr - integer(I4B), pointer :: idxbudroff => null() ! index of runoff terms in flowbudptr - integer(I4B), pointer :: idxbudiflw => null() ! index of inflow terms in flowbudptr - integer(I4B), pointer :: idxbudwdrl => null() ! index of withdrawal terms in flowbudptr - integer(I4B), pointer :: idxbudoutf => null() ! index of outflow terms in flowbudptr - real(DP), dimension(:), pointer, contiguous :: concrain => null() ! rainfall concentration - real(DP), dimension(:), pointer, contiguous :: concevap => null() ! evaporation concentration - real(DP), dimension(:), pointer, contiguous :: concroff => null() ! runoff concentration - real(DP), dimension(:), pointer, contiguous :: conciflw => null() ! inflow concentration + integer(I4B), pointer :: idxbudrain => null() ! index of rainfall terms in flowbudptr + integer(I4B), pointer :: idxbudevap => null() ! index of evaporation terms in flowbudptr + integer(I4B), pointer :: idxbudroff => null() ! index of runoff terms in flowbudptr + integer(I4B), pointer :: idxbudiflw => null() ! index of inflow terms in flowbudptr + integer(I4B), pointer :: idxbudwdrl => null() ! index of withdrawal terms in flowbudptr + integer(I4B), pointer :: idxbudoutf => null() ! index of outflow terms in flowbudptr + + real(DP), dimension(:), pointer, contiguous :: concrain => null() ! rainfall concentration + real(DP), dimension(:), pointer, contiguous :: concevap => null() ! evaporation concentration + real(DP), dimension(:), pointer, contiguous :: concroff => null() ! runoff concentration + real(DP), dimension(:), pointer, contiguous :: conciflw => null() ! inflow concentration contains - + procedure :: bnd_da => lkt_da procedure :: allocate_scalars procedure :: apt_allocate_arrays => lkt_allocate_arrays @@ -81,13 +83,14 @@ module GwtLktModule procedure :: lkt_wdrl_term procedure :: lkt_outf_term procedure :: pak_df_obs => lkt_df_obs + procedure :: pak_rp_obs => lkt_rp_obs procedure :: pak_bd_obs => lkt_bd_obs procedure :: pak_set_stressperiod => lkt_set_stressperiod - + end type GwtLktType - contains - +contains + subroutine lkt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & fmi) ! ****************************************************************************** @@ -98,10 +101,10 @@ subroutine lkt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(GwtFmiType), pointer :: fmi @@ -110,7 +113,7 @@ subroutine lkt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(lktobj) + allocate (lktobj) packobj => lktobj ! ! -- create name and memory path @@ -129,7 +132,7 @@ subroutine lkt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & packobj%ibcnum = ibcnum packobj%ncolbnd = 1 packobj%iscloc = 1 - + ! -- Store pointer to flow model interface. When the GwfGwt exchange is ! created, it sets fmi%bndlist so that the GWT model has access to all ! the flow packages @@ -171,7 +174,7 @@ subroutine find_lkt_package(this) ! else if (associated(this%fmi%gwfbndlist)) then - ! -- Look through gwfbndlist for a flow package with the same name as + ! -- Look through gwfbndlist for a flow package with the same name as ! this transport package name do ip = 1, this%fmi%gwfbndlist%Count() packobj => GetBndFromList(this%fmi%gwfbndlist, ip) @@ -182,8 +185,8 @@ subroutine find_lkt_package(this) ! use the select type to point to the budobj in flow package this%flowpackagebnd => packobj select type (packobj) - type is (LakType) - this%flowbudptr => packobj%budobj + type is (LakType) + this%flowbudptr => packobj%budobj end select end if if (found) exit @@ -193,60 +196,60 @@ subroutine find_lkt_package(this) ! ! -- error if flow package not found if (.not. found) then - write(errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& - &// trim(adjustl(this%flowpackagename)) // '.' + write (errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& + &//trim(adjustl(this%flowpackagename))//'.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! - ! -- allocate space for idxbudssm, which indicates whether this is a + ! -- allocate space for idxbudssm, which indicates whether this is a ! special budget term or one that is a general source and sink nbudterm = this%flowbudptr%nbudterm call mem_allocate(this%idxbudssm, nbudterm, 'IDXBUDSSM', this%memoryPath) ! ! -- Process budget terms and identify special budget terms - write(this%iout, '(/, a, a)') & - 'PROCESSING ' // ftype // ' INFORMATION FOR ', this%packName - write(this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN ' // flowtype // ' PACKAGE' - write(this%iout, '(a, i0)') & - ' NUMBER OF ' // flowtype // ' = ', this%flowbudptr%ncv + write (this%iout, '(/, a, a)') & + 'PROCESSING '//ftype//' INFORMATION FOR ', this%packName + write (this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN '//flowtype//' PACKAGE' + write (this%iout, '(a, i0)') & + ' NUMBER OF '//flowtype//' = ', this%flowbudptr%ncv icount = 1 do ip = 1, this%flowbudptr%nbudterm - select case(trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) - case('FLOW-JA-FACE') + select case (trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) + case ('FLOW-JA-FACE') this%idxbudfjf = ip this%idxbudssm(ip) = 0 - case('GWF') + case ('GWF') this%idxbudgwf = ip this%idxbudssm(ip) = 0 - case('STORAGE') + case ('STORAGE') this%idxbudsto = ip this%idxbudssm(ip) = 0 - case('RAINFALL') + case ('RAINFALL') this%idxbudrain = ip this%idxbudssm(ip) = 0 - case('EVAPORATION') + case ('EVAPORATION') this%idxbudevap = ip this%idxbudssm(ip) = 0 - case('RUNOFF') + case ('RUNOFF') this%idxbudroff = ip this%idxbudssm(ip) = 0 - case('EXT-INFLOW') + case ('EXT-INFLOW') this%idxbudiflw = ip this%idxbudssm(ip) = 0 - case('WITHDRAWAL') + case ('WITHDRAWAL') this%idxbudwdrl = ip this%idxbudssm(ip) = 0 - case('EXT-OUTFLOW') + case ('EXT-OUTFLOW') this%idxbudoutf = ip this%idxbudssm(ip) = 0 - case('TO-MVR') + case ('TO-MVR') this%idxbudtmvr = ip this%idxbudssm(ip) = 0 - case('FROM-MVR') + case ('FROM-MVR') this%idxbudfmvr = ip this%idxbudssm(ip) = 0 - case('AUXILIARY') + case ('AUXILIARY') this%idxbudaux = ip this%idxbudssm(ip) = 0 case default @@ -256,15 +259,15 @@ subroutine find_lkt_package(this) this%idxbudssm(ip) = icount icount = icount + 1 end select - write(this%iout, '(a, i0, " = ", a,/, a, i0)') & + write (this%iout, '(a, i0, " = ", a,/, a, i0)') & ' TERM ', ip, trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)), & ' MAX NO. OF ENTRIES = ', this%flowbudptr%budterm(ip)%maxlist end do - write(this%iout, '(a, //)') 'DONE PROCESSING ' // ftype // ' INFORMATION' + write (this%iout, '(a, //)') 'DONE PROCESSING '//ftype//' INFORMATION' ! ! -- Return return -end subroutine find_lkt_package + end subroutine find_lkt_package subroutine lkt_fc_expanded(this, rhs, ia, idxglo, amatsln) ! ****************************************************************************** @@ -426,7 +429,7 @@ subroutine lkt_solve(this) ! -- Return return end subroutine lkt_solve - + function lkt_get_nbudterms(this) result(nbudterms) ! ****************************************************************************** ! lkt_get_nbudterms -- function to return the number of budget terms just for @@ -449,7 +452,7 @@ function lkt_get_nbudterms(this) result(nbudterms) ! -- Return return end function lkt_get_nbudterms - + subroutine lkt_setup_budobj(this, idx) ! ****************************************************************************** ! lkt_setup_budobj -- Set up the budget object that stores all the lake flows @@ -467,7 +470,7 @@ subroutine lkt_setup_budobj(this, idx) character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! - ! -- + ! -- text = ' RAINFALL' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudrain)%maxlist @@ -480,7 +483,7 @@ subroutine lkt_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EVAPORATION' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudevap)%maxlist @@ -493,7 +496,7 @@ subroutine lkt_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' RUNOFF' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudroff)%maxlist @@ -506,7 +509,7 @@ subroutine lkt_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-INFLOW' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudiflw)%maxlist @@ -519,7 +522,7 @@ subroutine lkt_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' WITHDRAWAL' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudwdrl)%maxlist @@ -532,7 +535,7 @@ subroutine lkt_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-OUTFLOW' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudoutf)%maxlist @@ -569,7 +572,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) real(DP) :: q ! -- formats ! ----------------------------------------------------------------------------- - + ! -- RAIN idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudrain)%nlist @@ -579,8 +582,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EVAPORATION idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudevap)%nlist @@ -590,8 +592,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- RUNOFF idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudroff)%nlist @@ -601,8 +602,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EXT-INFLOW idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudiflw)%nlist @@ -612,8 +612,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- WITHDRAWAL idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudwdrl)%nlist @@ -623,8 +622,7 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EXT-OUTFLOW idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudoutf)%nlist @@ -634,7 +632,6 @@ subroutine lkt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - ! ! -- return @@ -665,7 +662,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%idxbudiflw, 'IDXBUDIFLW', this%memoryPath) call mem_allocate(this%idxbudwdrl, 'IDXBUDWDRL', this%memoryPath) call mem_allocate(this%idxbudoutf, 'IDXBUDOUTF', this%memoryPath) - ! + ! ! -- Initialize this%idxbudrain = 0 this%idxbudevap = 0 @@ -692,7 +689,7 @@ subroutine lkt_allocate_arrays(this) ! -- local integer(I4B) :: n ! ------------------------------------------------------------------------------ - ! + ! ! -- time series call mem_allocate(this%concrain, this%ncv, 'CONCRAIN', this%memoryPath) call mem_allocate(this%concevap, this%ncv, 'CONCEVAP', this%memoryPath) @@ -714,7 +711,7 @@ subroutine lkt_allocate_arrays(this) ! -- Return return end subroutine lkt_allocate_arrays - + subroutine lkt_da(this) ! ****************************************************************************** ! lkt_da @@ -781,7 +778,7 @@ subroutine lkt_rain_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine lkt_rain_term - + subroutine lkt_evap_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -816,13 +813,13 @@ subroutine lkt_evap_term(this, ientry, n1, n2, rrate, & if (present(rrate)) & rrate = omega * qbnd * this%xnewpak(n1) + & (DONE - omega) * qbnd * ctmp - if (present(rhsval)) rhsval = - (DONE - omega) * qbnd * ctmp + if (present(rhsval)) rhsval = -(DONE - omega) * qbnd * ctmp if (present(hcofval)) hcofval = omega * qbnd ! ! -- return return end subroutine lkt_evap_term - + subroutine lkt_roff_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -854,7 +851,7 @@ subroutine lkt_roff_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine lkt_roff_term - + subroutine lkt_iflw_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -886,7 +883,7 @@ subroutine lkt_iflw_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine lkt_iflw_term - + subroutine lkt_wdrl_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -918,7 +915,7 @@ subroutine lkt_wdrl_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine lkt_wdrl_term - + subroutine lkt_outf_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -950,7 +947,7 @@ subroutine lkt_outf_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine lkt_outf_term - + subroutine lkt_df_obs(this) ! ****************************************************************************** ! lkt_df_obs -- obs are supported? @@ -961,12 +958,46 @@ subroutine lkt_df_obs(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use GwtAptModule, only: apt_process_obsID ! -- dummy class(GwtLktType) :: this ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ + ! + ! -- Store obs type and assign procedure pointer + ! for concentration observation type. + call this%obs%StoreObsType('concentration', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for flow between features, such as lake to lake. + call this%obs%StoreObsType('flow-ja-face', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID12 + ! + ! -- Store obs type and assign procedure pointer + ! for from-mvr observation type. + call this%obs%StoreObsType('from-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for to-mvr observation type. + call this%obs%StoreObsType('to-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for storage observation type. + call this%obs%StoreObsType('storage', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for constant observation type. + call this%obs%StoreObsType('constant', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for observation type: lkt + call this%obs%StoreObsType('lkt', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID12 ! ! -- Store obs type and assign procedure pointer ! for rainfall observation type. @@ -1000,7 +1031,43 @@ subroutine lkt_df_obs(this) ! return end subroutine lkt_df_obs - + + !> @brief Process package specific obs + !! + !! Method to process specific observations for this package. + !! + !< + subroutine lkt_rp_obs(this, obsrv, found) + ! -- dummy + class(GwtLktType), intent(inout) :: this !< package class + type(ObserveType), intent(inout) :: obsrv !< observation object + logical, intent(inout) :: found !< indicate whether observation was found + ! -- local + ! + found = .true. + select case (obsrv%ObsTypeId) + case ('RAINFALL') + call this%rp_obs_byfeature(obsrv) + case ('EVAPORATION') + call this%rp_obs_byfeature(obsrv) + case ('RUNOFF') + call this%rp_obs_byfeature(obsrv) + case ('EXT-INFLOW') + call this%rp_obs_byfeature(obsrv) + case ('WITHDRAWAL') + call this%rp_obs_byfeature(obsrv) + case ('EXT-OUTFLOW') + call this%rp_obs_byfeature(obsrv) + case ('TO-MVR') + call this%rp_obs_budterm(obsrv, & + this%flowbudptr%budterm(this%idxbudtmvr)) + case default + found = .false. + end select + ! + return + end subroutine lkt_rp_obs + subroutine lkt_bd_obs(this, obstypeid, jj, v, found) ! ****************************************************************************** ! lkt_bd_obs -- calculate observation value and pass it back to APT @@ -1020,32 +1087,32 @@ subroutine lkt_bd_obs(this, obstypeid, jj, v, found) ! found = .true. select case (obstypeid) - case ('RAINFALL') - if (this%iboundpak(jj) /= 0) then - call this%lkt_rain_term(jj, n1, n2, v) - end if - case ('EVAPORATION') - if (this%iboundpak(jj) /= 0) then - call this%lkt_evap_term(jj, n1, n2, v) - end if - case ('RUNOFF') - if (this%iboundpak(jj) /= 0) then - call this%lkt_roff_term(jj, n1, n2, v) - end if - case ('EXT-INFLOW') - if (this%iboundpak(jj) /= 0) then - call this%lkt_iflw_term(jj, n1, n2, v) - end if - case ('WITHDRAWAL') - if (this%iboundpak(jj) /= 0) then - call this%lkt_wdrl_term(jj, n1, n2, v) - end if - case ('EXT-OUTFLOW') - if (this%iboundpak(jj) /= 0) then - call this%lkt_outf_term(jj, n1, n2, v) - end if - case default - found = .false. + case ('RAINFALL') + if (this%iboundpak(jj) /= 0) then + call this%lkt_rain_term(jj, n1, n2, v) + end if + case ('EVAPORATION') + if (this%iboundpak(jj) /= 0) then + call this%lkt_evap_term(jj, n1, n2, v) + end if + case ('RUNOFF') + if (this%iboundpak(jj) /= 0) then + call this%lkt_roff_term(jj, n1, n2, v) + end if + case ('EXT-INFLOW') + if (this%iboundpak(jj) /= 0) then + call this%lkt_iflw_term(jj, n1, n2, v) + end if + case ('WITHDRAWAL') + if (this%iboundpak(jj) /= 0) then + call this%lkt_wdrl_term(jj, n1, n2, v) + end if + case ('EXT-OUTFLOW') + if (this%iboundpak(jj) /= 0) then + call this%lkt_outf_term(jj, n1, n2, v) + end if + case default + found = .false. end select ! return @@ -1060,7 +1127,7 @@ subroutine lkt_set_stressperiod(this, itemno, keyword, found) ! ------------------------------------------------------------------------------ use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtLktType),intent(inout) :: this + class(GwtLktType), intent(inout) :: this integer(I4B), intent(in) :: itemno character(len=*), intent(in) :: keyword logical, intent(inout) :: found @@ -1080,61 +1147,60 @@ subroutine lkt_set_stressperiod(this, itemno, keyword, found) ! found = .true. select case (keyword) - case ('RAINFALL') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concrain(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RAINFALL') - case ('EVAPORATION') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concevap(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'EVAPORATION') - case ('RUNOFF') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concroff(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RUNOFF') - case ('EXT-INFLOW') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%conciflw(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'EXT-INFLOW') - case default - ! - ! -- keyword not recognized so return to caller with found = .false. - found = .false. + case ('RAINFALL') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concrain(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RAINFALL') + case ('EVAPORATION') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concevap(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'EVAPORATION') + case ('RUNOFF') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concroff(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RUNOFF') + case ('EXT-INFLOW') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%conciflw(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'EXT-INFLOW') + case default + ! + ! -- keyword not recognized so return to caller with found = .false. + found = .false. end select ! -999 continue +999 continue ! ! -- return return end subroutine lkt_set_stressperiod - end module GwtLktModule diff --git a/src/Model/GroundWaterTransport/gwt1mst1.f90 b/src/Model/GroundWaterTransport/gwt1mst1.f90 index a390ba211ec..bef0bb49e1b 100644 --- a/src/Model/GroundWaterTransport/gwt1mst1.f90 +++ b/src/Model/GroundWaterTransport/gwt1mst1.f90 @@ -1,6 +1,6 @@ !> -- @ brief Mobile Storage and Transfer (MST) Module !! -!! The GwtMstModule is contains the GwtMstType, which is the +!! The GwtMstModule is contains the GwtMstType, which is the !! derived type responsible for adding the effects of !! 1. Changes in dissolved solute mass !! 2. Decay of dissolved solute mass @@ -8,24 +8,24 @@ !! 4. Decay of sorbed solute mass !< module GwtMstModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: DONE, DZERO, DTWO, DHALF, LENBUDTXT - use SimVariablesModule, only: errmsg, warnmsg - use SimModule, only: store_error, count_errors, & - store_warning + + use KindModule, only: DP, I4B + use ConstantsModule, only: DONE, DZERO, DTWO, DHALF, LENBUDTXT + use SimVariablesModule, only: errmsg, warnmsg + use SimModule, only: store_error, count_errors, & + store_warning use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use GwtFmiModule, only: GwtFmiType - + use BaseDisModule, only: DisBaseType + use GwtFmiModule, only: GwtFmiType + implicit none public :: GwtMstType public :: mst_cr ! integer(I4B), parameter :: NBDITEMS = 4 character(len=LENBUDTXT), dimension(NBDITEMS) :: budtxt - data budtxt / ' STORAGE-AQUEOUS', ' DECAY-AQUEOUS', & - ' STORAGE-SORBED', ' DECAY-SORBED' / + data budtxt/' STORAGE-AQUEOUS', ' DECAY-AQUEOUS', & + ' STORAGE-SORBED', ' DECAY-SORBED'/ !> @ brief Mobile storage and transfer !! @@ -36,32 +36,32 @@ module GwtMstModule type, extends(NumericalPackageType) :: GwtMstType ! ! -- storage - real(DP), dimension(:), pointer, contiguous :: porosity => null() !< porosity - real(DP), dimension(:), pointer, contiguous :: prsity2 => null() !< sum of immobile porosity - real(DP), dimension(:), pointer, contiguous :: ratesto => null() !< rate of mobile storage + real(DP), dimension(:), pointer, contiguous :: porosity => null() !< porosity + real(DP), dimension(:), pointer, contiguous :: prsity2 => null() !< sum of immobile porosity + real(DP), dimension(:), pointer, contiguous :: ratesto => null() !< rate of mobile storage ! ! -- decay - integer(I4B), pointer :: idcy => null() !< order of decay rate (0:none, 1:first, 2:zero) - real(DP), dimension(:), pointer, contiguous :: decay => null() !< first or zero order decay rate (aqueous) - real(DP), dimension(:), pointer, contiguous :: decay_sorbed => null() !< first or zero order decay rate (sorbed) - real(DP), dimension(:), pointer, contiguous :: ratedcy => null() !< rate of decay - real(DP), dimension(:), pointer, contiguous :: decaylast => null() !< decay rate used for last iteration (needed for zero order decay) - real(DP), dimension(:), pointer, contiguous :: decayslast => null() !< sorbed decay rate used for last iteration (needed for zero order decay) + integer(I4B), pointer :: idcy => null() !< order of decay rate (0:none, 1:first, 2:zero) + real(DP), dimension(:), pointer, contiguous :: decay => null() !< first or zero order decay rate (aqueous) + real(DP), dimension(:), pointer, contiguous :: decay_sorbed => null() !< first or zero order decay rate (sorbed) + real(DP), dimension(:), pointer, contiguous :: ratedcy => null() !< rate of decay + real(DP), dimension(:), pointer, contiguous :: decaylast => null() !< decay rate used for last iteration (needed for zero order decay) + real(DP), dimension(:), pointer, contiguous :: decayslast => null() !< sorbed decay rate used for last iteration (needed for zero order decay) ! ! -- sorption - integer(I4B), pointer :: isrb => null() !< sorption active flag (0:off, 1:linear, 2:freundlich, 3:langmuir) - real(DP), dimension(:), pointer, contiguous :: bulk_density => null() !< bulk density - real(DP), dimension(:), pointer, contiguous :: distcoef => null() !< kd distribution coefficient - real(DP), dimension(:), pointer, contiguous :: sp2 => null() !< second sorption parameter - real(DP), dimension(:), pointer, contiguous :: ratesrb => null() !< rate of sorption - real(DP), dimension(:), pointer, contiguous :: ratedcys => null() !< rate of sorbed mass decay + integer(I4B), pointer :: isrb => null() !< sorption active flag (0:off, 1:linear, 2:freundlich, 3:langmuir) + real(DP), dimension(:), pointer, contiguous :: bulk_density => null() !< bulk density + real(DP), dimension(:), pointer, contiguous :: distcoef => null() !< kd distribution coefficient + real(DP), dimension(:), pointer, contiguous :: sp2 => null() !< second sorption parameter + real(DP), dimension(:), pointer, contiguous :: ratesrb => null() !< rate of sorption + real(DP), dimension(:), pointer, contiguous :: ratedcys => null() !< rate of sorbed mass decay ! ! -- misc - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object contains - + procedure :: mst_ar procedure :: mst_fc procedure :: mst_fc_sto @@ -83,11 +83,11 @@ module GwtMstModule procedure, private :: allocate_arrays procedure, private :: read_options procedure, private :: read_data - + end type GwtMstType - - contains - + +contains + !> @ brief Create a new package object !! !! Create a new MST object @@ -95,14 +95,14 @@ module GwtMstModule !< subroutine mst_cr(mstobj, name_model, inunit, iout, fmi) ! -- dummy - type(GwtMstType), pointer :: mstobj !< unallocated new mst object to create - character(len=*), intent(in) :: name_model !< name of the model - integer(I4B), intent(in) :: inunit !< unit number of WEL package input file - integer(I4B), intent(in) :: iout !< unit number of model listing file - type(GwtFmiType), intent(in), target :: fmi !< fmi package for this GWT model + type(GwtMstType), pointer :: mstobj !< unallocated new mst object to create + character(len=*), intent(in) :: name_model !< name of the model + integer(I4B), intent(in) :: inunit !< unit number of WEL package input file + integer(I4B), intent(in) :: iout !< unit number of model listing file + type(GwtFmiType), intent(in), target :: fmi !< fmi package for this GWT model ! ! -- Create the object - allocate(mstobj) + allocate (mstobj) ! ! -- create name and memory path call mstobj%set_names(1, name_model, 'MST', 'MST') @@ -130,24 +130,24 @@ end subroutine mst_cr subroutine mst_ar(this, dis, ibound) ! -- modules ! -- dummy - class(GwtMstType), intent(inout) :: this !< GwtMstType object - class(DisBaseType), pointer, intent(in) :: dis !< pointer to dis package - integer(I4B), dimension(:), pointer, contiguous :: ibound !< pointer to GWT ibound array + class(GwtMstType), intent(inout) :: this !< GwtMstType object + class(DisBaseType), pointer, intent(in) :: dis !< pointer to dis package + integer(I4B), dimension(:), pointer, contiguous :: ibound !< pointer to GWT ibound array ! -- local ! -- formats - character(len=*), parameter :: fmtmst = & + character(len=*), parameter :: fmtmst = & "(1x,/1x,'MST -- MOBILE STORAGE AND TRANSFER PACKAGE, VERSION 1, & &7/29/2020 INPUT READ FROM UNIT ', i0, //)" ! ! --print a message identifying the immobile domain package. - write(this%iout, fmtmst) this%inunit + write (this%iout, fmtmst) this%inunit ! ! -- Read options call this%read_options() ! ! -- store pointers to arguments that were passed in - this%dis => dis - this%ibound => ibound + this%dis => dis + this%ibound => ibound ! ! -- Allocate arrays call this%allocate_arrays(dis%nodes) @@ -158,7 +158,7 @@ subroutine mst_ar(this, dis, ibound) ! -- Return return end subroutine mst_ar - + !> @ brief Fill coefficient method for package !! !! Method to calculate and fill coefficients for the package. @@ -168,16 +168,16 @@ subroutine mst_fc(this, nodes, cold, nja, njasln, amatsln, idxglo, cnew, & rhs, kiter) ! -- modules ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer, intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - integer(I4B), intent(in) :: nja !< number of GWT connections - integer(I4B), intent(in) :: njasln !< number of connections in solution - real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix - integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - integer(I4B), intent(in) :: kiter !< solution outer iteration number + class(GwtMstType) :: this !< GwtMstType object + integer, intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + integer(I4B), intent(in) :: nja !< number of GWT connections + integer(I4B), intent(in) :: njasln !< number of connections in solution + real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix + integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + integer(I4B), intent(in) :: kiter !< solution outer iteration number ! -- local ! ! -- storage contribution @@ -203,7 +203,7 @@ subroutine mst_fc(this, nodes, cold, nja, njasln, amatsln, idxglo, cnew, & ! -- Return return end subroutine mst_fc - + !> @ brief Fill storage coefficient method for package !! !! Method to calculate and fill storage coefficients for the package. @@ -213,14 +213,14 @@ subroutine mst_fc_sto(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer, intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - integer(I4B), intent(in) :: nja !< number of GWT connections - integer(I4B), intent(in) :: njasln !< number of connections in solution - real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix - integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model + class(GwtMstType) :: this !< GwtMstType object + integer, intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + integer(I4B), intent(in) :: nja !< number of GWT connections + integer(I4B), intent(in) :: njasln !< number of connections in solution + real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix + integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model ! -- local integer(I4B) :: n, idiag real(DP) :: tled @@ -234,7 +234,7 @@ subroutine mst_fc_sto(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs) do n = 1, this%dis%nodes ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- calculate new and old water volumes vnew = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) * & @@ -249,32 +249,32 @@ subroutine mst_fc_sto(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs) idiag = this%dis%con%ia(n) amatsln(idxglo(idiag)) = amatsln(idxglo(idiag)) + hhcof rhs(n) = rhs(n) + rrhs - enddo + end do ! ! -- Return return end subroutine mst_fc_sto - + !> @ brief Fill decay coefficient method for package !! !! Method to calculate and fill decay coefficients for the package. !! !< - subroutine mst_fc_dcy(this, nodes, cold, cnew, nja, njasln, amatsln, & + subroutine mst_fc_dcy(this, nodes, cold, cnew, nja, njasln, amatsln, & idxglo, rhs, kiter) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer, intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - integer(I4B), intent(in) :: nja !< number of GWT connections - integer(I4B), intent(in) :: njasln !< number of connections in solution - real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix - integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model - integer(I4B), intent(in) :: kiter !< solution outer iteration number + class(GwtMstType) :: this !< GwtMstType object + integer, intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + integer(I4B), intent(in) :: nja !< number of GWT connections + integer(I4B), intent(in) :: njasln !< number of connections in solution + real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix + integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model + integer(I4B), intent(in) :: kiter !< solution outer iteration number ! -- local integer(I4B) :: n, idiag real(DP) :: hhcof, rrhs @@ -286,7 +286,7 @@ subroutine mst_fc_dcy(this, nodes, cold, cnew, nja, njasln, amatsln, & do n = 1, this%dis%nodes ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- calculate new and old water volumes vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -304,14 +304,14 @@ subroutine mst_fc_dcy(this, nodes, cold, cnew, nja, njasln, amatsln, & ! ! -- Call function to get zero-order decay rate, which may be changed ! from the user-specified rate to prevent negative concentrations - decay_rate = get_zero_order_decay(this%decay(n), this%decaylast(n), kiter, & - cold(n), cnew(n), delt) + decay_rate = get_zero_order_decay(this%decay(n), this%decaylast(n), & + kiter, cold(n), cnew(n), delt) this%decaylast(n) = decay_rate rrhs = decay_rate * vcell * swtpdt * this%porosity(n) rhs(n) = rhs(n) + rrhs - endif + end if ! - enddo + end do ! ! -- Return return @@ -322,20 +322,20 @@ end subroutine mst_fc_dcy !! Method to calculate and fill sorption coefficients for the package. !! !< - subroutine mst_fc_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs, & + subroutine mst_fc_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs, & cnew) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer, intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - integer(I4B), intent(in) :: nja !< number of GWT connections - integer(I4B), intent(in) :: njasln !< number of connections in solution - real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix - integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + class(GwtMstType) :: this !< GwtMstType object + integer, intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + integer(I4B), intent(in) :: nja !< number of GWT connections + integer(I4B), intent(in) :: njasln !< number of connections in solution + real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix + integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step ! -- local integer(I4B) :: n, idiag real(DP) :: tled @@ -354,7 +354,7 @@ subroutine mst_fc_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs, & do n = 1, this%dis%nodes ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- assign variables vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -366,43 +366,43 @@ subroutine mst_fc_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, rhs, & const2 = 0. if (this%isrb > 1) const2 = this%sp2(n) rhob = this%bulk_density(n) - call mst_srb_term(this%isrb, thetamfrac, rhob, vcell, tled, cnew(n), & - cold(n), swtpdt, swt, const1, const2, & - hcofval=hhcof, rhsval=rrhs) + call mst_srb_term(this%isrb, thetamfrac, rhob, vcell, tled, cnew(n), & + cold(n), swtpdt, swt, const1, const2, & + hcofval=hhcof, rhsval=rrhs) ! ! -- Add hhcof to diagonal and rrhs to right-hand side amatsln(idxglo(idiag)) = amatsln(idxglo(idiag)) + hhcof rhs(n) = rhs(n) + rrhs ! - enddo + end do ! ! -- Return return end subroutine mst_fc_srb - + !> @ brief Calculate sorption terms !! !! Subroutine to calculate sorption terms !! !< - subroutine mst_srb_term(isrb, thetamfrac, rhob, vcell, tled, cnew, cold, & - swnew, swold, const1, const2, rate, hcofval, rhsval) + subroutine mst_srb_term(isrb, thetamfrac, rhob, vcell, tled, cnew, cold, & + swnew, swold, const1, const2, rate, hcofval, rhsval) ! -- modules ! -- dummy - integer(I4B), intent(in) :: isrb !< sorption flag 1, 2, 3 are linear, freundlich, and langmuir - real(DP), intent(in) :: thetamfrac !< fraction of total porosity that is mobile - real(DP), intent(in) :: rhob !< bulk density - real(DP), intent(in) :: vcell !< volume of cell - real(DP), intent(in) :: tled !< one over time step length - real(DP), intent(in) :: cnew !< concentration at end of this time step - real(DP), intent(in) :: cold !< concentration at end of last time step - real(DP), intent(in) :: swnew !< cell saturation at end of this time step - real(DP), intent(in) :: swold !< cell saturation at end of last time step - real(DP), intent(in) :: const1 !< distribution coefficient or freundlich or langmuir constant - real(DP), intent(in) :: const2 !< zero, freundlich exponent, or langmuir sorption sites - real(DP), intent(out), optional :: rate !< calculated sorption rate - real(DP), intent(out), optional :: hcofval !< diagonal contribution to solution coefficient matrix - real(DP), intent(out), optional :: rhsval !< contribution to solution right-hand-side + integer(I4B), intent(in) :: isrb !< sorption flag 1, 2, 3 are linear, freundlich, and langmuir + real(DP), intent(in) :: thetamfrac !< fraction of total porosity that is mobile + real(DP), intent(in) :: rhob !< bulk density + real(DP), intent(in) :: vcell !< volume of cell + real(DP), intent(in) :: tled !< one over time step length + real(DP), intent(in) :: cnew !< concentration at end of this time step + real(DP), intent(in) :: cold !< concentration at end of last time step + real(DP), intent(in) :: swnew !< cell saturation at end of this time step + real(DP), intent(in) :: swold !< cell saturation at end of last time step + real(DP), intent(in) :: const1 !< distribution coefficient or freundlich or langmuir constant + real(DP), intent(in) :: const2 !< zero, freundlich exponent, or langmuir sorption sites + real(DP), intent(out), optional :: rate !< calculated sorption rate + real(DP), intent(out), optional :: hcofval !< diagonal contribution to solution coefficient matrix + real(DP), intent(out), optional :: rhsval !< contribution to solution right-hand-side ! -- local real(DP) :: term real(DP) :: derv @@ -415,14 +415,14 @@ subroutine mst_srb_term(isrb, thetamfrac, rhob, vcell, tled, cnew, cold, & ! -- Calculate based on type of sorption if (isrb == 1) then ! -- linear - term = - thetamfrac * rhob * vcell * tled * const1 + term = -thetamfrac * rhob * vcell * tled * const1 if (present(hcofval)) hcofval = term * swnew if (present(rhsval)) rhsval = term * swold * cold if (present(rate)) rate = term * swnew * cnew - term * swold * cold else ! ! -- calculate average aqueous concentration - cavg = DHALF * (cold + cnew) + cavg = DHALF * (cold + cnew) ! ! -- set values based on isotherm if (isrb == 2) then @@ -438,7 +438,7 @@ subroutine mst_srb_term(isrb, thetamfrac, rhob, vcell, tled, cnew, cold, & end if ! ! -- calculate hcof, rhs, and rate for freundlich and langmuir - term = - thetamfrac * rhob * vcell * tled + term = -thetamfrac * rhob * vcell * tled cbaravg = (cbarold + cbarnew) * DHALF swavg = (swnew + swold) * DHALF if (present(hcofval)) then @@ -460,21 +460,21 @@ end subroutine mst_srb_term !! Method to calculate and fill sorption-decay coefficients for the package. !! !< - subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & + subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & rhs, cnew, kiter) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer, intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - integer(I4B), intent(in) :: nja !< number of GWT connections - integer(I4B), intent(in) :: njasln !< number of connections in solution - real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix - integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - integer(I4B), intent(in) :: kiter !< solution outer iteration number + class(GwtMstType) :: this !< GwtMstType object + integer, intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + integer(I4B), intent(in) :: nja !< number of GWT connections + integer(I4B), intent(in) :: njasln !< number of connections in solution + real(DP), dimension(njasln), intent(inout) :: amatsln !< solution coefficient matrix + integer(I4B), intent(in), dimension(nja) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), intent(inout), dimension(nodes) :: rhs !< right-hand side vector for model + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + integer(I4B), intent(in) :: kiter !< solution outer iteration number ! -- local integer(I4B) :: n, idiag real(DP) :: hhcof, rrhs @@ -492,17 +492,17 @@ subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & do n = 1, this%dis%nodes ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- set variables hhcof = DZERO rrhs = DZERO vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) - swnew = this%fmi%gwfsat(n) + swnew = this%fmi%gwfsat(n) distcoef = this%distcoef(n) idiag = this%dis%con%ia(n) thetamfrac = this%get_thetamfrac(n) - term = this%decay_sorbed(n) * thetamfrac * this%bulk_density(n) * & + term = this%decay_sorbed(n) * thetamfrac * this%bulk_density(n) * & swnew * vcell ! ! -- add sorbed mass decay rate terms to accumulators @@ -512,7 +512,7 @@ subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & ! ! -- first order decay rate is a function of concentration, so add ! to left hand side - hhcof = - term * distcoef + hhcof = -term * distcoef else if (this%isrb == 2) then ! ! -- nonlinear Freundlich sorption, so add to RHS @@ -529,7 +529,7 @@ subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & ! -- Call function to get zero-order decay rate, which may be changed ! from the user-specified rate to prevent negative concentrations if (distcoef > DZERO) then - + if (this%isrb == 1) then csrbold = cold(n) * distcoef csrbnew = cnew(n) * distcoef @@ -540,26 +540,26 @@ subroutine mst_fc_dcy_srb(this, nodes, cold, nja, njasln, amatsln, idxglo, & csrbold = get_langmuir_conc(cold(n), distcoef, this%sp2(n)) csrbnew = get_langmuir_conc(cnew(n), distcoef, this%sp2(n)) end if - - decay_rate = get_zero_order_decay(this%decay_sorbed(n), & - this%decayslast(n), & + + decay_rate = get_zero_order_decay(this%decay_sorbed(n), & + this%decayslast(n), & kiter, csrbold, csrbnew, delt) this%decayslast(n) = decay_rate rrhs = decay_rate * thetamfrac * this%bulk_density(n) * swnew * vcell end if - - endif + + end if ! ! -- Add hhcof to diagonal and rrhs to right-hand side amatsln(idxglo(idiag)) = amatsln(idxglo(idiag)) + hhcof rhs(n) = rhs(n) + rrhs ! - enddo + end do ! ! -- Return return end subroutine mst_fc_dcy_srb - + !> @ brief Calculate flows for package !! !! Method to calculate flows for the package. @@ -568,11 +568,11 @@ end subroutine mst_fc_dcy_srb subroutine mst_cq(this, nodes, cnew, cold, flowja) ! -- modules ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes ! -- local ! ! - storage @@ -606,11 +606,11 @@ subroutine mst_cq_sto(this, nodes, cnew, cold, flowja) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes ! -- local integer(I4B) :: n integer(I4B) :: idiag @@ -619,7 +619,7 @@ subroutine mst_cq_sto(this, nodes, cnew, cold, flowja) real(DP) :: vnew, vold real(DP) :: hhcof, rrhs ! - ! -- initialize + ! -- initialize tled = DONE / delt ! ! -- Calculate storage change @@ -627,7 +627,7 @@ subroutine mst_cq_sto(this, nodes, cnew, cold, flowja) this%ratesto(n) = DZERO ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- calculate new and old water volumes vnew = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) * & @@ -643,7 +643,7 @@ subroutine mst_cq_sto(this, nodes, cnew, cold, flowja) this%ratesto(n) = rate idiag = this%dis%con%ia(n) flowja(idiag) = flowja(idiag) + rate - enddo + end do ! ! -- Return return @@ -658,11 +658,11 @@ subroutine mst_cq_dcy(this, nodes, cnew, cold, flowja) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes ! -- local integer(I4B) :: n integer(I4B) :: idiag @@ -672,14 +672,14 @@ subroutine mst_cq_dcy(this, nodes, cnew, cold, flowja) real(DP) :: vcell real(DP) :: decay_rate ! - ! -- initialize + ! -- initialize ! ! -- Calculate decay change do n = 1, nodes ! ! -- skip if transport inactive this%ratedcy(n) = DZERO - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- calculate new and old water volumes vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -692,16 +692,16 @@ subroutine mst_cq_dcy(this, nodes, cnew, cold, flowja) if (this%idcy == 1) then hhcof = -this%decay(n) * vcell * swtpdt * this%porosity(n) elseif (this%idcy == 2) then - decay_rate = get_zero_order_decay(this%decay(n), this%decaylast(n), & + decay_rate = get_zero_order_decay(this%decay(n), this%decaylast(n), & 0, cold(n), cnew(n), delt) rrhs = decay_rate * vcell * swtpdt * this%porosity(n) - endif + end if rate = hhcof * cnew(n) - rrhs this%ratedcy(n) = rate idiag = this%dis%con%ia(n) flowja(idiag) = flowja(idiag) + rate ! - enddo + end do ! ! -- Return return @@ -716,11 +716,11 @@ subroutine mst_cq_srb(this, nodes, cnew, cold, flowja) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes ! -- local integer(I4B) :: n integer(I4B) :: idiag @@ -733,7 +733,7 @@ subroutine mst_cq_srb(this, nodes, cnew, cold, flowja) real(DP) :: const2 real(DP) :: thetamfrac ! - ! -- initialize + ! -- initialize tled = DONE / delt ! ! -- Calculate sorption change @@ -743,7 +743,7 @@ subroutine mst_cq_srb(this, nodes, cnew, cold, flowja) this%ratesrb(n) = DZERO ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- assign variables vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) @@ -754,14 +754,14 @@ subroutine mst_cq_srb(this, nodes, cnew, cold, flowja) const1 = this%distcoef(n) const2 = 0. if (this%isrb > 1) const2 = this%sp2(n) - call mst_srb_term(this%isrb, thetamfrac, rhob, vcell, tled, cnew(n), & - cold(n), swtpdt, swt, const1, const2, & - rate=rate) + call mst_srb_term(this%isrb, thetamfrac, rhob, vcell, tled, cnew(n), & + cold(n), swtpdt, swt, const1, const2, & + rate=rate) this%ratesrb(n) = rate idiag = this%dis%con%ia(n) flowja(idiag) = flowja(idiag) + rate ! - enddo + end do ! ! -- Return return @@ -776,11 +776,11 @@ subroutine mst_cq_dcy_srb(this, nodes, cnew, cold, flowja) ! -- modules use TdisModule, only: delt ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes - real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step - real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes + real(DP), intent(in), dimension(nodes) :: cnew !< concentration at end of this time step + real(DP), intent(in), dimension(nodes) :: cold !< concentration at end of last time step + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes ! -- local integer(I4B) :: n integer(I4B) :: idiag @@ -804,16 +804,16 @@ subroutine mst_cq_dcy_srb(this, nodes, cnew, cold, flowja) this%ratedcys(n) = DZERO ! ! -- skip if transport inactive - if(this%ibound(n) <= 0) cycle + if (this%ibound(n) <= 0) cycle ! ! -- set variables hhcof = DZERO rrhs = DZERO vcell = this%dis%area(n) * (this%dis%top(n) - this%dis%bot(n)) - swnew = this%fmi%gwfsat(n) + swnew = this%fmi%gwfsat(n) distcoef = this%distcoef(n) thetamfrac = this%get_thetamfrac(n) - term = this%decay_sorbed(n) * thetamfrac * this%bulk_density(n) * & + term = this%decay_sorbed(n) * thetamfrac * this%bulk_density(n) * & swnew * vcell ! ! -- add sorbed mass decay rate terms to accumulators @@ -823,7 +823,7 @@ subroutine mst_cq_dcy_srb(this, nodes, cnew, cold, flowja) ! ! -- first order decay rate is a function of concentration, so add ! to left hand side - hhcof = - term * distcoef + hhcof = -term * distcoef else if (this%isrb == 2) then ! ! -- nonlinear Freundlich sorption, so add to RHS @@ -850,12 +850,12 @@ subroutine mst_cq_dcy_srb(this, nodes, cnew, cold, flowja) csrbold = get_langmuir_conc(cold(n), distcoef, this%sp2(n)) csrbnew = get_langmuir_conc(cnew(n), distcoef, this%sp2(n)) end if - decay_rate = get_zero_order_decay(this%decay_sorbed(n), & - this%decayslast(n), & + decay_rate = get_zero_order_decay(this%decay_sorbed(n), & + this%decayslast(n), & 0, csrbold, csrbnew, delt) rrhs = decay_rate * thetamfrac * this%bulk_density(n) * swnew * vcell - end if - endif + end if + end if ! ! -- calculate rate rate = hhcof * cnew(n) - rrhs @@ -863,7 +863,7 @@ subroutine mst_cq_dcy_srb(this, nodes, cnew, cold, flowja) idiag = this%dis%con%ia(n) flowja(idiag) = flowja(idiag) + rate ! - enddo + end do ! ! -- Return return @@ -879,43 +879,43 @@ subroutine mst_bd(this, isuppress_output, model_budget) use TdisModule, only: delt use BudgetModule, only: BudgetType, rate_accumulator ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: isuppress_output !< flag to supress output - type(BudgetType), intent(inout) :: model_budget !< model budget object + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: isuppress_output !< flag to supress output + type(BudgetType), intent(inout) :: model_budget !< model budget object ! -- local real(DP) :: rin real(DP) :: rout ! ! -- sto call rate_accumulator(this%ratesto, rin, rout) - call model_budget%addentry(rin, rout, delt, budtxt(1), & + call model_budget%addentry(rin, rout, delt, budtxt(1), & isuppress_output, rowlabel=this%packName) ! ! -- dcy if (this%idcy /= 0) then call rate_accumulator(this%ratedcy, rin, rout) - call model_budget%addentry(rin, rout, delt, budtxt(2), & - isuppress_output, rowlabel=this%packName) + call model_budget%addentry(rin, rout, delt, budtxt(2), & + isuppress_output, rowlabel=this%packName) end if ! ! -- srb if (this%isrb /= 0) then call rate_accumulator(this%ratesrb, rin, rout) - call model_budget%addentry(rin, rout, delt, budtxt(3), & - isuppress_output, rowlabel=this%packName) + call model_budget%addentry(rin, rout, delt, budtxt(3), & + isuppress_output, rowlabel=this%packName) end if ! ! -- srb dcy if (this%isrb /= 0 .and. this%idcy /= 0) then call rate_accumulator(this%ratedcys, rin, rout) - call model_budget%addentry(rin, rout, delt, budtxt(4), & - isuppress_output, rowlabel=this%packName) + call model_budget%addentry(rin, rout, delt, budtxt(4), & + isuppress_output, rowlabel=this%packName) end if ! ! -- Return return end subroutine mst_bd - + !> @ brief Output flow terms for package !! !! Method to output terms for the package. @@ -923,54 +923,54 @@ end subroutine mst_bd !< subroutine mst_ot_flow(this, icbcfl, icbcun) ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output - integer(I4B), intent(in) :: icbcun !< flag indication if cell-by-cell data should be saved + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output + integer(I4B), intent(in) :: icbcun !< flag indication if cell-by-cell data should be saved ! -- local integer(I4B) :: ibinun !character(len=16), dimension(2) :: aname integer(I4B) :: iprint, nvaluesp, nwidthp - character(len=1) :: cdatafmp=' ', editdesc=' ' + character(len=1) :: cdatafmp = ' ', editdesc = ' ' real(DP) :: dinact ! ! -- Set unit number for binary output - if(this%ipakcb < 0) then + if (this%ipakcb < 0) then ibinun = icbcun - elseif(this%ipakcb == 0) then + elseif (this%ipakcb == 0) then ibinun = 0 else ibinun = this%ipakcb - endif - if(icbcfl == 0) ibinun = 0 + end if + if (icbcfl == 0) ibinun = 0 ! ! -- Record the storage rate if requested - if(ibinun /= 0) then + if (ibinun /= 0) then iprint = 0 dinact = DZERO ! ! -- sto - call this%dis%record_array(this%ratesto, this%iout, iprint, -ibinun, & - budtxt(1), cdatafmp, nvaluesp, & + call this%dis%record_array(this%ratesto, this%iout, iprint, -ibinun, & + budtxt(1), cdatafmp, nvaluesp, & nwidthp, editdesc, dinact) ! ! -- dcy if (this%idcy /= 0) & - call this%dis%record_array(this%ratedcy, this%iout, iprint, -ibinun, & - budtxt(2), cdatafmp, nvaluesp, & - nwidthp, editdesc, dinact) + call this%dis%record_array(this%ratedcy, this%iout, iprint, -ibinun, & + budtxt(2), cdatafmp, nvaluesp, & + nwidthp, editdesc, dinact) ! ! -- srb if (this%isrb /= 0) & - call this%dis%record_array(this%ratesrb, this%iout, iprint, -ibinun, & - budtxt(3), cdatafmp, nvaluesp, & - nwidthp, editdesc, dinact) + call this%dis%record_array(this%ratesrb, this%iout, iprint, -ibinun, & + budtxt(3), cdatafmp, nvaluesp, & + nwidthp, editdesc, dinact) ! ! -- dcy srb if (this%isrb /= 0 .and. this%idcy /= 0) & - call this%dis%record_array(this%ratedcys, this%iout, iprint, -ibinun, & - budtxt(4), cdatafmp, nvaluesp, & - nwidthp, editdesc, dinact) - endif + call this%dis%record_array(this%ratedcys, this%iout, iprint, -ibinun, & + budtxt(4), cdatafmp, nvaluesp, & + nwidthp, editdesc, dinact) + end if ! ! -- Return return @@ -985,10 +985,10 @@ subroutine mst_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(GwtMstType) :: this !< GwtMstType object + class(GwtMstType) :: this !< GwtMstType object ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then call mem_deallocate(this%porosity) call mem_deallocate(this%prsity2) call mem_deallocate(this%ratesto) @@ -1006,7 +1006,7 @@ subroutine mst_da(this) call mem_deallocate(this%ratedcys) this%ibound => null() this%fmi => null() - endif + end if ! ! -- Scalars ! @@ -1026,7 +1026,7 @@ subroutine allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate, mem_setptr ! -- dummy - class(GwtMstType) :: this !< GwtMstType object + class(GwtMstType) :: this !< GwtMstType object ! -- local ! ! -- Allocate scalars in NumericalPackageType @@ -1054,8 +1054,8 @@ subroutine allocate_arrays(this, nodes) use MemoryManagerModule, only: mem_allocate use ConstantsModule, only: DZERO ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: nodes !< number of nodes + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: nodes !< number of nodes ! -- local integer(I4B) :: n ! @@ -1076,26 +1076,26 @@ subroutine allocate_arrays(this, nodes) call mem_allocate(this%decaylast, nodes, 'DECAYLAST', this%memoryPath) end if if (this%idcy /= 0 .and. this%isrb /= 0) then - call mem_allocate(this%ratedcys, this%dis%nodes, 'RATEDCYS', & + call mem_allocate(this%ratedcys, this%dis%nodes, 'RATEDCYS', & this%memoryPath) - call mem_allocate(this%decayslast, this%dis%nodes, 'DECAYSLAST', & + call mem_allocate(this%decayslast, this%dis%nodes, 'DECAYSLAST', & this%memoryPath) else call mem_allocate(this%ratedcys, 1, 'RATEDCYS', this%memoryPath) call mem_allocate(this%decayslast, 1, 'DECAYSLAST', this%memoryPath) - endif - call mem_allocate(this%decay_sorbed, 1, 'DECAY_SORBED', & + end if + call mem_allocate(this%decay_sorbed, 1, 'DECAY_SORBED', & this%memoryPath) ! ! -- srb if (this%isrb == 0) then call mem_allocate(this%bulk_density, 1, 'BULK_DENSITY', this%memoryPath) call mem_allocate(this%sp2, 1, 'SP2', this%memoryPath) - call mem_allocate(this%distcoef, 1, 'DISTCOEF', this%memoryPath) + call mem_allocate(this%distcoef, 1, 'DISTCOEF', this%memoryPath) call mem_allocate(this%ratesrb, 1, 'RATESRB', this%memoryPath) else call mem_allocate(this%bulk_density, nodes, 'BULK_DENSITY', this%memoryPath) - call mem_allocate(this%distcoef, nodes, 'DISTCOEF', this%memoryPath) + call mem_allocate(this%distcoef, nodes, 'DISTCOEF', this%memoryPath) call mem_allocate(this%ratesrb, nodes, 'RATESRB', this%memoryPath) if (this%isrb == 1) then call mem_allocate(this%sp2, 1, 'SP2', this%memoryPath) @@ -1109,7 +1109,7 @@ subroutine allocate_arrays(this, nodes) this%porosity(n) = DZERO this%prsity2(n) = DZERO this%ratesto(n) = DZERO - enddo + end do do n = 1, size(this%decay) this%decay(n) = DZERO this%ratedcy(n) = DZERO @@ -1139,27 +1139,27 @@ end subroutine allocate_arrays !< subroutine read_options(this) ! -- modules - use ConstantsModule, only: LINELENGTH + use ConstantsModule, only: LINELENGTH ! -- dummy - class(GwtMstType) :: this !< GwtMstType object + class(GwtMstType) :: this !< GwtMstType object ! -- local character(len=LINELENGTH) :: keyword, keyword2 integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtisrb = & - "(4x,'LINEAR SORPTION IS ACTIVE. ')" - character(len=*), parameter :: fmtfreundlich = & - "(4x,'FREUNDLICH SORPTION IS ACTIVE. ')" - character(len=*), parameter :: fmtlangmuir = & - "(4x,'LANGMUIR SORPTION IS ACTIVE. ')" - character(len=*), parameter :: fmtidcy1 = & - "(4x,'FIRST-ORDER DECAY IS ACTIVE. ')" - character(len=*), parameter :: fmtidcy2 = & - "(4x,'ZERO-ORDER DECAY IS ACTIVE. ')" + character(len=*), parameter :: fmtisvflow = & + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" + character(len=*), parameter :: fmtisrb = & + &"(4x,'LINEAR SORPTION IS ACTIVE. ')" + character(len=*), parameter :: fmtfreundlich = & + &"(4x,'FREUNDLICH SORPTION IS ACTIVE. ')" + character(len=*), parameter :: fmtlangmuir = & + &"(4x,'LANGMUIR SORPTION IS ACTIVE. ')" + character(len=*), parameter :: fmtidcy1 = & + &"(4x,'FIRST-ORDER DECAY IS ACTIVE. ')" + character(len=*), parameter :: fmtidcy2 = & + &"(4x,'ZERO-ORDER DECAY IS ACTIVE. ')" ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, blockRequired=.false., & @@ -1167,42 +1167,42 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)') 'PROCESSING MOBILE STORAGE AND TRANSFER OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING MOBILE STORAGE AND TRANSFER OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtisvflow) - case ('SORBTION', 'SORPTION') - this%isrb = 1 - call this%parser%GetStringCaps(keyword2) - if (trim(adjustl(keyword2)) == 'LINEAR') this%isrb = 1 - if (trim(adjustl(keyword2)) == 'FREUNDLICH') this%isrb = 2 - if (trim(adjustl(keyword2)) == 'LANGMUIR') this%isrb = 3 - select case (this%isrb) - case(1) - write(this%iout, fmtisrb) - case(2) - write(this%iout, fmtfreundlich) - case(3) - write(this%iout, fmtlangmuir) - end select - case ('FIRST_ORDER_DECAY') - this%idcy = 1 - write(this%iout, fmtidcy1) - case ('ZERO_ORDER_DECAY') - this%idcy = 2 - write(this%iout, fmtidcy2) - case default - write(errmsg,'(a,a)') 'UNKNOWN MST OPTION: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtisvflow) + case ('SORBTION', 'SORPTION') + this%isrb = 1 + call this%parser%GetStringCaps(keyword2) + if (trim(adjustl(keyword2)) == 'LINEAR') this%isrb = 1 + if (trim(adjustl(keyword2)) == 'FREUNDLICH') this%isrb = 2 + if (trim(adjustl(keyword2)) == 'LANGMUIR') this%isrb = 3 + select case (this%isrb) + case (1) + write (this%iout, fmtisrb) + case (2) + write (this%iout, fmtfreundlich) + case (3) + write (this%iout, fmtlangmuir) + end select + case ('FIRST_ORDER_DECAY') + this%idcy = 1 + write (this%iout, fmtidcy1) + case ('ZERO_ORDER_DECAY') + this%idcy = 2 + write (this%iout, fmtidcy2) + case default + write (errmsg, '(a,a)') 'UNKNOWN MST OPTION: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)') 'END OF MOBILE STORAGE AND TRANSFER OPTIONS' + write (this%iout, '(1x,a)') 'END OF MOBILE STORAGE AND TRANSFER OPTIONS' end if ! ! -- Return @@ -1216,10 +1216,10 @@ end subroutine read_options !< subroutine read_data(this) ! -- modules - use ConstantsModule, only: LINELENGTH + use ConstantsModule, only: LINELENGTH use MemoryManagerModule, only: mem_reallocate, mem_reassignptr ! -- dummy - class(GwtMstType) :: this !< GwtMstType object + class(GwtMstType) :: this !< GwtMstType object ! -- local character(len=LINELENGTH) :: keyword character(len=:), allocatable :: line @@ -1229,12 +1229,12 @@ subroutine read_data(this) character(len=24), dimension(6) :: aname ! -- formats ! -- data - data aname(1) /' MOBILE DOMAIN POROSITY'/ - data aname(2) /' BULK DENSITY'/ - data aname(3) /'DISTRIBUTION COEFFICIENT'/ - data aname(4) /' DECAY RATE'/ - data aname(5) /' DECAY SORBED RATE'/ - data aname(6) /' SECOND SORPTION PARAM'/ + data aname(1)/' MOBILE DOMAIN POROSITY'/ + data aname(2)/' BULK DENSITY'/ + data aname(3)/'DISTRIBUTION COEFFICIENT'/ + data aname(4)/' DECAY RATE'/ + data aname(5)/' DECAY SORBED RATE'/ + data aname(6)/' SECOND SORPTION PARAM'/ ! ! -- initialize isfound = .false. @@ -1242,8 +1242,8 @@ subroutine read_data(this) ! ! -- get griddata block call this%parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING GRIDDATA' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING GRIDDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -1251,85 +1251,85 @@ subroutine read_data(this) call this%parser%GetRemainingLine(line) lloc = 1 select case (keyword) - case ('POROSITY') - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%porosity, & - aname(1)) - lname(1) = .true. - case ('BULK_DENSITY') - if (this%isrb == 0) & - call mem_reallocate(this%bulk_density, this%dis%nodes, & - 'BULK_DENSITY', trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, & - this%bulk_density, aname(2)) - lname(2) = .true. - case ('DISTCOEF') - if (this%isrb == 0) & - call mem_reallocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & + case ('POROSITY') + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%porosity, & + aname(1)) + lname(1) = .true. + case ('BULK_DENSITY') + if (this%isrb == 0) & + call mem_reallocate(this%bulk_density, this%dis%nodes, & + 'BULK_DENSITY', trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, & + this%bulk_density, aname(2)) + lname(2) = .true. + case ('DISTCOEF') + if (this%isrb == 0) & + call mem_reallocate(this%distcoef, this%dis%nodes, 'DISTCOEF', & trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%distcoef, & - aname(3)) - lname(3) = .true. - case ('DECAY') - if (this%idcy == 0) & - call mem_reallocate(this%decay, this%dis%nodes, 'DECAY', & - trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%decay, & - aname(4)) - lname(4) = .true. - case ('DECAY_SORBED') - call mem_reallocate(this%decay_sorbed, this%dis%nodes, & - 'DECAY_SORBED', trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, & - this%decay_sorbed, aname(5)) - lname(5) = .true. - case ('SP2') - if (this%isrb < 2) & - call mem_reallocate(this%sp2, this%dis%nodes, 'SP2', & + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%distcoef, & + aname(3)) + lname(3) = .true. + case ('DECAY') + if (this%idcy == 0) & + call mem_reallocate(this%decay, this%dis%nodes, 'DECAY', & trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout,& - this%parser%iuactive, this%sp2, & - aname(6)) - lname(6) = .true. - case default - write(errmsg,'(a,a)') 'UNKNOWN GRIDDATA TAG: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%decay, & + aname(4)) + lname(4) = .true. + case ('DECAY_SORBED') + call mem_reallocate(this%decay_sorbed, this%dis%nodes, & + 'DECAY_SORBED', trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, & + this%decay_sorbed, aname(5)) + lname(5) = .true. + case ('SP2') + if (this%isrb < 2) & + call mem_reallocate(this%sp2, this%dis%nodes, 'SP2', & + trim(this%memoryPath)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, this%sp2, & + aname(6)) + lname(6) = .true. + case default + write (errmsg, '(a,a)') 'UNKNOWN GRIDDATA TAG: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)') 'END PROCESSING GRIDDATA' + write (this%iout, '(1x,a)') 'END PROCESSING GRIDDATA' else - write(errmsg,'(a)') 'REQUIRED GRIDDATA BLOCK NOT FOUND.' + write (errmsg, '(a)') 'REQUIRED GRIDDATA BLOCK NOT FOUND.' call store_error(errmsg) call this%parser%StoreErrorUnit() end if ! ! -- Check for rquired porosity - if(.not. lname(1)) then - write(errmsg, '(a)') 'POROSITY NOT SPECIFIED IN GRIDDATA BLOCK.' + if (.not. lname(1)) then + write (errmsg, '(a)') 'POROSITY NOT SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) end if ! ! -- Check for required sorption variables if (this%isrb > 0) then if (.not. lname(2)) then - write(errmsg, '(a)') 'SORPTION IS ACTIVE BUT BULK_DENSITY & + write (errmsg, '(a)') 'SORPTION IS ACTIVE BUT BULK_DENSITY & &NOT SPECIFIED. BULK_DENSITY MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (.not. lname(3)) then - write(errmsg, '(a)') 'SORPTION IS ACTIVE BUT DISTRIBUTION & + write (errmsg, '(a)') 'SORPTION IS ACTIVE BUT DISTRIBUTION & &COEFFICIENT NOT SPECIFIED. DISTCOEF MUST BE SPECIFIED IN & &GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (this%isrb > 1) then if (.not. lname(6)) then - write(errmsg, '(a)') 'FREUNDLICH OR LANGMUIR SORPTION IS ACTIVE & + write (errmsg, '(a)') 'FREUNDLICH OR LANGMUIR SORPTION IS ACTIVE & &BUT SP2 NOT SPECIFIED. SP2 MUST BE SPECIFIED IN & &GRIDDATA BLOCK.' call store_error(errmsg) @@ -1337,68 +1337,68 @@ subroutine read_data(this) end if else if (lname(2)) then - write(warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & + write (warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & &BULK_DENSITY WAS SPECIFIED. BULK_DENSITY WILL HAVE NO AFFECT ON & &SIMULATION RESULTS.' call store_warning(warnmsg) - write(this%iout, '(1x,a)') 'WARNING. ' // warnmsg - endif + write (this%iout, '(1x,a)') 'WARNING. '//warnmsg + end if if (lname(3)) then - write(warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & + write (warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & &DISTRIBUTION COEFFICIENT WAS SPECIFIED. DISTCOEF WILL HAVE & &NO AFFECT ON SIMULATION RESULTS.' call store_warning(warnmsg) - write(this%iout, '(1x,a)') 'WARNING. ' // warnmsg - endif + write (this%iout, '(1x,a)') 'WARNING. '//warnmsg + end if if (lname(6)) then - write(warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & + write (warnmsg, '(a)') 'SORPTION IS NOT ACTIVE BUT & &SP2 WAS SPECIFIED. SP2 WILL HAVE & &NO AFFECT ON SIMULATION RESULTS.' call store_warning(warnmsg) - write(this%iout, '(1x,a)') 'WARNING. ' // warnmsg - endif - endif + write (this%iout, '(1x,a)') 'WARNING. '//warnmsg + end if + end if ! ! -- Check for required decay/production rate coefficients if (this%idcy > 0) then if (.not. lname(4)) then - write(errmsg, '(a)') 'FIRST OR ZERO ORDER DECAY IS & + write (errmsg, '(a)') 'FIRST OR ZERO ORDER DECAY IS & &ACTIVE BUT THE FIRST RATE COEFFICIENT IS NOT SPECIFIED. DECAY & &MUST BE SPECIFIED IN GRIDDATA BLOCK.' call store_error(errmsg) - endif + end if if (.not. lname(5)) then ! ! -- If DECAY_SORBED not specified and sorption is active, then ! terminate with an error if (this%isrb > 0) then - write(errmsg, '(a)') 'DECAY_SORBED not provided in GRIDDATA & + write (errmsg, '(a)') 'DECAY_SORBED not provided in GRIDDATA & &block but decay and sorption are active. Specify DECAY_SORBED & &in GRIDDATA block.' call store_error(errmsg) - endif - endif + end if + end if else if (lname(4)) then - write(warnmsg, '(a)') 'FIRST OR ZERO ORER DECAY & + write (warnmsg, '(a)') 'FIRST OR ZERO ORER DECAY & &IS NOT ACTIVE BUT DECAY WAS SPECIFIED. DECAY WILL & &HAVE NO AFFECT ON SIMULATION RESULTS.' call store_warning(warnmsg) - write(this%iout, '(1x,a)') 'WARNING. ' // warnmsg - endif + write (this%iout, '(1x,a)') 'WARNING. '//warnmsg + end if if (lname(5)) then - write(warnmsg, '(a)') 'FIRST OR ZERO ORER DECAY & + write (warnmsg, '(a)') 'FIRST OR ZERO ORER DECAY & &IS NOT ACTIVE BUT DECAY_SORBED WAS SPECIFIED. & &DECAY_SORBED WILL HAVE NO AFFECT ON SIMULATION RESULTS.' call store_warning(warnmsg) - write(this%iout, '(1x,a)') 'WARNING. ' // warnmsg - endif - endif + write (this%iout, '(1x,a)') 'WARNING. '//warnmsg + end if + end if ! ! -- terminate if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return @@ -1406,15 +1406,15 @@ end subroutine read_data !> @ brief Add porosity values to prsity2 !! - !! Method to add immobile domain porosities, which are stored as a + !! Method to add immobile domain porosities, which are stored as a !! cumulative value in prsity2. !! !< subroutine addto_prsity2(this, thetaim) ! -- modules ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - real(DP), dimension(:), intent(in) :: thetaim !< immobile domain porosity that contributes to total porosity + class(GwtMstType) :: this !< GwtMstType object + real(DP), dimension(:), intent(in) :: thetaim !< immobile domain porosity that contributes to total porosity ! -- local integer(I4B) :: n ! @@ -1436,8 +1436,8 @@ end subroutine addto_prsity2 function get_thetamfrac(this, node) result(thetamfrac) ! -- modules ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: node !< node number + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: node !< node number ! -- return real(DP) :: thetamfrac ! @@ -1447,7 +1447,7 @@ function get_thetamfrac(this, node) result(thetamfrac) ! -- Return return end function get_thetamfrac - + !> @ brief Return immobile porosity fraction !! !! Pass in an immobile domain porosity and calculate the fraction @@ -1457,19 +1457,19 @@ end function get_thetamfrac function get_thetaimfrac(this, node, thetaim) result(thetaimfrac) ! -- modules ! -- dummy - class(GwtMstType) :: this !< GwtMstType object - integer(I4B), intent(in) :: node !< node number - real(DP), intent(in) :: thetaim !< immobile domain porosity + class(GwtMstType) :: this !< GwtMstType object + integer(I4B), intent(in) :: node !< node number + real(DP), intent(in) :: thetaim !< immobile domain porosity ! -- return real(DP) :: thetaimfrac ! thetaimfrac = thetaim / & - (this%porosity(node) + this%prsity2(node)) + (this%porosity(node) + this%prsity2(node)) ! ! -- Return return end function get_thetaimfrac - + !> @ brief Calculate sorption concentration using Freundlich !! !! Function to calculate sorption concentration using Freundlich @@ -1477,20 +1477,20 @@ end function get_thetaimfrac !< function get_freundlich_conc(conc, kf, a) result(cbar) ! -- dummy - real(DP), intent(in) :: conc !< solute concentration - real(DP), intent(in) :: kf !< freundlich constant - real(DP), intent(in) :: a !< freundlich exponent + real(DP), intent(in) :: conc !< solute concentration + real(DP), intent(in) :: kf !< freundlich constant + real(DP), intent(in) :: a !< freundlich exponent ! -- return real(DP) :: cbar ! if (conc > DZERO) then - cbar = kf * conc ** a + cbar = kf * conc**a else cbar = DZERO end if return - end function - + end function + !> @ brief Calculate sorption concentration using Langmuir !! !! Function to calculate sorption concentration using Langmuir @@ -1498,9 +1498,9 @@ function get_freundlich_conc(conc, kf, a) result(cbar) !< function get_langmuir_conc(conc, kl, sbar) result(cbar) ! -- dummy - real(DP), intent(in) :: conc !< solute concentration - real(DP), intent(in) :: kl !< langmuir constant - real(DP), intent(in) :: sbar !< langmuir sorption sites + real(DP), intent(in) :: conc !< solute concentration + real(DP), intent(in) :: kl !< langmuir constant + real(DP), intent(in) :: sbar !< langmuir sorption sites ! -- return real(DP) :: cbar ! @@ -1510,8 +1510,8 @@ function get_langmuir_conc(conc, kl, sbar) result(cbar) cbar = DZERO end if return - end function - + end function + !> @ brief Calculate sorption derivative using Freundlich !! !! Function to calculate sorption derivative using Freundlich @@ -1519,20 +1519,20 @@ function get_langmuir_conc(conc, kl, sbar) result(cbar) !< function get_freundlich_derivative(conc, kf, a) result(derv) ! -- dummy - real(DP), intent(in) :: conc !< solute concentration - real(DP), intent(in) :: kf !< freundlich constant - real(DP), intent(in) :: a !< freundlich exponent + real(DP), intent(in) :: conc !< solute concentration + real(DP), intent(in) :: kf !< freundlich constant + real(DP), intent(in) :: a !< freundlich exponent ! -- return real(DP) :: derv ! if (conc > DZERO) then - derv = kf * a * conc ** (a - DONE) + derv = kf * a * conc**(a - DONE) else derv = DZERO end if return - end function - + end function + !> @ brief Calculate sorption derivative using Langmuir !! !! Function to calculate sorption derivative using Langmuir @@ -1540,20 +1540,20 @@ function get_freundlich_derivative(conc, kf, a) result(derv) !< function get_langmuir_derivative(conc, kl, sbar) result(derv) ! -- dummy - real(DP), intent(in) :: conc !< solute concentration - real(DP), intent(in) :: kl !< langmuir constant - real(DP), intent(in) :: sbar !< langmuir sorption sites + real(DP), intent(in) :: conc !< solute concentration + real(DP), intent(in) :: kl !< langmuir constant + real(DP), intent(in) :: sbar !< langmuir sorption sites ! -- return real(DP) :: derv ! if (conc > DZERO) then - derv = (kl * sbar) / (DONE + kl * conc) ** DTWO + derv = (kl * sbar) / (DONE + kl * conc)**DTWO else derv = DZERO end if return - end function - + end function + !> @ brief Calculate zero-order decay rate and constrain if necessary !! !! Function to calculate the zero-order decay rate from the user specified @@ -1565,14 +1565,14 @@ function get_langmuir_derivative(conc, kl, sbar) result(derv) function get_zero_order_decay(decay_rate_usr, decay_rate_last, kiter, & cold, cnew, delt) result(decay_rate) ! -- dummy - real(DP), intent(in) :: decay_rate_usr !< user-entered decay rate - real(DP), intent(in) :: decay_rate_last !< decay rate used for last iteration - integer(I4B), intent(in) :: kiter !< Picard iteration counter - real(DP), intent(in) :: cold !< concentration at end of last time step - real(DP), intent(in) :: cnew !< concentration at end of this time step - real(DP), intent(in) :: delt !< length of time step + real(DP), intent(in) :: decay_rate_usr !< user-entered decay rate + real(DP), intent(in) :: decay_rate_last !< decay rate used for last iteration + integer(I4B), intent(in) :: kiter !< Picard iteration counter + real(DP), intent(in) :: cold !< concentration at end of last time step + real(DP), intent(in) :: cnew !< concentration at end of this time step + real(DP), intent(in) :: delt !< length of time step ! -- return - real(DP) :: decay_rate !< returned value for decay rate + real(DP) :: decay_rate !< returned value for decay rate ! ! -- Return user rate if production, otherwise constrain, if necessary if (decay_rate_usr < DZERO) then @@ -1599,6 +1599,5 @@ function get_zero_order_decay(decay_rate_usr, decay_rate_last, kiter, & end if return end function get_zero_order_decay - - -end module GwtMstModule \ No newline at end of file + +end module GwtMstModule diff --git a/src/Model/GroundWaterTransport/gwt1mvt1.f90 b/src/Model/GroundWaterTransport/gwt1mvt1.f90 index 1045983ff9a..8a8242405df 100644 --- a/src/Model/GroundWaterTransport/gwt1mvt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1mvt1.f90 @@ -1,13 +1,13 @@ ! -- Groundwater Transport Mover Module ! -- This module is responsible for sending mass from providers into ! -- receiver qmfrommvr arrays and writing a mover transport budget - + module GwtMvtModule - + use KindModule, only: DP, I4B use ConstantsModule, only: LINELENGTH, MAXCHARLEN, DZERO, LENPAKLOC, & DNODATA, LENPACKAGENAME, TABCENTER, LENMODELNAME - + use SimModule, only: store_error use BaseDisModule, only: DisBaseType use NumericalPackageModule, only: NumericalPackageType @@ -17,24 +17,24 @@ module GwtMvtModule use TableModule, only: TableType, table_cr implicit none - + private public :: GwtMvtType public :: mvt_cr - + type, extends(NumericalPackageType) :: GwtMvtType - character(len=LENMODELNAME) :: gwfmodelname1 = '' !< name of model 1 - character(len=LENMODELNAME) :: gwfmodelname2 = '' !< name of model 2 (set to modelname 1 for single model MVT) - integer(I4B), pointer :: maxpackages !< max number of packages - integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file - integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file - type(GwtFmiType), pointer :: fmi1 => null() !< pointer to fmi object for model 1 - type(GwtFmiType), pointer :: fmi2 => null() !< pointer to fmi object for model 2 (set to fmi1 for single model) - type(BudgetType), pointer :: budget => null() !< mover transport budget object (used to write balance table) - type(BudgetObjectType), pointer :: budobj => null() !< budget container (used to write binary file) - type(BudgetObjectType), pointer :: mvrbudobj => null() !< pointer to the water mover budget object - character(len=LENPACKAGENAME), & - dimension(:), pointer, contiguous :: paknames => null() !< array of package names + character(len=LENMODELNAME) :: gwfmodelname1 = '' !< name of model 1 + character(len=LENMODELNAME) :: gwfmodelname2 = '' !< name of model 2 (set to modelname 1 for single model MVT) + integer(I4B), pointer :: maxpackages !< max number of packages + integer(I4B), pointer :: ibudgetout => null() !< unit number for budget output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for csv budget output file + type(GwtFmiType), pointer :: fmi1 => null() !< pointer to fmi object for model 1 + type(GwtFmiType), pointer :: fmi2 => null() !< pointer to fmi object for model 2 (set to fmi1 for single model) + type(BudgetType), pointer :: budget => null() !< mover transport budget object (used to write balance table) + type(BudgetObjectType), pointer :: budobj => null() !< budget container (used to write binary file) + type(BudgetObjectType), pointer :: mvrbudobj => null() !< pointer to the water mover budget object + character(len=LENPACKAGENAME), & + dimension(:), pointer, contiguous :: paknames => null() !< array of package names ! ! -- table objects type(TableType), pointer :: outputtab => null() @@ -60,7 +60,7 @@ module GwtMvtModule procedure, private :: mvt_print_outputtab end type GwtMvtType - contains +contains subroutine mvt_cr(mvt, name_model, inunit, iout, fmi1, gwfmodelname1, & gwfmodelname2, fmi2) @@ -82,7 +82,7 @@ subroutine mvt_cr(mvt, name_model, inunit, iout, fmi1, gwfmodelname1, & ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(mvt) + allocate (mvt) ! ! -- create name and memory path call mvt%set_names(1, name_model, 'MVT', 'MVT') @@ -104,10 +104,10 @@ subroutine mvt_cr(mvt, name_model, inunit, iout, fmi1, gwfmodelname1, & ! ! -- set model names if (present(gwfmodelname1)) then - mvt%gwfmodelname1 = gwfmodelname1 + mvt%gwfmodelname1 = gwfmodelname1 end if if (present(gwfmodelname2)) then - mvt%gwfmodelname2 = gwfmodelname2 + mvt%gwfmodelname2 = gwfmodelname2 end if ! ! -- create the budget object @@ -130,8 +130,8 @@ subroutine mvt_df(this, dis) class(DisBaseType), pointer, intent(in) :: dis ! -- local ! -- formats - character(len=*), parameter :: fmtmvt = & - "(1x,/1x,'MVT -- MOVER TRANSPORT PACKAGE, VERSION 1, 4/15/2020', & + character(len=*), parameter :: fmtmvt = & + "(1x,/1x,'MVT -- MOVER TRANSPORT PACKAGE, VERSION 1, 4/15/2020', & &' INPUT READ FROM UNIT ', i0, //)" ! ------------------------------------------------------------------------------ ! @@ -139,7 +139,7 @@ subroutine mvt_df(this, dis) this%dis => dis ! ! -- print a message identifying the MVT package. - write(this%iout, fmtmvt) this%inunit + write (this%iout, fmtmvt) this%inunit ! ! -- Initialize block parser call this%parser%Initialize(this%inunit, this%iout) @@ -153,7 +153,7 @@ subroutine mvt_df(this, dis) ! -- Return return end subroutine mvt_df - + !> @ brief Set pointer to mvrbudobj !! !! Store a pointer to mvrbudobj, which contains the simulated water @@ -166,7 +166,7 @@ subroutine set_pointer_mvrbudobj(this, mvrbudobj) type(BudgetObjectType), intent(in), target :: mvrbudobj this%mvrbudobj => mvrbudobj end subroutine set_pointer_mvrbudobj - + subroutine mvt_ar(this) ! ****************************************************************************** ! mvt_ar -- Allocate and read water mover information @@ -223,7 +223,7 @@ subroutine mvt_rp(this) ! -- Return return end subroutine mvt_rp - + subroutine mvt_fc(this, cnew1, cnew2) ! ****************************************************************************** ! mvt_fc -- Calculate coefficients and fill amat and rhs @@ -251,8 +251,8 @@ subroutine mvt_fc(this, cnew1, cnew2) real(DP) :: q, cp real(DP), dimension(:), pointer :: concpak real(DP), dimension(:), contiguous, pointer :: cnew - type(GwtFmiType), pointer :: fmi_pr !< pointer to provider model fmi package - type(GwtFmiType), pointer :: fmi_rc !< pointer to receiver model fmi package + type(GwtFmiType), pointer :: fmi_pr !< pointer to provider model fmi package + type(GwtFmiType), pointer :: fmi_rc !< pointer to receiver model fmi package ! ------------------------------------------------------------------------------ ! ! -- Add mover QC terms to the receiver packages @@ -302,17 +302,18 @@ subroutine mvt_fc(this, cnew1, cnew2) ! ! -- Provider is a regular stress package (WEL, DRN, RIV, etc.) or the ! provider is an advanced stress package but is not represented with - ! SFT, LKT, MWT, or UZT, so use the GWT cell concentration + ! SFT, LKT, MWT, or UZT, so use the GWT cell concentration igwtnode = fmi_pr%gwfpackages(ipr)%nodelist(id1) cp = cnew(igwtnode) - + end if ! ! -- add the mover rate times the provider concentration into the receiver ! make sure these are accumulated since multiple providers can move ! water into the same receiver if (fmi_rc%iatp(irc) /= 0) then - fmi_rc%datp(irc)%qmfrommvr(id2) = fmi_rc%datp(irc)%qmfrommvr(id2) - q * cp + fmi_rc%datp(irc)%qmfrommvr(id2) = fmi_rc%datp(irc)%qmfrommvr(id2) - & + q * cp end if end do end if @@ -321,14 +322,14 @@ subroutine mvt_fc(this, cnew1, cnew2) ! -- Return return end subroutine mvt_fc - + !> @ brief Set the fmi_pr and fmi_rc pointers !! !! The fmi_pr and fmi_rc arguments are pointers to the provider !! and receiver FMI Packages. If this MVT Package is owned by !! a single GWT model, then these pointers are both set to the !! FMI Package of this GWT model's FMI Package. If this MVT - !! Package is owned by a GWTGWT Exchange, then the fmi_pr and + !! Package is owned by a GWTGWT Exchange, then the fmi_pr and !! fmi_rc pointers may be assigned to FMI Packages in different models. !! !< @@ -349,7 +350,8 @@ subroutine set_fmi_pr_rc(this, ibudterm, fmi_pr, fmi_rc) if (this%mvrbudobj%budterm(ibudterm)%text1id1 == this%gwfmodelname1) then ! -- model 1 is the provider fmi_pr => this%fmi1 - else if (this%mvrbudobj%budterm(ibudterm)%text1id1 == this%gwfmodelname2) then + else if (this%mvrbudobj%budterm(ibudterm)%text1id1 == & + this%gwfmodelname2) then ! -- model 2 is the provider fmi_pr => this%fmi2 else @@ -360,12 +362,13 @@ subroutine set_fmi_pr_rc(this, ibudterm, fmi_pr, fmi_rc) print *, this%gwfmodelname2 stop "error in set_fmi_pr_rc" end if - + ! modelname for receiver is this%mvrbudobj%budterm(i)%text1id2 if (this%mvrbudobj%budterm(ibudterm)%text1id2 == this%gwfmodelname1) then ! -- model 1 is the receiver fmi_rc => this%fmi1 - else if (this%mvrbudobj%budterm(ibudterm)%text1id2 == this%gwfmodelname2) then + else if (this%mvrbudobj%budterm(ibudterm)%text1id2 == & + this%gwfmodelname2) then ! -- model 2 is the receiver fmi_rc => this%fmi2 else @@ -377,7 +380,7 @@ subroutine set_fmi_pr_rc(this, ibudterm, fmi_pr, fmi_rc) stop "error in set_fmi_pr_rc" end if end if - + if (.not. associated(fmi_pr)) then print *, 'Could not find FMI Package...' stop "error in set_fmi_pr_rc" @@ -399,14 +402,14 @@ subroutine mvt_cc(this, kiter, iend, icnvgmod, cpak, dpak) ! ------------------------------------------------------------------------------ ! -- dummy class(GwtMvtType) :: this - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: iend - integer(I4B),intent(in) :: icnvgmod + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: iend + integer(I4B), intent(in) :: icnvgmod character(len=LENPAKLOC), intent(inout) :: cpak real(DP), intent(inout) :: dpak ! -- local ! -- formats - character(len=*),parameter :: fmtmvrcnvg = & + character(len=*), parameter :: fmtmvrcnvg = & "(/,1x,'MOVER PACKAGE REQUIRES AT LEAST TWO OUTER ITERATIONS. CONVERGE & &FLAG HAS BEEN RESET TO FALSE.')" ! ------------------------------------------------------------------------------ @@ -416,14 +419,14 @@ subroutine mvt_cc(this, kiter, iend, icnvgmod, cpak, dpak) if (icnvgmod == 1 .and. kiter == 1) then dpak = DNODATA cpak = trim(this%packName) - write(this%iout, fmtmvrcnvg) - endif - endif + write (this%iout, fmtmvrcnvg) + end if + end if ! ! -- return return end subroutine mvt_cc - + subroutine mvt_bd(this, cnew1, cnew2) ! ****************************************************************************** ! mvt_bd -- Write mover terms to listing file @@ -434,8 +437,8 @@ subroutine mvt_bd(this, cnew1, cnew2) ! -- modules ! -- dummy class(GwtMvtType) :: this - real(DP), dimension(:), contiguous, intent(in) :: cnew1 - real(DP), dimension(:), contiguous, intent(in) :: cnew2 + real(DP), dimension(:), contiguous, intent(in) :: cnew1 + real(DP), dimension(:), contiguous, intent(in) :: cnew2 ! -- local ! ------------------------------------------------------------------------------ ! @@ -445,7 +448,7 @@ subroutine mvt_bd(this, cnew1, cnew2) ! -- return return end subroutine mvt_bd - + subroutine mvt_ot_saveflow(this, icbcfl, ibudfl) ! ****************************************************************************** ! mvt_bd -- Write mover terms @@ -454,7 +457,7 @@ subroutine mvt_ot_saveflow(this, icbcfl, ibudfl) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use TdisModule, only : kstp, kper, delt, pertim, totim + use TdisModule, only: kstp, kper, delt, pertim, totim ! -- dummy class(GwtMvttype) :: this integer(I4B), intent(in) :: icbcfl @@ -465,13 +468,13 @@ subroutine mvt_ot_saveflow(this, icbcfl, ibudfl) ! ! -- Save the mover flows from the budobj to a mover binary file ibinun = 0 - if(this%ibudgetout /= 0) then + if (this%ibudgetout /= 0) then ibinun = this%ibudgetout end if - if(icbcfl == 0) ibinun = 0 + if (icbcfl == 0) ibinun = 0 if (ibinun > 0) then call this%budobj%save_flows(this%dis, ibinun, kstp, kper, delt, & - pertim, totim, this%iout) + pertim, totim, this%iout) end if ! ! -- Return @@ -521,42 +524,42 @@ subroutine mvt_ot_bdsummary(this, ibudfl) ! ------------------------------------------------------------------------------ ! ! -- Allocate and initialize ratin/ratout - allocate(ratin(this%maxpackages), ratout(this%maxpackages)) + allocate (ratin(this%maxpackages), ratout(this%maxpackages)) do j = 1, this%maxpackages ratin(j) = DZERO ratout(j) = DZERO - enddo + end do ! ! -- Accumulate the rates do i = 1, this%maxpackages - + do j = 1, this%budobj%nbudterm - + do n = 1, this%budobj%budterm(j)%nlist ! ! -- provider is inflow to mover - if(this%paknames(i) == this%budobj%budterm(j)%text2id1) then + if (this%paknames(i) == this%budobj%budterm(j)%text2id1) then ratin(i) = ratin(i) + this%budobj%budterm(j)%flow(n) - endif + end if ! ! -- receiver is outflow from mover - if(this%paknames(i) == this%budobj%budterm(j)%text2id2) then + if (this%paknames(i) == this%budobj%budterm(j)%text2id2) then ratout(i) = ratout(i) + this%budobj%budterm(j)%flow(n) - endif - + end if + end do - + end do - + end do - + ! ! -- Send rates to budget object call this%budget%reset() do j = 1, this%maxpackages call this%budget%addentry(ratin(j), ratout(j), delt, this%paknames(j)) - enddo + end do ! ! -- Write the budget if (ibudfl /= 0) then @@ -567,7 +570,7 @@ subroutine mvt_ot_bdsummary(this, ibudfl) call this%budget%writecsv(totim) ! ! -- Deallocate - deallocate(ratin, ratout) + deallocate (ratin, ratout) ! ! -- Output mvr budget ! Not using budobj write_table here because it would result @@ -594,27 +597,27 @@ subroutine mvt_da(this) ! ------------------------------------------------------------------------------ ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then ! ! -- character array - deallocate(this%paknames) + deallocate (this%paknames) ! ! -- budget object call this%budget%budget_da() - deallocate(this%budget) + deallocate (this%budget) ! ! -- budobj call this%budobj%budgetobject_da() - deallocate(this%budobj) - nullify(this%budobj) + deallocate (this%budobj) + nullify (this%budobj) ! ! -- output table object if (associated(this%outputtab)) then call this%outputtab%table_da() - deallocate(this%outputtab) - nullify(this%outputtab) + deallocate (this%outputtab) + nullify (this%outputtab) end if - endif + end if ! ! -- Scalars this%fmi1 => null() @@ -679,10 +682,11 @@ subroutine read_options(this) character(len=MAXCHARLEN) :: fname integer(I4B) :: ierr logical :: isfound, endOfBlock - character(len=*),parameter :: fmtflow = & - "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I0)" - character(len=*),parameter :: fmtflow2 = & - "(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE')" + character(len=*), parameter :: fmtflow = & + "(4x, a, 1x, a, 1x, ' WILL BE SAVED TO FILE: ', a, & + &/4x, 'OPENED ON UNIT: ', I0)" + character(len=*), parameter :: fmtflow2 = & + &"(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE')" ! ------------------------------------------------------------------------------ ! ! -- get options block @@ -691,53 +695,54 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING MVT OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING MVT OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtflow2) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'MVT INPUT WILL BE PRINTED.' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') & - 'MVT FLOWS WILL BE PRINTED TO LISTING FILE.' - case('BUDGET') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudgetout = getunit() - call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & - form, access, 'REPLACE') - write(this%iout,fmtflow) 'MVT', 'BUDGET', fname, this%ibudgetout - else - call store_error('OPTIONAL BUDGET KEYWORD MUST BE FOLLOWED BY FILEOUT') - end if - case('BUDGETCSV') - call this%parser%GetStringCaps(keyword) - if (keyword == 'FILEOUT') then - call this%parser%GetString(fname) - this%ibudcsv = getunit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', & - filstat_opt='REPLACE') - write(this%iout,fmtflow) 'MVT', 'BUDGET CSV', fname, this%ibudcsv - else - call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & - &FILEOUT') - end if - case default - write(errmsg,'(4x,a,a)')'***ERROR. UNKNOWN MVT OPTION: ', & - trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtflow2) + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') 'MVT INPUT WILL BE PRINTED.' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') & + 'MVT FLOWS WILL BE PRINTED TO LISTING FILE.' + case ('BUDGET') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudgetout = getunit() + call openfile(this%ibudgetout, this%iout, fname, 'DATA(BINARY)', & + form, access, 'REPLACE') + write (this%iout, fmtflow) 'MVT', 'BUDGET', fname, this%ibudgetout + else + call store_error('OPTIONAL BUDGET KEYWORD MUST & + &BE FOLLOWED BY FILEOUT') + end if + case ('BUDGETCSV') + call this%parser%GetStringCaps(keyword) + if (keyword == 'FILEOUT') then + call this%parser%GetString(fname) + this%ibudcsv = getunit() + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') + write (this%iout, fmtflow) 'MVT', 'BUDGET CSV', fname, this%ibudcsv + else + call store_error('OPTIONAL BUDGETCSV KEYWORD MUST BE FOLLOWED BY & + &FILEOUT') + end if + case default + write (errmsg, '(4x,a,a)') '***ERROR. UNKNOWN MVT OPTION: ', & + trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)') 'END OF MVT OPTIONS' + write (this%iout, '(1x,a)') 'END OF MVT OPTIONS' end if ! ! -- return @@ -761,8 +766,8 @@ subroutine mvt_setup_budobj(this) integer(I4B) :: maxlist integer(I4B) :: i integer(I4B) :: naux - character (len=LENMODELNAME) :: modelname1, modelname2 - character (len=LENPACKAGENAME) :: packagename1, packagename2 + character(len=LENMODELNAME) :: modelname1, modelname2 + character(len=LENPACKAGENAME) :: packagename1, packagename2 character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! @@ -791,7 +796,7 @@ subroutine mvt_setup_budobj(this) maxlist, .false., .false., & naux) end do - + ! ! -- return return @@ -810,7 +815,7 @@ subroutine mvt_fill_budobj(this, cnew1, cnew2) real(DP), intent(in), dimension(:), contiguous, target :: cnew1 real(DP), intent(in), dimension(:), contiguous, target :: cnew2 ! -- local - type(GwtFmiType), pointer :: fmi_pr + type(GwtFmiType), pointer :: fmi_pr type(GwtFmiType), pointer :: fmi_rc real(DP), dimension(:), contiguous, pointer :: cnew integer(I4B) :: nbudterm @@ -899,7 +904,7 @@ subroutine mvt_scan_mvrbudobj(this) this%maxpackages = maxpackages ! ! -- allocate paknames - allocate(this%paknames(this%maxpackages)) + allocate (this%paknames(this%maxpackages)) do i = 1, this%maxpackages this%paknames(i) = '' end do @@ -923,7 +928,7 @@ subroutine mvt_scan_mvrbudobj(this) ! -- Return return end subroutine mvt_scan_mvrbudobj - + subroutine mvt_setup_outputtab(this) ! ****************************************************************************** ! mvt_setup_outputtab -- set up output table @@ -932,7 +937,7 @@ subroutine mvt_setup_outputtab(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwtMvtType),intent(inout) :: this + class(GwtMvtType), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -949,15 +954,15 @@ subroutine mvt_setup_outputtab(this) maxrow = 0 ! ! -- initialize the output table object - title = 'TRANSPORT MOVER PACKAGE (' // trim(this%packName) // & + title = 'TRANSPORT MOVER PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call table_cr(this%outputtab, this%packName, title) call this%outputtab%table_df(maxrow, ntabcol, this%iout, & - transient=.TRUE.) + transient=.TRUE.) text = 'NUMBER' call this%outputtab%initialize_column(text, 10, alignment=TABCENTER) text = 'PROVIDER LOCATION' - ilen = LENMODELNAME+LENPACKAGENAME+1 + ilen = LENMODELNAME + LENPACKAGENAME + 1 call this%outputtab%initialize_column(text, ilen) text = 'PROVIDER ID' call this%outputtab%initialize_column(text, 10) @@ -966,11 +971,11 @@ subroutine mvt_setup_outputtab(this) text = 'PROVIDER TRANSPORT RATE' call this%outputtab%initialize_column(text, 10) text = 'RECEIVER LOCATION' - ilen = LENMODELNAME+LENPACKAGENAME+1 + ilen = LENMODELNAME + LENPACKAGENAME + 1 call this%outputtab%initialize_column(text, ilen) text = 'RECEIVER ID' call this%outputtab%initialize_column(text, 10) - + end if ! ! -- return @@ -987,10 +992,10 @@ subroutine mvt_print_outputtab(this) ! -- module use TdisModule, only: kstp, kper ! -- dummy - class(GwtMvttype),intent(inout) :: this + class(GwtMvttype), intent(inout) :: this ! -- local - character (len=LINELENGTH) :: title - character(len=LENMODELNAME+LENPACKAGENAME+1) :: cloc1, cloc2 + character(len=LINELENGTH) :: title + character(len=LENMODELNAME + LENPACKAGENAME + 1) :: cloc1, cloc2 integer(I4B) :: i integer(I4B) :: n integer(I4B) :: inum @@ -1009,7 +1014,7 @@ subroutine mvt_print_outputtab(this) call this%outputtab%set_kstpkper(kstp, kper) ! ! -- Add terms and print the table - title = 'TRANSPORT MOVER PACKAGE (' // trim(this%packName) // & + title = 'TRANSPORT MOVER PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call this%outputtab%set_title(title) call this%outputtab%set_maxbound(ntabrows) @@ -1019,9 +1024,9 @@ subroutine mvt_print_outputtab(this) do i = 1, this%budobj%nbudterm nlist = this%budobj%budterm(i)%nlist do n = 1, nlist - cloc1 = trim(adjustl(this%budobj%budterm(i)%text1id1)) // ' ' // & + cloc1 = trim(adjustl(this%budobj%budterm(i)%text1id1))//' '// & trim(adjustl(this%budobj%budterm(i)%text2id1)) - cloc2 = trim(adjustl(this%budobj%budterm(i)%text1id2)) // ' ' // & + cloc2 = trim(adjustl(this%budobj%budterm(i)%text1id2))//' '// & trim(adjustl(this%budobj%budterm(i)%text2id2)) call this%outputtab%add_term(inum) call this%outputtab%add_term(cloc1) @@ -1039,4 +1044,4 @@ subroutine mvt_print_outputtab(this) end subroutine mvt_print_outputtab end module GwtMvtModule - \ No newline at end of file + diff --git a/src/Model/GroundWaterTransport/gwt1mwt1.f90 b/src/Model/GroundWaterTransport/gwt1mwt1.f90 index d9bcd38f22d..f6493f80ab1 100644 --- a/src/Model/GroundWaterTransport/gwt1mwt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1mwt1.f90 @@ -18,11 +18,11 @@ ! FW-RATE idxbudfwrt FW-RATE q * cwell ! RATE-TO-MVR idxbudrtmv RATE-TO-MVR q * cwell ! FW-RATE-TO-MVR idxbudfrtm FW-RATE-TO-MVR q * cwell - + ! -- terms from MAW that should be skipped ! CONSTANT-TO-MVR ? CONSTANT-TO-MVR q * cwell - ! -- terms from a flow file that should be skipped +! -- terms from a flow file that should be skipped ! CONSTANT none none none ! AUXILIARY none none none @@ -31,7 +31,7 @@ ! none none AUXILIARY none ! none none CONSTANT accumulate ! -! +! module GwtMwtModule use KindModule, only: DP, I4B @@ -40,26 +40,28 @@ module GwtMwtModule use BndModule, only: BndType, GetBndFromList use GwtFmiModule, only: GwtFmiType use MawModule, only: MawType - use GwtAptModule, only: GwtAptType - + use ObserveModule, only: ObserveType + use GwtAptModule, only: GwtAptType, apt_process_obsID, & + apt_process_obsID12 + implicit none - + public mwt_create - + character(len=*), parameter :: ftype = 'MWT' character(len=*), parameter :: flowtype = 'MAW' - character(len=16) :: text = ' MWT' - + character(len=16) :: text = ' MWT' + type, extends(GwtAptType) :: GwtMwtType - - integer(I4B), pointer :: idxbudrate => null() ! index of well rate terms in flowbudptr - integer(I4B), pointer :: idxbudfwrt => null() ! index of flowing well rate terms in flowbudptr - integer(I4B), pointer :: idxbudrtmv => null() ! index of rate to mover terms in flowbudptr - integer(I4B), pointer :: idxbudfrtm => null() ! index of flowing well rate to mover terms in flowbudptr - real(DP), dimension(:), pointer, contiguous :: concrate => null() ! well rate concentration + + integer(I4B), pointer :: idxbudrate => null() ! index of well rate terms in flowbudptr + integer(I4B), pointer :: idxbudfwrt => null() ! index of flowing well rate terms in flowbudptr + integer(I4B), pointer :: idxbudrtmv => null() ! index of rate to mover terms in flowbudptr + integer(I4B), pointer :: idxbudfrtm => null() ! index of flowing well rate to mover terms in flowbudptr + real(DP), dimension(:), pointer, contiguous :: concrate => null() ! well rate concentration contains - + procedure :: bnd_da => mwt_da procedure :: allocate_scalars procedure :: apt_allocate_arrays => mwt_allocate_arrays @@ -74,13 +76,14 @@ module GwtMwtModule procedure :: mwt_rtmv_term procedure :: mwt_frtm_term procedure :: pak_df_obs => mwt_df_obs + procedure :: pak_rp_obs => mwt_rp_obs procedure :: pak_bd_obs => mwt_bd_obs procedure :: pak_set_stressperiod => mwt_set_stressperiod - + end type GwtMwtType - contains - +contains + subroutine mwt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & fmi) ! ****************************************************************************** @@ -91,10 +94,10 @@ subroutine mwt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(GwtFmiType), pointer :: fmi @@ -103,7 +106,7 @@ subroutine mwt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(mwtobj) + allocate (mwtobj) packobj => mwtobj ! ! -- create name and memory path @@ -122,7 +125,7 @@ subroutine mwt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & packobj%ibcnum = ibcnum packobj%ncolbnd = 1 packobj%iscloc = 1 - + ! -- Store pointer to flow model interface. When the GwfGwt exchange is ! created, it sets fmi%bndlist so that the GWT model has access to all ! the flow packages @@ -164,7 +167,7 @@ subroutine find_mwt_package(this) ! else if (associated(this%fmi%gwfbndlist)) then - ! -- Look through gwfbndlist for a flow package with the same name as + ! -- Look through gwfbndlist for a flow package with the same name as ! this transport package name do ip = 1, this%fmi%gwfbndlist%Count() packobj => GetBndFromList(this%fmi%gwfbndlist, ip) @@ -175,8 +178,8 @@ subroutine find_mwt_package(this) ! use the select type to point to the budobj in flow package this%flowpackagebnd => packobj select type (packobj) - type is (MawType) - this%flowbudptr => packobj%budobj + type is (MawType) + this%flowbudptr => packobj%budobj end select end if if (found) exit @@ -186,54 +189,54 @@ subroutine find_mwt_package(this) ! ! -- error if flow package not found if (.not. found) then - write(errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& - &// trim(adjustl(this%flowpackagename)) // '.' + write (errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& + &//trim(adjustl(this%flowpackagename))//'.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! - ! -- allocate space for idxbudssm, which indicates whether this is a + ! -- allocate space for idxbudssm, which indicates whether this is a ! special budget term or one that is a general source and sink nbudterm = this%flowbudptr%nbudterm call mem_allocate(this%idxbudssm, nbudterm, 'IDXBUDSSM', this%memoryPath) ! ! -- Process budget terms and identify special budget terms - write(this%iout, '(/, a, a)') & - 'PROCESSING ' // ftype // ' INFORMATION FOR ', this%packName - write(this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN ' // flowtype // ' PACKAGE' - write(this%iout, '(a, i0)') & - ' NUMBER OF ' // flowtype // ' = ', this%flowbudptr%ncv + write (this%iout, '(/, a, a)') & + 'PROCESSING '//ftype//' INFORMATION FOR ', this%packName + write (this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN '//flowtype//' PACKAGE' + write (this%iout, '(a, i0)') & + ' NUMBER OF '//flowtype//' = ', this%flowbudptr%ncv icount = 1 do ip = 1, this%flowbudptr%nbudterm - select case(trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) - case('FLOW-JA-FACE') + select case (trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) + case ('FLOW-JA-FACE') this%idxbudfjf = ip this%idxbudssm(ip) = 0 - case('GWF') + case ('GWF') this%idxbudgwf = ip this%idxbudssm(ip) = 0 - case('STORAGE') + case ('STORAGE') this%idxbudsto = ip this%idxbudssm(ip) = 0 - case('RATE') + case ('RATE') this%idxbudrate = ip this%idxbudssm(ip) = 0 - case('FW-RATE') + case ('FW-RATE') this%idxbudfwrt = ip this%idxbudssm(ip) = 0 - case('RATE-TO-MVR') + case ('RATE-TO-MVR') this%idxbudrtmv = ip this%idxbudssm(ip) = 0 - case('FW-RATE-TO-MVR') + case ('FW-RATE-TO-MVR') this%idxbudfrtm = ip this%idxbudssm(ip) = 0 - case('TO-MVR') + case ('TO-MVR') this%idxbudtmvr = ip this%idxbudssm(ip) = 0 - case('FROM-MVR') + case ('FROM-MVR') this%idxbudfmvr = ip this%idxbudssm(ip) = 0 - case('AUXILIARY') + case ('AUXILIARY') this%idxbudaux = ip this%idxbudssm(ip) = 0 case default @@ -243,11 +246,11 @@ subroutine find_mwt_package(this) this%idxbudssm(ip) = icount icount = icount + 1 end select - write(this%iout, '(a, i0, " = ", a,/, a, i0)') & + write (this%iout, '(a, i0, " = ", a,/, a, i0)') & ' TERM ', ip, trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)), & ' MAX NO. OF ENTRIES = ', this%flowbudptr%budterm(ip)%maxlist end do - write(this%iout, '(a, //)') 'DONE PROCESSING ' // ftype // ' INFORMATION' + write (this%iout, '(a, //)') 'DONE PROCESSING '//ftype//' INFORMATION' ! ! -- Return return @@ -328,7 +331,7 @@ end subroutine mwt_fc_expanded subroutine mwt_solve(this) ! ****************************************************************************** ! mwt_solve -- add terms specific to multi-aquifer wells to the explicit multi- -! aquifer well solve +! aquifer well solve ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -376,7 +379,7 @@ subroutine mwt_solve(this) ! -- Return return end subroutine mwt_solve - + function mwt_get_nbudterms(this) result(nbudterms) ! ****************************************************************************** ! mwt_get_nbudterms -- function to return the number of budget terms just for @@ -402,7 +405,7 @@ function mwt_get_nbudterms(this) result(nbudterms) ! -- Return return end function mwt_get_nbudterms - + subroutine mwt_setup_budobj(this, idx) ! ****************************************************************************** ! mwt_setup_budobj -- Set up the budget object that stores all the multi- @@ -421,7 +424,7 @@ subroutine mwt_setup_budobj(this, idx) character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! - ! -- + ! -- text = ' RATE' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudrate)%maxlist @@ -433,9 +436,9 @@ subroutine mwt_setup_budobj(this, idx) this%packName, & maxlist, .false., .false., & naux) - + ! - ! -- + ! -- if (this%idxbudfwrt /= 0) then text = ' FW-RATE' idx = idx + 1 @@ -449,9 +452,9 @@ subroutine mwt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! - ! -- + ! -- if (this%idxbudrtmv /= 0) then text = ' RATE-TO-MVR' idx = idx + 1 @@ -465,9 +468,9 @@ subroutine mwt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! - ! -- + ! -- if (this%idxbudfrtm /= 0) then text = ' FW-RATE-TO-MVR' idx = idx + 1 @@ -481,7 +484,7 @@ subroutine mwt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! ! -- return return @@ -507,7 +510,7 @@ subroutine mwt_fill_budobj(this, idx, x, ccratin, ccratout) real(DP) :: q ! -- formats ! ----------------------------------------------------------------------------- - + ! -- RATE idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudrate)%nlist @@ -517,7 +520,7 @@ subroutine mwt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - + ! -- FW-RATE if (this%idxbudfwrt /= 0) then idx = idx + 1 @@ -529,7 +532,7 @@ subroutine mwt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- RATE-TO-MVR if (this%idxbudrtmv /= 0) then idx = idx + 1 @@ -541,7 +544,7 @@ subroutine mwt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- FW-RATE-TO-MVR if (this%idxbudfrtm /= 0) then idx = idx + 1 @@ -553,7 +556,7 @@ subroutine mwt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! ! -- return return @@ -581,7 +584,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%idxbudfwrt, 'IDXBUDFWRT', this%memoryPath) call mem_allocate(this%idxbudrtmv, 'IDXBUDRTMV', this%memoryPath) call mem_allocate(this%idxbudfrtm, 'IDXBUDFRTM', this%memoryPath) - ! + ! ! -- Initialize this%idxbudrate = 0 this%idxbudfwrt = 0 @@ -606,7 +609,7 @@ subroutine mwt_allocate_arrays(this) ! -- local integer(I4B) :: n ! ------------------------------------------------------------------------------ - ! + ! ! -- time series call mem_allocate(this%concrate, this%ncv, 'CONCRATE', this%memoryPath) ! @@ -622,7 +625,7 @@ subroutine mwt_allocate_arrays(this) ! -- Return return end subroutine mwt_allocate_arrays - + subroutine mwt_da(this) ! ****************************************************************************** ! mwt_da @@ -694,7 +697,7 @@ subroutine mwt_rate_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine mwt_rate_term - + subroutine mwt_fwrt_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -726,7 +729,7 @@ subroutine mwt_fwrt_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine mwt_fwrt_term - + subroutine mwt_rtmv_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -758,7 +761,7 @@ subroutine mwt_rtmv_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine mwt_rtmv_term - + subroutine mwt_frtm_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -790,7 +793,7 @@ subroutine mwt_frtm_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine mwt_frtm_term - + subroutine mwt_df_obs(this) ! ****************************************************************************** ! mwt_df_obs -- obs are supported? @@ -801,12 +804,44 @@ subroutine mwt_df_obs(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use GwtAptModule, only: apt_process_obsID ! -- dummy class(GwtMwtType) :: this ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ + ! + ! -- Store obs type and assign procedure pointer + ! for concentration observation type. + call this%obs%StoreObsType('concentration', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- flow-ja-face not supported for MWT + !call this%obs%StoreObsType('flow-ja-face', .true., indx) + !this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for from-mvr observation type. + call this%obs%StoreObsType('from-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- to-mvr not supported for mwt + !call this%obs%StoreObsType('to-mvr', .true., indx) + !this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for storage observation type. + call this%obs%StoreObsType('storage', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for constant observation type. + call this%obs%StoreObsType('constant', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for observation type: mwt + call this%obs%StoreObsType('mwt', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID12 ! ! -- Store obs type and assign procedure pointer ! for rate observation type. @@ -830,7 +865,36 @@ subroutine mwt_df_obs(this) ! return end subroutine mwt_df_obs - + + !> @brief Process package specific obs + !! + !! Method to process specific observations for this package. + !! + !< + subroutine mwt_rp_obs(this, obsrv, found) + ! -- dummy + class(GwtMwtType), intent(inout) :: this !< package class + type(ObserveType), intent(inout) :: obsrv !< observation object + logical, intent(inout) :: found !< indicate whether observation was found + ! -- local + ! + found = .true. + select case (obsrv%ObsTypeId) + case ('RATE') + call this%rp_obs_byfeature(obsrv) + case ('FW-RATE') + call this%rp_obs_byfeature(obsrv) + case ('RATE-TO-MVR') + call this%rp_obs_byfeature(obsrv) + case ('FW-RATE-TO-MVR') + call this%rp_obs_byfeature(obsrv) + case default + found = .false. + end select + ! + return + end subroutine mwt_rp_obs + subroutine mwt_bd_obs(this, obstypeid, jj, v, found) ! ****************************************************************************** ! mwt_bd_obs -- calculate observation value and pass it back to APT @@ -850,24 +914,24 @@ subroutine mwt_bd_obs(this, obstypeid, jj, v, found) ! found = .true. select case (obstypeid) - case ('RATE') - if (this%iboundpak(jj) /= 0) then - call this%mwt_rate_term(jj, n1, n2, v) - end if - case ('FW-RATE') - if (this%iboundpak(jj) /= 0 .and. this%idxbudfwrt > 0) then - call this%mwt_fwrt_term(jj, n1, n2, v) - end if - case ('RATE-TO-MVR') - if (this%iboundpak(jj) /= 0 .and. this%idxbudrtmv > 0) then - call this%mwt_rtmv_term(jj, n1, n2, v) - end if - case ('FW-RATE-TO-MVR') - if (this%iboundpak(jj) /= 0 .and. this%idxbudfrtm > 0) then - call this%mwt_frtm_term(jj, n1, n2, v) - end if - case default - found = .false. + case ('RATE') + if (this%iboundpak(jj) /= 0) then + call this%mwt_rate_term(jj, n1, n2, v) + end if + case ('FW-RATE') + if (this%iboundpak(jj) /= 0 .and. this%idxbudfwrt > 0) then + call this%mwt_fwrt_term(jj, n1, n2, v) + end if + case ('RATE-TO-MVR') + if (this%iboundpak(jj) /= 0 .and. this%idxbudrtmv > 0) then + call this%mwt_rtmv_term(jj, n1, n2, v) + end if + case ('FW-RATE-TO-MVR') + if (this%iboundpak(jj) /= 0 .and. this%idxbudfrtm > 0) then + call this%mwt_frtm_term(jj, n1, n2, v) + end if + case default + found = .false. end select ! return @@ -882,7 +946,7 @@ subroutine mwt_set_stressperiod(this, itemno, keyword, found) ! ------------------------------------------------------------------------------ use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtMwtType),intent(inout) :: this + class(GwtMwtType), intent(inout) :: this integer(I4B), intent(in) :: itemno character(len=*), intent(in) :: keyword logical, intent(inout) :: found @@ -898,28 +962,27 @@ subroutine mwt_set_stressperiod(this, itemno, keyword, found) ! found = .true. select case (keyword) - case ('RATE') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concrate(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RATE') - case default - ! - ! -- keyword not recognized so return to caller with found = .false. - found = .false. + case ('RATE') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concrate(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RATE') + case default + ! + ! -- keyword not recognized so return to caller with found = .false. + found = .false. end select ! -999 continue +999 continue ! ! -- return return end subroutine mwt_set_stressperiod - -end module GwtMwtModule \ No newline at end of file +end module GwtMwtModule diff --git a/src/Model/GroundWaterTransport/gwt1obs1.f90 b/src/Model/GroundWaterTransport/gwt1obs1.f90 index 13645031db9..b16c0658f12 100644 --- a/src/Model/GroundWaterTransport/gwt1obs1.f90 +++ b/src/Model/GroundWaterTransport/gwt1obs1.f90 @@ -1,13 +1,13 @@ module GwtObsModule - use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, MAXOBSTYPES - use BaseDisModule, only: DisBaseType - use GwtIcModule, only: GwtIcType - use ObserveModule, only: ObserveType - use ObsModule, only: ObsType - use SimModule, only: count_errors, store_error, & - store_error_unit + use KindModule, only: DP, I4B + use ConstantsModule, only: LINELENGTH, MAXOBSTYPES + use BaseDisModule, only: DisBaseType + use GwtIcModule, only: GwtIcType + use ObserveModule, only: ObserveType + use ObsModule, only: ObsType + use SimModule, only: count_errors, store_error, & + store_error_unit implicit none private @@ -15,9 +15,9 @@ module GwtObsModule type, extends(ObsType) :: GwtObsType ! -- Private members - type(GwtIcType), pointer, private :: ic => null() ! initial conditions - real(DP), dimension(:), pointer, contiguous, private :: x => null() ! concentration - real(DP), dimension(:), pointer, contiguous, private :: flowja => null() ! intercell flows + type(GwtIcType), pointer, private :: ic => null() ! initial conditions + real(DP), dimension(:), pointer, contiguous, private :: x => null() ! concentration + real(DP), dimension(:), pointer, contiguous, private :: flowja => null() ! intercell flows contains ! -- Public procedures procedure, public :: gwt_obs_ar @@ -42,11 +42,11 @@ subroutine gwt_obs_cr(obs, inobs) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(GwtObsType), pointer, intent(out) :: obs + type(GwtObsType), pointer, intent(out) :: obs integer(I4B), pointer, intent(in) :: inobs ! ------------------------------------------------------------------------------ ! - allocate(obs) + allocate (obs) call obs%allocate_scalars() obs%active = .false. obs%inputFilename = '' @@ -63,8 +63,8 @@ subroutine gwt_obs_ar(this, ic, x, flowja) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwtObsType), intent(inout) :: this - type(GwtIcType), pointer, intent(in) :: ic + class(GwtObsType), intent(inout) :: this + type(GwtIcType), pointer, intent(in) :: ic real(DP), dimension(:), pointer, contiguous, intent(in) :: x real(DP), dimension(:), pointer, contiguous, intent(in) :: flowja ! ------------------------------------------------------------------------------ @@ -90,7 +90,7 @@ subroutine gwt_obs_df(this, iout, pkgname, filtyp, dis) integer(I4B), intent(in) :: iout character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: filtyp - class(DisBaseType), pointer :: dis + class(DisBaseType), pointer :: dis ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ @@ -120,7 +120,7 @@ subroutine gwt_obs_bd(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(GwtObsType), intent(inout) :: this + class(GwtObsType), intent(inout) :: this ! -- local integer(I4B) :: i, jaindex, nodenumber character(len=100) :: msg @@ -131,7 +131,7 @@ subroutine gwt_obs_bd(this) ! ! -- iterate through all GWT observations if (this%npakobs > 0) then - do i=1,this%npakobs + do i = 1, this%npakobs obsrv => this%pakobs(i)%obsrv nodenumber = obsrv%NodeNumber jaindex = obsrv%JaIndex @@ -141,12 +141,12 @@ subroutine gwt_obs_bd(this) case ('FLOW-JA-FACE') call this%SaveOneSimval(obsrv, this%flowja(jaindex)) case default - msg = 'Error: Unrecognized observation type: ' // trim(obsrv%ObsTypeId) + msg = 'Error: Unrecognized observation type: '//trim(obsrv%ObsTypeId) call store_error(msg) call store_error_unit(this%inUnitObs) end select - enddo - endif + end do + end if ! return end subroutine gwt_obs_bd @@ -176,9 +176,9 @@ subroutine gwt_obs_da(this) class(GwtObsType), intent(inout) :: this ! ------------------------------------------------------------------------------ ! - nullify(this%ic) - nullify(this%x) - nullify(this%flowja) + nullify (this%ic) + nullify (this%x) + nullify (this%flowja) call this%ObsType%obs_da() ! return @@ -215,10 +215,10 @@ subroutine gwt_process_concentration_obs_id(obsrv, dis, inunitobs, iout) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1 integer(I4B) :: icol, istart, istop @@ -240,7 +240,7 @@ subroutine gwt_process_concentration_obs_id(obsrv, dis, inunitobs, iout) ermsg = 'Error reading data from ID string' call store_error(ermsg) call store_error_unit(inunitobs) - endif + end if ! return end subroutine gwt_process_concentration_obs_id @@ -253,16 +253,16 @@ subroutine gwt_process_intercell_obs_id(obsrv, dis, inunitobs, iout) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout ! -- local integer(I4B) :: nn1, nn2 integer(I4B) :: icol, istart, istop, jaidx character(len=LINELENGTH) :: ermsg, strng ! formats - 70 format('Error: No connection exists between cells identified in text: ',a) +70 format('Error: No connection exists between cells identified in text: ', a) ! ------------------------------------------------------------------------------ ! ! -- Initialize variables @@ -277,32 +277,32 @@ subroutine gwt_process_intercell_obs_id(obsrv, dis, inunitobs, iout) if (nn1 > 0) then obsrv%NodeNumber = nn1 else - ermsg = 'Error reading data from ID string: ' // strng(istart:istop) + ermsg = 'Error reading data from ID string: '//strng(istart:istop) call store_error(ermsg) - endif + end if ! ! Get node number, with option for ID string to be either node ! number or lay, row, column (when dis is structured). nn2 = dis%noder_from_string(icol, istart, istop, inunitobs, & - iout, strng, .false.) + iout, strng, .false.) if (nn2 > 0) then obsrv%NodeNumber2 = nn2 else - ermsg = 'Error reading data from ID string: ' // strng(istart:istop) + ermsg = 'Error reading data from ID string: '//strng(istart:istop) call store_error(ermsg) - endif + end if ! ! -- store JA index - jaidx = dis%con%getjaindex(nn1,nn2) - if (jaidx==0) then - write(ermsg,70)trim(strng) + jaidx = dis%con%getjaindex(nn1, nn2) + if (jaidx == 0) then + write (ermsg, 70) trim(strng) call store_error(ermsg) - endif + end if obsrv%JaIndex = jaidx ! if (count_errors() > 0) then call store_error_unit(inunitobs) - endif + end if ! return end subroutine gwt_process_intercell_obs_id diff --git a/src/Model/GroundWaterTransport/gwt1oc1.f90 b/src/Model/GroundWaterTransport/gwt1oc1.f90 index 7d55fa3e6d1..d186d713259 100644 --- a/src/Model/GroundWaterTransport/gwt1oc1.f90 +++ b/src/Model/GroundWaterTransport/gwt1oc1.f90 @@ -1,10 +1,10 @@ module GwtOcModule - use BaseDisModule, only: DisBaseType - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMODELNAME - use OutputControlModule, only: OutputControlType - use OutputControlDataModule, only: OutputControlDataType, ocd_cr + use BaseDisModule, only: DisBaseType + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMODELNAME + use OutputControlModule, only: OutputControlType + use OutputControlDataModule, only: OutputControlDataType, ocd_cr implicit none private @@ -19,8 +19,8 @@ module GwtOcModule contains procedure :: oc_ar end type GwtOcType - - contains + +contains !> @ brief Create GwtOcType !! @@ -30,13 +30,13 @@ module GwtOcModule !< subroutine oc_cr(ocobj, name_model, inunit, iout) ! -- dummy - type(GwtOcType), pointer :: ocobj !< GwtOcType object - character(len=*), intent(in) :: name_model !< name of the model - integer(I4B), intent(in) :: inunit !< unit number for input - integer(I4B), intent(in) :: iout !< unit number for output + type(GwtOcType), pointer :: ocobj !< GwtOcType object + character(len=*), intent(in) :: name_model !< name of the model + integer(I4B), intent(in) :: inunit !< unit number for input + integer(I4B), intent(in) :: iout !< unit number for output ! ! -- Create the object - allocate(ocobj) + allocate (ocobj) ! ! -- Allocate scalars call ocobj%allocate_scalars(name_model) @@ -59,42 +59,42 @@ end subroutine oc_cr !< subroutine oc_ar(this, conc, dis, dnodata) ! -- dummy - class(GwtOcType) :: this !< GwtOcType object - real(DP), dimension(:), pointer, contiguous, intent(in) :: conc !< model concentration - class(DisBaseType), pointer, intent(in) :: dis !< model discretization package - real(DP), intent(in) :: dnodata !< no data value + class(GwtOcType) :: this !< GwtOcType object + real(DP), dimension(:), pointer, contiguous, intent(in) :: conc !< model concentration + class(DisBaseType), pointer, intent(in) :: dis !< model discretization package + real(DP), intent(in) :: dnodata !< no data value ! -- local integer(I4B) :: i, nocdobj, inodata - type(OutputControlDataType), pointer :: ocdobjptr + type(OutputControlDataType), pointer :: ocdobjptr real(DP), dimension(:), pointer, contiguous :: nullvec => null() ! ! -- Initialize variables inodata = 0 nocdobj = 2 - allocate(this%ocdobj(nocdobj)) + allocate (this%ocdobj(nocdobj)) do i = 1, nocdobj call ocd_cr(ocdobjptr) select case (i) case (1) - call ocdobjptr%init_dbl('BUDGET', nullvec, dis, 'PRINT LAST ', & - 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & + call ocdobjptr%init_dbl('BUDGET', nullvec, dis, 'PRINT LAST ', & + 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & this%iout, dnodata) case (2) - call ocdobjptr%init_dbl('CONCENTRATION', conc, dis, 'PRINT LAST ', & - 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & + call ocdobjptr%init_dbl('CONCENTRATION', conc, dis, 'PRINT LAST ', & + 'COLUMNS 10 WIDTH 11 DIGITS 4 GENERAL ', & this%iout, dnodata) end select this%ocdobj(i) = ocdobjptr - deallocate(ocdobjptr) - enddo + deallocate (ocdobjptr) + end do ! ! -- Read options or set defaults if this package not on - if(this%inunit > 0) then + if (this%inunit > 0) then call this%read_options() - endif + end if ! ! -- Return return end subroutine oc_ar - + end module GwtOcModule diff --git a/src/Model/GroundWaterTransport/gwt1sft1.f90 b/src/Model/GroundWaterTransport/gwt1sft1.f90 index bfc886db307..f9fdfabee9c 100644 --- a/src/Model/GroundWaterTransport/gwt1sft1.f90 +++ b/src/Model/GroundWaterTransport/gwt1sft1.f90 @@ -5,7 +5,7 @@ ! ! SFR flows (sfrbudptr) index var SFT term Transport Type !--------------------------------------------------------------------------------- - + ! -- terms from SFR that will be handled by parent APT Package ! FLOW-JA-FACE idxbudfjf FLOW-JA-FACE cv2cv ! GWF (aux FLOW-AREA) idxbudgwf GWF cv2gwf @@ -19,7 +19,7 @@ ! RUNOFF idxbudroff RUNOFF q * croff ! EXT-INFLOW idxbudiflw EXT-INFLOW q * ciflw ! EXT-OUTFLOW idxbudoutf EXT-OUTFLOW q * cfeat - + ! -- terms from a flow file that should be skipped ! CONSTANT none none none ! AUXILIARY none none none @@ -38,31 +38,33 @@ module GwtSftModule use BndModule, only: BndType, GetBndFromList use GwtFmiModule, only: GwtFmiType use SfrModule, only: SfrType - use GwtAptModule, only: GwtAptType - + use ObserveModule, only: ObserveType + use GwtAptModule, only: GwtAptType, apt_process_obsID, & + apt_process_obsID12 + implicit none - + public sft_create - + character(len=*), parameter :: ftype = 'SFT' character(len=*), parameter :: flowtype = 'SFR' - character(len=16) :: text = ' SFT' - + character(len=16) :: text = ' SFT' + type, extends(GwtAptType) :: GwtSftType - - integer(I4B), pointer :: idxbudrain => null() ! index of rainfall terms in flowbudptr - integer(I4B), pointer :: idxbudevap => null() ! index of evaporation terms in flowbudptr - integer(I4B), pointer :: idxbudroff => null() ! index of runoff terms in flowbudptr - integer(I4B), pointer :: idxbudiflw => null() ! index of inflow terms in flowbudptr - integer(I4B), pointer :: idxbudoutf => null() ! index of outflow terms in flowbudptr - real(DP), dimension(:), pointer, contiguous :: concrain => null() ! rainfall concentration - real(DP), dimension(:), pointer, contiguous :: concevap => null() ! evaporation concentration - real(DP), dimension(:), pointer, contiguous :: concroff => null() ! runoff concentration - real(DP), dimension(:), pointer, contiguous :: conciflw => null() ! inflow concentration + integer(I4B), pointer :: idxbudrain => null() ! index of rainfall terms in flowbudptr + integer(I4B), pointer :: idxbudevap => null() ! index of evaporation terms in flowbudptr + integer(I4B), pointer :: idxbudroff => null() ! index of runoff terms in flowbudptr + integer(I4B), pointer :: idxbudiflw => null() ! index of inflow terms in flowbudptr + integer(I4B), pointer :: idxbudoutf => null() ! index of outflow terms in flowbudptr + + real(DP), dimension(:), pointer, contiguous :: concrain => null() ! rainfall concentration + real(DP), dimension(:), pointer, contiguous :: concevap => null() ! evaporation concentration + real(DP), dimension(:), pointer, contiguous :: concroff => null() ! runoff concentration + real(DP), dimension(:), pointer, contiguous :: conciflw => null() ! inflow concentration contains - + procedure :: bnd_da => sft_da procedure :: allocate_scalars procedure :: apt_allocate_arrays => sft_allocate_arrays @@ -78,13 +80,14 @@ module GwtSftModule procedure :: sft_iflw_term procedure :: sft_outf_term procedure :: pak_df_obs => sft_df_obs + procedure :: pak_rp_obs => sft_rp_obs procedure :: pak_bd_obs => sft_bd_obs procedure :: pak_set_stressperiod => sft_set_stressperiod - + end type GwtSftType - contains - +contains + subroutine sft_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & fmi) ! ****************************************************************************** @@ -95,10 +98,10 @@ subroutine sft_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(GwtFmiType), pointer :: fmi @@ -107,7 +110,7 @@ subroutine sft_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(lktobj) + allocate (lktobj) packobj => lktobj ! ! -- create name and memory path @@ -126,7 +129,7 @@ subroutine sft_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & packobj%ibcnum = ibcnum packobj%ncolbnd = 1 packobj%iscloc = 1 - + ! -- Store pointer to flow model interface. When the GwfGwt exchange is ! created, it sets fmi%bndlist so that the GWT model has access to all ! the flow packages @@ -168,7 +171,7 @@ subroutine find_sft_package(this) ! else if (associated(this%fmi%gwfbndlist)) then - ! -- Look through gwfbndlist for a flow package with the same name as + ! -- Look through gwfbndlist for a flow package with the same name as ! this transport package name do ip = 1, this%fmi%gwfbndlist%Count() packobj => GetBndFromList(this%fmi%gwfbndlist, ip) @@ -179,8 +182,8 @@ subroutine find_sft_package(this) ! use the select type to point to the budobj in flow package this%flowpackagebnd => packobj select type (packobj) - type is (SfrType) - this%flowbudptr => packobj%budobj + type is (SfrType) + this%flowbudptr => packobj%budobj end select end if if (found) exit @@ -190,57 +193,57 @@ subroutine find_sft_package(this) ! ! -- error if flow package not found if (.not. found) then - write(errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& - &// trim(adjustl(this%flowpackagename)) // '.' + write (errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& + &//trim(adjustl(this%flowpackagename))//'.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! - ! -- allocate space for idxbudssm, which indicates whether this is a + ! -- allocate space for idxbudssm, which indicates whether this is a ! special budget term or one that is a general source and sink nbudterm = this%flowbudptr%nbudterm call mem_allocate(this%idxbudssm, nbudterm, 'IDXBUDSSM', this%memoryPath) ! ! -- Process budget terms and identify special budget terms - write(this%iout, '(/, a, a)') & - 'PROCESSING ' // ftype // ' INFORMATION FOR ', this%packName - write(this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN ' // flowtype // ' PACKAGE' - write(this%iout, '(a, i0)') & - ' NUMBER OF ' // flowtype // ' = ', this%flowbudptr%ncv + write (this%iout, '(/, a, a)') & + 'PROCESSING '//ftype//' INFORMATION FOR ', this%packName + write (this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN '//flowtype//' PACKAGE' + write (this%iout, '(a, i0)') & + ' NUMBER OF '//flowtype//' = ', this%flowbudptr%ncv icount = 1 do ip = 1, this%flowbudptr%nbudterm - select case(trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) - case('FLOW-JA-FACE') + select case (trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) + case ('FLOW-JA-FACE') this%idxbudfjf = ip this%idxbudssm(ip) = 0 - case('GWF') + case ('GWF') this%idxbudgwf = ip this%idxbudssm(ip) = 0 - case('STORAGE') + case ('STORAGE') this%idxbudsto = ip this%idxbudssm(ip) = 0 - case('RAINFALL') + case ('RAINFALL') this%idxbudrain = ip this%idxbudssm(ip) = 0 - case('EVAPORATION') + case ('EVAPORATION') this%idxbudevap = ip this%idxbudssm(ip) = 0 - case('RUNOFF') + case ('RUNOFF') this%idxbudroff = ip this%idxbudssm(ip) = 0 - case('EXT-INFLOW') + case ('EXT-INFLOW') this%idxbudiflw = ip this%idxbudssm(ip) = 0 - case('EXT-OUTFLOW') + case ('EXT-OUTFLOW') this%idxbudoutf = ip this%idxbudssm(ip) = 0 - case('TO-MVR') + case ('TO-MVR') this%idxbudtmvr = ip this%idxbudssm(ip) = 0 - case('FROM-MVR') + case ('FROM-MVR') this%idxbudfmvr = ip this%idxbudssm(ip) = 0 - case('AUXILIARY') + case ('AUXILIARY') this%idxbudaux = ip this%idxbudssm(ip) = 0 case default @@ -250,15 +253,15 @@ subroutine find_sft_package(this) this%idxbudssm(ip) = icount icount = icount + 1 end select - write(this%iout, '(a, i0, " = ", a,/, a, i0)') & + write (this%iout, '(a, i0, " = ", a,/, a, i0)') & ' TERM ', ip, trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)), & ' MAX NO. OF ENTRIES = ', this%flowbudptr%budterm(ip)%maxlist end do - write(this%iout, '(a, //)') 'DONE PROCESSING ' // ftype // ' INFORMATION' + write (this%iout, '(a, //)') 'DONE PROCESSING '//ftype//' INFORMATION' ! ! -- Return return -end subroutine find_sft_package + end subroutine find_sft_package subroutine sft_fc_expanded(this, rhs, ia, idxglo, amatsln) ! ****************************************************************************** @@ -401,7 +404,7 @@ subroutine sft_solve(this) ! -- Return return end subroutine sft_solve - + function sft_get_nbudterms(this) result(nbudterms) ! ****************************************************************************** ! sft_get_nbudterms -- function to return the number of budget terms just for @@ -424,7 +427,7 @@ function sft_get_nbudterms(this) result(nbudterms) ! -- Return return end function sft_get_nbudterms - + subroutine sft_setup_budobj(this, idx) ! ****************************************************************************** ! sft_setup_budobj -- Set up the budget object that stores all the sfr flows @@ -442,7 +445,7 @@ subroutine sft_setup_budobj(this, idx) character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! - ! -- + ! -- text = ' RAINFALL' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudrain)%maxlist @@ -455,7 +458,7 @@ subroutine sft_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EVAPORATION' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudevap)%maxlist @@ -468,7 +471,7 @@ subroutine sft_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' RUNOFF' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudroff)%maxlist @@ -481,7 +484,7 @@ subroutine sft_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-INFLOW' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudiflw)%maxlist @@ -494,7 +497,7 @@ subroutine sft_setup_budobj(this, idx) maxlist, .false., .false., & naux) ! - ! -- + ! -- text = ' EXT-OUTFLOW' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudoutf)%maxlist @@ -531,7 +534,7 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) real(DP) :: q ! -- formats ! ----------------------------------------------------------------------------- - + ! -- RAIN idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudrain)%nlist @@ -541,8 +544,7 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EVAPORATION idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudevap)%nlist @@ -552,8 +554,7 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- RUNOFF idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudroff)%nlist @@ -563,8 +564,7 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EXT-INFLOW idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudiflw)%nlist @@ -574,8 +574,7 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - - + ! -- EXT-OUTFLOW idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudoutf)%nlist @@ -585,7 +584,6 @@ subroutine sft_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - ! ! -- return @@ -615,7 +613,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%idxbudroff, 'IDXBUDROFF', this%memoryPath) call mem_allocate(this%idxbudiflw, 'IDXBUDIFLW', this%memoryPath) call mem_allocate(this%idxbudoutf, 'IDXBUDOUTF', this%memoryPath) - ! + ! ! -- Initialize this%idxbudrain = 0 this%idxbudevap = 0 @@ -641,7 +639,7 @@ subroutine sft_allocate_arrays(this) ! -- local integer(I4B) :: n ! ------------------------------------------------------------------------------ - ! + ! ! -- time series call mem_allocate(this%concrain, this%ncv, 'CONCRAIN', this%memoryPath) call mem_allocate(this%concevap, this%ncv, 'CONCEVAP', this%memoryPath) @@ -663,7 +661,7 @@ subroutine sft_allocate_arrays(this) ! -- Return return end subroutine sft_allocate_arrays - + subroutine sft_da(this) ! ****************************************************************************** ! sft_da @@ -729,7 +727,7 @@ subroutine sft_rain_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine sft_rain_term - + subroutine sft_evap_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -764,13 +762,13 @@ subroutine sft_evap_term(this, ientry, n1, n2, rrate, & if (present(rrate)) & rrate = omega * qbnd * this%xnewpak(n1) + & (DONE - omega) * qbnd * ctmp - if (present(rhsval)) rhsval = - (DONE - omega) * qbnd * ctmp + if (present(rhsval)) rhsval = -(DONE - omega) * qbnd * ctmp if (present(hcofval)) hcofval = omega * qbnd ! ! -- return return end subroutine sft_evap_term - + subroutine sft_roff_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -802,7 +800,7 @@ subroutine sft_roff_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine sft_roff_term - + subroutine sft_iflw_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -834,7 +832,7 @@ subroutine sft_iflw_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine sft_iflw_term - + subroutine sft_outf_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -866,7 +864,7 @@ subroutine sft_outf_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine sft_outf_term - + subroutine sft_df_obs(this) ! ****************************************************************************** ! sft_df_obs -- obs are supported? @@ -877,12 +875,46 @@ subroutine sft_df_obs(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use GwtAptModule, only: apt_process_obsID ! -- dummy class(GwtSftType) :: this ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ + ! + ! -- Store obs type and assign procedure pointer + ! for concentration observation type. + call this%obs%StoreObsType('concentration', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for flow between reaches. + call this%obs%StoreObsType('flow-ja-face', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID12 + ! + ! -- Store obs type and assign procedure pointer + ! for from-mvr observation type. + call this%obs%StoreObsType('from-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for to-mvr observation type. + call this%obs%StoreObsType('to-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for storage observation type. + call this%obs%StoreObsType('storage', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for constant observation type. + call this%obs%StoreObsType('constant', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for observation type: sft + call this%obs%StoreObsType('sft', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID ! ! -- Store obs type and assign procedure pointer ! for rainfall observation type. @@ -911,7 +943,40 @@ subroutine sft_df_obs(this) ! return end subroutine sft_df_obs - + + !> @brief Process package specific obs + !! + !! Method to process specific observations for this package. + !! + !< + subroutine sft_rp_obs(this, obsrv, found) + ! -- dummy + class(GwtSftType), intent(inout) :: this !< package class + type(ObserveType), intent(inout) :: obsrv !< observation object + logical, intent(inout) :: found !< indicate whether observation was found + ! -- local + ! + found = .true. + select case (obsrv%ObsTypeId) + case ('RAINFALL') + call this%rp_obs_byfeature(obsrv) + case ('EVAPORATION') + call this%rp_obs_byfeature(obsrv) + case ('RUNOFF') + call this%rp_obs_byfeature(obsrv) + case ('EXT-INFLOW') + call this%rp_obs_byfeature(obsrv) + case ('EXT-OUTFLOW') + call this%rp_obs_byfeature(obsrv) + case ('TO-MVR') + call this%rp_obs_byfeature(obsrv) + case default + found = .false. + end select + ! + return + end subroutine sft_rp_obs + subroutine sft_bd_obs(this, obstypeid, jj, v, found) ! ****************************************************************************** ! sft_bd_obs -- calculate observation value and pass it back to APT @@ -931,28 +996,28 @@ subroutine sft_bd_obs(this, obstypeid, jj, v, found) ! found = .true. select case (obstypeid) - case ('RAINFALL') - if (this%iboundpak(jj) /= 0) then - call this%sft_rain_term(jj, n1, n2, v) - end if - case ('EVAPORATION') - if (this%iboundpak(jj) /= 0) then - call this%sft_evap_term(jj, n1, n2, v) - end if - case ('RUNOFF') - if (this%iboundpak(jj) /= 0) then - call this%sft_roff_term(jj, n1, n2, v) - end if - case ('EXT-INFLOW') - if (this%iboundpak(jj) /= 0) then - call this%sft_iflw_term(jj, n1, n2, v) - end if - case ('EXT-OUTFLOW') - if (this%iboundpak(jj) /= 0) then - call this%sft_outf_term(jj, n1, n2, v) - end if - case default - found = .false. + case ('RAINFALL') + if (this%iboundpak(jj) /= 0) then + call this%sft_rain_term(jj, n1, n2, v) + end if + case ('EVAPORATION') + if (this%iboundpak(jj) /= 0) then + call this%sft_evap_term(jj, n1, n2, v) + end if + case ('RUNOFF') + if (this%iboundpak(jj) /= 0) then + call this%sft_roff_term(jj, n1, n2, v) + end if + case ('EXT-INFLOW') + if (this%iboundpak(jj) /= 0) then + call this%sft_iflw_term(jj, n1, n2, v) + end if + case ('EXT-OUTFLOW') + if (this%iboundpak(jj) /= 0) then + call this%sft_outf_term(jj, n1, n2, v) + end if + case default + found = .false. end select ! return @@ -967,7 +1032,7 @@ subroutine sft_set_stressperiod(this, itemno, keyword, found) ! ------------------------------------------------------------------------------ use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtSftType),intent(inout) :: this + class(GwtSftType), intent(inout) :: this integer(I4B), intent(in) :: itemno character(len=*), intent(in) :: keyword logical, intent(inout) :: found @@ -987,61 +1052,60 @@ subroutine sft_set_stressperiod(this, itemno, keyword, found) ! found = .true. select case (keyword) - case ('RAINFALL') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concrain(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RAINFALL') - case ('EVAPORATION') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concevap(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'EVAPORATION') - case ('RUNOFF') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concroff(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'RUNOFF') - case ('INFLOW') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%conciflw(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'INFLOW') - case default - ! - ! -- keyword not recognized so return to caller with found = .false. - found = .false. + case ('RAINFALL') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concrain(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RAINFALL') + case ('EVAPORATION') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concevap(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'EVAPORATION') + case ('RUNOFF') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%concroff(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'RUNOFF') + case ('INFLOW') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(text) + jj = 1 + bndElem => this%conciflw(itemno) + call read_value_or_time_series_adv(text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'INFLOW') + case default + ! + ! -- keyword not recognized so return to caller with found = .false. + found = .false. end select ! -999 continue +999 continue ! ! -- return return end subroutine sft_set_stressperiod - end module GwtSftModule diff --git a/src/Model/GroundWaterTransport/gwt1src1.f90 b/src/Model/GroundWaterTransport/gwt1src1.f90 index 605bcb10fc6..137a931dd15 100644 --- a/src/Model/GroundWaterTransport/gwt1src1.f90 +++ b/src/Model/GroundWaterTransport/gwt1src1.f90 @@ -14,7 +14,7 @@ module GwtSrcModule public :: src_create ! character(len=LENFTYPE) :: ftype = 'SRC' - character(len=16) :: text = ' SRC' + character(len=16) :: text = ' SRC' ! type, extends(BndType) :: GwtSrcType contains @@ -43,10 +43,10 @@ subroutine src_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname ! -- local @@ -54,7 +54,7 @@ subroutine src_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname) ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(srcobj) + allocate (srcobj) packobj => srcobj ! ! -- create name and memory path @@ -142,26 +142,26 @@ subroutine src_cf(this, reset_mover) ! ------------------------------------------------------------------------------ ! ! -- Return if no sources - if(this%nbound == 0) return + if (this%nbound == 0) return ! ! -- pakmvrobj cf lrm = .true. if (present(reset_mover)) lrm = reset_mover - if(this%imover == 1 .and. lrm) then + if (this%imover == 1 .and. lrm) then call this%pakmvrobj%cf() - endif + end if ! ! -- Calculate hcof and rhs for each source entry do i = 1, this%nbound node = this%nodelist(i) this%hcof(i) = DZERO - if(this%ibound(node) <= 0) then + if (this%ibound(node) <= 0) then this%rhs(i) = DZERO cycle end if - q = this%bound(1,i) + q = this%bound(1, i) this%rhs(i) = -q - enddo + end do ! return end subroutine src_cf @@ -184,9 +184,9 @@ subroutine src_fc(this, rhs, ia, idxglo, amatsln) ! -------------------------------------------------------------------------- ! ! -- pakmvrobj fc - if(this%imover == 1) then + if (this%imover == 1) then call this%pakmvrobj%fc() - endif + end if ! ! -- Copy package rhs and hcof into solution rhs and amat do i = 1, this%nbound @@ -197,10 +197,10 @@ subroutine src_fc(this, rhs, ia, idxglo, amatsln) ! ! -- If mover is active and mass is being withdrawn, ! store available mass (as positive value). - if(this%imover == 1 .and. this%rhs(i) > DZERO) then + if (this%imover == 1 .and. this%rhs(i) > DZERO) then call this%pakmvrobj%accumulate_qformvr(i, this%rhs(i)) - endif - enddo + end if + end do ! ! -- return return @@ -218,21 +218,21 @@ subroutine define_listlabel(this) ! ------------------------------------------------------------------------------ ! ! -- create the header list label - this%listlabel = trim(this%filtyp) // ' NO.' - if(this%dis%ndim == 3) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' - elseif(this%dis%ndim == 2) then - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' + this%listlabel = trim(this%filtyp)//' NO.' + if (this%dis%ndim == 3) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'ROW' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'COL' + elseif (this%dis%ndim == 2) then + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'LAYER' + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'CELL2D' else - write(this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' - endif - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' - if(this%inamedbound == 1) then - write(this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' - endif + write (this%listlabel, '(a, a7)') trim(this%listlabel), 'NODE' + end if + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'STRESS RATE' + if (this%inamedbound == 1) then + write (this%listlabel, '(a, a16)') trim(this%listlabel), 'BOUNDARY NAME' + end if ! ! -- return return @@ -240,36 +240,36 @@ end subroutine define_listlabel ! -- Procedures related to observations logical function src_obs_supported(this) - ! ****************************************************************************** - ! src_obs_supported - ! -- Return true because SRC package supports observations. - ! -- Overrides BndType%bnd_obs_supported() - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! src_obs_supported + ! -- Return true because SRC package supports observations. + ! -- Overrides BndType%bnd_obs_supported() + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ implicit none class(GwtSrcType) :: this - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ src_obs_supported = .true. return end function src_obs_supported subroutine src_df_obs(this) - ! ****************************************************************************** - ! src_df_obs (implements bnd_df_obs) - ! -- Store observation type supported by SRC package. - ! -- Overrides BndType%bnd_df_obs - ! ****************************************************************************** - ! - ! SPECIFICATIONS: - ! ------------------------------------------------------------------------------ + ! ****************************************************************************** + ! src_df_obs (implements bnd_df_obs) + ! -- Store observation type supported by SRC package. + ! -- Overrides BndType%bnd_df_obs + ! ****************************************************************************** + ! + ! SPECIFICATIONS: + ! ------------------------------------------------------------------------------ implicit none ! -- dummy class(GwtSrcType) :: this ! -- local integer(I4B) :: indx - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ call this%obs%StoreObsType('src', .true., indx) this%obs%obsData(indx)%ProcessIdPtr => DefaultObsIdProcessor ! @@ -296,14 +296,14 @@ subroutine src_rp_ts(this) type(TimeSeriesLinkType), pointer :: tslink => null() ! nlinks = this%TsManager%boundtslinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%TsManager%boundtslinks, i) if (associated(tslink)) then - if (tslink%JCol==1) then + if (tslink%JCol == 1) then tslink%Text = 'SMASSRATE' - endif - endif - enddo + end if + end if + end do ! return end subroutine src_rp_ts diff --git a/src/Model/GroundWaterTransport/gwt1ssm1.f90 b/src/Model/GroundWaterTransport/gwt1ssm1.f90 index 8dd988b47f7..8a1ffca3071 100644 --- a/src/Model/GroundWaterTransport/gwt1ssm1.f90 +++ b/src/Model/GroundWaterTransport/gwt1ssm1.f90 @@ -1,51 +1,51 @@ -!> @brief This module contains the GwtSsm Module +!> @brief This module contains the GwtSsm Module !! -!! This module contains the code for handling sources and sinks +!! This module contains the code for handling sources and sinks !! associated with groundwater flow model stress packages. !! !! todo: need observations for SSM terms !< module GwtSsmModule - - use KindModule, only: DP, I4B, LGP - use ConstantsModule, only: DONE, DZERO, LENAUXNAME, LENFTYPE, & - LENPACKAGENAME, LINELENGTH, & - TABLEFT, TABCENTER, LENBUDROWLABEL - use SimModule, only: store_error, count_errors, store_error_unit - use SimVariablesModule, only: errmsg + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: DONE, DZERO, LENAUXNAME, LENFTYPE, & + LENPACKAGENAME, LINELENGTH, & + TABLEFT, TABCENTER, LENBUDROWLABEL + use SimModule, only: store_error, count_errors, store_error_unit + use SimVariablesModule, only: errmsg use NumericalPackageModule, only: NumericalPackageType - use BaseDisModule, only: DisBaseType - use GwtFmiModule, only: GwtFmiType - use TableModule, only: TableType, table_cr - use GwtSpcModule, only: GwtSpcType - + use BaseDisModule, only: DisBaseType + use GwtFmiModule, only: GwtFmiType + use TableModule, only: TableType, table_cr + use GwtSpcModule, only: GwtSpcType + implicit none public :: GwtSsmType public :: ssm_cr - character(len=LENFTYPE) :: ftype = 'SSM' - character(len=LENPACKAGENAME) :: text = ' SOURCE-SINK MIX' + character(len=LENFTYPE) :: ftype = 'SSM' + character(len=LENPACKAGENAME) :: text = ' SOURCE-SINK MIX' - !> @brief Derived type for the SSM Package + !> @brief Derived type for the SSM Package !! !! This derived type corresponds to the SSM Package, which adds !! the effects of groundwater sources and sinks to the solute transport - !! equation. + !! equation. !! !< type, extends(NumericalPackageType) :: GwtSsmType - - integer(I4B), pointer :: nbound !< total number of flow boundaries in this time step - integer(I4B), dimension(:), pointer, contiguous :: isrctype => null() !< source type 0 is unspecified, 1 is aux, 2 is auxmixed, 3 is ssmi, 4 is ssmimixed - integer(I4B), dimension(:), pointer, contiguous :: iauxpak => null() !< aux col for concentration - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - real(DP), dimension(:), pointer, contiguous :: cnew => null() !< pointer to gwt%x - type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object - type(TableType), pointer :: outputtab => null() !< output table object - type(GwtSpcType), dimension(:), pointer :: ssmivec => null() !< array of stress package concentration objects - + + integer(I4B), pointer :: nbound !< total number of flow boundaries in this time step + integer(I4B), dimension(:), pointer, contiguous :: isrctype => null() !< source type 0 is unspecified, 1 is aux, 2 is auxmixed, 3 is ssmi, 4 is ssmimixed + integer(I4B), dimension(:), pointer, contiguous :: iauxpak => null() !< aux col for concentration + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + real(DP), dimension(:), pointer, contiguous :: cnew => null() !< pointer to gwt%x + type(GwtFmiType), pointer :: fmi => null() !< pointer to fmi object + type(TableType), pointer :: outputtab => null() !< output table object + type(GwtSpcType), dimension(:), pointer :: ssmivec => null() !< array of stress package concentration objects + contains - + procedure :: ssm_df procedure :: ssm_ar procedure :: ssm_rp @@ -66,27 +66,27 @@ module GwtSsmModule procedure, private :: set_iauxpak procedure, private :: set_ssmivec procedure, private :: get_ssm_conc - + end type GwtSsmType - - contains - + +contains + !> @ brief Create a new SSM package !! !! Create a new SSM package by defining names, allocating scalars - !! and initializing the parser. + !! and initializing the parser. !! !< subroutine ssm_cr(ssmobj, name_model, inunit, iout, fmi) ! -- dummy - type(GwtSsmType), pointer :: ssmobj !< GwtSsmType object - character(len=*), intent(in) :: name_model !< name of the model - integer(I4B), intent(in) :: inunit !< fortran unit for input - integer(I4B), intent(in) :: iout !< fortran unit for output - type(GwtFmiType), intent(in), target :: fmi !< GWT FMI package + type(GwtSsmType), pointer :: ssmobj !< GwtSsmType object + character(len=*), intent(in) :: name_model !< name of the model + integer(I4B), intent(in) :: inunit !< fortran unit for input + integer(I4B), intent(in) :: iout !< fortran unit for output + type(GwtFmiType), intent(in), target :: fmi !< GWT FMI package ! ! -- Create the object - allocate(ssmobj) + allocate (ssmobj) ! ! -- create name and memory path call ssmobj%set_names(1, name_model, 'SSM', 'SSM') @@ -117,7 +117,7 @@ subroutine ssm_df(this) ! -- modules use MemoryManagerModule, only: mem_setptr ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local ! -- formats ! @@ -135,33 +135,35 @@ subroutine ssm_ar(this, dis, ibound, cnew) ! -- modules use MemoryManagerModule, only: mem_setptr ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object - class(DisBaseType), pointer, intent(in) :: dis !< discretization package - integer(I4B), dimension(:), pointer, contiguous :: ibound !< GWT model ibound - real(DP), dimension(:), pointer, contiguous :: cnew !< GWT model dependent variable + class(GwtSsmType) :: this !< GwtSsmType object + class(DisBaseType), pointer, intent(in) :: dis !< discretization package + integer(I4B), dimension(:), pointer, contiguous :: ibound !< GWT model ibound + real(DP), dimension(:), pointer, contiguous :: cnew !< GWT model dependent variable ! -- local ! -- formats - character(len=*), parameter :: fmtssm = & - "(1x,/1x,'SSM -- SOURCE-SINK MIXING PACKAGE, VERSION 1, 8/25/2017', & + character(len=*), parameter :: fmtssm = & + "(1x,/1x,'SSM -- SOURCE-SINK MIXING PACKAGE, VERSION 1, 8/25/2017', & &' INPUT READ FROM UNIT ', i0, //)" ! ! --print a message identifying the storage package. - write(this%iout, fmtssm) this%inunit + write (this%iout, fmtssm) this%inunit ! ! -- store pointers to arguments that were passed in - this%dis => dis - this%ibound => ibound - this%cnew => cnew + this%dis => dis + this%ibound => ibound + this%cnew => cnew ! ! -- Check to make sure that there are flow packages if (this%fmi%nflowpack == 0) then - write(errmsg, '(a)') 'SSM PACKAGE DOES NOT HAVE & - &BOUNDARY FLOWS. ACTIVATE GWF-GWT EXCHANGE & - &OR TURN ON FMI AND PROVIDE A BUDGET FILE & - &THAT CONTAINS BOUNDARY FLOWS.' + write (errmsg, '(a)') 'SSM PACKAGE DOES NOT DETECT ANY BOUNDARY FLOWS & + &THAT REQUIRE SSM TERMS. ACTIVATE GWF-GWT & + &EXCHANGE OR ACTIVATE FMI PACKAGE AND PROVIDE A & + &BUDGET FILE THAT CONTAINS BOUNDARY FLOWS. IF NO & + &BOUNDARY FLOWS ARE PRESENT IN CORRESPONDING GWF & + &MODEL THEN THIS SSM PACKAGE SHOULD BE REMOVED.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Allocate arrays call this%allocate_arrays() @@ -190,7 +192,7 @@ end subroutine ssm_ar subroutine ssm_rp(this) ! -- modules ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local integer(I4B) :: ip type(GwtSpcType), pointer :: ssmiptr @@ -221,7 +223,7 @@ end subroutine ssm_rp subroutine ssm_ad(this) ! -- modules ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local integer(I4B) :: ip type(GwtSpcType), pointer :: ssmiptr @@ -243,13 +245,13 @@ subroutine ssm_ad(this) end do end do ! - ! -- Call the ad method on any ssm input files so that values for + ! -- Call the ad method on any ssm input files so that values for ! time-series are interpolated do ip = 1, this%fmi%nflowpack if (this%fmi%iatp(ip) /= 0) cycle if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then ssmiptr => this%ssmivec(ip) - call ssmiptr%spc_ad(this%fmi%gwfpackages(ip)%nbound, & + call ssmiptr%spc_ad(this%fmi%gwfpackages(ip)%nbound, & this%fmi%gwfpackages(ip)%budtxt) end if end do @@ -257,26 +259,26 @@ subroutine ssm_ad(this) ! -- Return return end subroutine ssm_ad - + !> @ brief Calculate the SSM mass flow rate and hcof and rhs values !! !! This is the primary SSM routine that calculates the matrix coefficient !! and right-hand-side value for any package and package entry. It returns - !! several different optional variables that are used throughout this + !! several different optional variables that are used throughout this !! package to update matrix terms, budget calculations, and output tables. !! !< - subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, & + subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, & cssm, qssm) ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType - integer(I4B), intent(in) :: ipackage !< package number - integer(I4B), intent(in) :: ientry !< bound number - real(DP), intent(out), optional :: rrate !< calculated mass flow rate - real(DP), intent(out), optional :: rhsval !< calculated rhs value - real(DP), intent(out), optional :: hcofval !< calculated hcof value - real(DP), intent(out), optional :: cssm !< calculated source concentration depending on flow direction - real(DP), intent(out), optional :: qssm !< water flow rate into model cell from boundary package + class(GwtSsmType) :: this !< GwtSsmType + integer(I4B), intent(in) :: ipackage !< package number + integer(I4B), intent(in) :: ientry !< bound number + real(DP), intent(out), optional :: rrate !< calculated mass flow rate + real(DP), intent(out), optional :: rhsval !< calculated rhs value + real(DP), intent(out), optional :: hcofval !< calculated hcof value + real(DP), intent(out), optional :: cssm !< calculated source concentration depending on flow direction + real(DP), intent(out), optional :: qssm !< water flow rate into model cell from boundary package ! -- local logical(LGP) :: lauxmixed integer(I4B) :: n @@ -301,46 +303,46 @@ subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, & call this%get_ssm_conc(ipackage, ientry, ctmp, lauxmixed) ! ! -- assign values for hcoftmp, rhstmp, and ctmp for subsequent assigment - ! of hcof, rhs, and rate - if(.not. lauxmixed) then + ! of hcof, rhs, and rate + if (.not. lauxmixed) then ! - ! -- If qbnd is positive, then concentration represents the inflow + ! -- If qbnd is positive, then concentration represents the inflow ! concentration. If qbnd is negative, then the outflow concentration ! is set equal to the simulated cell concentration if (qbnd >= DZERO) then - omega = DZERO ! rhs + omega = DZERO ! rhs else ctmp = this%cnew(n) - omega = DONE ! lhs + omega = DONE ! lhs if (ctmp < DZERO) then omega = DZERO ! concentration is negative, so set mass flux to zero end if end if else ! - ! -- lauxmixed value indicates that this is a mixed sink type where - ! the concentration value represents the injected concentration if - ! qbnd is positive. If qbnd is negative, then the withdrawn water - ! is equal to the minimum of the aux concentration and the cell + ! -- lauxmixed value indicates that this is a mixed sink type where + ! the concentration value represents the injected concentration if + ! qbnd is positive. If qbnd is negative, then the withdrawn water + ! is equal to the minimum of the aux concentration and the cell ! concentration. if (qbnd >= DZERO) then - omega = DZERO ! rhs (ctmp is aux value) + omega = DZERO ! rhs (ctmp is aux value) else if (ctmp < this%cnew(n)) then - omega = DZERO ! rhs (ctmp is aux value) + omega = DZERO ! rhs (ctmp is aux value) else omega = DONE ! lhs (ctmp is cell concentration) ctmp = this%cnew(n) end if end if - endif + end if ! ! -- Add terms based on qbnd sign - if(qbnd <= DZERO) then + if (qbnd <= DZERO) then hcoftmp = qbnd * omega else rhstmp = -qbnd * ctmp * (DONE - omega) - endif + end if ! ! -- end of active ibound end if @@ -355,44 +357,44 @@ subroutine ssm_term(this, ipackage, ientry, rrate, rhsval, hcofval, & ! -- return return end subroutine ssm_term - + !> @ brief Provide bound concentration and mixed flag !! !! SSM concentrations can be provided in auxiliary variables or !! through separate SPC files. If not provided, the default !! concentration is zero. This single routine provides the SSM !! bound concentration based on these different approaches. - !! The mixed flag indicates whether or not + !! The mixed flag indicates whether or not !! !< subroutine get_ssm_conc(this, ipackage, ientry, conc, lauxmixed) ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType - integer(I4B), intent(in) :: ipackage !< package number - integer(I4B), intent(in) :: ientry !< bound number - real(DP), intent(out) :: conc !< user-specified concentration for this bound - logical(LGP), intent(out) :: lauxmixed !< user-specified flag for marking this as a mixed boundary + class(GwtSsmType) :: this !< GwtSsmType + integer(I4B), intent(in) :: ipackage !< package number + integer(I4B), intent(in) :: ientry !< bound number + real(DP), intent(out) :: conc !< user-specified concentration for this bound + logical(LGP), intent(out) :: lauxmixed !< user-specified flag for marking this as a mixed boundary ! -- local integer(I4B) :: isrctype integer(I4B) :: iauxpos - + conc = DZERO lauxmixed = .false. isrctype = this%isrctype(ipackage) - - select case(isrctype) - case(1, 2) + + select case (isrctype) + case (1, 2) iauxpos = this%iauxpak(ipackage) conc = this%fmi%gwfpackages(ipackage)%auxvar(iauxpos, ientry) if (isrctype == 2) lauxmixed = .true. - case(3, 4) + case (3, 4) conc = this%ssmivec(ipackage)%get_value(ientry) if (isrctype == 4) lauxmixed = .true. end select - + return end subroutine get_ssm_conc - + !> @ brief Fill coefficients !! !! This routine adds the effects of the SSM to the matrix equations by @@ -431,14 +433,14 @@ subroutine ssm_fc(this, amatsln, idxglo, rhs) amatsln(idiag) = amatsln(idiag) + hcofval rhs(n) = rhs(n) + rhsval ! - enddo + end do ! - enddo + end do ! ! -- Return return end subroutine ssm_fc - + !> @ brief Calculate flow !! !! Calulate the resulting mass flow between the boundary and the connected @@ -449,8 +451,8 @@ end subroutine ssm_fc subroutine ssm_cq(this, flowja) ! -- modules ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow across each face in the model grid + class(GwtSsmType) :: this !< GwtSsmType object + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow across each face in the model grid ! -- local integer(I4B) :: ip integer(I4B) :: i @@ -472,9 +474,9 @@ subroutine ssm_cq(this, flowja) idiag = this%dis%con%ia(n) flowja(idiag) = flowja(idiag) + rate ! - enddo + end do ! - enddo + end do ! ! -- Return return @@ -491,9 +493,9 @@ subroutine ssm_bd(this, isuppress_output, model_budget) use TdisModule, only: delt use BudgetModule, only: BudgetType ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object - integer(I4B), intent(in) :: isuppress_output !< flag to suppress output - type(BudgetType), intent(inout) :: model_budget !< budget object for the GWT model + class(GwtSsmType) :: this !< GwtSsmType object + integer(I4B), intent(in) :: isuppress_output !< flag to suppress output + type(BudgetType), intent(inout) :: model_budget !< budget object for the GWT model ! -- local character(len=LENBUDROWLABEL) :: rowlabel integer(I4B) :: ip @@ -519,19 +521,19 @@ subroutine ssm_bd(this, isuppress_output, model_budget) n = this%fmi%gwfpackages(ip)%nodelist(i) if (n <= 0) cycle call this%ssm_term(ip, i, rrate=rate) - if(rate < DZERO) then + if (rate < DZERO) then rout = rout - rate else rin = rin + rate - endif + end if ! - enddo + end do ! - rowlabel = 'SSM_' // adjustl(trim(this%fmi%flowpacknamearray(ip))) - call model_budget%addentry(rin, rout, delt, & - this%fmi%gwfpackages(ip)%budtxt, & + rowlabel = 'SSM_'//adjustl(trim(this%fmi%flowpacknamearray(ip))) + call model_budget%addentry(rin, rout, delt, & + this%fmi%gwfpackages(ip)%budtxt, & isuppress_output, rowlabel=rowlabel) - enddo + end do ! ! -- Return return @@ -549,12 +551,12 @@ subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun) use TdisModule, only: kstp, kper use ConstantsModule, only: LENPACKAGENAME, LENBOUNDNAME, LENAUXNAME, DZERO ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object - integer(I4B), intent(in) :: icbcfl !< flag for writing binary budget terms - integer(I4B), intent(in) :: ibudfl !< flag for printing budget terms to list file - integer(I4B), intent(in) :: icbcun !< fortran unit number for binary budget file + class(GwtSsmType) :: this !< GwtSsmType object + integer(I4B), intent(in) :: icbcfl !< flag for writing binary budget terms + integer(I4B), intent(in) :: ibudfl !< flag for printing budget terms to list file + integer(I4B), intent(in) :: icbcun !< fortran unit number for binary budget file ! -- local - character (len=LINELENGTH) :: title + character(len=LINELENGTH) :: title integer(I4B) :: node, nodeu character(len=20) :: nodestr integer(I4B) :: maxrows @@ -564,13 +566,13 @@ subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun) real(DP) :: qssm real(DP) :: cssm integer(I4B) :: naux - real(DP), dimension(0,0) :: auxvar + real(DP), dimension(0, 0) :: auxvar character(len=LENAUXNAME), dimension(0) :: auxname ! -- for observations character(len=LENBOUNDNAME) :: bname ! -- formats character(len=*), parameter :: fmttkk = & - "(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" + &"(1X,/1X,A,' PERIOD ',I0,' STEP ',I0)" ! ! -- set maxrows maxrows = 0 @@ -590,7 +592,7 @@ subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun) if (maxrows > 0) then call this%outputtab%set_maxbound(maxrows) end if - title = 'SSM PACKAGE (' // trim(this%packName) // & + title = 'SSM PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call this%outputtab%set_title(title) end if @@ -606,15 +608,16 @@ subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun) if (icbcfl == 0) ibinun = 0 ! ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun /= 0) then + if (ibinun /= 0) then naux = 0 - call this%dis%record_srcdst_list_header(text, this%name_model, & - this%name_model, this%name_model, this%packName, naux, & - auxname, ibinun, this%nbound, this%iout) - endif + call this%dis%record_srcdst_list_header(text, this%name_model, & + this%name_model, this%name_model, & + this%packName, naux, auxname, & + ibinun, this%nbound, this%iout) + end if ! ! -- If no boundaries, skip flow calculations. - if(this%nbound > 0) then + if (this%nbound > 0) then ! ! -- Loop through each boundary calculating flow. do ip = 1, this%fmi%nflowpack @@ -649,18 +652,18 @@ subroutine ssm_ot_flow(this, icbcfl, ibudfl, icbcun) ! -- If saving cell-by-cell flows in list, write flow if (ibinun /= 0) then n2 = i - call this%dis%record_mf6_list_entry(ibinun, node, n2, rrate, & - naux, auxvar(:,i), & + call this%dis%record_mf6_list_entry(ibinun, node, n2, rrate, & + naux, auxvar(:, i), & olconv2=.FALSE.) end if ! - enddo + end do ! - enddo - endif + end do + end if if (ibudfl /= 0) then if (this%iprflow /= 0) then - write(this%iout,'(1x)') + write (this%iout, '(1x)') end if end if ! @@ -677,35 +680,35 @@ subroutine ssm_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local integer(I4B) :: ip type(GwtSpcType), pointer :: ssmiptr ! ! -- Deallocate the ssmi objects if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then do ip = 1, size(this%ssmivec) if (this%isrctype(ip) == 3 .or. this%isrctype(ip) == 4) then ssmiptr => this%ssmivec(ip) call ssmiptr%spc_da() end if end do - deallocate(this%ssmivec) + deallocate (this%ssmivec) end if ! ! -- Deallocate arrays if package was active - if(this%inunit > 0) then + if (this%inunit > 0) then call mem_deallocate(this%iauxpak) call mem_deallocate(this%isrctype) this%ibound => null() this%fmi => null() - endif + end if ! ! -- output table object if (associated(this%outputtab)) then call this%outputtab%table_da() - deallocate(this%outputtab) - nullify(this%outputtab) + deallocate (this%outputtab) + nullify (this%outputtab) end if ! ! -- Scalars @@ -727,7 +730,7 @@ subroutine allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate, mem_setptr ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local ! ! -- allocate scalars in NumericalPackageType @@ -752,11 +755,11 @@ subroutine allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate, mem_setptr ! -- dummy - class(GwtSsmType) :: this !< GwtSsmType object + class(GwtSsmType) :: this !< GwtSsmType object ! -- local integer(I4B) :: nflowpack integer(I4B) :: i - ! + ! ! -- Allocate nflowpack = this%fmi%nflowpack call mem_allocate(this%iauxpak, nflowpack, 'IAUXPAK', this%memoryPath) @@ -769,12 +772,12 @@ subroutine allocate_arrays(this) end do ! ! -- Allocate the ssmivec array - allocate(this%ssmivec(nflowpack)) + allocate (this%ssmivec(nflowpack)) ! ! -- Return return end subroutine allocate_arrays - + !> @ brief Read package options !! !! Read and set the SSM Package options @@ -783,18 +786,18 @@ end subroutine allocate_arrays subroutine read_options(this) ! -- modules ! -- dummy - class(GwtSSMType) :: this !< GwtSsmType object + class(GwtSSMType) :: this !< GwtSsmType object ! -- local character(len=LINELENGTH) :: keyword integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*), parameter :: fmtiprflow = & - "(4x,'SSM FLOW INFORMATION WILL BE PRINTED TO LISTING FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" - character(len=*), parameter :: fmtisvflow = & - "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE " // & - "WHENEVER ICBCFL IS NOT ZERO.')" + character(len=*), parameter :: fmtiprflow = & + "(4x,'SSM FLOW INFORMATION WILL BE PRINTED TO LISTING FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" + character(len=*), parameter :: fmtisvflow = & + "(4x,'CELL-BY-CELL FLOW INFORMATION WILL BE SAVED TO BINARY FILE & + &WHENEVER ICBCFL IS NOT ZERO.')" ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, blockRequired=.false., & @@ -802,25 +805,25 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING SSM OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING SSM OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout, fmtiprflow) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtisvflow) - case default - write(errmsg,'(4x,a,a)') 'UNKNOWN SSM OPTION: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, fmtiprflow) + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtisvflow) + case default + write (errmsg, '(4x,a,a)') 'UNKNOWN SSM OPTION: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF SSM OPTIONS' + write (this%iout, '(1x,a)') 'END OF SSM OPTIONS' end if ! ! -- Return @@ -834,7 +837,7 @@ end subroutine read_options !< subroutine read_data(this) ! -- dummy - class(GwtSsmtype) :: this !< GwtSsmtype object + class(GwtSsmtype) :: this !< GwtSsmtype object ! ! -- read and process required SOURCES block call this%read_sources_aux() @@ -843,7 +846,7 @@ subroutine read_data(this) call this%read_sources_fileinput() return end subroutine read_data - + !> @ brief Read SOURCES block !! !! Read SOURCES block and look for auxiliary columns in @@ -852,7 +855,7 @@ end subroutine read_data !< subroutine read_sources_aux(this) ! -- dummy - class(GwtSsmtype) :: this !< GwtSsmtype object + class(GwtSsmtype) :: this !< GwtSsmtype object ! -- local character(len=LINELENGTH) :: keyword character(len=20) :: srctype @@ -872,11 +875,11 @@ subroutine read_sources_aux(this) nflowpack = this%fmi%nflowpack ! ! -- get sources block - call this%parser%GetBlock('SOURCES', isfound, ierr, & - supportOpenClose=.true., & + call this%parser%GetBlock('SOURCES', isfound, ierr, & + supportOpenClose=.true., & blockrequired=.true.) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING SOURCES' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING SOURCES' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -888,18 +891,18 @@ subroutine read_sources_aux(this) if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == keyword) then pakfound = .true. exit - endif - enddo + end if + end do if (.not. pakfound) then - write(errmsg,'(1x, a, a)') 'FLOW PACKAGE CANNOT BE FOUND: ', & - trim(keyword) + write (errmsg, '(1x, a, a)') 'FLOW PACKAGE CANNOT BE FOUND: ', & + trim(keyword) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Ensure package was not specified more than once in SOURCES block if (this%isrctype(ip) /= 0) then - write(errmsg,'(1x, a, a)') & + write (errmsg, '(1x, a, a)') & 'A PACKAGE CANNOT BE SPECIFIED MORE THAN ONCE IN THE SSM SOURCES & &BLOCK. THE FOLLOWING PACKAGE WAS SPECIFIED MORE THAN ONCE: ', & trim(keyword) @@ -909,16 +912,16 @@ subroutine read_sources_aux(this) ! ! -- read the source type call this%parser%GetStringCaps(srctype) - select case(srctype) - case('AUX') - write(this%iout,'(1x,a)') 'AUX SOURCE DETECTED.' + select case (srctype) + case ('AUX') + write (this%iout, '(1x,a)') 'AUX SOURCE DETECTED.' isrctype = 1 - case('AUXMIXED') - write(this%iout,'(1x,a)') 'AUXMIXED SOURCE DETECTED.' + case ('AUXMIXED') + write (this%iout, '(1x,a)') 'AUXMIXED SOURCE DETECTED.' lauxmixed = .true. isrctype = 2 case default - write(errmsg,'(1x, a, a)') & + write (errmsg, '(1x, a, a)') & 'SRCTYPE MUST BE AUX OR AUXMIXED. FOUND: ', trim(srctype) call store_error(errmsg) call this%parser%StoreErrorUnit() @@ -929,24 +932,24 @@ subroutine read_sources_aux(this) ! ! -- Find and store the auxiliary column call this%set_iauxpak(ip, trim(keyword)) - + end do - write(this%iout,'(1x,a)')'END PROCESSING SOURCES' + write (this%iout, '(1x,a)') 'END PROCESSING SOURCES' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED SOURCES BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED SOURCES BLOCK NOT FOUND.' call store_error(errmsg) call this%parser%StoreErrorUnit() end if ! ! -- terminate if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return end subroutine read_sources_aux - + !> @ brief Read FILEINPUT block !! !! Read optional FILEINPUT block and initialize an @@ -955,7 +958,7 @@ end subroutine read_sources_aux !< subroutine read_sources_fileinput(this) ! -- dummy - class(GwtSsmtype) :: this !< GwtSsmtype object + class(GwtSsmtype) :: this !< GwtSsmtype object ! -- local character(len=LINELENGTH) :: keyword character(len=LINELENGTH) :: keyword2 @@ -976,11 +979,11 @@ subroutine read_sources_fileinput(this) nflowpack = this%fmi%nflowpack ! ! -- get sources_file block - call this%parser%GetBlock('FILEINPUT', isfound, ierr, & - supportOpenClose=.true., & + call this%parser%GetBlock('FILEINPUT', isfound, ierr, & + supportOpenClose=.true., & blockrequired=.false.) - if(isfound) then - write(this%iout,'(1x,a)')'PROCESSING FILEINPUT' + if (isfound) then + write (this%iout, '(1x,a)') 'PROCESSING FILEINPUT' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -992,18 +995,18 @@ subroutine read_sources_fileinput(this) if (trim(adjustl(this%fmi%gwfpackages(ip)%name)) == keyword) then pakfound = .true. exit - endif - enddo + end if + end do if (.not. pakfound) then - write(errmsg,'(1x, a, a)') 'FLOW PACKAGE CANNOT BE FOUND: ', & - trim(keyword) + write (errmsg, '(1x, a, a)') 'FLOW PACKAGE CANNOT BE FOUND: ', & + trim(keyword) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- Ensure package was not specified more than once in SOURCES block if (this%isrctype(ip) /= 0) then - write(errmsg,'(1x, a, a)') & + write (errmsg, '(1x, a, a)') & 'A PACKAGE CANNOT BE SPECIFIED MORE THAN ONCE IN THE SSM SOURCES & &AND SOURCES_FILES BLOCKS. THE FOLLOWING PACKAGE WAS SPECIFIED & &MORE THAN ONCE: ', & @@ -1014,16 +1017,16 @@ subroutine read_sources_fileinput(this) ! ! -- read the source type call this%parser%GetStringCaps(srctype) - select case(srctype) - case('SPC6') - write(this%iout,'(1x,a)') 'SPC6 SOURCE DETECTED.' + select case (srctype) + case ('SPC6') + write (this%iout, '(1x,a)') 'SPC6 SOURCE DETECTED.' isrctype = 3 ! ! verify filein is next call this%parser%GetStringCaps(keyword2) - if(trim(adjustl(keyword2)) /= 'FILEIN') then - errmsg = 'SPC6 keyword must be followed by "FILEIN" ' // & - 'then by filename and optionally by .' + if (trim(adjustl(keyword2)) /= 'FILEIN') then + errmsg = 'SPC6 keyword must be followed by "FILEIN" '// & + 'then by filename and optionally by .' call store_error(errmsg) call this%parser%StoreErrorUnit() end if @@ -1036,11 +1039,11 @@ subroutine read_sources_fileinput(this) call this%parser%GetStringCaps(keyword2) if (trim(keyword2) == 'MIXED') then isrctype = 4 - write(this%iout,'(1x,a,a)') 'ASSIGNED MIXED SSM TYPE TO PACKAGE ',& + write (this%iout, '(1x,a,a)') 'ASSIGNED MIXED SSM TYPE TO PACKAGE ', & trim(keyword) end if case default - write(errmsg,'(1x, a, a)') & + write (errmsg, '(1x, a, a)') & 'SRCTYPE MUST BE SPC6. FOUND: ', trim(srctype) call store_error(errmsg) call this%parser%StoreErrorUnit() @@ -1048,23 +1051,23 @@ subroutine read_sources_fileinput(this) ! ! -- Store the source type (3 or 4) this%isrctype(ip) = isrctype - + end do - write(this%iout,'(1x,a)')'END PROCESSING FILEINPUT' + write (this%iout, '(1x,a)') 'END PROCESSING FILEINPUT' else - write(this%iout,'(1x,a)') & + write (this%iout, '(1x,a)') & 'OPTIONAL FILEINPUT BLOCK NOT FOUND. CONTINUING.' end if ! ! -- terminate if errors - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return end subroutine read_sources_fileinput - + !> @ brief Set iauxpak array value for package ip !! !! The next call to parser will return the auxiliary name for @@ -1076,11 +1079,11 @@ end subroutine read_sources_fileinput !< subroutine set_iauxpak(this, ip, packname) ! -- dummy - class(GwtSsmtype),intent(inout) :: this !< GwtSsmtype - integer(I4B), intent(in) :: ip !< package number + class(GwtSsmtype), intent(inout) :: this !< GwtSsmtype + integer(I4B), intent(in) :: ip !< package number character(len=*), intent(in) :: packname !< name of package ! -- local - character(len=LENAUXNAME) :: auxname + character(len=LENAUXNAME) :: auxname logical :: auxfound integer(I4B) :: iaux ! @@ -1088,28 +1091,28 @@ subroutine set_iauxpak(this, ip, packname) call this%parser%GetStringCaps(auxname) auxfound = .false. do iaux = 1, this%fmi%gwfpackages(ip)%naux - if (trim(this%fmi%gwfpackages(ip)%auxname(iaux)) == & + if (trim(this%fmi%gwfpackages(ip)%auxname(iaux)) == & trim(auxname)) then auxfound = .true. exit - endif - enddo + end if + end do if (.not. auxfound) then - write(errmsg,'(1x, a, a)') & + write (errmsg, '(1x, a, a)') & 'AUXILIARY NAME CANNOT BE FOUND: ', trim(auxname) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- set iauxpak and write message this%iauxpak(ip) = iaux - write(this%iout, '(4x, a, i0, a, a)') 'USING AUX COLUMN ', & + write (this%iout, '(4x, a, i0, a, a)') 'USING AUX COLUMN ', & iaux, ' IN PACKAGE ', trim(packname) ! ! -- return return end subroutine set_iauxpak - + !> @ brief Set ssmivec array value for package ip !! !! The next call to parser will return the input file name for @@ -1119,10 +1122,10 @@ end subroutine set_iauxpak !< subroutine set_ssmivec(this, ip, packname) ! -- module - use InputOutputModule, only: openfile, getunit + use InputOutputModule, only: openfile, getunit ! -- dummy - class(GwtSsmtype),intent(inout) :: this !< GwtSsmtype - integer(I4B), intent(in) :: ip !< package number + class(GwtSsmtype), intent(inout) :: this !< GwtSsmtype + integer(I4B), intent(in) :: ip !< package number character(len=*), intent(in) :: packname !< name of package ! -- local character(len=LINELENGTH) :: filename @@ -1133,19 +1136,19 @@ subroutine set_ssmivec(this, ip, packname) call this%parser%GetString(filename) inunit = getunit() call openfile(inunit, this%iout, filename, 'SPC', filstat_opt='OLD') - + ! -- Create the SPC file object ssmiptr => this%ssmivec(ip) - call ssmiptr%initialize(this%dis, ip, inunit, this%iout, this%name_model, & + call ssmiptr%initialize(this%dis, ip, inunit, this%iout, this%name_model, & trim(packname)) - - write(this%iout, '(4x, a, a, a, a)') 'USING SPC INPUT FILE ', & + + write (this%iout, '(4x, a, a, a, a)') 'USING SPC INPUT FILE ', & trim(filename), ' TO SET CONCENTRATIONS FOR PACKAGE ', trim(packname) ! ! -- return return end subroutine set_ssmivec - + !> @ brief Setup the output table !! !! Setup the output table by creating the column headers. @@ -1153,7 +1156,7 @@ end subroutine set_ssmivec !< subroutine pak_setup_outputtab(this) ! -- dummy - class(GwtSsmtype),intent(inout) :: this + class(GwtSsmtype), intent(inout) :: this ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -1169,7 +1172,7 @@ subroutine pak_setup_outputtab(this) !end if ! ! -- initialize the output table object - title = 'SSM PACKAGE (' // trim(this%packName) // & + title = 'SSM PACKAGE ('//trim(this%packName)// & ') FLOW RATES' call table_cr(this%outputtab, this%packName, title) call this%outputtab%table_df(1, ntabcol, this%iout, transient=.TRUE.) @@ -1195,4 +1198,4 @@ subroutine pak_setup_outputtab(this) return end subroutine pak_setup_outputtab -end module GwtSsmModule \ No newline at end of file +end module GwtSsmModule diff --git a/src/Model/GroundWaterTransport/gwt1uzt1.f90 b/src/Model/GroundWaterTransport/gwt1uzt1.f90 index a5206a87bbd..2ed2a4f146a 100644 --- a/src/Model/GroundWaterTransport/gwt1uzt1.f90 +++ b/src/Model/GroundWaterTransport/gwt1uzt1.f90 @@ -13,7 +13,7 @@ ! STORAGE (aux VOLUME) idxbudsto none used for water volumes ! FROM-MVR idxbudfmvr FROM-MVR q * cext = this%qfrommvr(:) ! AUXILIARY none none none -! none none STORAGE (aux MASS) +! none none STORAGE (aux MASS) ! none none AUXILIARY none ! -- terms from UZF that need to be handled here @@ -23,8 +23,7 @@ ! REJ-INF-TO-MVR idxbudritm REJ-INF-TO-MVR q * cinfil? ! -- terms from UZF that should be skipped - - + module GwtUztModule use KindModule, only: DP, I4B @@ -33,27 +32,29 @@ module GwtUztModule use BndModule, only: BndType, GetBndFromList use GwtFmiModule, only: GwtFmiType use UzfModule, only: UzfType - use GwtAptModule, only: GwtAptType - + use ObserveModule, only: ObserveType + use GwtAptModule, only: GwtAptType, apt_process_obsID, & + apt_process_obsID12 + implicit none - + public uzt_create - + character(len=*), parameter :: ftype = 'UZT' character(len=*), parameter :: flowtype = 'UZF' - character(len=16) :: text = ' UZT' - + character(len=16) :: text = ' UZT' + type, extends(GwtAptType) :: GwtUztType - - integer(I4B), pointer :: idxbudinfl => null() ! index of uzf infiltration terms in flowbudptr - integer(I4B), pointer :: idxbudrinf => null() ! index of rejected infiltration terms in flowbudptr - integer(I4B), pointer :: idxbuduzet => null() ! index of unsat et terms in flowbudptr - integer(I4B), pointer :: idxbudritm => null() ! index of rej infil to mover rate to mover terms in flowbudptr - real(DP), dimension(:), pointer, contiguous :: concinfl => null() ! infiltration concentration - real(DP), dimension(:), pointer, contiguous :: concuzet => null() ! unsat et concentration + + integer(I4B), pointer :: idxbudinfl => null() ! index of uzf infiltration terms in flowbudptr + integer(I4B), pointer :: idxbudrinf => null() ! index of rejected infiltration terms in flowbudptr + integer(I4B), pointer :: idxbuduzet => null() ! index of unsat et terms in flowbudptr + integer(I4B), pointer :: idxbudritm => null() ! index of rej infil to mover rate to mover terms in flowbudptr + real(DP), dimension(:), pointer, contiguous :: concinfl => null() ! infiltration concentration + real(DP), dimension(:), pointer, contiguous :: concuzet => null() ! unsat et concentration contains - + procedure :: bnd_da => uzt_da procedure :: allocate_scalars procedure :: apt_allocate_arrays => uzt_allocate_arrays @@ -68,13 +69,14 @@ module GwtUztModule procedure :: uzt_uzet_term procedure :: uzt_ritm_term procedure :: pak_df_obs => uzt_df_obs + procedure :: pak_rp_obs => uzt_rp_obs procedure :: pak_bd_obs => uzt_bd_obs procedure :: pak_set_stressperiod => uzt_set_stressperiod - + end type GwtUztType - contains - +contains + subroutine uzt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & fmi) ! ****************************************************************************** @@ -85,10 +87,10 @@ subroutine uzt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! -- dummy class(BndType), pointer :: packobj - integer(I4B),intent(in) :: id - integer(I4B),intent(in) :: ibcnum - integer(I4B),intent(in) :: inunit - integer(I4B),intent(in) :: iout + integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: ibcnum + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout character(len=*), intent(in) :: namemodel character(len=*), intent(in) :: pakname type(GwtFmiType), pointer :: fmi @@ -97,7 +99,7 @@ subroutine uzt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & ! ------------------------------------------------------------------------------ ! ! -- allocate the object and assign values to object variables - allocate(uztobj) + allocate (uztobj) packobj => uztobj ! ! -- create name and memory path @@ -116,7 +118,7 @@ subroutine uzt_create(packobj, id, ibcnum, inunit, iout, namemodel, pakname, & packobj%ibcnum = ibcnum packobj%ncolbnd = 1 packobj%iscloc = 1 - + ! -- Store pointer to flow model interface. When the GwfGwt exchange is ! created, it sets fmi%bndlist so that the GWT model has access to all ! the flow packages @@ -158,7 +160,7 @@ subroutine find_uzt_package(this) ! else if (associated(this%fmi%gwfbndlist)) then - ! -- Look through gwfbndlist for a flow package with the same name as + ! -- Look through gwfbndlist for a flow package with the same name as ! this transport package name do ip = 1, this%fmi%gwfbndlist%Count() packobj => GetBndFromList(this%fmi%gwfbndlist, ip) @@ -169,8 +171,8 @@ subroutine find_uzt_package(this) ! use the select type to point to the budobj in flow package this%flowpackagebnd => packobj select type (packobj) - type is (UzfType) - this%flowbudptr => packobj%budobj + type is (UzfType) + this%flowbudptr => packobj%budobj end select end if if (found) exit @@ -180,54 +182,54 @@ subroutine find_uzt_package(this) ! ! -- error if flow package not found if (.not. found) then - write(errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& - &// trim(adjustl(this%flowpackagename)) // '.' + write (errmsg, '(a)') 'COULD NOT FIND FLOW PACKAGE WITH NAME '& + &//trim(adjustl(this%flowpackagename))//'.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! - ! -- allocate space for idxbudssm, which indicates whether this is a + ! -- allocate space for idxbudssm, which indicates whether this is a ! special budget term or one that is a general source and sink nbudterm = this%flowbudptr%nbudterm call mem_allocate(this%idxbudssm, nbudterm, 'IDXBUDSSM', this%memoryPath) ! ! -- Process budget terms and identify special budget terms - write(this%iout, '(/, a, a)') & - 'PROCESSING ' // ftype // ' INFORMATION FOR ', this%packName - write(this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN ' // flowtype // ' PACKAGE' - write(this%iout, '(a, i0)') & - ' NUMBER OF ' // flowtype // ' = ', this%flowbudptr%ncv + write (this%iout, '(/, a, a)') & + 'PROCESSING '//ftype//' INFORMATION FOR ', this%packName + write (this%iout, '(a)') ' IDENTIFYING FLOW TERMS IN '//flowtype//' PACKAGE' + write (this%iout, '(a, i0)') & + ' NUMBER OF '//flowtype//' = ', this%flowbudptr%ncv icount = 1 do ip = 1, this%flowbudptr%nbudterm - select case(trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) - case('FLOW-JA-FACE') + select case (trim(adjustl(this%flowbudptr%budterm(ip)%flowtype))) + case ('FLOW-JA-FACE') this%idxbudfjf = ip this%idxbudssm(ip) = 0 - case('GWF') + case ('GWF') this%idxbudgwf = ip this%idxbudssm(ip) = 0 - case('STORAGE') + case ('STORAGE') this%idxbudsto = ip this%idxbudssm(ip) = 0 - case('INFILTRATION') + case ('INFILTRATION') this%idxbudinfl = ip this%idxbudssm(ip) = 0 - case('REJ-INF') + case ('REJ-INF') this%idxbudrinf = ip this%idxbudssm(ip) = 0 - case('UZET') + case ('UZET') this%idxbuduzet = ip this%idxbudssm(ip) = 0 - case('REJ-INF-TO-MVR') + case ('REJ-INF-TO-MVR') this%idxbudritm = ip this%idxbudssm(ip) = 0 - case('TO-MVR') + case ('TO-MVR') this%idxbudtmvr = ip this%idxbudssm(ip) = 0 - case('FROM-MVR') + case ('FROM-MVR') this%idxbudfmvr = ip this%idxbudssm(ip) = 0 - case('AUXILIARY') + case ('AUXILIARY') this%idxbudaux = ip this%idxbudssm(ip) = 0 case default @@ -237,11 +239,11 @@ subroutine find_uzt_package(this) this%idxbudssm(ip) = icount icount = icount + 1 end select - write(this%iout, '(a, i0, " = ", a,/, a, i0)') & + write (this%iout, '(a, i0, " = ", a,/, a, i0)') & ' TERM ', ip, trim(adjustl(this%flowbudptr%budterm(ip)%flowtype)), & ' MAX NO. OF ENTRIES = ', this%flowbudptr%budterm(ip)%maxlist end do - write(this%iout, '(a, //)') 'DONE PROCESSING ' // ftype // ' INFORMATION' + write (this%iout, '(a, //)') 'DONE PROCESSING '//ftype//' INFORMATION' ! ! -- Return return @@ -321,7 +323,7 @@ end subroutine uzt_fc_expanded subroutine uzt_solve(this) ! ****************************************************************************** -! uzt_solve -- add terms specific to the unsaturated zone to the explicit +! uzt_solve -- add terms specific to the unsaturated zone to the explicit ! unsaturated-zone solve ! ****************************************************************************** ! @@ -370,7 +372,7 @@ subroutine uzt_solve(this) ! -- Return return end subroutine uzt_solve - + function uzt_get_nbudterms(this) result(nbudterms) ! ****************************************************************************** ! uzt_get_nbudterms -- function to return the number of budget terms just for @@ -397,7 +399,7 @@ function uzt_get_nbudterms(this) result(nbudterms) ! -- Return return end function uzt_get_nbudterms - + subroutine uzt_setup_budobj(this, idx) ! ****************************************************************************** ! uzt_setup_budobj -- Set up the budget object that stores all the unsaturated- @@ -416,7 +418,7 @@ subroutine uzt_setup_budobj(this, idx) character(len=LENBUDTXT) :: text ! ------------------------------------------------------------------------------ ! - ! -- + ! -- text = ' INFILTRATION' idx = idx + 1 maxlist = this%flowbudptr%budterm(this%idxbudinfl)%maxlist @@ -428,9 +430,9 @@ subroutine uzt_setup_budobj(this, idx) this%packName, & maxlist, .false., .false., & naux) - + ! - ! -- + ! -- if (this%idxbudrinf /= 0) then text = ' REJ-INF' idx = idx + 1 @@ -444,9 +446,9 @@ subroutine uzt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! - ! -- + ! -- if (this%idxbuduzet /= 0) then text = ' UZET' idx = idx + 1 @@ -460,9 +462,9 @@ subroutine uzt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! - ! -- + ! -- if (this%idxbudritm /= 0) then text = ' INF-REJ-TO-MVR' idx = idx + 1 @@ -476,7 +478,7 @@ subroutine uzt_setup_budobj(this, idx) maxlist, .false., .false., & naux) end if - + ! ! -- return return @@ -502,7 +504,7 @@ subroutine uzt_fill_budobj(this, idx, x, ccratin, ccratout) real(DP) :: q ! -- formats ! ----------------------------------------------------------------------------- - + ! -- INFILTRATION idx = idx + 1 nlist = this%flowbudptr%budterm(this%idxbudinfl)%nlist @@ -512,7 +514,7 @@ subroutine uzt_fill_budobj(this, idx, x, ccratin, ccratout) call this%budobj%budterm(idx)%update_term(n1, n2, q) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do - + ! -- REJ-INF if (this%idxbudrinf /= 0) then idx = idx + 1 @@ -524,7 +526,7 @@ subroutine uzt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- UZET if (this%idxbuduzet /= 0) then idx = idx + 1 @@ -536,7 +538,7 @@ subroutine uzt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! -- REJ-INF-TO-MVR if (this%idxbudritm /= 0) then idx = idx + 1 @@ -548,7 +550,7 @@ subroutine uzt_fill_budobj(this, idx, x, ccratin, ccratout) call this%apt_accumulate_ccterm(n1, q, ccratin, ccratout) end do end if - + ! ! -- return return @@ -576,7 +578,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%idxbudrinf, 'IDXBUDRINF', this%memoryPath) call mem_allocate(this%idxbuduzet, 'IDXBUDUZET', this%memoryPath) call mem_allocate(this%idxbudritm, 'IDXBUDRITM', this%memoryPath) - ! + ! ! -- Initialize this%idxbudinfl = 0 this%idxbudrinf = 0 @@ -601,7 +603,7 @@ subroutine uzt_allocate_arrays(this) ! -- local integer(I4B) :: n ! ------------------------------------------------------------------------------ - ! + ! ! -- time series call mem_allocate(this%concinfl, this%ncv, 'CONCINFL', this%memoryPath) call mem_allocate(this%concuzet, this%ncv, 'CONCUZET', this%memoryPath) @@ -619,7 +621,7 @@ subroutine uzt_allocate_arrays(this) ! -- Return return end subroutine uzt_allocate_arrays - + subroutine uzt_da(this) ! ****************************************************************************** ! uzt_da @@ -692,7 +694,7 @@ subroutine uzt_infl_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine uzt_infl_term - + subroutine uzt_rinf_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -724,7 +726,7 @@ subroutine uzt_rinf_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine uzt_rinf_term - + subroutine uzt_uzet_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -759,13 +761,13 @@ subroutine uzt_uzet_term(this, ientry, n1, n2, rrate, & if (present(rrate)) & rrate = omega * qbnd * this%xnewpak(n1) + & (DONE - omega) * qbnd * ctmp - if (present(rhsval)) rhsval = - (DONE - omega) * qbnd * ctmp + if (present(rhsval)) rhsval = -(DONE - omega) * qbnd * ctmp if (present(hcofval)) hcofval = omega * qbnd ! ! -- return return end subroutine uzt_uzet_term - + subroutine uzt_ritm_term(this, ientry, n1, n2, rrate, & rhsval, hcofval) ! ****************************************************************************** @@ -797,7 +799,7 @@ subroutine uzt_ritm_term(this, ientry, n1, n2, rrate, & ! -- return return end subroutine uzt_ritm_term - + subroutine uzt_df_obs(this) ! ****************************************************************************** ! uzt_df_obs -- obs are supported? @@ -808,12 +810,45 @@ subroutine uzt_df_obs(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use GwtAptModule, only: apt_process_obsID ! -- dummy class(GwtUztType) :: this ! -- local integer(I4B) :: indx ! ------------------------------------------------------------------------------ + ! + ! -- Store obs type and assign procedure pointer + ! for concentration observation type. + call this%obs%StoreObsType('concentration', .false., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for flow between uzt cells. + call this%obs%StoreObsType('flow-ja-face', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID12 + ! + ! -- Store obs type and assign procedure pointer + ! for from-mvr observation type. + call this%obs%StoreObsType('from-mvr', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- to-mvr not supported for uzt + !call this%obs%StoreObsType('to-mvr', .true., indx) + !this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for storage observation type. + call this%obs%StoreObsType('storage', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for constant observation type. + call this%obs%StoreObsType('constant', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID + ! + ! -- Store obs type and assign procedure pointer + ! for observation type: uzt + call this%obs%StoreObsType('uzt', .true., indx) + this%obs%obsData(indx)%ProcessIdPtr => apt_process_obsID ! ! -- Store obs type and assign procedure pointer ! for observation type. @@ -837,7 +872,36 @@ subroutine uzt_df_obs(this) ! return end subroutine uzt_df_obs - + + !> @brief Process package specific obs + !! + !! Method to process specific observations for this package. + !! + !< + subroutine uzt_rp_obs(this, obsrv, found) + ! -- dummy + class(GwtUztType), intent(inout) :: this !< package class + type(ObserveType), intent(inout) :: obsrv !< observation object + logical, intent(inout) :: found !< indicate whether observation was found + ! -- local + ! + found = .true. + select case (obsrv%ObsTypeId) + case ('INFILTRATION') + call this%rp_obs_byfeature(obsrv) + case ('REJ-INF') + call this%rp_obs_byfeature(obsrv) + case ('UZET') + call this%rp_obs_byfeature(obsrv) + case ('REJ-INF-TO-MVR') + call this%rp_obs_byfeature(obsrv) + case default + found = .false. + end select + ! + return + end subroutine uzt_rp_obs + subroutine uzt_bd_obs(this, obstypeid, jj, v, found) ! ****************************************************************************** ! uzt_bd_obs -- calculate observation value and pass it back to APT @@ -857,24 +921,24 @@ subroutine uzt_bd_obs(this, obstypeid, jj, v, found) ! found = .true. select case (obstypeid) - case ('INFILTRATION') - if (this%iboundpak(jj) /= 0 .and. this%idxbudinfl > 0) then - call this%uzt_infl_term(jj, n1, n2, v) - end if - case ('REJ-INF') - if (this%iboundpak(jj) /= 0 .and. this%idxbudrinf > 0) then - call this%uzt_rinf_term(jj, n1, n2, v) - end if - case ('UZET') - if (this%iboundpak(jj) /= 0 .and. this%idxbuduzet > 0) then - call this%uzt_uzet_term(jj, n1, n2, v) - end if - case ('REJ-INF-TO-MVR') - if (this%iboundpak(jj) /= 0 .and. this%idxbudritm > 0) then - call this%uzt_ritm_term(jj, n1, n2, v) - end if - case default - found = .false. + case ('INFILTRATION') + if (this%iboundpak(jj) /= 0 .and. this%idxbudinfl > 0) then + call this%uzt_infl_term(jj, n1, n2, v) + end if + case ('REJ-INF') + if (this%iboundpak(jj) /= 0 .and. this%idxbudrinf > 0) then + call this%uzt_rinf_term(jj, n1, n2, v) + end if + case ('UZET') + if (this%iboundpak(jj) /= 0 .and. this%idxbuduzet > 0) then + call this%uzt_uzet_term(jj, n1, n2, v) + end if + case ('REJ-INF-TO-MVR') + if (this%iboundpak(jj) /= 0 .and. this%idxbudritm > 0) then + call this%uzt_ritm_term(jj, n1, n2, v) + end if + case default + found = .false. end select ! return @@ -889,12 +953,12 @@ subroutine uzt_set_stressperiod(this, itemno, keyword, found) ! ------------------------------------------------------------------------------ use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtUztType),intent(inout) :: this + class(GwtUztType), intent(inout) :: this integer(I4B), intent(in) :: itemno character(len=*), intent(in) :: keyword logical, intent(inout) :: found ! -- local - character(len=LINELENGTH) :: text + character(len=LINELENGTH) :: temp_text integer(I4B) :: ierr integer(I4B) :: jj real(DP), pointer :: bndElem => null() @@ -906,39 +970,38 @@ subroutine uzt_set_stressperiod(this, itemno, keyword, found) ! found = .true. select case (keyword) - case ('INFILTRATION') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concinfl(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'INFILTRATION') - case ('UZET') - ierr = this%apt_check_valid(itemno) - if (ierr /= 0) then - goto 999 - end if - call this%parser%GetString(text) - jj = 1 - bndElem => this%concuzet(itemno) - call read_value_or_time_series_adv(text, itemno, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'UZET') - case default - ! - ! -- keyword not recognized so return to caller with found = .false. - found = .false. + case ('INFILTRATION') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(temp_text) + jj = 1 + bndElem => this%concinfl(itemno) + call read_value_or_time_series_adv(temp_text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'INFILTRATION') + case ('UZET') + ierr = this%apt_check_valid(itemno) + if (ierr /= 0) then + goto 999 + end if + call this%parser%GetString(temp_text) + jj = 1 + bndElem => this%concuzet(itemno) + call read_value_or_time_series_adv(temp_text, itemno, jj, bndElem, & + this%packName, 'BND', this%tsManager, & + this%iprpak, 'UZET') + case default + ! + ! -- keyword not recognized so return to caller with found = .false. + found = .false. end select ! -999 continue +999 continue ! ! -- return return end subroutine uzt_set_stressperiod - end module GwtUztModule diff --git a/src/Model/ModelUtilities/BoundaryPackage.f90 b/src/Model/ModelUtilities/BoundaryPackage.f90 index b42503a1252..e602b2436ed 100644 --- a/src/Model/ModelUtilities/BoundaryPackage.f90 +++ b/src/Model/ModelUtilities/BoundaryPackage.f90 @@ -1,35 +1,36 @@ -!> @brief This module contains the base boundary package +!> @brief This module contains the base boundary package !! -!! This module contains the base model boundary package class that is -!! extended by all model boundary packages. The base model boundary +!! This module contains the base model boundary package class that is +!! extended by all model boundary packages. The base model boundary !! package extends the NumericalPackageType. !! !< module BndModule - use KindModule, only: DP, LGP, I4B - use ConstantsModule, only: LENAUXNAME, LENBOUNDNAME, LENFTYPE, & - DZERO, DONE, & - LENMODELNAME, LENPACKAGENAME, & - LENMEMPATH, MAXCHARLEN, LINELENGTH, & - DNODATA, LENLISTLABEL, LENPAKLOC, & - TABLEFT, TABCENTER - use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error, & - store_error_unit - use NumericalPackageModule, only: NumericalPackageType - use ObsModule, only: ObsType, obs_cr - use TdisModule, only: delt, totimc - use ObserveModule, only: ObserveType - use InputOutputModule, only: GetUnit, openfile + use KindModule, only: DP, LGP, I4B + use ConstantsModule, only: LENAUXNAME, LENBOUNDNAME, LENFTYPE, & + DZERO, DONE, & + LENMODELNAME, LENPACKAGENAME, & + LENMEMPATH, MAXCHARLEN, LINELENGTH, & + DNODATA, LENLISTLABEL, LENPAKLOC, & + TABLEFT, TABCENTER + use SimVariablesModule, only: errmsg + use SimModule, only: count_errors, store_error, & + store_error_unit + use NumericalPackageModule, only: NumericalPackageType + use ObsModule, only: ObsType, obs_cr + use TdisModule, only: delt, totimc + use ObserveModule, only: ObserveType + use InputOutputModule, only: GetUnit, openfile use TimeArraySeriesManagerModule, only: TimeArraySeriesManagerType - use TimeSeriesLinkModule, only: TimeSeriesLinkType - use TimeSeriesManagerModule, only: TimeSeriesManagerType - use ListModule, only: ListType - use PackageMoverModule, only: PackageMoverType - use BaseDisModule, only: DisBaseType - use BlockParserModule, only: BlockParserType - use TableModule, only: TableType, table_cr + use TimeSeriesLinkModule, only: TimeSeriesLinkType + use TimeSeriesManagerModule, only: TimeSeriesManagerType + use ListModule, only: ListType + use PackageMoverModule, only: PackageMoverType + use BaseDisModule, only: DisBaseType + use BlockParserModule, only: BlockParserType + use TableModule, only: TableType, table_cr + use CharacterStringModule, only: CharacterStringType implicit none @@ -45,64 +46,71 @@ module BndModule !< type, extends(NumericalPackageType) :: BndType ! -- characters - character(len=LENLISTLABEL), pointer :: listlabel => null() !< title of table written for RP - character(len=LENPACKAGENAME) :: text = '' !< text string for package flow term - character(len=LENAUXNAME), dimension(:), pointer, & - contiguous :: auxname => null() !< vector of auxname - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: boundname => null() !< vector of boundnames + character(len=LENLISTLABEL), pointer :: listlabel => null() !< title of table written for RP + character(len=LENPACKAGENAME) :: text = '' !< text string for package flow term + character(len=LENAUXNAME), dimension(:), pointer, & + contiguous :: auxname => null() !< vector of auxname + type(CharacterStringType), dimension(:), pointer, & + contiguous :: auxname_cst => null() !< copy of vector auxname that can be stored in memory manager + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: boundname => null() !< vector of boundnames + type(CharacterStringType), dimension(:), pointer, & + contiguous :: boundname_cst => null() !< copy of vector boundname that can be stored in memory manager ! ! -- scalars - integer(I4B), pointer :: isadvpak => null() !< flag indicating package is advanced (1) or not (0) - integer(I4B), pointer :: ibcnum => null() !< consecutive package number for this boundary condition - integer(I4B), pointer :: maxbound => null() !< max number of boundaries - integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period - integer(I4B), pointer :: ncolbnd => null() !< number of columns of the bound array - integer(I4B), pointer :: iscloc => null() !< bound column to scale with SFAC - integer(I4B), pointer :: naux => null() !< number of auxiliary variables - integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames - integer(I4B), pointer :: iauxmultcol => null() !< column to use as multiplier for column iscloc - integer(I4B), pointer :: npakeq => null() !< number of equations in this package (normally 0 unless package adds rows to matrix) - integer(I4B), pointer :: ioffset => null() !< offset of this package in the model + integer(I4B), pointer :: isadvpak => null() !< flag indicating package is advanced (1) or not (0) + integer(I4B), pointer :: ibcnum => null() !< consecutive package number for this boundary condition + integer(I4B), pointer :: maxbound => null() !< max number of boundaries + integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period + integer(I4B), pointer :: ncolbnd => null() !< number of columns of the bound array + integer(I4B), pointer :: iscloc => null() !< bound column to scale with SFAC + integer(I4B), pointer :: naux => null() !< number of auxiliary variables + integer(I4B), pointer :: inamedbound => null() !< flag to read boundnames + integer(I4B), pointer :: iauxmultcol => null() !< column to use as multiplier for column iscloc + integer(I4B), pointer :: npakeq => null() !< number of equations in this package (normally 0 unless package adds rows to matrix) + integer(I4B), pointer :: ioffset => null() !< offset of this package in the model ! -- arrays - integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() !< vector of reduced node numbers - integer(I4B), dimension(:), pointer, contiguous :: noupdateauxvar => null() !< override auxvars from being updated - real(DP), dimension(:,:), pointer, contiguous :: bound => null() !< array of package specific boundary numbers - real(DP), dimension(:), pointer, contiguous :: hcof => null() !< diagonal contribution - real(DP), dimension(:), pointer, contiguous :: rhs => null() !< right-hand side contribution - real(DP), dimension(:,:), pointer, contiguous :: auxvar => null() !< auxiliary variable array - real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated values - real(DP), dimension(:), pointer, contiguous :: simtomvr => null() !< simulated to mover values + integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() !< vector of reduced node numbers + integer(I4B), dimension(:), pointer, contiguous :: noupdateauxvar => null() !< override auxvars from being updated + real(DP), dimension(:, :), pointer, contiguous :: bound => null() !< array of package specific boundary numbers + real(DP), dimension(:), pointer, contiguous :: hcof => null() !< diagonal contribution + real(DP), dimension(:), pointer, contiguous :: rhs => null() !< right-hand side contribution + real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< auxiliary variable array + real(DP), dimension(:), pointer, contiguous :: simvals => null() !< simulated values + real(DP), dimension(:), pointer, contiguous :: simtomvr => null() !< simulated to mover values ! ! -- water mover flag and object - integer(I4B), pointer :: imover => null() !< flag indicating of the mover is active in the package - type(PackageMoverType), pointer :: pakmvrobj => null() !< mover object for package + integer(I4B), pointer :: imover => null() !< flag indicating if the mover is active in the package + type(PackageMoverType), pointer :: pakmvrobj => null() !< mover object for package + ! + ! -- viscosity flag and safe-copy of conductance array + integer(I4B), pointer :: ivsc => null() !< flag indicating if viscosity is active in the model + real(DP), dimension(:), pointer, contiguous :: condinput => null() !< stores user-specified conductance values ! ! -- timeseries - type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager - type(TimeArraySeriesManagerType), pointer :: TasManager => null() !< time array series manager - integer(I4B) :: indxconvertflux = 0 !< indxconvertflux is column of bound to multiply by area to convert flux to rate + type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager + type(TimeArraySeriesManagerType), pointer :: TasManager => null() !< time array series manager + integer(I4B) :: indxconvertflux = 0 !< indxconvertflux is column of bound to multiply by area to convert flux to rate logical(LGP) :: AllowTimeArraySeries = .false. ! ! -- pointers for observations - integer(I4B), pointer :: inobspkg => null() !< unit number for obs package - type(ObsType), pointer :: obs => null() !< observation package + integer(I4B), pointer :: inobspkg => null() !< unit number for obs package + type(ObsType), pointer :: obs => null() !< observation package ! ! -- pointers to model/solution variables - integer(I4B), pointer :: neq !< number of equations for model - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< model ibound array - real(DP), dimension(:), pointer, contiguous :: xnew => null() !< model dependent variable (head) for this time step - real(DP), dimension(:), pointer, contiguous :: xold => null() !< model dependent variable for last time step - real(DP), dimension(:), pointer, contiguous :: flowja => null() !< model intercell flows - integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< pointer to icelltype array in NPF - character(len=LENMEMPATH) :: ictMemPath = '' !< memory path to the icelltype data (for GWF this is in NPF) + integer(I4B), pointer :: neq !< number of equations for model + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< model ibound array + real(DP), dimension(:), pointer, contiguous :: xnew => null() !< model dependent variable (head) for this time step + real(DP), dimension(:), pointer, contiguous :: xold => null() !< model dependent variable for last time step + real(DP), dimension(:), pointer, contiguous :: flowja => null() !< model intercell flows + integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< pointer to icelltype array in NPF + character(len=LENMEMPATH) :: ictMemPath = '' !< memory path to the icelltype data (for GWF this is in NPF) ! ! -- table objects - type(TableType), pointer :: inputtab => null() !< input table object - type(TableType), pointer :: outputtab => null() !< output table object for package flows writtent to the model listing file - type(TableType), pointer :: errortab => null() !< package error table + type(TableType), pointer :: inputtab => null() !< input table object + type(TableType), pointer :: outputtab => null() !< output table object for package flows writtent to the model listing file + type(TableType), pointer :: errortab => null() !< package error table - contains procedure :: bnd_df procedure :: bnd_ac @@ -127,14 +135,15 @@ module BndModule procedure :: allocate_scalars procedure :: allocate_arrays procedure :: pack_initialize - procedure :: read_options => bnd_read_options - procedure :: read_dimensions => bnd_read_dimensions + procedure :: read_options => bnd_read_options + procedure :: read_dimensions => bnd_read_dimensions procedure :: read_initial_attr => bnd_read_initial_attr procedure :: bnd_options procedure :: bnd_cq_simrate procedure :: bnd_cq_simtomvr procedure :: set_pointers procedure :: define_listlabel + procedure :: copy_boundname procedure, private :: pak_setup_outputtab ! ! -- procedures to support observations @@ -147,1398 +156,1510 @@ module BndModule ! -- procedure to support time series procedure, public :: bnd_rp_ts ! + ! -- procedure to inform package that viscosity active + procedure, public :: bnd_activate_viscosity + ! + ! -- procedure to backup user-specified conductance + procedure, private :: bnd_store_user_cond + ! end type BndType - contains +contains - !> @ brief Define boundary package options and dimensions + !> @ brief Define boundary package options and dimensions !! - !! Define base boundary package options and dimensions for + !! Define base boundary package options and dimensions for !! a model boundary package. !! - !< - subroutine bnd_df(this, neq, dis) - ! -- modules - use TimeSeriesManagerModule, only: tsmanager_cr - use TimeArraySeriesManagerModule, only: tasmanager_cr - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - integer(I4B), intent(inout) :: neq !< number of equations - class(DisBaseType), pointer :: dis !< discretization object - ! - ! -- set pointer to dis object for the model - this%dis => dis - ! - ! -- Create time series managers - call tsmanager_cr(this%TsManager, this%iout) - call tasmanager_cr(this%TasManager, dis, this%iout) - ! - ! -- create obs package - call obs_cr(this%obs, this%inobspkg) - ! - ! -- Write information to model list file - write(this%iout,1) this%filtyp, trim(adjustl(this%text)), this%inunit - 1 format(1X,/1X,a,' -- ',a,' PACKAGE, VERSION 8, 2/22/2014', & - ' INPUT READ FROM UNIT ',I0) - ! - ! -- Initialize block parser - call this%parser%Initialize(this%inunit, this%iout) - ! - ! -- set and read options - call this%read_options() - ! - ! -- Now that time series will have been read, need to call the df - ! routine to define the manager - call this%tsmanager%tsmanager_df() - call this%tasmanager%tasmanager_df() - ! - ! -- read the package dimensions block - call this%read_dimensions() - ! - ! -- update package moffset for packages that add rows - if (this%npakeq > 0) then - this%ioffset = neq - this%dis%nodes - end if - ! - ! -- update neq - neq = neq + this%npakeq - ! - ! -- Store information needed for observations - if (this%bnd_obs_supported()) then - call this%obs%obs_df(this%iout, this%packName, this%filtyp, this%dis) - call this%bnd_df_obs() - endif - ! - ! -- return - return - end subroutine bnd_df + !< + subroutine bnd_df(this, neq, dis) + ! -- modules + use TimeSeriesManagerModule, only: tsmanager_cr + use TimeArraySeriesManagerModule, only: tasmanager_cr + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(inout) :: neq !< number of equations + class(DisBaseType), pointer :: dis !< discretization object + ! + ! -- set pointer to dis object for the model + this%dis => dis + ! + ! -- Create time series managers + call tsmanager_cr(this%TsManager, this%iout) + call tasmanager_cr(this%TasManager, dis, this%iout) + ! + ! -- create obs package + call obs_cr(this%obs, this%inobspkg) + ! + ! -- Write information to model list file + write (this%iout, 1) this%filtyp, trim(adjustl(this%text)), this%inunit +1 format(1X, /1X, a, ' -- ', a, ' PACKAGE, VERSION 8, 2/22/2014', & + ' INPUT READ FROM UNIT ', I0) + ! + ! -- Initialize block parser + call this%parser%Initialize(this%inunit, this%iout) + ! + ! -- set and read options + call this%read_options() + ! + ! -- Now that time series will have been read, need to call the df + ! routine to define the manager + call this%tsmanager%tsmanager_df() + call this%tasmanager%tasmanager_df() + ! + ! -- read the package dimensions block + call this%read_dimensions() + ! + ! -- update package moffset for packages that add rows + if (this%npakeq > 0) then + this%ioffset = neq - this%dis%nodes + end if + ! + ! -- update neq + neq = neq + this%npakeq + ! + ! -- Store information needed for observations + if (this%bnd_obs_supported()) then + call this%obs%obs_df(this%iout, this%packName, this%filtyp, this%dis) + call this%bnd_df_obs() + end if + ! + ! -- return + return + end subroutine bnd_df - !> @ brief Add boundary package connection to matrix + !> @ brief Add boundary package connection to matrix !! - !! Add boundary package connection to the matrix for packages that add - !! connections to the coefficient matrix. An example would be the GWF model + !! Add boundary package connection to the matrix for packages that add + !! connections to the coefficient matrix. An example would be the GWF model !! MAW package. Base implementation that must be extended. !! - !< - subroutine bnd_ac(this, moffset, sparse) - ! -- modules - use SparseModule, only: sparsematrix - use SimModule, only: store_error - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - integer(I4B), intent(in) :: moffset !< solution matrix model offset - type(sparsematrix), intent(inout) :: sparse !< sparse object - ! - ! -- return - return - end subroutine bnd_ac + !< + subroutine bnd_ac(this, moffset, sparse) + ! -- modules + use SparseModule, only: sparsematrix + use SimModule, only: store_error + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(in) :: moffset !< solution matrix model offset + type(sparsematrix), intent(inout) :: sparse !< sparse object + ! + ! -- return + return + end subroutine bnd_ac - !> @ brief Map boundary package connection to matrix + !> @ brief Map boundary package connection to matrix !! - !! Map boundary package connection to the matrix for packages that add - !! connections to the coefficient matrix. An example would be the GWF model + !! Map boundary package connection to the matrix for packages that add + !! connections to the coefficient matrix. An example would be the GWF model !! MAW package. Base implementation that must be extended. !! - !< - subroutine bnd_mc(this, moffset, iasln, jasln) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - integer(I4B), intent(in) :: moffset !< solution matrix model offset - integer(I4B), dimension(:), intent(in) :: iasln !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: jasln !< solution CRS column pointers - ! - ! -- return - return - end subroutine bnd_mc + !< + subroutine bnd_mc(this, moffset, iasln, jasln) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(in) :: moffset !< solution matrix model offset + integer(I4B), dimension(:), intent(in) :: iasln !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: jasln !< solution CRS column pointers + ! + ! -- return + return + end subroutine bnd_mc - !> @ brief Allocate and read method for boundary package + !> @ brief Allocate and read method for boundary package !! - !! Generic method to allocate and read static data for model boundary + !! Generic method to allocate and read static data for model boundary !! packages. A boundary package only needs to overide this method if !! input data varies from the standard boundary package. !! - !< - subroutine bnd_ar(this) - ! -- modules - use MemoryManagerModule, only: mem_setptr - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! - ! -- allocate and read observations - call this%obs%obs_ar() - ! - ! -- Allocate arrays in package superclass - call this%allocate_arrays() - ! - ! -- read optional initial package parameters - call this%read_initial_attr() - ! - ! -- setup pakmvrobj for standard stress packages - if (this%imover == 1) then - allocate(this%pakmvrobj) - call this%pakmvrobj%ar(this%maxbound, 0, this%memoryPath) - endif - ! - ! -- return - return - end subroutine bnd_ar - - !> @ brief Allocate and read method for package + !< + subroutine bnd_ar(this) + ! -- modules + use MemoryManagerModule, only: mem_setptr + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! + ! -- allocate and read observations + call this%obs%obs_ar() + ! + ! -- Allocate arrays in package superclass + call this%allocate_arrays() + ! + ! -- read optional initial package parameters + call this%read_initial_attr() + ! + ! -- setup pakmvrobj for standard stress packages + if (this%imover == 1) then + allocate (this%pakmvrobj) + call this%pakmvrobj%ar(this%maxbound, 0, this%memoryPath) + end if + ! + ! -- return + return + end subroutine bnd_ar + + !> @ brief Allocate and read method for package !! - !! Generic method to read and prepare period data for model boundary + !! Generic method to read and prepare period data for model boundary !! packages. A boundary package only needs to overide this method if !! period data varies from the standard boundary package. !! - !< - subroutine bnd_rp(this) - ! -- modules - use TdisModule, only: kper, nper - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! -- local variables - integer(I4B) :: ierr - integer(I4B) :: nlist - logical(LGP) :: isfound - character(len=LINELENGTH) :: line - ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" - character(len=*), parameter :: fmtnbd = & - "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6, & - &') IS GREATER THAN MAXIMUM(',I6,')')" - ! - ! -- Set ionper to the stress period number for which a new block of data - ! will be read. - if(this%inunit == 0) return + !< + subroutine bnd_rp(this) + ! -- modules + use TdisModule, only: kper, nper + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + integer(I4B) :: ierr + integer(I4B) :: nlist + logical(LGP) :: isfound + character(len=LINELENGTH) :: line + ! -- formats + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtnbd = & + "(1X,/1X,'THE NUMBER OF ACTIVE ',A,'S (',I6, & + &') IS GREATER THAN MAXIMUM(',I6,')')" + ! + ! -- Set ionper to the stress period number for which a new block of data + ! will be read. + if (this%inunit == 0) return + ! + ! -- get stress period data + if (this%ionper < kper) then ! - ! -- get stress period data - if (this%ionper < kper) then + ! -- get period block + call this%parser%GetBlock('PERIOD', isfound, ierr, & + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! - ! -- get period block - call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if (isfound) then - ! - ! -- read ionper and check for increasing period numbers - call this%read_check_ionper() + ! -- read ionper and check for increasing period numbers + call this%read_check_ionper() + else + ! + ! -- PERIOD block not found + if (ierr < 0) then + ! -- End of file found; data applies for remainder of simulation. + this%ionper = nper + 1 else - ! - ! -- PERIOD block not found - if (ierr < 0) then - ! -- End of file found; data applies for remainder of simulation. - this%ionper = nper + 1 - else - ! -- Found invalid block - call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) - call store_error(errmsg) - call this%parser%StoreErrorUnit() - end if - endif + ! -- Found invalid block + call this%parser%GetCurrentLine(line) + write (errmsg, fmtblkerr) adjustl(trim(line)) + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end if + end if + end if + ! + ! -- read data if ionper == kper + if (this%ionper == kper) then + nlist = -1 + ! -- Remove all time-series and time-array-series links associated with + ! this package. + call this%TsManager%Reset(this%packName) + call this%TasManager%Reset(this%packName) + ! + ! -- Read data as a list + call this%dis%read_list(this%parser%iuactive, this%iout, & + this%iprpak, nlist, this%inamedbound, & + this%iauxmultcol, this%nodelist, & + this%bound, this%auxvar, this%auxname, & + this%boundname, this%listlabel, & + this%packName, this%tsManager, this%iscloc) + this%nbound = nlist + ! + ! -- save user-specified conductance if vsc package is active + if (this%ivsc == 1) then + call this%bnd_store_user_cond(nlist, this%nodelist, this%bound, & + this%condinput) end if ! - ! -- read data if ionper == kper - if(this%ionper == kper) then - nlist = -1 - ! -- Remove all time-series and time-array-series links associated with - ! this package. - call this%TsManager%Reset(this%packName) - call this%TasManager%Reset(this%packName) - ! - ! -- Read data as a list - call this%dis%read_list(this%parser%iuactive, this%iout, & - this%iprpak, nlist, this%inamedbound, & - this%iauxmultcol, this%nodelist, & - this%bound, this%auxvar, this%auxname, & - this%boundname, this%listlabel, & - this%packName, this%tsManager, this%iscloc) - this%nbound = nlist - ! - ! Define the tsLink%Text value(s) appropriately. - ! E.g. for WEL package, entry 1, assign tsLink%Text = 'Q' - ! For RIV package, entry 1 text = 'STAGE', entry 2 text = 'COND', - ! entry 3 text = 'RBOT'; etc. - call this%bnd_rp_ts() - ! - ! -- Terminate the block - call this%parser%terminateblock() - ! - else - write(this%iout,fmtlsp) trim(this%filtyp) - endif + ! Define the tsLink%Text value(s) appropriately. + ! E.g. for WEL package, entry 1, assign tsLink%Text = 'Q' + ! For RIV package, entry 1 text = 'STAGE', entry 2 text = 'COND', + ! entry 3 text = 'RBOT'; etc. + call this%bnd_rp_ts() + ! + ! -- Terminate the block + call this%parser%terminateblock() + ! + ! -- Copy boundname into boundname_cst + call this%copy_boundname() ! - ! -- return - return - end subroutine bnd_rp + else + write (this%iout, fmtlsp) trim(this%filtyp) + end if + ! + ! -- return + return + end subroutine bnd_rp - !> @ brief Advance the boundary package + !> @ brief Advance the boundary package !! !! Advance data in the boundary package. The method sets advances - !! time series, time array series, and observation data. A boundary + !! time series, time array series, and observation data. A boundary !! package only needs to overide this method if additional data !! needs to be advanced. !! - !< - subroutine bnd_ad(this) - ! -- dummy variables - class(BndType) :: this !< BndType object - ! -- local variables - real(DP) :: begintime, endtime - ! - ! -- Initialize time variables - begintime = totimc - endtime = begintime + delt - ! - ! -- Advance the time series managers - call this%TsManager%ad() - call this%TasManager%ad() - ! - ! -- For each observation, push simulated value and corresponding - ! simulation time from "current" to "preceding" and reset - ! "current" value. - call this%obs%obs_ad() - ! - return - end subroutine bnd_ad + !< + subroutine bnd_ad(this) + ! -- dummy variables + class(BndType) :: this !< BndType object + ! -- local variables + real(DP) :: begintime, endtime + ! + ! -- Initialize time variables + begintime = totimc + endtime = begintime + delt + ! + ! -- Advance the time series managers + call this%TsManager%ad() + call this%TasManager%ad() + ! + ! -- For each observation, push simulated value and corresponding + ! simulation time from "current" to "preceding" and reset + ! "current" value. + call this%obs%obs_ad() + ! + return + end subroutine bnd_ad - !> @ brief Check boundary package period data + !> @ brief Check boundary package period data !! - !! Check the boundary package period data. Base implementation that + !! Check the boundary package period data. Base implementation that !! must be extended by each model boundary package. !! - !< - subroutine bnd_ck(this) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! - ! -- check stress period data - ! -- each package must override generic functionality - ! - ! -- return - return - end subroutine bnd_ck + !< + subroutine bnd_ck(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! + ! -- check stress period data + ! -- each package must override generic functionality + ! + ! -- return + return + end subroutine bnd_ck - !> @ brief Formulate the package hcof and rhs terms. + !> @ brief Formulate the package hcof and rhs terms. !! !! Formulate the hcof and rhs terms for the package that will be !! added to the coefficient matrix and right-hand side vector. - !! Base implementation that must be extended by each model + !! Base implementation that must be extended by each model !! boundary package. !! - !< - subroutine bnd_cf(this, reset_mover) - ! -- modules - class(BndType) :: this !< BndType object - logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover - ! - ! -- bnd has no cf routine - ! - ! -- return - return - end subroutine bnd_cf + !< + subroutine bnd_cf(this, reset_mover) + ! -- modules + class(BndType) :: this !< BndType object + logical(LGP), intent(in), optional :: reset_mover !< boolean for resetting mover + ! + ! -- bnd has no cf routine + ! + ! -- return + return + end subroutine bnd_cf - !> @ brief Copy hcof and rhs terms into solution. + !> @ brief Copy hcof and rhs terms into solution. !! - !! Add the hcof and rhs terms for the boundary package to the - !! coefficient matrix and right-hand side vector. A boundary + !! Add the hcof and rhs terms for the boundary package to the + !! coefficient matrix and right-hand side vector. A boundary !! package only needs to overide this method if it is different for !! a specific boundary package. !! - !< - subroutine bnd_fc(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(BndType) :: this !< BndType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! -- local variables - integer(I4B) :: i - integer(I4B) :: n - integer(I4B) :: ipos - ! - ! -- Copy package rhs and hcof into solution rhs and amat - do i = 1, this%nbound - n = this%nodelist(i) - rhs(n) = rhs(n) + this%rhs(i) - ipos = ia(n) - amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) - end do - ! - ! -- return - return - end subroutine bnd_fc + !< + subroutine bnd_fc(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(BndType) :: this !< BndType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! -- local variables + integer(I4B) :: i + integer(I4B) :: n + integer(I4B) :: ipos + ! + ! -- Copy package rhs and hcof into solution rhs and amat + do i = 1, this%nbound + n = this%nodelist(i) + rhs(n) = rhs(n) + this%rhs(i) + ipos = ia(n) + amatsln(idxglo(ipos)) = amatsln(idxglo(ipos)) + this%hcof(i) + end do + ! + ! -- return + return + end subroutine bnd_fc - !> @ brief Add Newton-Raphson terms for package into solution. + !> @ brief Add Newton-Raphson terms for package into solution. !! - !! Calculate and add the Newton-Raphson terms for the boundary package - !! to the coefficient matrix and right-hand side vector. A boundary - !! package only needs to overide this method if a specific boundary + !! Calculate and add the Newton-Raphson terms for the boundary package + !! to the coefficient matrix and right-hand side vector. A boundary + !! package only needs to overide this method if a specific boundary !! package needs to add Newton-Raphson terms. !! - !< - subroutine bnd_fn(this, rhs, ia, idxglo, amatsln) - ! -- dummy variables - class(BndType) :: this !< BndType object - real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model - integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers - integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) - real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix - ! - ! -- No addition terms for Newton-Raphson with constant conductance - ! boundary conditions - ! - ! -- return - return - end subroutine bnd_fn + !< + subroutine bnd_fn(this, rhs, ia, idxglo, amatsln) + ! -- dummy variables + class(BndType) :: this !< BndType object + real(DP), dimension(:), intent(inout) :: rhs !< right-hand side vector for model + integer(I4B), dimension(:), intent(in) :: ia !< solution CRS row pointers + integer(I4B), dimension(:), intent(in) :: idxglo !< mapping vector for model (local) to solution (global) + real(DP), dimension(:), intent(inout) :: amatsln !< solution coefficient matrix + ! + ! -- No addition terms for Newton-Raphson with constant conductance + ! boundary conditions + ! + ! -- return + return + end subroutine bnd_fn - !> @ brief Apply Newton-Raphson under-relaxation for package. + !> @ brief Apply Newton-Raphson under-relaxation for package. !! - !! Apply Newton-Raphson under-relaxation for a boundary package. A boundary - !! package only needs to overide this method if a specific boundary + !! Apply Newton-Raphson under-relaxation for a boundary package. A boundary + !! package only needs to overide this method if a specific boundary !! package needs to apply Newton-Raphson under-relaxation. An example is !! the MAW package which adds rows to the system of equations and may need !! to have the dependent-variable constrained by the bottom of the model. !! - !< - subroutine bnd_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax) - ! -- dummy variables - class(BndType), intent(inout) :: this !< BndType object - integer(I4B), intent(in) :: neqpak !< number of equations in the package - real(DP), dimension(neqpak), intent(inout) :: x !< dependent variable - real(DP), dimension(neqpak), intent(in) :: xtemp !< previous dependent variable - real(DP), dimension(neqpak), intent(inout) :: dx !< change in dependent variable - integer(I4B), intent(inout) :: inewtonur !< flag indicating if newton-raphson under-relaxation should be applied - real(DP), intent(inout) :: dxmax !< maximum change in the dependent variable - integer(I4B), intent(inout) :: locmax !< location of the maximum change in the dependent variable - ! -- local variables - ! - ! -- Newton-Raphson under-relaxation - ! - ! -- return - return - end subroutine bnd_nur + !< + subroutine bnd_nur(this, neqpak, x, xtemp, dx, inewtonur, dxmax, locmax) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(in) :: neqpak !< number of equations in the package + real(DP), dimension(neqpak), intent(inout) :: x !< dependent variable + real(DP), dimension(neqpak), intent(in) :: xtemp !< previous dependent variable + real(DP), dimension(neqpak), intent(inout) :: dx !< change in dependent variable + integer(I4B), intent(inout) :: inewtonur !< flag indicating if newton-raphson under-relaxation should be applied + real(DP), intent(inout) :: dxmax !< maximum change in the dependent variable + integer(I4B), intent(inout) :: locmax !< location of the maximum change in the dependent variable + ! -- local variables + ! + ! -- Newton-Raphson under-relaxation + ! + ! -- return + return + end subroutine bnd_nur - !> @ brief Convergence check for package. + !> @ brief Convergence check for package. !! !! Perform additional convergence checks on the flow between the package !! and the model it is attached to. This additional convergence check is !! applied to pacakages that solve their own continuity equation as !! part of the formulate step at the beginning of a Picard iteration. - !! A boundary package only needs to overide this method if a specific boundary - !! package solves its own continuity equation. Example packages that implement + !! A boundary package only needs to overide this method if a specific boundary + !! package solves its own continuity equation. Example packages that implement !! this additional convergence check is the CSUB, SFR, LAK, and UZF packages. !! - !< - subroutine bnd_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) - ! -- dummy variables - class(BndType), intent(inout) :: this !< BndType object - integer(I4B), intent(in) :: innertot !< total number of inner iterations - integer(I4B), intent(in) :: kiter !< Picard iteration number - integer(I4B),intent(in) :: iend !< flag indicating if this is the last Picard iteration - integer(I4B), intent(in) :: icnvgmod !< flag inficating if the model has met specific convergence criteria - character(len=LENPAKLOC), intent(inout) :: cpak !< string for user node - integer(I4B), intent(inout) :: ipak !< location of the maximum dependent variable change - real(DP), intent(inout) :: dpak !< maximum dependent variable change - ! - ! -- No addition convergence check for boundary conditions - ! - ! -- return - return - end subroutine bnd_cc + !< + subroutine bnd_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(in) :: innertot !< total number of inner iterations + integer(I4B), intent(in) :: kiter !< Picard iteration number + integer(I4B), intent(in) :: iend !< flag indicating if this is the last Picard iteration + integer(I4B), intent(in) :: icnvgmod !< flag inficating if the model has met specific convergence criteria + character(len=LENPAKLOC), intent(inout) :: cpak !< string for user node + integer(I4B), intent(inout) :: ipak !< location of the maximum dependent variable change + real(DP), intent(inout) :: dpak !< maximum dependent variable change + ! + ! -- No addition convergence check for boundary conditions + ! + ! -- return + return + end subroutine bnd_cc - !> @ brief Calculate advanced package flows. + !> @ brief Calculate advanced package flows. !! - !! Calculate the flow between connected advanced package control volumes. + !! Calculate the flow between connected advanced package control volumes. !! Only advanced boundary packages need to overide this method. !! - !< - subroutine bnd_cq(this, x, flowja, iadv) - ! -- dummy variables - class(BndType), intent(inout) :: this !< BndType object - real(DP), dimension(:), intent(in) :: x !< current dependent-variable value - real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes - integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package - ! -- local variables - integer(I4B) :: imover - ! ------------------------------------------------------------------------------ - ! - ! -- check for iadv optional variable to indicate this is an advanced - ! package and that mover calculations should not be done here - if (present(iadv)) then - if (iadv == 1) then - imover = 0 - else - imover = 1 - end if + !< + subroutine bnd_cq(this, x, flowja, iadv) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + real(DP), dimension(:), intent(in) :: x !< current dependent-variable value + real(DP), dimension(:), contiguous, intent(inout) :: flowja !< flow between two connected control volumes + integer(I4B), optional, intent(in) :: iadv !< flag that indicates if this is an advance package + ! -- local variables + integer(I4B) :: imover + ! ------------------------------------------------------------------------------ + ! + ! -- check for iadv optional variable to indicate this is an advanced + ! package and that mover calculations should not be done here + if (present(iadv)) then + if (iadv == 1) then + imover = 0 else - imover = this%imover - end if - ! - ! -- Calculate package flows. In the first call, simval is calculated - ! from hcof, rhs, and head. The second call may reduce the value in - ! simval by what is sent to the mover. The mover rate is stored in - ! simtomvr. imover is set to zero here for advanced packages, which - ! handle and store mover quantities separately. - call this%bnd_cq_simrate(x, flowja, imover) - if (imover == 1) then - call this%bnd_cq_simtomvr(flowja) + imover = 1 end if - ! - ! -- return - return - end subroutine bnd_cq + else + imover = this%imover + end if + ! + ! -- Calculate package flows. In the first call, simval is calculated + ! from hcof, rhs, and head. The second call may reduce the value in + ! simval by what is sent to the mover. The mover rate is stored in + ! simtomvr. imover is set to zero here for advanced packages, which + ! handle and store mover quantities separately. + call this%bnd_cq_simrate(x, flowja, imover) + if (imover == 1) then + call this%bnd_cq_simtomvr(flowja) + end if + ! + ! -- return + return + end subroutine bnd_cq - !> @ brief Calculate simrate. + !> @ brief Calculate simrate. !! - !! Calculate the flow between package and the model (for example, GHB and - !! groundwater cell) and store in the simvals variable. This method only + !! Calculate the flow between package and the model (for example, GHB and + !! groundwater cell) and store in the simvals variable. This method only !! needs to be overridden if a different calculation needs to be made. !! - !< - subroutine bnd_cq_simrate(this, hnew, flowja, imover) - ! -- dummy variables - class(BndType) :: this !< BndType object - real(DP), dimension(:), intent(in) :: hnew !< current dependent-variable value - real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model - integer(I4B), intent(in) :: imover !< flag indicating if the mover package is active - ! -- local variables - integer(I4B) :: i - integer(I4B) :: node - integer(I4B) :: idiag - real(DP) :: rrate - ! -- formats - ! ------------------------------------------------------------------------------ + !< + subroutine bnd_cq_simrate(this, hnew, flowja, imover) + ! -- dummy variables + class(BndType) :: this !< BndType object + real(DP), dimension(:), intent(in) :: hnew !< current dependent-variable value + real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model + integer(I4B), intent(in) :: imover !< flag indicating if the mover package is active + ! -- local variables + integer(I4B) :: i + integer(I4B) :: node + integer(I4B) :: idiag + real(DP) :: rrate + ! -- formats + ! ------------------------------------------------------------------------------ + ! + ! -- If no boundaries, skip flow calculations. + if (this%nbound > 0) then ! - ! -- If no boundaries, skip flow calculations. - if (this%nbound > 0) then + ! -- Loop through each boundary calculating flow. + do i = 1, this%nbound + node = this%nodelist(i) ! - ! -- Loop through each boundary calculating flow. - do i = 1, this%nbound - node = this%nodelist(i) - ! - ! -- If cell is no-flow or constant-head, then ignore it. - rrate = DZERO - if (node > 0) then - idiag = this%dis%con%ia(node) - if(this%ibound(node) > 0) then - ! - ! -- Calculate the flow rate into the cell. - rrate = this%hcof(i) * hnew(node) - this%rhs(i) - end if - flowja(idiag) = flowja(idiag) + rrate + ! -- If cell is no-flow or constant-head, then ignore it. + rrate = DZERO + if (node > 0) then + idiag = this%dis%con%ia(node) + if (this%ibound(node) > 0) then + ! + ! -- Calculate the flow rate into the cell. + rrate = this%hcof(i) * hnew(node) - this%rhs(i) end if - ! - ! -- Save simulated value to simvals array. - this%simvals(i) = rrate - ! - end do - endif - ! - ! -- return - return - end subroutine bnd_cq_simrate + flowja(idiag) = flowja(idiag) + rrate + end if + ! + ! -- Save simulated value to simvals array. + this%simvals(i) = rrate + ! + end do + end if + ! + ! -- return + return + end subroutine bnd_cq_simrate - !> @ brief Calculate flow to the mover. + !> @ brief Calculate flow to the mover. !! - !! Calculate the flow between package and the model that is sent to the - !! mover package and store in the simtomvr variable. This method only + !! Calculate the flow between package and the model that is sent to the + !! mover package and store in the simtomvr variable. This method only !! needs to be overridden if a different calculation needs to be made. !! - !< - subroutine bnd_cq_simtomvr(this, flowja) - ! -- dummy variables - class(BndType) :: this !< BndType object - real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model - ! -- local variables - integer(I4B) :: i - integer(I4B) :: node - real(DP) :: q - real(DP) :: fact - real(DP) :: rrate + !< + subroutine bnd_cq_simtomvr(this, flowja) + ! -- dummy variables + class(BndType) :: this !< BndType object + real(DP), dimension(:), intent(inout) :: flowja !< flow between package and model + ! -- local variables + integer(I4B) :: i + integer(I4B) :: node + real(DP) :: q + real(DP) :: fact + real(DP) :: rrate + ! + ! -- If no boundaries, skip flow calculations. + if (this%nbound > 0) then ! - ! -- If no boundaries, skip flow calculations. - if (this%nbound > 0) then + ! -- Loop through each boundary calculating flow. + do i = 1, this%nbound + node = this%nodelist(i) ! - ! -- Loop through each boundary calculating flow. - do i = 1, this%nbound - node = this%nodelist(i) - ! - ! -- If cell is no-flow or constant-head, then ignore it. - rrate = DZERO - if (node > 0) then - if(this%ibound(node) > 0) then + ! -- If cell is no-flow or constant-head, then ignore it. + rrate = DZERO + if (node > 0) then + if (this%ibound(node) > 0) then + ! + ! -- Calculate the flow rate into the cell. + q = this%simvals(i) + + if (q < DZERO) then + rrate = this%pakmvrobj%get_qtomvr(i) ! - ! -- Calculate the flow rate into the cell. - q = this%simvals(i) - - - if (q < DZERO) then - rrate = this%pakmvrobj%get_qtomvr(i) - ! - ! -- Evaluate if qtomvr exceeds the calculated rrate. - ! When fact is greater than 1, qtomvr is numerically - ! larger than rrate (which should never happen) and - ! represents a water budget error. When this happens, - ! rrate is set to 0. so that the water budget error is - ! correctly accounted for in the listing water budget. - fact = -rrate / q - if (fact > DONE) then - ! -- all flow goes to mover - q = DZERO - else - ! -- magnitude of rrate (which is negative) is reduced by - ! qtomvr (which is positive) - q = q + rrate - end if - this%simvals(i) = q - - if (rrate > DZERO) then - rrate = -rrate - end if + ! -- Evaluate if qtomvr exceeds the calculated rrate. + ! When fact is greater than 1, qtomvr is numerically + ! larger than rrate (which should never happen) and + ! represents a water budget error. When this happens, + ! rrate is set to 0. so that the water budget error is + ! correctly accounted for in the listing water budget. + fact = -rrate / q + if (fact > DONE) then + ! -- all flow goes to mover + q = DZERO + else + ! -- magnitude of rrate (which is negative) is reduced by + ! qtomvr (which is positive) + q = q + rrate + end if + this%simvals(i) = q + + if (rrate > DZERO) then + rrate = -rrate end if end if end if - ! - ! -- Save simulated value to simtomvr array. - this%simtomvr(i) = rrate - ! - end do - endif - ! - ! -- return - return - end subroutine bnd_cq_simtomvr - - !> @ brief Add package flows to model budget. - !! - !! Add the flow between package and the model (ratin and ratout) to the - !! model budget. This method only needs to be overridden if a different + end if + ! + ! -- Save simulated value to simtomvr array. + this%simtomvr(i) = rrate + ! + end do + end if + ! + ! -- return + return + end subroutine bnd_cq_simtomvr + + !> @ brief Add package flows to model budget. + !! + !! Add the flow between package and the model (ratin and ratout) to the + !! model budget. This method only needs to be overridden if a different !! calculation needs to be made. !! - !< - subroutine bnd_bd(this, model_budget) - ! -- modules - use TdisModule, only: delt - use BudgetModule, only: BudgetType, rate_accumulator - ! -- dummy variables - class(BndType) :: this !< BndType object - type(BudgetType), intent(inout) :: model_budget !< model budget object - ! -- local variables - character (len=LENPACKAGENAME) :: text - real(DP) :: ratin - real(DP) :: ratout - integer(I4B) :: isuppress_output - ! - ! -- initialize local variables - isuppress_output = 0 - ! - ! -- call accumulator and add to the model budget - call rate_accumulator(this%simvals(1:this%nbound), ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, this%text, & - isuppress_output, this%packName) - if (this%imover == 1 .and. this%isadvpak == 0) then - text = trim(adjustl(this%text)) // '-TO-MVR' - text = adjustr(text) - call rate_accumulator(this%simtomvr(1:this%nbound), ratin, ratout) - call model_budget%addentry(ratin, ratout, delt, text, & - isuppress_output, this%packName) - end if - ! - ! -- return - return - end subroutine bnd_bd + !< + subroutine bnd_bd(this, model_budget) + ! -- modules + use TdisModule, only: delt + use BudgetModule, only: BudgetType, rate_accumulator + ! -- dummy variables + class(BndType) :: this !< BndType object + type(BudgetType), intent(inout) :: model_budget !< model budget object + ! -- local variables + character(len=LENPACKAGENAME) :: text + real(DP) :: ratin + real(DP) :: ratout + integer(I4B) :: isuppress_output + ! + ! -- initialize local variables + isuppress_output = 0 + ! + ! -- call accumulator and add to the model budget + call rate_accumulator(this%simvals(1:this%nbound), ratin, ratout) + call model_budget%addentry(ratin, ratout, delt, this%text, & + isuppress_output, this%packName) + if (this%imover == 1 .and. this%isadvpak == 0) then + text = trim(adjustl(this%text))//'-TO-MVR' + text = adjustr(text) + call rate_accumulator(this%simtomvr(1:this%nbound), ratin, ratout) + call model_budget%addentry(ratin, ratout, delt, text, & + isuppress_output, this%packName) + end if + ! + ! -- return + return + end subroutine bnd_bd - !> @ brief Output advanced package flow terms. + !> @ brief Output advanced package flow terms. !! !! Output advanced boundary package flow terms. This method only needs to - !! be overridden for advanced packages that save flow terms than contribute + !! be overridden for advanced packages that save flow terms than contribute !! to the continuity equation for each control volume. !! - !< - subroutine bnd_ot_package_flows(this, icbcfl, ibudfl) - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output - integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved - ! - ! -- override for advanced packages - ! - ! -- return - return - end subroutine bnd_ot_package_flows - - !> @ brief Output advanced package dependent-variable terms. + !< + subroutine bnd_ot_package_flows(this, icbcfl, ibudfl) + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), intent(in) :: icbcfl !< flag and unit number for cell-by-cell output + integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved + ! + ! -- override for advanced packages + ! + ! -- return + return + end subroutine bnd_ot_package_flows + + !> @ brief Output advanced package dependent-variable terms. !! - !! Output advanced boundary package dependent-variable terms. This method only needs + !! Output advanced boundary package dependent-variable terms. This method only needs !! to be overridden for advanced packages that save dependent variable terms !! for each control volume. !! - !< - subroutine bnd_ot_dv(this, idvsave, idvprint) - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output - integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file - ! - ! -- override for advanced packages - ! - ! -- return - return - end subroutine bnd_ot_dv - - !> @ brief Output advanced package budget summary. + !< + subroutine bnd_ot_dv(this, idvsave, idvprint) + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), intent(in) :: idvsave !< flag and unit number for dependent-variable output + integer(I4B), intent(in) :: idvprint !< flag indicating if dependent-variable should be written to the model listing file + ! + ! -- override for advanced packages + ! + ! -- return + return + end subroutine bnd_ot_dv + + !> @ brief Output advanced package budget summary. !! - !! Output advanced boundary package budget summary. This method only needs + !! Output advanced boundary package budget summary. This method only needs !! to be overridden for advanced packages that save budget summaries !! to the model listing file. !! - !< - subroutine bnd_ot_bdsummary(this, kstp, kper, iout, ibudfl) - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kper !< period number - integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file - integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written - ! - ! -- override for advanced packages - ! - ! -- return - return - end subroutine bnd_ot_bdsummary - - !> @ brief Output package flow terms. + !< + subroutine bnd_ot_bdsummary(this, kstp, kper, iout, ibudfl) + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kper !< period number + integer(I4B), intent(in) :: iout !< flag and unit number for the model listing file + integer(I4B), intent(in) :: ibudfl !< flag indicating budget should be written + ! + ! -- override for advanced packages + ! + ! -- return + return + end subroutine bnd_ot_bdsummary + + !> @ brief Output package flow terms. !! - !! Output flow terms between the boundary package and model to a binary file and/or + !! Output flow terms between the boundary package and model to a binary file and/or !! print flows to the model listing file. This method should not need to !! be overridden. !! - !< - subroutine bnd_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), intent(in) :: icbcfl !< flag for cell-by-cell output - integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved - integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell output - integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping vector that converts the 1 to nbound values to lake number, maw number, etc. - ! -- local variables - character (len=LINELENGTH) :: title - character (len=LENPACKAGENAME) :: text - integer(I4B) :: imover - ! - ! -- Call generic subroutine to save and print simvals and simtomvr - title = trim(adjustl(this%text)) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' - if (present(imap)) then - call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, this%simvals, & - this%ibound, title, this%text, this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, & - this%boundname, imap) - else - call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, this%simvals, & - this%ibound, title, this%text, this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, & - this%boundname) - end if - ! - ! -- Set mover flag, and shut off if this is an advanced package. Advanced - ! packages must handle mover flows differently by including them in - ! their balance equations. These simtomvr flows are the general - ! flow to mover terms calculated by bnd_cq_simtomvr() - imover = this%imover - if (this%isadvpak /= 0) imover = 0 - if (imover == 1) then - text = trim(adjustl(this%text)) // '-TO-MVR' - text = adjustr(text) - title = trim(adjustl(this%text)) // ' PACKAGE (' // & - trim(this%packName) // ') FLOW RATES TO-MVR' - call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & - this%outputtab, this%nbound, this%nodelist, this%simtomvr, & - this%ibound, title, text, this%ipakcb, this%dis, this%naux, & - this%name_model, this%name_model, this%name_model, this%packName, & - this%auxname, this%auxvar, this%iout, this%inamedbound, this%boundname) - end if - ! - ! -- return - return - end subroutine bnd_ot_model_flows + !< + subroutine bnd_ot_model_flows(this, icbcfl, ibudfl, icbcun, imap) + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), intent(in) :: icbcfl !< flag for cell-by-cell output + integer(I4B), intent(in) :: ibudfl !< flag indication if cell-by-cell data should be saved + integer(I4B), intent(in) :: icbcun !< unit number for cell-by-cell output + integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping vector that converts the 1 to nbound values to lake number, maw number, etc. + ! -- local variables + character(len=LINELENGTH) :: title + character(len=LENPACKAGENAME) :: text + integer(I4B) :: imover + ! + ! -- Call generic subroutine to save and print simvals and simtomvr + title = trim(adjustl(this%text))//' PACKAGE ('//trim(this%packName)// & + ') FLOW RATES' + if (present(imap)) then + call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & + this%outputtab, this%nbound, this%nodelist, & + this%simvals, this%ibound, title, this%text, & + this%ipakcb, this%dis, this%naux, & + this%name_model, this%name_model, & + this%name_model, this%packName, & + this%auxname, this%auxvar, this%iout, & + this%inamedbound, this%boundname, imap) + else + call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & + this%outputtab, this%nbound, this%nodelist, & + this%simvals, this%ibound, title, this%text, & + this%ipakcb, this%dis, this%naux, & + this%name_model, this%name_model, & + this%name_model, this%packName, & + this%auxname, this%auxvar, this%iout, & + this%inamedbound, this%boundname) + end if + ! + ! -- Set mover flag, and shut off if this is an advanced package. Advanced + ! packages must handle mover flows differently by including them in + ! their balance equations. These simtomvr flows are the general + ! flow to mover terms calculated by bnd_cq_simtomvr() + imover = this%imover + if (this%isadvpak /= 0) imover = 0 + if (imover == 1) then + text = trim(adjustl(this%text))//'-TO-MVR' + text = adjustr(text) + title = trim(adjustl(this%text))//' PACKAGE ('// & + trim(this%packName)//') FLOW RATES TO-MVR' + call save_print_model_flows(icbcfl, ibudfl, icbcun, this%iprflow, & + this%outputtab, this%nbound, this%nodelist, & + this%simtomvr, this%ibound, title, text, & + this%ipakcb, this%dis, this%naux, & + this%name_model, this%name_model, & + this%name_model, this%packName, & + this%auxname, this%auxvar, this%iout, & + this%inamedbound, this%boundname) + end if + ! + ! -- return + return + end subroutine bnd_ot_model_flows - !> @ brief Deallocate package memory + !> @ brief Deallocate package memory !! - !! Deallocate base boundary package scalars and arrays. This method - !! only needs to be overridden if additional variables are defined + !! Deallocate base boundary package scalars and arrays. This method + !! only needs to be overridden if additional variables are defined !! for a specific package. !! - !< - subroutine bnd_da(this) - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy variables - class(BndType) :: this !< BndType object - ! - ! -- deallocate arrays - call mem_deallocate(this%nodelist, 'NODELIST', this%memoryPath) - call mem_deallocate(this%noupdateauxvar, 'NOUPDATEAUXVAR', this%memoryPath) - call mem_deallocate(this%bound, 'BOUND', this%memoryPath) - call mem_deallocate(this%hcof, 'HCOF', this%memoryPath) - call mem_deallocate(this%rhs, 'RHS', this%memoryPath) - call mem_deallocate(this%simvals, 'SIMVALS', this%memoryPath) - call mem_deallocate(this%simtomvr, 'SIMTOMVR', this%memoryPath) - call mem_deallocate(this%auxvar, 'AUXVAR', this%memoryPath) - call mem_deallocate(this%boundname, 'BOUNDNAME', this%memoryPath) - call mem_deallocate(this%auxname, 'AUXNAME', this%memoryPath) - nullify(this%icelltype) - ! - ! -- pakmvrobj - if (this%imover /= 0) then - call this%pakmvrobj%da() - deallocate(this%pakmvrobj) - nullify(this%pakmvrobj) - endif - ! - ! -- input table object - if (associated(this%inputtab)) then - call this%inputtab%table_da() - deallocate(this%inputtab) - nullify(this%inputtab) - end if - ! - ! -- output table object - if (associated(this%outputtab)) then - call this%outputtab%table_da() - deallocate(this%outputtab) - nullify(this%outputtab) - end if - ! - ! -- error table object - if (associated(this%errortab)) then - call this%errortab%table_da() - deallocate(this%errortab) - nullify(this%errortab) - end if - ! - ! -- deallocate character variables - call mem_deallocate(this%listlabel, 'LISTLABEL', this%memoryPath) - ! - ! -- Deallocate scalars - call mem_deallocate(this%isadvpak) - call mem_deallocate(this%ibcnum) - call mem_deallocate(this%maxbound) - call mem_deallocate(this%nbound) - call mem_deallocate(this%ncolbnd) - call mem_deallocate(this%iscloc) - call mem_deallocate(this%naux) - call mem_deallocate(this%inamedbound) - call mem_deallocate(this%iauxmultcol) - call mem_deallocate(this%inobspkg) - call mem_deallocate(this%imover) - call mem_deallocate(this%npakeq) - call mem_deallocate(this%ioffset) - ! - ! -- deallocate methods on objects - call this%obs%obs_da() - call this%TsManager%da() - call this%TasManager%da() - ! - ! -- deallocate objects - deallocate(this%obs) - deallocate(this%TsManager) - deallocate(this%TasManager) - nullify(this%TsManager) - nullify(this%TasManager) - ! - ! -- Deallocate parent object - call this%NumericalPackageType%da() - ! - ! -- return - return - end subroutine bnd_da + !< + subroutine bnd_da(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy variables + class(BndType) :: this !< BndType object + ! + ! -- deallocate arrays + call mem_deallocate(this%nodelist, 'NODELIST', this%memoryPath) + call mem_deallocate(this%noupdateauxvar, 'NOUPDATEAUXVAR', this%memoryPath) + call mem_deallocate(this%bound, 'BOUND', this%memoryPath) + call mem_deallocate(this%condinput, 'CONDINPUT', this%memoryPath) + call mem_deallocate(this%hcof, 'HCOF', this%memoryPath) + call mem_deallocate(this%rhs, 'RHS', this%memoryPath) + call mem_deallocate(this%simvals, 'SIMVALS', this%memoryPath) + call mem_deallocate(this%simtomvr, 'SIMTOMVR', this%memoryPath) + call mem_deallocate(this%auxvar, 'AUXVAR', this%memoryPath) + call mem_deallocate(this%boundname, 'BOUNDNAME', this%memoryPath) + call mem_deallocate(this%boundname_cst, 'BOUNDNAME_CST', this%memoryPath) + call mem_deallocate(this%auxname, 'AUXNAME', this%memoryPath) + call mem_deallocate(this%auxname_cst, 'AUXNAME_CST', this%memoryPath) + nullify (this%icelltype) + ! + ! -- pakmvrobj + if (this%imover /= 0) then + call this%pakmvrobj%da() + deallocate (this%pakmvrobj) + nullify (this%pakmvrobj) + end if + ! + ! -- input table object + if (associated(this%inputtab)) then + call this%inputtab%table_da() + deallocate (this%inputtab) + nullify (this%inputtab) + end if + ! + ! -- output table object + if (associated(this%outputtab)) then + call this%outputtab%table_da() + deallocate (this%outputtab) + nullify (this%outputtab) + end if + ! + ! -- error table object + if (associated(this%errortab)) then + call this%errortab%table_da() + deallocate (this%errortab) + nullify (this%errortab) + end if + ! + ! -- deallocate character variables + call mem_deallocate(this%listlabel, 'LISTLABEL', this%memoryPath) + ! + ! -- Deallocate scalars + call mem_deallocate(this%isadvpak) + call mem_deallocate(this%ibcnum) + call mem_deallocate(this%maxbound) + call mem_deallocate(this%nbound) + call mem_deallocate(this%ncolbnd) + call mem_deallocate(this%iscloc) + call mem_deallocate(this%naux) + call mem_deallocate(this%inamedbound) + call mem_deallocate(this%iauxmultcol) + call mem_deallocate(this%inobspkg) + call mem_deallocate(this%imover) + call mem_deallocate(this%npakeq) + call mem_deallocate(this%ioffset) + call mem_deallocate(this%ivsc) + ! + ! -- deallocate methods on objects + call this%obs%obs_da() + call this%TsManager%da() + call this%TasManager%da() + ! + ! -- deallocate objects + deallocate (this%obs) + deallocate (this%TsManager) + deallocate (this%TasManager) + nullify (this%TsManager) + nullify (this%TasManager) + ! + ! -- Deallocate parent object + call this%NumericalPackageType%da() + ! + ! -- return + return + end subroutine bnd_da - !> @ brief Allocate package scalars - !! - !! Allocate and initialize base boundary package scalars. This method - !! only needs to be overridden if additional scalars are defined - !! for a specific package. - !! - !< - subroutine allocate_scalars(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate, mem_setptr - use MemoryHelperModule, only: create_mem_path - ! -- dummy variables - class(BndType) :: this !< BndType object - ! -- local variables - integer(I4B), pointer :: imodelnewton => null() - ! - ! -- allocate scalars in NumericalPackageType - call this%NumericalPackageType%allocate_scalars() - ! - ! -- allocate character variables - call mem_allocate(this%listlabel, LENLISTLABEL, 'LISTLABEL', this%memoryPath) - ! - ! -- allocate integer variables - call mem_allocate(this%isadvpak, 'ISADVPAK', this%memoryPath) - call mem_allocate(this%ibcnum, 'IBCNUM', this%memoryPath) - call mem_allocate(this%maxbound, 'MAXBOUND', this%memoryPath) - call mem_allocate(this%nbound, 'NBOUND', this%memoryPath) - call mem_allocate(this%ncolbnd, 'NCOLBND', this%memoryPath) - call mem_allocate(this%iscloc, 'ISCLOC', this%memoryPath) - call mem_allocate(this%naux, 'NAUX', this%memoryPath) - call mem_allocate(this%inamedbound, 'INAMEDBOUND', this%memoryPath) - call mem_allocate(this%iauxmultcol, 'IAUXMULTCOL', this%memoryPath) - call mem_allocate(this%inobspkg, 'INOBSPKG', this%memoryPath) - ! - ! -- allocate the object and assign values to object variables - call mem_allocate(this%imover, 'IMOVER', this%memoryPath) - ! - ! -- allocate scalars for packages that add rows to the matrix (e.g. MAW) - call mem_allocate(this%npakeq, 'NPAKEQ', this%memoryPath) - call mem_allocate(this%ioffset, 'IOFFSET', this%memoryPath) - ! - ! -- allocate TS objects - allocate(this%TsManager) - allocate(this%TasManager) - ! - ! -- allocate text strings - call mem_allocate(this%auxname, LENAUXNAME, 0, 'AUXNAME', this%memoryPath) - ! - ! -- Initialize variables - this%isadvpak = 0 - this%ibcnum = 0 - this%maxbound = 0 - this%nbound = 0 - this%ncolbnd = 0 - this%iscloc = 0 - this%naux = 0 - this%inamedbound = 0 - this%iauxmultcol = 0 - this%inobspkg = 0 - this%imover = 0 - this%npakeq = 0 - this%ioffset = 0 - ! - ! -- Set pointer to model inewton variable - call mem_setptr(imodelnewton, 'INEWTON', create_mem_path(this%name_model)) - this%inewton = imodelnewton - imodelnewton => null() - ! - ! -- return - return - end subroutine allocate_scalars + !> @ brief Allocate package scalars + !! + !! Allocate and initialize base boundary package scalars. This method + !! only needs to be overridden if additional scalars are defined + !! for a specific package. + !! + !< + subroutine allocate_scalars(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate, mem_setptr + use MemoryHelperModule, only: create_mem_path + ! -- dummy variables + class(BndType) :: this !< BndType object + ! -- local variables + integer(I4B), pointer :: imodelnewton => null() + ! + ! -- allocate scalars in NumericalPackageType + call this%NumericalPackageType%allocate_scalars() + ! + ! -- allocate character variables + call mem_allocate(this%listlabel, LENLISTLABEL, 'LISTLABEL', & + this%memoryPath) + ! + ! -- allocate integer variables + call mem_allocate(this%isadvpak, 'ISADVPAK', this%memoryPath) + call mem_allocate(this%ibcnum, 'IBCNUM', this%memoryPath) + call mem_allocate(this%maxbound, 'MAXBOUND', this%memoryPath) + call mem_allocate(this%nbound, 'NBOUND', this%memoryPath) + call mem_allocate(this%ncolbnd, 'NCOLBND', this%memoryPath) + call mem_allocate(this%iscloc, 'ISCLOC', this%memoryPath) + call mem_allocate(this%naux, 'NAUX', this%memoryPath) + call mem_allocate(this%inamedbound, 'INAMEDBOUND', this%memoryPath) + call mem_allocate(this%iauxmultcol, 'IAUXMULTCOL', this%memoryPath) + call mem_allocate(this%inobspkg, 'INOBSPKG', this%memoryPath) + ! + ! -- allocate the object and assign values to object variables + call mem_allocate(this%imover, 'IMOVER', this%memoryPath) + ! + ! -- allocate flag for determining if vsc active + call mem_allocate(this%ivsc, 'IVSC', this%memoryPath) + ! + ! -- allocate scalars for packages that add rows to the matrix (e.g. MAW) + call mem_allocate(this%npakeq, 'NPAKEQ', this%memoryPath) + call mem_allocate(this%ioffset, 'IOFFSET', this%memoryPath) + ! + ! -- allocate TS objects + allocate (this%TsManager) + allocate (this%TasManager) + ! + ! -- allocate text strings + call mem_allocate(this%auxname, LENAUXNAME, 0, 'AUXNAME', this%memoryPath) + call mem_allocate(this%auxname_cst, LENAUXNAME, 0, 'AUXNAME_CST', & + this%memoryPath) + ! + ! -- Initialize variables + this%isadvpak = 0 + this%ibcnum = 0 + this%maxbound = 0 + this%nbound = 0 + this%ncolbnd = 0 + this%iscloc = 0 + this%naux = 0 + this%inamedbound = 0 + this%iauxmultcol = 0 + this%inobspkg = 0 + this%imover = 0 + this%npakeq = 0 + this%ioffset = 0 + this%ivsc = 0 + ! + ! -- Set pointer to model inewton variable + call mem_setptr(imodelnewton, 'INEWTON', create_mem_path(this%name_model)) + this%inewton = imodelnewton + imodelnewton => null() + ! + ! -- return + return + end subroutine allocate_scalars - !> @ brief Allocate package arrays - !! - !! Allocate and initialize base boundary package arrays. This method - !! only needs to be overridden if additional arrays are defined - !! for a specific package. - !! - !< - subroutine allocate_arrays(this, nodelist, auxvar) - ! -- modules - use MemoryManagerModule, only: mem_allocate, mem_setptr - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist !< package nodelist - real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar !< package aux variable array - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - ! - ! -- Point nodelist if it is passed in, otherwise allocate - if(present(nodelist)) then - this%nodelist => nodelist - else - call mem_allocate(this%nodelist, this%maxbound, 'NODELIST', & - this%memoryPath) - do j = 1, this%maxbound - this%nodelist(j) = 0 - end do - endif - ! - ! -- noupdateauxvar (allows an external caller to stop auxvars from being - ! recalculated - call mem_allocate(this%noupdateauxvar, this%naux, 'NOUPDATEAUXVAR', this%memoryPath) - this%noupdateauxvar(:) = 0 - ! - ! -- Allocate the bound array - call mem_allocate(this%bound, this%ncolbnd, this%maxbound, 'BOUND', & - this%memoryPath) - ! - ! -- Allocate hcof and rhs - call mem_allocate(this%hcof, this%maxbound, 'HCOF', this%memoryPath) - call mem_allocate(this%rhs, this%maxbound, 'RHS', this%memoryPath) - ! - ! -- Allocate the simvals array - call mem_allocate(this%simvals, this%maxbound, 'SIMVALS', this%memoryPath) - if (this%imover == 1) then - call mem_allocate(this%simtomvr, this%maxbound, 'SIMTOMVR', this%memoryPath) - do i = 1, this%maxbound - this%simtomvr(i) = DZERO - enddo - else - call mem_allocate(this%simtomvr, 0, 'SIMTOMVR', this%memoryPath) - endif - ! - ! -- Point or allocate auxvar - if(present(auxvar)) then - this%auxvar => auxvar - else - call mem_allocate(this%auxvar, this%naux, this%maxbound, 'AUXVAR', & - this%memoryPath) - do i = 1, this%maxbound - do j = 1, this%naux - this%auxvar(j, i) = DZERO - end do - end do - endif - ! - ! -- Allocate boundname - if (this%inamedbound /= 0) then - call mem_allocate(this%boundname, LENBOUNDNAME, this%maxbound, & - 'BOUNDNAME', this%memoryPath) - else - call mem_allocate(this%boundname, LENBOUNDNAME, 0, & - 'BOUNDNAME', this%memoryPath) - end if - ! - ! -- Set pointer to ICELLTYPE. For GWF boundary packages, - ! this%ictMemPath will be 'NPF'. If boundary packages do not set - ! this%ictMemPath, then icelltype will remain as null() - if (this%ictMemPath /= '') then - call mem_setptr(this%icelltype, 'ICELLTYPE', this%ictMemPath) - end if - ! - ! -- Initialize values + !> @ brief Allocate package arrays + !! + !! Allocate and initialize base boundary package arrays. This method + !! only needs to be overridden if additional arrays are defined + !! for a specific package. + !! + !< + subroutine allocate_arrays(this, nodelist, auxvar) + ! -- modules + use MemoryManagerModule, only: mem_allocate, mem_setptr + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), dimension(:), pointer, contiguous, optional :: nodelist !< package nodelist + real(DP), dimension(:, :), pointer, contiguous, optional :: auxvar !< package aux variable array + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + ! + ! -- Point nodelist if it is passed in, otherwise allocate + if (present(nodelist)) then + this%nodelist => nodelist + else + call mem_allocate(this%nodelist, this%maxbound, 'NODELIST', & + this%memoryPath) do j = 1, this%maxbound - do i = 1, this%ncolbnd - this%bound(i, j) = DZERO - end do + this%nodelist(j) = 0 end do + end if + ! + ! -- noupdateauxvar (allows an external caller to stop auxvars from being + ! recalculated + call mem_allocate(this%noupdateauxvar, this%naux, 'NOUPDATEAUXVAR', & + this%memoryPath) + this%noupdateauxvar(:) = 0 + ! + ! -- Allocate the bound array + call mem_allocate(this%bound, this%ncolbnd, this%maxbound, 'BOUND', & + this%memoryPath) + ! + !-- Allocate array for storing user-specified conductances + ! Will be reallocated to size maxbound if vsc active + call mem_allocate(this%condinput, 0, 'CONDINPUT', this%memoryPath) + ! + ! -- Allocate hcof and rhs + call mem_allocate(this%hcof, this%maxbound, 'HCOF', this%memoryPath) + call mem_allocate(this%rhs, this%maxbound, 'RHS', this%memoryPath) + ! + ! -- Allocate the simvals array + call mem_allocate(this%simvals, this%maxbound, 'SIMVALS', this%memoryPath) + if (this%imover == 1) then + call mem_allocate(this%simtomvr, this%maxbound, 'SIMTOMVR', & + this%memoryPath) do i = 1, this%maxbound - this%hcof(i) = DZERO - this%rhs(i) = DZERO + this%simtomvr(i) = DZERO end do - ! - ! -- setup the output table - call this%pak_setup_outputtab() - ! - ! -- return - return - end subroutine allocate_arrays + else + call mem_allocate(this%simtomvr, 0, 'SIMTOMVR', this%memoryPath) + end if + ! + ! -- Point or allocate auxvar + if (present(auxvar)) then + this%auxvar => auxvar + else + call mem_allocate(this%auxvar, this%naux, this%maxbound, 'AUXVAR', & + this%memoryPath) + do i = 1, this%maxbound + do j = 1, this%naux + this%auxvar(j, i) = DZERO + end do + end do + end if + ! + ! -- Allocate boundname + if (this%inamedbound /= 0) then + call mem_allocate(this%boundname, LENBOUNDNAME, this%maxbound, & + 'BOUNDNAME', this%memoryPath) + call mem_allocate(this%boundname_cst, LENBOUNDNAME, this%maxbound, & + 'BOUNDNAME_CST', this%memoryPath) + else + call mem_allocate(this%boundname, LENBOUNDNAME, 0, & + 'BOUNDNAME', this%memoryPath) + call mem_allocate(this%boundname_cst, LENBOUNDNAME, 0, & + 'BOUNDNAME_CST', this%memoryPath) + end if + ! + ! -- Set pointer to ICELLTYPE. For GWF boundary packages, + ! this%ictMemPath will be 'NPF'. If boundary packages do not set + ! this%ictMemPath, then icelltype will remain as null() + if (this%ictMemPath /= '') then + call mem_setptr(this%icelltype, 'ICELLTYPE', this%ictMemPath) + end if + ! + ! -- Initialize values + do j = 1, this%maxbound + do i = 1, this%ncolbnd + this%bound(i, j) = DZERO + end do + end do + do i = 1, this%maxbound + this%hcof(i) = DZERO + this%rhs(i) = DZERO + end do + ! + ! -- setup the output table + call this%pak_setup_outputtab() + ! + ! -- return + return + end subroutine allocate_arrays - !> @ brief Allocate and initialize select package members + !> @ brief Allocate and initialize select package members !! - !! Allocate and initialize select base boundary package members. - !! This method needs to be overridden by a package if it is + !! Allocate and initialize select base boundary package members. + !! This method needs to be overridden by a package if it is !! needed for a specific package. !! - !< - subroutine pack_initialize(this) - ! -- dummy variables - class(BndType) :: this !< BndType object - ! - ! -- return - return - end subroutine pack_initialize + !< + subroutine pack_initialize(this) + ! -- dummy variables + class(BndType) :: this !< BndType object + ! + ! -- return + return + end subroutine pack_initialize - !> @ brief Set pointers to model variables + !> @ brief Set pointers to model variables !! !! Set pointers to model variables so that a package has access to these !! variables. This base method should not need to be overridden. !! - !< - subroutine set_pointers(this, neq, ibound, xnew, xold, flowja) - ! -- dummy variables - class(BndType) :: this !< BndType object - integer(I4B), pointer :: neq !< number of equations in the model - integer(I4B), dimension(:), pointer, contiguous :: ibound !< model idomain - real(DP), dimension(:), pointer, contiguous :: xnew !< current dependent variable - real(DP), dimension(:), pointer, contiguous :: xold !< previous dependent variable - real(DP), dimension(:), pointer, contiguous :: flowja !< connection flow terms - ! - ! -- Set the pointers - this%neq => neq - this%ibound => ibound - this%xnew => xnew - this%xold => xold - this%flowja => flowja - ! - ! -- return - end subroutine set_pointers + !< + subroutine set_pointers(this, neq, ibound, xnew, xold, flowja) + ! -- dummy variables + class(BndType) :: this !< BndType object + integer(I4B), pointer :: neq !< number of equations in the model + integer(I4B), dimension(:), pointer, contiguous :: ibound !< model idomain + real(DP), dimension(:), pointer, contiguous :: xnew !< current dependent variable + real(DP), dimension(:), pointer, contiguous :: xold !< previous dependent variable + real(DP), dimension(:), pointer, contiguous :: flowja !< connection flow terms + ! + ! -- Set the pointers + this%neq => neq + this%ibound => ibound + this%xnew => xnew + this%xold => xold + this%flowja => flowja + ! + ! -- return + end subroutine set_pointers - !> @ brief Read additional options for package + !> @ brief Read additional options for package !! !! Read base options for boundary packages. !! - !< - subroutine bnd_read_options(this) - ! -- modules - use InputOutputModule, only: urdaux - use MemoryManagerModule, only: mem_reallocate - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! -- local variables - character(len=:), allocatable :: line - character(len=LINELENGTH) :: fname - character(len=LINELENGTH) :: keyword - character(len=LENAUXNAME) :: sfacauxname - character(len=LENAUXNAME), dimension(:), allocatable :: caux - integer(I4B) :: lloc - integer(I4B) :: istart - integer(I4B) :: istop - integer(I4B) :: n - integer(I4B) :: ierr - integer(I4B) :: inobs - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - logical(LGP) :: foundchildclassoption - ! -- format - character(len=*),parameter :: fmtflow = & - "(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" - character(len=*),parameter :: fmtflow2 = & - "(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL')" - character(len=*), parameter :: fmttas = & - "(4x, 'TIME-ARRAY SERIES DATA WILL BE READ FROM FILE: ', a)" - character(len=*), parameter :: fmtts = & - "(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" - character(len=*), parameter :: fmtnme = & - "(a, i0, a)" - ! - ! -- set default options - ! - ! -- get options block - call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - ! - ! -- parse options block if detected - if (isfound) then - write(this%iout,'(/1x,a)') 'PROCESSING '//trim(adjustl(this%text)) & - //' OPTIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) then - exit + !< + subroutine bnd_read_options(this) + ! -- modules + use InputOutputModule, only: urdaux + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + character(len=:), allocatable :: line + character(len=LINELENGTH) :: fname + character(len=LINELENGTH) :: keyword + character(len=LENAUXNAME) :: sfacauxname + character(len=LENAUXNAME), dimension(:), allocatable :: caux + integer(I4B) :: lloc + integer(I4B) :: istart + integer(I4B) :: istop + integer(I4B) :: n + integer(I4B) :: ierr + integer(I4B) :: inobs + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + logical(LGP) :: foundchildclassoption + ! -- format + character(len=*), parameter :: fmtflow = & + &"(4x, 'FLOWS WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + character(len=*), parameter :: fmtflow2 = & + &"(4x, 'FLOWS WILL BE SAVED TO BUDGET FILE SPECIFIED IN OUTPUT CONTROL')" + character(len=*), parameter :: fmttas = & + &"(4x, 'TIME-ARRAY SERIES DATA WILL BE READ FROM FILE: ', a)" + character(len=*), parameter :: fmtts = & + &"(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" + character(len=*), parameter :: fmtnme = & + &"(a, i0, a)" + ! + ! -- set default options + ! + ! -- get options block + call this%parser%GetBlock('OPTIONS', isfound, ierr, & + supportOpenClose=.true., blockRequired=.false.) + ! + ! -- parse options block if detected + if (isfound) then + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text)) & + //' OPTIONS' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) then + exit + end if + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('AUX', 'AUXILIARY') + call this%parser%GetRemainingLine(line) + lloc = 1 + call urdaux(this%naux, this%parser%iuactive, this%iout, lloc, & + istart, istop, caux, line, this%text) + call mem_reallocate(this%auxname, LENAUXNAME, this%naux, & + 'AUXNAME', this%memoryPath) + call mem_reallocate(this%auxname_cst, LENAUXNAME, this%naux, & + 'AUXNAME_CST', this%memoryPath) + do n = 1, this%naux + this%auxname(n) = caux(n) + this%auxname_cst(n) = caux(n) + end do + deallocate (caux) + case ('SAVE_FLOWS') + this%ipakcb = -1 + write (this%iout, fmtflow2) + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, '(4x,a)') & + 'LISTS OF '//trim(adjustl(this%text))//' CELLS WILL BE PRINTED.' + case ('PRINT_FLOWS') + this%iprflow = 1 + write (this%iout, '(4x,a)') trim(adjustl(this%text))// & + ' FLOWS WILL BE PRINTED TO LISTING FILE.' + case ('BOUNDNAMES') + this%inamedbound = 1 + write (this%iout, '(4x,a)') trim(adjustl(this%text))// & + ' BOUNDARIES HAVE NAMES IN LAST COLUMN.' + case ('TS6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' + call store_error(errmsg) + end if + call this%parser%GetString(fname) + write (this%iout, fmtts) trim(fname) + call this%TsManager%add_tsfile(fname, this%inunit) + case ('TAS6') + if (this%AllowTimeArraySeries) then + if (.not. this%dis%supports_layers()) then + errmsg = 'TAS6 FILE cannot be used '// & + 'with selected discretization type.' + call store_error(errmsg) + end if + else + errmsg = 'The '//trim(this%filtyp)// & + ' package does not support TIMEARRAYSERIESFILE' + call store_error(errmsg) + call this%parser%StoreErrorUnit() end if call this%parser%GetStringCaps(keyword) - select case (keyword) - case('AUX', 'AUXILIARY') - call this%parser%GetRemainingLine(line) - lloc = 1 - call urdaux(this%naux, this%parser%iuactive, this%iout, lloc, & - istart, istop, caux, line, this%text) - call mem_reallocate(this%auxname, LENAUXNAME, this%naux, & - 'AUXNAME', this%memoryPath) - do n = 1, this%naux - this%auxname(n) = caux(n) - end do - deallocate(caux) - case ('SAVE_FLOWS') - this%ipakcb = -1 - write(this%iout, fmtflow2) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout,'(4x,a)') 'LISTS OF '//trim(adjustl(this%text))// & - ' CELLS WILL BE PRINTED.' - case ('PRINT_FLOWS') - this%iprflow = 1 - write(this%iout,'(4x,a)') trim(adjustl(this%text))// & - ' FLOWS WILL BE PRINTED TO LISTING FILE.' - case ('BOUNDNAMES') - this%inamedbound = 1 - write(this%iout,'(4x,a)') trim(adjustl(this%text))// & - ' BOUNDARIES HAVE NAMES IN LAST COLUMN.' - case ('TS6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - endif - call this%parser%GetString(fname) - write(this%iout,fmtts)trim(fname) - call this%TsManager%add_tsfile(fname, this%inunit) - case ('TAS6') - if (this%AllowTimeArraySeries) then - if (.not. this%dis%supports_layers()) then - errmsg = 'TAS6 FILE cannot be used ' // & - 'with selected discretization type.' - call store_error(errmsg) - endif - else - errmsg = 'The ' // trim(this%filtyp) // & - ' package does not support TIMEARRAYSERIESFILE' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TAS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - write(this%iout,fmttas)trim(fname) - call this%TasManager%add_tasfile(fname) - case ('AUXMULTNAME') - call this%parser%GetStringCaps(sfacauxname) - this%iauxmultcol = -1 - write(this%iout, '(4x,a,a)') & - 'AUXILIARY MULTIPLIER NAME: ', sfacauxname - case ('OBS6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'OBS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - if (this%obs%active) then - errmsg = 'Multiple OBS6 keywords detected in OPTIONS block. ' // & - 'Only one OBS6 entry allowed for a package.' - call store_error(errmsg) - endif - this%obs%active = .true. - call this%parser%GetString(this%obs%inputFilename) - inobs = GetUnit() - call openfile(inobs, this%iout, this%obs%inputFilename, 'OBS') - this%obs%inUnitObs = inobs - ! - ! -- right now these are options that are only available in the - ! development version and are not included in the documentation. - ! These options are only available when IDEVELOPMODE in - ! constants module is set to 1 - case ('DEV_NO_NEWTON') - call this%parser%DevOpt() - this%inewton = 0 - write(this%iout, '(4x,a)') & - 'NEWTON-RAPHSON method disabled for unconfined cells' - case default - ! - ! -- Check for child class options - call this%bnd_options(keyword, foundchildclassoption) - ! - ! -- No child class options found, so print error message - if(.not. foundchildclassoption) then - write(errmsg,'(a,3(1x,a))') & - 'UNKNOWN', trim(adjustl(this%text)), 'OPTION:', trim(keyword) - call store_error(errmsg) - endif - end select - end do - write(this%iout,'(1x,a)') 'END OF '//trim(adjustl(this%text)) // ' OPTIONS' - else - write(this%iout,'(1x,a)') 'NO '//trim(adjustl(this%text)) // & - ' OPTION BLOCK DETECTED.' + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TAS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + write (this%iout, fmttas) trim(fname) + call this%TasManager%add_tasfile(fname) + case ('AUXMULTNAME') + call this%parser%GetStringCaps(sfacauxname) + this%iauxmultcol = -1 + write (this%iout, '(4x,a,a)') & + 'AUXILIARY MULTIPLIER NAME: ', sfacauxname + case ('OBS6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'OBS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end if + if (this%obs%active) then + errmsg = 'Multiple OBS6 keywords detected in OPTIONS block. '// & + 'Only one OBS6 entry allowed for a package.' + call store_error(errmsg) + end if + this%obs%active = .true. + call this%parser%GetString(this%obs%inputFilename) + inobs = GetUnit() + call openfile(inobs, this%iout, this%obs%inputFilename, 'OBS') + this%obs%inUnitObs = inobs + ! + ! -- right now these are options that are only available in the + ! development version and are not included in the documentation. + ! These options are only available when IDEVELOPMODE in + ! constants module is set to 1 + case ('DEV_NO_NEWTON') + call this%parser%DevOpt() + this%inewton = 0 + write (this%iout, '(4x,a)') & + 'NEWTON-RAPHSON method disabled for unconfined cells' + case default + ! + ! -- Check for child class options + call this%bnd_options(keyword, foundchildclassoption) + ! + ! -- No child class options found, so print error message + if (.not. foundchildclassoption) then + write (errmsg, '(a,3(1x,a))') & + 'UNKNOWN', trim(adjustl(this%text)), 'OPTION:', trim(keyword) + call store_error(errmsg) + end if + end select + end do + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' OPTIONS' + else + write (this%iout, '(1x,a)') 'NO '//trim(adjustl(this%text))// & + ' OPTION BLOCK DETECTED.' + end if + ! + ! -- AUXMULTNAME was specified, so find column of auxvar that will be multiplier + if (this%iauxmultcol < 0) then + ! + ! -- Error if no aux variable specified + if (this%naux == 0) then + write (errmsg, '(a,2(1x,a))') & + 'AUXMULTNAME WAS SPECIFIED AS', trim(adjustl(sfacauxname)), & + 'BUT NO AUX VARIABLES SPECIFIED.' + call store_error(errmsg) end if ! - ! -- AUXMULTNAME was specified, so find column of auxvar that will be multiplier - if(this%iauxmultcol < 0) then - ! - ! -- Error if no aux variable specified - if(this%naux == 0) then - write(errmsg,'(a,2(1x,a))') & - 'AUXMULTNAME WAS SPECIFIED AS', trim(adjustl(sfacauxname)), & - 'BUT NO AUX VARIABLES SPECIFIED.' - call store_error(errmsg) - endif - ! - ! -- Assign mult column - this%iauxmultcol = 0 - do n = 1, this%naux - if(sfacauxname == this%auxname(n)) then - this%iauxmultcol = n - exit - endif - enddo - ! - ! -- Error if aux variable cannot be found - if(this%iauxmultcol == 0) then - write(errmsg,'(a,2(1x,a))') & - 'AUXMULTNAME WAS SPECIFIED AS', trim(adjustl(sfacauxname)), & - 'BUT NO AUX VARIABLE FOUND WITH THIS NAME.' - call store_error(errmsg) - endif - end if + ! -- Assign mult column + this%iauxmultcol = 0 + do n = 1, this%naux + if (sfacauxname == this%auxname(n)) then + this%iauxmultcol = n + exit + end if + end do ! - ! -- terminate if errors were detected - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() + ! -- Error if aux variable cannot be found + if (this%iauxmultcol == 0) then + write (errmsg, '(a,2(1x,a))') & + 'AUXMULTNAME WAS SPECIFIED AS', trim(adjustl(sfacauxname)), & + 'BUT NO AUX VARIABLE FOUND WITH THIS NAME.' + call store_error(errmsg) end if - ! - ! -- return - return - end subroutine bnd_read_options + end if + ! + ! -- terminate if errors were detected + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine bnd_read_options - !> @ brief Read dimensions for package + !> @ brief Read dimensions for package !! !! Read base dimensions for boundary packages. This method should not !! need to be overridden unless more than MAXBOUND is specified in the !! DIMENSIONS block. !! - !< - subroutine bnd_read_dimensions(this) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! -- local variables - character(len=LINELENGTH) :: keyword - logical(LGP) :: isfound - logical(LGP) :: endOfBlock - integer(I4B) :: ierr - ! - ! -- get dimensions block - call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) - ! - ! -- parse dimensions block if detected - if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(this%text))// & - ' DIMENSIONS' - do - call this%parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call this%parser%GetStringCaps(keyword) - select case (keyword) - case ('MAXBOUND') - this%maxbound = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)') 'MAXBOUND = ', this%maxbound - case default - write(errmsg,'(a,3(1x,a))') & - 'UNKNOWN', trim(this%text), 'DIMENSION:', trim(keyword) - call store_error(errmsg) - end select - end do - ! - write(this%iout,'(1x,a)')'END OF '//trim(adjustl(this%text))//' DIMENSIONS' - else - call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') - call this%parser%StoreErrorUnit() - end if + !< + subroutine bnd_read_dimensions(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + character(len=LINELENGTH) :: keyword + logical(LGP) :: isfound + logical(LGP) :: endOfBlock + integer(I4B) :: ierr + ! + ! -- get dimensions block + call this%parser%GetBlock('DIMENSIONS', isfound, ierr, & + supportOpenClose=.true.) + ! + ! -- parse dimensions block if detected + if (isfound) then + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(this%text))// & + ' DIMENSIONS' + do + call this%parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call this%parser%GetStringCaps(keyword) + select case (keyword) + case ('MAXBOUND') + this%maxbound = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'MAXBOUND = ', this%maxbound + case default + write (errmsg, '(a,3(1x,a))') & + 'UNKNOWN', trim(this%text), 'DIMENSION:', trim(keyword) + call store_error(errmsg) + end select + end do ! - ! -- verify dimensions were set - if(this%maxbound <= 0) then - write(errmsg, '(a)') 'MAXBOUND MUST BE AN INTEGER GREATER THAN ZERO.' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(this%text))//' DIMENSIONS' + else + call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') + call this%parser%StoreErrorUnit() + end if + ! + ! -- verify dimensions were set + if (this%maxbound <= 0) then + write (errmsg, '(a)') 'MAXBOUND MUST BE AN INTEGER GREATER THAN ZERO.' + call store_error(errmsg) + end if + ! + ! -- terminate if there are errors + if (count_errors() > 0) then + call this%parser%StoreErrorUnit() + end if + ! + ! -- Call define_listlabel to construct the list label that is written + ! when PRINT_INPUT option is used. + call this%define_listlabel() + ! + ! -- return + return + end subroutine bnd_read_dimensions + + !> @ brief Store user-specified conductances when vsc is active + !! + !! VSC will update boundary package conductance values. Because + !! viscosity can change every stress period, but user-specified + !! conductances may not, the base user-input should be stored in + !! backup array so that viscosity-updated conductances may be + !! recalculated every stress period/time step + !! + !< + subroutine bnd_store_user_cond(this, nlist, nodelist, rlist, condinput) + ! -- modules + use SimModule, only: store_error + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B), intent(in) :: nlist + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: nodelist + real(DP), dimension(:, :), pointer, contiguous, intent(in) :: rlist + real(DP), dimension(:), pointer, contiguous, intent(inout) :: condinput + ! -- local variables + integer(I4B) :: l + integer(I4B) :: nodeu, noder + character(len=LINELENGTH) :: nodestr + ! + ! -- store backup copy of conductance values + do l = 1, nlist + nodeu = nodelist(l) + noder = this%dis%get_nodenumber(nodeu, 0) + if (noder <= 0) then + call this%dis%nodeu_to_string(nodeu, nodestr) + write (errmsg, *) & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) end if - ! - ! -- terminate if there are errors - if (count_errors() > 0) then - call this%parser%StoreErrorUnit() - end if - ! - ! -- Call define_listlabel to construct the list label that is written - ! when PRINT_INPUT option is used. - call this%define_listlabel() - ! - ! -- return - return - end subroutine bnd_read_dimensions + condinput(l) = rlist(2, l) + end do + ! + ! -- return + return + end subroutine - !> @ brief Read initial parameters for package + !> @ brief Read initial parameters for package !! !! Read initial parameters for a boundary package. This method is not !! needed for most boundary packages. The SFR package is an example of a !! package that has overridden this method. !! - !< - subroutine bnd_read_initial_attr(this) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! - ! -- return - return - end subroutine bnd_read_initial_attr + !< + subroutine bnd_read_initial_attr(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! + ! -- return + return + end subroutine bnd_read_initial_attr - !> @ brief Read additional options for package + !> @ brief Read additional options for package !! !! Read additional options for a boundary package. This method should !! be overridden options in addition to the base options are implemented !! in a boundary package. !! - !< - subroutine bnd_options(this, option, found) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - character(len=*), intent(inout) :: option !< option keyword string - logical(LGP), intent(inout) :: found !< boolean indicating if the option was found - ! - ! Return with found = .false. - found = .false. - ! - ! -- return - return - end subroutine bnd_options + !< + subroutine bnd_options(this, option, found) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + character(len=*), intent(inout) :: option !< option keyword string + logical(LGP), intent(inout) :: found !< boolean indicating if the option was found + ! + ! Return with found = .false. + found = .false. + ! + ! -- return + return + end subroutine bnd_options - !> @ brief Setup output table for package + !> @ brief Copy boundnames into boundnames_cst + !! + !! boundnames_cst is an array of type(CharacterStringType), + !! which can be stored in the MemoryManager. + !! + !< + subroutine copy_boundname(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + integer(I4B) :: i + ! + ! copy from boundname to boundname_cst, which can be + ! stored in the memory manager + if (this%inamedbound /= 0) then + do i = 1, size(this%boundname) + this%boundname_cst(i) = this%boundname(i) + end do + end if + ! + ! -- return + return + end subroutine copy_boundname + + !> @ brief Setup output table for package !! !! Setup output table for a boundary package that is used to output !! package to model flow terms to the model listing file. !! - !< - subroutine pak_setup_outputtab(this) - ! -- dummy variables - class(BndType),intent(inout) :: this !< BndType object - ! -- local variables - character(len=LINELENGTH) :: title - character(len=LINELENGTH) :: text - integer(I4B) :: ntabcol + !< + subroutine pak_setup_outputtab(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + character(len=LINELENGTH) :: title + character(len=LINELENGTH) :: text + integer(I4B) :: ntabcol + ! + ! -- allocate and initialize the output table + if (this%iprflow /= 0) then ! - ! -- allocate and initialize the output table - if (this%iprflow /= 0) then - ! - ! -- dimension table - ntabcol = 3 - if (this%inamedbound > 0) then - ntabcol = ntabcol + 1 - end if - ! - ! -- initialize the output table object - title = trim(adjustl(this%text)) // ' PACKAGE (' // trim(this%packName) // & - ') FLOW RATES' - call table_cr(this%outputtab, this%packName, title) - call this%outputtab%table_df(this%maxbound, ntabcol, this%iout, & - transient=.TRUE.) - text = 'NUMBER' - call this%outputtab%initialize_column(text, 10, alignment=TABCENTER) - text = 'CELLID' - call this%outputtab%initialize_column(text, 20, alignment=TABLEFT) - text = 'RATE' - call this%outputtab%initialize_column(text, 15, alignment=TABCENTER) - if (this%inamedbound > 0) then - text = 'NAME' - call this%outputtab%initialize_column(text, LENBOUNDNAME, alignment=TABLEFT) - end if + ! -- dimension table + ntabcol = 3 + if (this%inamedbound > 0) then + ntabcol = ntabcol + 1 end if ! - ! -- return - return - end subroutine pak_setup_outputtab - + ! -- initialize the output table object + title = trim(adjustl(this%text))//' PACKAGE ('//trim(this%packName)// & + ') FLOW RATES' + call table_cr(this%outputtab, this%packName, title) + call this%outputtab%table_df(this%maxbound, ntabcol, this%iout, & + transient=.TRUE.) + text = 'NUMBER' + call this%outputtab%initialize_column(text, 10, alignment=TABCENTER) + text = 'CELLID' + call this%outputtab%initialize_column(text, 20, alignment=TABLEFT) + text = 'RATE' + call this%outputtab%initialize_column(text, 15, alignment=TABCENTER) + if (this%inamedbound > 0) then + text = 'NAME' + call this%outputtab%initialize_column(text, LENBOUNDNAME, & + alignment=TABLEFT) + end if + end if + ! + ! -- return + return + end subroutine pak_setup_outputtab - !> @ brief Define the list label for the package + !> @ brief Define the list label for the package !! !! Method defined the list label for the boundary package. This method !! needs to be overridden by each boundary package. !! - !< - subroutine define_listlabel(this) - ! -- dummy variables - class(BndType), intent(inout) :: this !< BndType object - ! - ! -- return - return - end subroutine define_listlabel + !< + subroutine define_listlabel(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! + ! -- return + return + end subroutine define_listlabel - ! -- Procedures related to observations + ! -- Procedures related to observations - !> @brief Determine if observations are supported. + !> @brief Determine if observations are supported. !! !! Function to determine if observations are supported by the boundary package. !! By default, observations are not supported. This method should be overridden @@ -1546,405 +1667,441 @@ end subroutine define_listlabel !! !! @return supported boolean indicating if observations are supported !! - !< - function bnd_obs_supported(this) result(supported) - ! -- return variable - logical(LGP) :: supported !< boolean indicating if observations are supported - ! -- dummy variables - class(BndType) :: this !< BndType object - ! - ! -- initialize return variables - supported = .false. - ! - ! -- return - return - end function bnd_obs_supported + !< + function bnd_obs_supported(this) result(supported) + ! -- return variable + logical(LGP) :: supported !< boolean indicating if observations are supported + ! -- dummy variables + class(BndType) :: this !< BndType object + ! + ! -- initialize return variables + supported = .false. + ! + ! -- return + return + end function bnd_obs_supported - !> @brief Define the observation types available in the package + !> @brief Define the observation types available in the package !! - !! Method to define the observation types available in a boundary - !! package. This method should be overridden if observations are + !! Method to define the observation types available in a boundary + !! package. This method should be overridden if observations are !! supported in a boundary package. !! - !< - subroutine bnd_df_obs(this) - ! - ! -- dummy variables - class(BndType) :: this !< BndType object - ! - ! -- do nothing here. Override as needed. - ! - ! -- return - return - end subroutine bnd_df_obs + !< + subroutine bnd_df_obs(this) + ! + ! -- dummy variables + class(BndType) :: this !< BndType object + ! + ! -- do nothing here. Override as needed. + ! + ! -- return + return + end subroutine bnd_df_obs - !> @brief Read and prepare observations for a package + !> @brief Read and prepare observations for a package !! !! Method to read and prepare observations for a boundary package !! This method should not need to be overridden for most boundary !! packages. !! - !< - subroutine bnd_rp_obs(this) - ! -- dummy variables - class(BndType), intent(inout) :: this !< BndType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: j - class(ObserveType), pointer :: obsrv => null() - character(len=LENBOUNDNAME) :: bname - logical(LGP) :: jfound + !< + subroutine bnd_rp_obs(this) + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: j + class(ObserveType), pointer :: obsrv => null() + character(len=LENBOUNDNAME) :: bname + logical(LGP) :: jfound + ! + if (.not. this%bnd_obs_supported()) return + ! + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv ! - if (.not. this%bnd_obs_supported()) return + ! -- indxbnds needs to be reset each stress period because + ! list of boundaries can change each stress period. + call obsrv%ResetObsIndex() + obsrv%BndFound = .false. ! - do i = 1, this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv + bname = obsrv%FeatureName + if (bname /= '') then ! - ! -- indxbnds needs to be reset each stress period because - ! list of boundaries can change each stress period. - call obsrv%ResetObsIndex() - obsrv%BndFound = .false. + ! -- Observation location(s) is(are) based on a boundary name. + ! Iterate through all boundaries to identify and store + ! corresponding index(indices) in bound array. + jfound = .false. + do j = 1, this%nbound + if (this%boundname(j) == bname) then + jfound = .true. + obsrv%BndFound = .true. + obsrv%CurrentTimeStepEndValue = DZERO + call obsrv%AddObsIndex(j) + end if + end do + else ! - bname = obsrv%FeatureName - if (bname /= '') then - ! - ! -- Observation location(s) is(are) based on a boundary name. - ! Iterate through all boundaries to identify and store - ! corresponding index(indices) in bound array. - jfound = .false. - do j=1,this%nbound - if (this%boundname(j) == bname) then - jfound = .true. - obsrv%BndFound = .true. - obsrv%CurrentTimeStepEndValue = DZERO - call obsrv%AddObsIndex(j) - end if - end do - else - ! - ! -- Observation location is a single node number - jfound = .false. - jloop: do j=1,this%nbound - if (this%nodelist(j) == obsrv%NodeNumber) then - jfound = .true. - obsrv%BndFound = .true. - obsrv%CurrentTimeStepEndValue = DZERO - call obsrv%AddObsIndex(j) - end if - end do jloop - end if - end do - ! - if (count_errors() > 0) then - call store_error_unit(this%inunit) - endif - ! - return - end subroutine bnd_rp_obs + ! -- Observation location is a single node number + jfound = .false. + jloop: do j = 1, this%nbound + if (this%nodelist(j) == obsrv%NodeNumber) then + jfound = .true. + obsrv%BndFound = .true. + obsrv%CurrentTimeStepEndValue = DZERO + call obsrv%AddObsIndex(j) + end if + end do jloop + end if + end do + ! + if (count_errors() > 0) then + call store_error_unit(this%inunit) + end if + ! + return + end subroutine bnd_rp_obs - !> @brief Save observations for the package + !> @brief Save observations for the package !! !! Method to save simulated values for the boundary package. !! This method will need to be overridden for boundary packages !! with more observations than the calculate flow term (simvals) !! and to-mover. !! - !< - subroutine bnd_bd_obs(this) - ! -- dummy variables - class(BndType) :: this !< BndType object - ! -- local variables - integer(I4B) :: i - integer(I4B) :: n - real(DP) :: v - type(ObserveType), pointer :: obsrv => null() - ! - ! -- clear the observations - call this%obs%obs_bd_clear() - ! - ! -- Save simulated values for all of package's observations. - do i = 1, this%obs%npakobs - obsrv => this%obs%pakobs(i)%obsrv - if (obsrv%BndFound) then - do n = 1, obsrv%indxbnds_count - if (obsrv%ObsTypeId == 'TO-MVR') then - if (this%imover == 1) then - v = this%pakmvrobj%get_qtomvr(obsrv%indxbnds(n)) - if (v > DZERO) then - v = -v - end if - else - v = DNODATA + !< + subroutine bnd_bd_obs(this) + ! -- dummy variables + class(BndType) :: this !< BndType object + ! -- local variables + integer(I4B) :: i + integer(I4B) :: n + real(DP) :: v + type(ObserveType), pointer :: obsrv => null() + ! + ! -- clear the observations + call this%obs%obs_bd_clear() + ! + ! -- Save simulated values for all of package's observations. + do i = 1, this%obs%npakobs + obsrv => this%obs%pakobs(i)%obsrv + if (obsrv%BndFound) then + do n = 1, obsrv%indxbnds_count + if (obsrv%ObsTypeId == 'TO-MVR') then + if (this%imover == 1) then + v = this%pakmvrobj%get_qtomvr(obsrv%indxbnds(n)) + if (v > DZERO) then + v = -v end if else - v = this%simvals(obsrv%indxbnds(n)) + v = DNODATA end if - call this%obs%SaveOneSimval(obsrv, v) - end do - else - call this%obs%SaveOneSimval(obsrv, DNODATA) - end if - end do - ! - ! -- return - return - end subroutine bnd_bd_obs + else + v = this%simvals(obsrv%indxbnds(n)) + end if + call this%obs%SaveOneSimval(obsrv, v) + end do + else + call this%obs%SaveOneSimval(obsrv, DNODATA) + end if + end do + ! + ! -- return + return + end subroutine bnd_bd_obs - !> @brief Output observations for the package + !> @brief Output observations for the package !! !! Method to output simulated values for the boundary package. !! This method should not need to be overridden. !! - !< - subroutine bnd_ot_obs(this) - ! -- dummy variables - class(BndType) :: this !< BndType object - ! - ! -- call the observation output method - call this%obs%obs_ot() - ! - ! -- return - return - end subroutine bnd_ot_obs + !< + subroutine bnd_ot_obs(this) + ! -- dummy variables + class(BndType) :: this !< BndType object + ! + ! -- call the observation output method + call this%obs%obs_ot() + ! + ! -- return + return + end subroutine bnd_ot_obs - ! -- Procedures related to time series + ! -- Procedures related to time series - !> @brief Assign time series links for the package + !> @brief Assign time series links for the package !! !! Assign the time series links for the boundary package. This !! method will need to be overridden for boundary packages that !! support time series. !! - !< - subroutine bnd_rp_ts(this) - ! -- dummy variables - class(BndType), intent(inout) :: this - ! - ! -- return - return - end subroutine bnd_rp_ts + !< + subroutine bnd_rp_ts(this) + ! -- dummy variables + class(BndType), intent(inout) :: this + ! + ! -- return + return + end subroutine bnd_rp_ts - ! -- Procedures related to casting + ! -- Procedures related to casting - !> @brief Cast as a boundary tyoe + !> @brief Cast as a boundary tyoe !! !! Subroutine to cast an object as a boundary package type. !! - !< - function CastAsBndClass(obj) result(res) - class(*), pointer, intent(inout) :: obj !< input object - class(BndType), pointer :: res !< output class of type BndType - ! - ! -- initialize res - res => null() - ! - ! -- make sure obj is associated - if (.not. associated(obj)) return - ! - ! -- point res to obj - select type (obj) - class is (BndType) - res => obj - end select - ! - ! -- return - return - end function CastAsBndClass + !< + function CastAsBndClass(obj) result(res) + class(*), pointer, intent(inout) :: obj !< input object + class(BndType), pointer :: res !< output class of type BndType + ! + ! -- initialize res + res => null() + ! + ! -- make sure obj is associated + if (.not. associated(obj)) return + ! + ! -- point res to obj + select type (obj) + class is (BndType) + res => obj + end select + ! + ! -- return + return + end function CastAsBndClass - !> @brief Add boundary to package list + !> @brief Add boundary to package list !! !! Subroutine to add a boundary package to a package list. !! - !< - subroutine AddBndToList(list, bnd) - ! -- dummy variables - type(ListType), intent(inout) :: list !< package list - class(BndType), pointer, intent(inout) :: bnd !< boundary package - ! -- local variables - class(*), pointer :: obj - ! - obj => bnd - call list%Add(obj) - ! - ! -- return - return - end subroutine AddBndToList + !< + subroutine AddBndToList(list, bnd) + ! -- dummy variables + type(ListType), intent(inout) :: list !< package list + class(BndType), pointer, intent(inout) :: bnd !< boundary package + ! -- local variables + class(*), pointer :: obj + ! + obj => bnd + call list%Add(obj) + ! + ! -- return + return + end subroutine AddBndToList - !> @brief Get boundary from package list + !> @brief Get boundary from package list !! !! Function to get a boundary package from a package list. !! !! @return res boundary package object !! - !< - function GetBndFromList(list, idx) result (res) - ! -- dummy variables - type(ListType), intent(inout) :: list !< package list - integer(I4B), intent(in) :: idx !< package number - class(BndType), pointer :: res !< boundary package idx - ! -- local variables - class(*), pointer :: obj - ! - ! -- get the package from the list - obj => list%GetItem(idx) - res => CastAsBndClass(obj) - ! - ! -- return - return - end function GetBndFromList + !< + function GetBndFromList(list, idx) result(res) + ! -- dummy variables + type(ListType), intent(inout) :: list !< package list + integer(I4B), intent(in) :: idx !< package number + class(BndType), pointer :: res !< boundary package idx + ! -- local variables + class(*), pointer :: obj + ! + ! -- get the package from the list + obj => list%GetItem(idx) + res => CastAsBndClass(obj) + ! + ! -- return + return + end function GetBndFromList - !> @brief Save and/or print flows for a package + !> @brief Save and/or print flows for a package !! !! Subroutine to save and/or print package flows to a model to a !! binary cell-by-cell flow file and the model listing file. !! - !< - subroutine save_print_model_flows(icbcfl, ibudfl, icbcun, iprflow, & - outputtab, nbound, nodelist, flow, ibound, title, text, ipakcb, dis, naux, & - textmodel, textpackage, dstmodel, dstpackage, auxname, auxvar, iout, & - inamedbound, boundname, imap) - ! -- modules - use TdisModule, only: kstp, kper - ! -- dummy variables - integer(I4B), intent(in) :: icbcfl !< flag indicating if the flow should be saved to the binary cell-by-cell flow file - integer(I4B), intent(in) :: ibudfl !< flag indicating if the flow should be saved or printed - integer(I4B), intent(in) :: icbcun !< file unit number for the binary cell-by-cell file - integer(I4B), intent(in) :: iprflow !< print flows to list file - type(TableType), pointer, intent(inout) :: outputtab !< output table object - integer(I4B), intent(in) :: nbound !< number of boundaries this stress period - integer(I4B), dimension(:), contiguous, intent(in) :: nodelist !< boundary node list - real(DP), dimension(:), contiguous, intent(in) :: flow !< boundary flow terms - integer(I4B), dimension(:), contiguous, intent(in) :: ibound !< ibound array for the model - character(len=*), intent(in) :: title !< title for the output table - character(len=*), intent(in) :: text !< flow term description - integer(I4B), intent(in) :: ipakcb !< flag indicating if flows will be saved - class(DisBaseType), intent(in) :: dis !< model discretization object - integer(I4B), intent(in) :: naux !< number of aux variables - character(len=*), intent(in) :: textmodel !< model name - character(len=*), intent(in) :: textpackage !< package name - character(len=*), intent(in) :: dstmodel !< mover destination model - character(len=*), intent(in) :: dstpackage !< mover destination package - character(len=*), dimension(:), intent(in) :: auxname !< aux variable name - real(DP), dimension(:, :), intent(in) :: auxvar !< aux variable - integer(I4B), intent(in) :: iout !< model listing file unit - integer(I4B), intent(in) :: inamedbound !< flag indicating if boundnames are defined for the boundary entries - character(len=LENBOUNDNAME), dimension(:), contiguous :: boundname !< bound names - integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping array - ! -- local variables - character(len=20) :: nodestr - integer(I4B) :: nodeu - integer(I4B) :: maxrows - integer(I4B) :: i - integer(I4B) :: node - integer(I4B) :: n2 - integer(I4B) :: ibinun - integer(I4B) :: nboundcount - real(DP) :: rrate - ! -- for observations - character(len=LENBOUNDNAME) :: bname - ! - ! -- set table kstp and kper - if (iprflow /= 0) then - call outputtab%set_kstpkper(kstp, kper) - end if - ! - ! -- set maxrows - maxrows = 0 - if (ibudfl /= 0 .and. iprflow /= 0) then - do i = 1, nbound - node = nodelist(i) - if (node > 0) then - maxrows = maxrows + 1 - end if - end do - if (maxrows > 0) then - call outputtab%set_maxbound(maxrows) + !< + subroutine save_print_model_flows(icbcfl, ibudfl, icbcun, iprflow, & + outputtab, nbound, nodelist, flow, ibound, & + title, text, ipakcb, dis, naux, textmodel, & + textpackage, dstmodel, dstpackage, & + auxname, auxvar, iout, inamedbound, & + boundname, imap) + ! -- modules + use TdisModule, only: kstp, kper + ! -- dummy variables + integer(I4B), intent(in) :: icbcfl !< flag indicating if the flow should be saved to the binary cell-by-cell flow file + integer(I4B), intent(in) :: ibudfl !< flag indicating if the flow should be saved or printed + integer(I4B), intent(in) :: icbcun !< file unit number for the binary cell-by-cell file + integer(I4B), intent(in) :: iprflow !< print flows to list file + type(TableType), pointer, intent(inout) :: outputtab !< output table object + integer(I4B), intent(in) :: nbound !< number of boundaries this stress period + integer(I4B), dimension(:), contiguous, intent(in) :: nodelist !< boundary node list + real(DP), dimension(:), contiguous, intent(in) :: flow !< boundary flow terms + integer(I4B), dimension(:), contiguous, intent(in) :: ibound !< ibound array for the model + character(len=*), intent(in) :: title !< title for the output table + character(len=*), intent(in) :: text !< flow term description + integer(I4B), intent(in) :: ipakcb !< flag indicating if flows will be saved + class(DisBaseType), intent(in) :: dis !< model discretization object + integer(I4B), intent(in) :: naux !< number of aux variables + character(len=*), intent(in) :: textmodel !< model name + character(len=*), intent(in) :: textpackage !< package name + character(len=*), intent(in) :: dstmodel !< mover destination model + character(len=*), intent(in) :: dstpackage !< mover destination package + character(len=*), dimension(:), intent(in) :: auxname !< aux variable name + real(DP), dimension(:, :), intent(in) :: auxvar !< aux variable + integer(I4B), intent(in) :: iout !< model listing file unit + integer(I4B), intent(in) :: inamedbound !< flag indicating if boundnames are defined for the boundary entries + character(len=LENBOUNDNAME), dimension(:), contiguous :: boundname !< bound names + integer(I4B), dimension(:), optional, intent(in) :: imap !< mapping array + ! -- local variables + character(len=20) :: nodestr + integer(I4B) :: nodeu + integer(I4B) :: maxrows + integer(I4B) :: i + integer(I4B) :: node + integer(I4B) :: n2 + integer(I4B) :: ibinun + integer(I4B) :: nboundcount + real(DP) :: rrate + ! -- for observations + character(len=LENBOUNDNAME) :: bname + ! + ! -- set table kstp and kper + if (iprflow /= 0) then + call outputtab%set_kstpkper(kstp, kper) + end if + ! + ! -- set maxrows + maxrows = 0 + if (ibudfl /= 0 .and. iprflow /= 0) then + do i = 1, nbound + node = nodelist(i) + if (node > 0) then + maxrows = maxrows + 1 end if - call outputtab%set_title(title) - end if - ! - ! -- Set unit number for binary output - if (ipakcb < 0) then - ibinun = icbcun - else if (ipakcb == 0) then - ibinun = 0 - else - ibinun = ipakcb - end if - if (icbcfl == 0) then - ibinun = 0 + end do + if (maxrows > 0) then + call outputtab%set_maxbound(maxrows) end if - ! - ! -- If cell-by-cell flows will be saved as a list, write header. - if(ibinun /= 0) then - ! - ! -- Count nbound as the number of entries with node > 0 - ! SFR, for example, can have a 'none' connection, which - ! means it should be excluded from budget file - nboundcount = 0 - do i = 1, nbound - node = nodelist(i) - if (node > 0) nboundcount = nboundcount + 1 - end do - call dis%record_srcdst_list_header(text, textmodel, textpackage, & - dstmodel, dstpackage, naux, & - auxname, ibinun, nboundcount, iout) - endif - ! - ! -- If no boundaries, skip flow calculations. - if (nbound > 0) then + call outputtab%set_title(title) + end if + ! + ! -- Set unit number for binary output + if (ipakcb < 0) then + ibinun = icbcun + else if (ipakcb == 0) then + ibinun = 0 + else + ibinun = ipakcb + end if + if (icbcfl == 0) then + ibinun = 0 + end if + ! + ! -- If cell-by-cell flows will be saved as a list, write header. + if (ibinun /= 0) then + ! + ! -- Count nbound as the number of entries with node > 0 + ! SFR, for example, can have a 'none' connection, which + ! means it should be excluded from budget file + nboundcount = 0 + do i = 1, nbound + node = nodelist(i) + if (node > 0) nboundcount = nboundcount + 1 + end do + call dis%record_srcdst_list_header(text, textmodel, textpackage, & + dstmodel, dstpackage, naux, & + auxname, ibinun, nboundcount, iout) + end if + ! + ! -- If no boundaries, skip flow calculations. + if (nbound > 0) then + ! + ! -- Loop through each boundary calculating flow. + do i = 1, nbound + node = nodelist(i) + ! -- assign boundary name + if (inamedbound > 0) then + bname = boundname(i) + else + bname = '' + end if ! - ! -- Loop through each boundary calculating flow. - do i = 1, nbound - node = nodelist(i) - ! -- assign boundary name - if (inamedbound > 0) then - bname = boundname(i) - else - bname = '' - end if + ! -- If cell is no-flow or constant-head, then ignore it. + rrate = DZERO + if (node > 0) then ! - ! -- If cell is no-flow or constant-head, then ignore it. - rrate = DZERO - if (node > 0) then - ! - ! -- Use simval, which was calculated in cq() - rrate = flow(i) - ! - ! -- Print the individual rates if the budget is being printed - ! and PRINT_FLOWS was specified (iprflow < 0). Rates are - ! printed even if ibound < 1. - if (ibudfl /= 0) then - if (iprflow /= 0) then - ! - ! -- set nodestr and write outputtab table - nodeu = dis%get_nodeuser(node) - call dis%nodeu_to_string(nodeu, nodestr) - call outputtab%print_list_entry(i, trim(adjustl(nodestr)), & - rrate, bname) - end if - end if - ! - ! -- If saving cell-by-cell flows in list, write flow - if (ibinun /= 0) then - n2 = i - if (present(imap)) n2 = imap(i) - call dis%record_mf6_list_entry(ibinun, node, n2, rrate, naux, & - auxvar(:,i), olconv2=.FALSE.) + ! -- Use simval, which was calculated in cq() + rrate = flow(i) + ! + ! -- Print the individual rates if the budget is being printed + ! and PRINT_FLOWS was specified (iprflow < 0). Rates are + ! printed even if ibound < 1. + if (ibudfl /= 0) then + if (iprflow /= 0) then + ! + ! -- set nodestr and write outputtab table + nodeu = dis%get_nodeuser(node) + call dis%nodeu_to_string(nodeu, nodestr) + call outputtab%print_list_entry(i, trim(adjustl(nodestr)), & + rrate, bname) end if end if ! - end do - if (ibudfl /= 0) then - if (iprflow /= 0) then - write(iout,'(1x)') + ! -- If saving cell-by-cell flows in list, write flow + if (ibinun /= 0) then + n2 = i + if (present(imap)) n2 = imap(i) + call dis%record_mf6_list_entry(ibinun, node, n2, rrate, naux, & + auxvar(:, i), olconv2=.FALSE.) end if end if + ! + end do + if (ibudfl /= 0) then + if (iprflow /= 0) then + write (iout, '(1x)') + end if + end if - endif - ! - ! -- return - return - end subroutine save_print_model_flows + end if + ! + ! -- return + return + end subroutine save_print_model_flows + + !> @brief Activate viscosity terms + !! + !! Method to activate addition of viscosity terms when package type + !! is DRN, GHB, or RIV (method not needed by other packages at this point) + !! + !< + subroutine bnd_activate_viscosity(this) + ! -- modules + use MemoryManagerModule, only: mem_reallocate + ! -- dummy variables + class(BndType), intent(inout) :: this !< BndType object + ! -- local variables + integer(I4B) :: i + ! + ! -- Set ivsc and reallocate viscratios to be of size MAXBOUND + this%ivsc = 1 + ! + ! -- Allocate array for storing user-specified conductances + ! modified by updated viscosity values + call mem_reallocate(this%condinput, this%maxbound, 'CONDINPUT', & + this%memoryPath) + do i = 1, this%maxbound + this%condinput(i) = DZERO + end do + ! + ! -- Notify user via listing file viscosity accounted for by standard + ! boundary package. + write (this%iout, '(/1x,a,a)') 'VISCOSITY ACTIVE IN ', & + trim(this%filtyp)//' PACKAGE CALCULATIONS: '//trim(adjustl(this%packName)) + ! + ! -- return + return + end subroutine bnd_activate_viscosity end module BndModule diff --git a/src/Model/ModelUtilities/Connections.f90 b/src/Model/ModelUtilities/Connections.f90 index 27cae2d2d97..de138daabcb 100644 --- a/src/Model/ModelUtilities/Connections.f90 +++ b/src/Model/ModelUtilities/Connections.f90 @@ -6,7 +6,7 @@ module ConnectionsModule use GenericUtilitiesModule, only: sim_message use SimVariablesModule, only: errmsg use BlockParserModule, only: BlockParserType - + implicit none private public :: ConnectionsType @@ -14,27 +14,27 @@ module ConnectionsModule public :: fillisym public :: filljas - + type ConnectionsType - character(len=LENMEMPATH) :: memoryPath !< memory path of the connections data - character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model - integer(I4B), pointer :: nodes => null() !< number of nodes - integer(I4B), pointer :: nja => null() !< number of connections - integer(I4B), pointer :: njas => null() !< number of symmetric connections - integer(I4B), pointer :: ianglex => null() !< indicates whether or not anglex is present - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< (size:nodes+1) csr index array - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< (size:nja) csr pointer array - integer(I4B), dimension(:), pointer, contiguous :: mask => null() !< (size:nja) to mask certain connections: ==0 means masked. Do not set the mask directly, use set_mask instead! - real(DP), dimension(:), pointer, contiguous :: cl1 => null() !< (size:njas) connection length between node n and shared face with node m - real(DP), dimension(:), pointer, contiguous :: cl2 => null() !< (size:njas) connection length between node m and shared face with node n - real(DP), dimension(:), pointer, contiguous :: hwva => null() !< (size:njas) horizontal perpendicular width (ihc>0) or vertical flow area (ihc=0) - real(DP), dimension(:), pointer, contiguous :: anglex => null() !< (size:njas) connection angle of face normal with x axis (read in degrees, stored as radians) - integer(I4B), dimension(:), pointer, contiguous :: isym => null() !< (size:nja) returns csr index of symmetric counterpart - integer(I4B), dimension(:), pointer, contiguous :: jas => null() !< (size:nja) map any connection to upper triangle (for pulling out of symmetric array) - integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !< (size:njas) horizontal connection (0:vertical, 1:mean thickness, 2:staggered) - integer(I4B), dimension(:), pointer, contiguous :: iausr => null() !< (size:nodesusr+1) - integer(I4B), dimension(:), pointer, contiguous :: jausr => null() !< (size:nja) - type(BlockParserType) :: parser !< block parser + character(len=LENMEMPATH) :: memoryPath !< memory path of the connections data + character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model + integer(I4B), pointer :: nodes => null() !< number of nodes + integer(I4B), pointer :: nja => null() !< number of connections + integer(I4B), pointer :: njas => null() !< number of symmetric connections + integer(I4B), pointer :: ianglex => null() !< indicates whether or not anglex is present + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< (size:nodes+1) csr index array + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< (size:nja) csr pointer array + integer(I4B), dimension(:), pointer, contiguous :: mask => null() !< (size:nja) to mask certain connections: ==0 means masked. Do not set the mask directly, use set_mask instead! + real(DP), dimension(:), pointer, contiguous :: cl1 => null() !< (size:njas) connection length between node n and shared face with node m + real(DP), dimension(:), pointer, contiguous :: cl2 => null() !< (size:njas) connection length between node m and shared face with node n + real(DP), dimension(:), pointer, contiguous :: hwva => null() !< (size:njas) horizontal perpendicular width (ihc>0) or vertical flow area (ihc=0) + real(DP), dimension(:), pointer, contiguous :: anglex => null() !< (size:njas) connection angle of face normal with x axis (read in degrees, stored as radians) + integer(I4B), dimension(:), pointer, contiguous :: isym => null() !< (size:nja) returns csr index of symmetric counterpart + integer(I4B), dimension(:), pointer, contiguous :: jas => null() !< (size:nja) map any connection to upper triangle (for pulling out of symmetric array) + integer(I4B), dimension(:), pointer, contiguous :: ihc => null() !< (size:njas) horizontal connection (0:vertical, 1:mean thickness, 2:staggered) + integer(I4B), dimension(:), pointer, contiguous :: iausr => null() !< (size:nodesusr+1) + integer(I4B), dimension(:), pointer, contiguous :: jausr => null() !< (size:nja) + type(BlockParserType) :: parser !< block parser contains procedure :: con_da procedure :: allocate_scalars @@ -50,8 +50,8 @@ module ConnectionsModule procedure :: set_mask end type ConnectionsType - contains - +contains + subroutine con_da(this) ! ****************************************************************************** ! con_da -- Deallocate connection variables @@ -66,7 +66,7 @@ subroutine con_da(this) ! ------------------------------------------------------------------------------ ! ! -- Strings - deallocate(this%name_model) + deallocate (this%name_model) ! ! -- Scalars call mem_deallocate(this%nodes) @@ -75,38 +75,38 @@ subroutine con_da(this) call mem_deallocate(this%ianglex) ! ! -- iausr and jausr - if(associated(this%iausr, this%ia)) then - nullify(this%iausr) + if (associated(this%iausr, this%ia)) then + nullify (this%iausr) else call mem_deallocate(this%iausr) - endif - if(associated(this%jausr, this%ja)) then - nullify(this%jausr) + end if + if (associated(this%jausr, this%ja)) then + nullify (this%jausr) else call mem_deallocate(this%jausr) - endif + end if ! -- mask if (associated(this%mask, this%ja)) then - nullify(this%mask) + nullify (this%mask) else call mem_deallocate(this%mask) - end if + end if ! ! -- Arrays call mem_deallocate(this%ia) - call mem_deallocate(this%ja) + call mem_deallocate(this%ja) call mem_deallocate(this%isym) call mem_deallocate(this%jas) call mem_deallocate(this%hwva) call mem_deallocate(this%anglex) call mem_deallocate(this%ihc) call mem_deallocate(this%cl1) - call mem_deallocate(this%cl2) + call mem_deallocate(this%cl2) ! ! -- return return end subroutine con_da - + subroutine allocate_scalars(this, name_model) ! ****************************************************************************** ! allocate_scalars -- Allocate scalars for ConnectionsType @@ -123,8 +123,8 @@ subroutine allocate_scalars(this, name_model) ! ------------------------------------------------------------------------------ ! ! -- allocate - allocate(this%name_model) - + allocate (this%name_model) + this%memoryPath = create_mem_path(name_model, 'CON') call mem_allocate(this%nodes, 'NODES', this%memoryPath) call mem_allocate(this%nja, 'NJA', this%memoryPath) @@ -153,7 +153,7 @@ subroutine allocate_arrays(this) ! ------------------------------------------------------------------------------ ! ! -- allocate space for connection arrays - call mem_allocate(this%ia, this%nodes+1, 'IA', this%memoryPath) + call mem_allocate(this%ia, this%nodes + 1, 'IA', this%memoryPath) call mem_allocate(this%ja, this%nja, 'JA', this%memoryPath) call mem_allocate(this%isym, this%nja, 'ISYM', this%memoryPath) call mem_allocate(this%jas, this%nja, 'JAS', this%memoryPath) @@ -164,15 +164,15 @@ subroutine allocate_arrays(this) call mem_allocate(this%cl2, this%njas, 'CL2', this%memoryPath) call mem_allocate(this%iausr, 1, 'IAUSR', this%memoryPath) call mem_allocate(this%jausr, 1, 'JAUSR', this%memoryPath) - ! - ! -- let mask point to ja, which is always nonzero, + ! + ! -- let mask point to ja, which is always nonzero, ! until someone decides to do a 'set_mask' this%mask => this%ja ! ! -- Return return end subroutine allocate_arrays - + subroutine con_finalize(this, ihctemp, cl12temp, hwvatemp, angldegx) ! ****************************************************************************** ! con_finalize -- Finalize connection data @@ -192,60 +192,60 @@ subroutine con_finalize(this, ihctemp, cl12temp, hwvatemp, angldegx) ! -- local integer(I4B) :: ii, n, m integer(I4B), parameter :: nname = 6 - character(len=24),dimension(nname) :: aname(nname) + character(len=24), dimension(nname) :: aname(nname) ! -- formats - character(len=*),parameter :: fmtsymerr = & - &"('Error in array: ',a,'.', & - &' Array is not symmetric in positions: ',i0,' and ',i0,'.', & - &' Values in these positions are: ',1pg15.6,' and ', 1pg15.6, & + character(len=*), parameter :: fmtsymerr = & + &"('Error in array: ',a,'.', & + &' Array is not symmetric in positions: ',i0,' and ',i0,'.', & + &' Values in these positions are: ',1pg15.6,' and ', 1pg15.6, & &' For node ',i0,' connected to node ',i0)" - character(len=*),parameter :: fmtsymerrja = & - &"('Error in array: ',a,'.', & - &' Array does not have symmetric counterpart in position ',i0, & + character(len=*), parameter :: fmtsymerrja = & + &"('Error in array: ',a,'.', & + &' Array does not have symmetric counterpart in position ',i0, & &' for cell ',i0,' connected to cell ',i0)" - character(len=*),parameter :: fmtjanmerr = & - &"('Error in array: ',a,'.', & - &' First value for cell : ',i0,' must equal ',i0,'.', & + character(len=*), parameter :: fmtjanmerr = & + &"('Error in array: ',a,'.', & + &' First value for cell : ',i0,' must equal ',i0,'.', & &' Found ',i0,' instead.')" - character(len=*),parameter :: fmtjasorterr = & - &"('Error in array: ',a,'.', & - &' Entries not sorted for row: ',i0,'.', & + character(len=*), parameter :: fmtjasorterr = & + &"('Error in array: ',a,'.', & + &' Entries not sorted for row: ',i0,'.', & &' Offending entries are: ',i0,' and ',i0)" - character(len=*),parameter :: fmtihcerr = & - "('IHC must be 0, 1, or 2. Found: ',i0)" + character(len=*), parameter :: fmtihcerr = & + "('IHC must be 0, 1, or 2. Found: ',i0)" ! -- data - data aname(1) /' IAC'/ - data aname(2) /' JA'/ - data aname(3) /' IHC'/ - data aname(4) /' CL12'/ - data aname(5) /' HWVA'/ - data aname(6) /' ANGLDEGX'/ + data aname(1)/' IAC'/ + data aname(2)/' JA'/ + data aname(3)/' IHC'/ + data aname(4)/' CL12'/ + data aname(5)/' HWVA'/ + data aname(6)/' ANGLDEGX'/ ! ------------------------------------------------------------------------------ ! ! -- Convert any negative ja numbers to positive do ii = 1, this%nja - if(this%ja(ii) < 0) this%ja(ii) = -this%ja(ii) - enddo + if (this%ja(ii) < 0) this%ja(ii) = -this%ja(ii) + end do ! ! -- Ensure ja is sorted with the row column listed first do n = 1, this%nodes m = this%ja(this%ia(n)) if (n /= m) then - write(errmsg, fmtjanmerr) trim(adjustl(aname(2))), n, n, m + write (errmsg, fmtjanmerr) trim(adjustl(aname(2))), n, n, m call store_error(errmsg) - endif + end if do ii = this%ia(n) + 1, this%ia(n + 1) - 2 m = this%ja(ii) - if(m > this%ja(ii+1)) then - write(errmsg, fmtjasorterr) trim(adjustl(aname(2))), n, & - m, this%ja(ii+1) + if (m > this%ja(ii + 1)) then + write (errmsg, fmtjasorterr) trim(adjustl(aname(2))), n, & + m, this%ja(ii + 1) call store_error(errmsg) - endif - enddo - enddo - if(count_errors() > 0) then + end if + end do + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- fill the isym arrays call fillisym(this%nodes, this%nja, this%ia, this%ja, this%isym) @@ -255,15 +255,15 @@ subroutine con_finalize(this, ihctemp, cl12temp, hwvatemp, angldegx) do n = 1, this%nodes do ii = this%ia(n), this%ia(n + 1) - 1 m = this%ja(ii) - if(this%isym(ii) == 0) then - write(errmsg, fmtsymerrja) trim(adjustl(aname(2))), ii, n, m + if (this%isym(ii) == 0) then + write (errmsg, fmtsymerrja) trim(adjustl(aname(2))), ii, n, m call store_error(errmsg) - endif - enddo - enddo - if(count_errors() > 0) then + end if + end do + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Fill the jas array, which maps any connection to upper triangle call filljas(this%nodes, this%nja, this%ia, this%ja, this%isym, this%jas) @@ -272,30 +272,30 @@ subroutine con_finalize(this, ihctemp, cl12temp, hwvatemp, angldegx) do n = 1, this%nodes do ii = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ii) - if(ihctemp(ii) /= ihctemp(this%isym(ii))) then - write(errmsg, fmtsymerr) trim(adjustl(aname(3))), ii, this%isym(ii), & - ihctemp(ii), ihctemp(this%isym(ii)), n, m + if (ihctemp(ii) /= ihctemp(this%isym(ii))) then + write (errmsg, fmtsymerr) trim(adjustl(aname(3))), ii, this%isym(ii), & + ihctemp(ii), ihctemp(this%isym(ii)), n, m call store_error(errmsg) else this%ihc(this%jas(ii)) = ihctemp(ii) - endif - enddo - enddo - if(count_errors() > 0) then + end if + end do + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Put cl12 into symmetric arrays cl1 and cl2 do n = 1, this%nodes do ii = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ii) - if(m > n) then + if (m > n) then this%cl1(this%jas(ii)) = cl12temp(ii) - elseif(n > m) then + elseif (n > m) then this%cl2(this%jas(ii)) = cl12temp(ii) - endif - enddo - enddo + end if + end do + end do ! ! -- Put HWVA into symmetric array based on the value of IHC ! IHC = 0, vertical connection, HWVA is vertical flow area @@ -306,41 +306,41 @@ subroutine con_finalize(this, ihctemp, cl12temp, hwvatemp, angldegx) do n = 1, this%nodes do ii = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ii) - if(hwvatemp(ii) /= hwvatemp(this%isym(ii))) then - write(errmsg, fmtsymerr) trim(adjustl(aname(5))), ii, this%isym(ii), & - hwvatemp(ii), hwvatemp(this%isym(ii)), n, m + if (hwvatemp(ii) /= hwvatemp(this%isym(ii))) then + write (errmsg, fmtsymerr) trim(adjustl(aname(5))), ii, this%isym(ii), & + hwvatemp(ii), hwvatemp(this%isym(ii)), n, m call store_error(errmsg) - endif - if(ihctemp(ii) < 0 .or. ihctemp(ii) > 2) then - write(errmsg, fmtihcerr) ihctemp(ii) + end if + if (ihctemp(ii) < 0 .or. ihctemp(ii) > 2) then + write (errmsg, fmtihcerr) ihctemp(ii) call store_error(errmsg) - endif + end if this%hwva(this%jas(ii)) = hwvatemp(ii) - enddo - enddo - if(count_errors() > 0) then + end do + end do + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Put anglextemp into this%anglex; store only upper triangle - if(this%ianglex /= 0) then + if (this%ianglex /= 0) then do n = 1, this%nodes do ii = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ii) - if(n > m) cycle + if (n > m) cycle this%anglex(this%jas(ii)) = angldegx(ii) * DPIO180 - enddo - enddo + end do + end do else do n = 1, size(this%anglex) this%anglex(n) = DNODATA - enddo - endif + end do + end if ! ! -- Return return end subroutine con_finalize - + subroutine read_connectivity_from_block(this, name_model, nodes, nja, iout) ! ****************************************************************************** ! read_connectivity_from_block -- Read and process IAC and JA from an @@ -361,22 +361,22 @@ subroutine read_connectivity_from_block(this, name_model, nodes, nja, iout) ! -- local character(len=LINELENGTH) :: line character(len=LINELENGTH) :: keyword - integer(I4B) :: ii,n,m + integer(I4B) :: ii, n, m integer(I4B) :: ierr logical :: isfound, endOfBlock integer(I4B), parameter :: nname = 2 - logical,dimension(nname) :: lname - character(len=24),dimension(nname) :: aname(nname) + logical, dimension(nname) :: lname + character(len=24), dimension(nname) :: aname(nname) ! -- formats - character(len=*),parameter :: fmtsymerr = & + character(len=*), parameter :: fmtsymerr = & &"(/,'Error in array: ',(a),/, & &'Array is not symmetric in positions: ',2i9,/, & &'Values in these positions are: ', 2(1pg15.6))" - character(len=*),parameter :: fmtihcerr = & + character(len=*), parameter :: fmtihcerr = & &"(/,'IHC must be 0, 1, or 2. Found: ',i0)" ! -- data - data aname(1) /' IAC'/ - data aname(2) /' JA'/ + data aname(1)/' IAC'/ + data aname(2)/' JA'/ ! ------------------------------------------------------------------------------ ! ! -- Allocate and initialize dimensions @@ -391,28 +391,29 @@ subroutine read_connectivity_from_block(this, name_model, nodes, nja, iout) ! -- get connectiondata block call this%parser%GetBlock('CONNECTIONDATA', isfound, ierr) lname(:) = .false. - if(isfound) then - write(iout,'(1x,a)')'PROCESSING CONNECTIONDATA' + if (isfound) then + write (iout, '(1x,a)') 'PROCESSING CONNECTIONDATA' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('IAC') - call ReadArray(this%parser%iuactive, this%ia, aname(1), 1, & - this%nodes, iout, 0) - lname(1) = .true. - case ('JA') - call ReadArray(this%parser%iuactive, this%ja, aname(2), 1, & - this%nja, iout, 0) - lname(2) = .true. - case default - write(errmsg,'(4x,a,a)') 'UNKNOWN CONNECTIONDATA TAG: ', trim(keyword) - call store_error(errmsg) - call this%parser%StoreErrorUnit() + case ('IAC') + call ReadArray(this%parser%iuactive, this%ia, aname(1), 1, & + this%nodes, iout, 0) + lname(1) = .true. + case ('JA') + call ReadArray(this%parser%iuactive, this%ja, aname(2), 1, & + this%nja, iout, 0) + lname(2) = .true. + case default + write (errmsg, '(4x,a,a)') & + 'UNKNOWN CONNECTIONDATA TAG: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)')'END PROCESSING CONNECTIONDATA' + write (iout, '(1x,a)') 'END PROCESSING CONNECTIONDATA' else call store_error('REQUIRED CONNECTIONDATA BLOCK NOT FOUND.') call this%parser%StoreErrorUnit() @@ -420,29 +421,29 @@ subroutine read_connectivity_from_block(this, name_model, nodes, nja, iout) ! ! -- verify all items were read do n = 1, nname - if(.not. lname(n)) then - write(errmsg,'(1x,a,a)') & - 'REQUIRED INPUT WAS NOT SPECIFIED: ',aname(n) + if (.not. lname(n)) then + write (errmsg, '(1x,a,a)') & + 'REQUIRED INPUT WAS NOT SPECIFIED: ', aname(n) call store_error(errmsg) - endif - enddo + end if + end do if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Convert iac to ia do n = 2, this%nodes + 1 - this%ia(n) = this%ia(n) + this%ia(n-1) - enddo + this%ia(n) = this%ia(n) + this%ia(n - 1) + end do do n = this%nodes + 1, 2, -1 this%ia(n) = this%ia(n - 1) + 1 - enddo + end do this%ia(1) = 1 ! ! -- Convert any negative ja numbers to positive do ii = 1, this%nja - if(this%ja(ii) < 0) this%ja(ii) = -this%ja(ii) - enddo + if (this%ja(ii) < 0) this%ja(ii) = -this%ja(ii) + end do ! ! -- fill the isym and jas arrays call fillisym(this%nodes, this%nja, this%ia, this%ja, this%isym) @@ -453,25 +454,25 @@ subroutine read_connectivity_from_block(this, name_model, nodes, nja, iout) do n = 1, this%nodes do ii = this%ia(n), this%ia(n + 1) - 1 m = this%ja(ii) - if(n /= this%ja(this%isym(ii))) then - write(line, fmtsymerr) aname(2), ii, this%isym(ii) + if (n /= this%ja(this%isym(ii))) then + write (line, fmtsymerr) aname(2), ii, this%isym(ii) call sim_message(line) call this%parser%StoreErrorUnit() - endif - enddo - enddo + end if + end do + end do ! - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! ! -- Return return end subroutine read_connectivity_from_block - + subroutine set_cl1_cl2_from_fleng(this, fleng) ! ****************************************************************************** -! set_cl1_cl2_from_fleng -- Using a vector of cell lengths, +! set_cl1_cl2_from_fleng -- Using a vector of cell lengths, ! calculate the cl1 and cl2 arrays. ! ****************************************************************************** ! @@ -492,15 +493,15 @@ subroutine set_cl1_cl2_from_fleng(this, fleng) m = this%ja(ii) this%cl1(this%jas(ii)) = fleng(n) * DHALF this%cl2(this%jas(ii)) = fleng(m) * DHALF - enddo - enddo + end do + end do ! ! -- Return return end subroutine set_cl1_cl2_from_fleng - - subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & - nrsize, delr, delc, top, bot, nodereduced, & + + subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & + nrsize, delr, delc, top, bot, nodereduced, & nodeuser) ! ****************************************************************************** ! disconnections -- Construct the connectivity arrays for a structured @@ -521,12 +522,12 @@ subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & integer(I4B), intent(in) :: nrow integer(I4B), intent(in) :: nlay integer(I4B), intent(in) :: nrsize - real(DP), dimension(ncol), intent(in) :: delr - real(DP), dimension(nrow), intent(in) :: delc - real(DP), dimension(nodes), intent(in) :: top - real(DP), dimension(nodes), intent(in) :: bot - integer(I4B), dimension(:), target, intent(in) :: nodereduced - integer(I4B), dimension(:), intent(in) :: nodeuser + real(DP), dimension(ncol), intent(in) :: delr + real(DP), dimension(nrow), intent(in) :: delc + real(DP), dimension(nodes), intent(in) :: top + real(DP), dimension(nodes), intent(in) :: bot + integer(I4B), dimension(:), target, intent(in) :: nodereduced + integer(I4B), dimension(:), intent(in) :: nodeuser ! -- local integer(I4B), dimension(:, :, :), pointer :: nrdcd_ptr => null() !non-contiguous because is a slice integer(I4B), dimension(:), allocatable :: rowmaxnnz @@ -543,16 +544,16 @@ subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & this%ianglex = 1 ! ! -- Setup the sparse matrix object - allocate(rowmaxnnz(this%nodes)) + allocate (rowmaxnnz(this%nodes)) do i = 1, this%nodes rowmaxnnz(i) = 6 - enddo + end do call sparse%init(this%nodes, this%nodes, rowmaxnnz) ! ! -- Create a 3d pointer to nodereduced for easier processing - if(nrsize /= 0) then + if (nrsize /= 0) then nrdcd_ptr(1:ncol, 1:nrow, 1:nlay) => nodereduced - endif + end if ! ! -- Add connections to sparse do k = 1, nlay @@ -561,96 +562,96 @@ subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & ! ! -- Find the reduced node number and then cycle if the ! node is always inactive - if(nrsize == 0) then + if (nrsize == 0) then nr = get_node(k, i, j, nlay, nrow, ncol) else nr = nrdcd_ptr(j, i, k) - endif - if(nr <= 0) cycle + end if + if (nr <= 0) cycle ! ! -- Process diagonal call sparse%addconnection(nr, nr, 1) ! ! -- Up direction - if(k > 1) then + if (k > 1) then do kk = k - 1, 1, -1 - if(nrsize == 0) then + if (nrsize == 0) then mr = get_node(kk, i, j, nlay, nrow, ncol) else mr = nrdcd_ptr(j, i, kk) - endif - if(mr >= 0) exit - enddo - if(mr > 0) then + end if + if (mr >= 0) exit + end do + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Back direction - if(i > 1) then - if(nrsize == 0) then - mr = get_node(k, i-1, j, nlay, nrow, ncol) + if (i > 1) then + if (nrsize == 0) then + mr = get_node(k, i - 1, j, nlay, nrow, ncol) else - mr = nrdcd_ptr(j, i-1, k) - endif - if(mr > 0) then + mr = nrdcd_ptr(j, i - 1, k) + end if + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Left direction - if(j > 1) then - if(nrsize == 0) then - mr = get_node(k, i, j-1, nlay, nrow, ncol) + if (j > 1) then + if (nrsize == 0) then + mr = get_node(k, i, j - 1, nlay, nrow, ncol) else - mr = nrdcd_ptr(j-1, i, k) - endif - if(mr > 0) then + mr = nrdcd_ptr(j - 1, i, k) + end if + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Right direction - if(j < ncol) then - if(nrsize == 0) then - mr = get_node(k, i, j+1, nlay, nrow, ncol) - else - mr = nrdcd_ptr(j+1, i, k) - endif - if(mr > 0) then + if (j < ncol) then + if (nrsize == 0) then + mr = get_node(k, i, j + 1, nlay, nrow, ncol) + else + mr = nrdcd_ptr(j + 1, i, k) + end if + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Front direction - if(i < nrow) then !front - if(nrsize == 0) then - mr = get_node(k, i+1, j, nlay, nrow, ncol) - else - mr = nrdcd_ptr(j, i+1, k) - endif - if(mr > 0) then + if (i < nrow) then !front + if (nrsize == 0) then + mr = get_node(k, i + 1, j, nlay, nrow, ncol) + else + mr = nrdcd_ptr(j, i + 1, k) + end if + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Down direction - if(k < nlay) then + if (k < nlay) then do kk = k + 1, nlay - if(nrsize == 0) then + if (nrsize == 0) then mr = get_node(kk, i, j, nlay, nrow, ncol) else mr = nrdcd_ptr(j, i, kk) - endif - if(mr >= 0) exit - enddo - if(mr > 0) then + end if + if (mr >= 0) exit + end do + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif - enddo - enddo - enddo + end if + end if + end do + end do + end do this%nja = sparse%nnz this%njas = (this%nja - this%nodes) / 2 ! @@ -672,72 +673,72 @@ subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & do j = 1, ncol ! ! -- cycle if node is always inactive - if(nrsize == 0) then + if (nrsize == 0) then nr = get_node(k, i, j, nlay, nrow, ncol) else nr = nrdcd_ptr(j, i, k) - endif - if(nr <= 0) cycle + end if + if (nr <= 0) cycle ! ! -- right connection - if(j < ncol) then - if(nrsize == 0) then - mr = get_node(k, i, j+1, nlay, nrow, ncol) + if (j < ncol) then + if (nrsize == 0) then + mr = get_node(k, i, j + 1, nlay, nrow, ncol) else - mr = nrdcd_ptr(j+1, i, k) - endif - if(mr > 0) then + mr = nrdcd_ptr(j + 1, i, k) + end if + if (mr > 0) then this%ihc(isympos) = 1 this%cl1(isympos) = DHALF * delr(j) this%cl2(isympos) = DHALF * delr(j + 1) this%hwva(isympos) = delc(i) this%anglex(isympos) = DZERO isympos = isympos + 1 - endif - endif + end if + end if ! ! -- front connection - if(i < nrow) then - if(nrsize == 0) then - mr = get_node(k, i+1, j, nlay, nrow, ncol) + if (i < nrow) then + if (nrsize == 0) then + mr = get_node(k, i + 1, j, nlay, nrow, ncol) else - mr = nrdcd_ptr(j, i+1, k) - endif - if(mr > 0) then + mr = nrdcd_ptr(j, i + 1, k) + end if + if (mr > 0) then this%ihc(isympos) = 1 this%cl1(isympos) = DHALF * delc(i) this%cl2(isympos) = DHALF * delc(i + 1) this%hwva(isympos) = delr(j) this%anglex(isympos) = DTHREE / DTWO * DPI isympos = isympos + 1 - endif - endif + end if + end if ! ! -- down connection - if(k < nlay) then + if (k < nlay) then do kk = k + 1, nlay - if(nrsize == 0) then + if (nrsize == 0) then mr = get_node(kk, i, j, nlay, nrow, ncol) else mr = nrdcd_ptr(j, i, kk) - endif - if(mr >= 0) exit - enddo - if(mr > 0) then + end if + if (mr >= 0) exit + end do + if (mr > 0) then this%ihc(isympos) = 0 this%cl1(isympos) = DHALF * (top(nr) - bot(nr)) this%cl2(isympos) = DHALF * (top(mr) - bot(mr)) this%hwva(isympos) = delr(j) * delc(i) this%anglex(isympos) = DZERO isympos = isympos + 1 - endif - endif - enddo - enddo - enddo + end if + end if + end do + end do + end do ! ! -- Deallocate temporary arrays - deallocate(rowmaxnnz) + deallocate (rowmaxnnz) ! ! -- If reduced system, then need to build iausr and jausr, otherwise point ! them to ia and ja. @@ -748,8 +749,8 @@ subroutine disconnections(this, name_model, nodes, ncol, nrow, nlay, & return end subroutine disconnections - subroutine disvconnections(this, name_model, nodes, ncpl, nlay, nrsize, & - nvert, vertex, iavert, javert, cellxy, & + subroutine disvconnections(this, name_model, nodes, ncpl, nlay, nrsize, & + nvert, vertex, iavert, javert, cellxy, & top, bot, nodereduced, nodeuser) ! ****************************************************************************** ! disvconnections -- Construct the connectivity arrays using cell disv @@ -765,21 +766,21 @@ subroutine disvconnections(this, name_model, nodes, ncpl, nlay, nrsize, & use DisvGeom, only: DisvGeomType use MemoryManagerModule, only: mem_reallocate ! -- dummy - class(ConnectionsType) :: this - character(len=*), intent(in) :: name_model - integer(I4B), intent(in) :: nodes - integer(I4B), intent(in) :: ncpl - integer(I4B), intent(in) :: nlay - integer(I4B), intent(in) :: nrsize - integer(I4B), intent(in) :: nvert - real(DP), dimension(2, nvert), intent(in) :: vertex - integer(I4B), dimension(:), intent(in) :: iavert - integer(I4B), dimension(:), intent(in) :: javert - real(DP), dimension(2, ncpl), intent(in) :: cellxy - real(DP), dimension(nodes), intent(in) :: top - real(DP), dimension(nodes), intent(in) :: bot - integer(I4B), dimension(:), intent(in) :: nodereduced - integer(I4B), dimension(:), intent(in) :: nodeuser + class(ConnectionsType) :: this + character(len=*), intent(in) :: name_model + integer(I4B), intent(in) :: nodes + integer(I4B), intent(in) :: ncpl + integer(I4B), intent(in) :: nlay + integer(I4B), intent(in) :: nrsize + integer(I4B), intent(in) :: nvert + real(DP), dimension(2, nvert), intent(in) :: vertex + integer(I4B), dimension(:), intent(in) :: iavert + integer(I4B), dimension(:), intent(in) :: javert + real(DP), dimension(2, ncpl), intent(in) :: cellxy + real(DP), dimension(nodes), intent(in) :: top + real(DP), dimension(nodes), intent(in) :: bot + integer(I4B), dimension(:), intent(in) :: nodereduced + integer(I4B), dimension(:), intent(in) :: nodeuser ! -- local integer(I4B), dimension(:), allocatable :: itemp type(sparsematrix) :: sparse, vertcellspm @@ -795,28 +796,28 @@ subroutine disvconnections(this, name_model, nodes, ncpl, nlay, nrsize, & this%ianglex = 1 ! ! -- Initialize DisvGeomType objects - call cell1%init(nlay, ncpl, nodes, top, bot, iavert, javert, vertex, & + call cell1%init(nlay, ncpl, nodes, top, bot, iavert, javert, vertex, & cellxy, nodereduced, nodeuser) - call cell2%init(nlay, ncpl, nodes, top, bot, iavert, javert, vertex, & + call cell2%init(nlay, ncpl, nodes, top, bot, iavert, javert, vertex, & cellxy, nodereduced, nodeuser) ! ! -- Create a sparse matrix array with a row for each vertex. The columns ! in the sparse matrix contains the cells that include that vertex. ! This array will be used to determine horizontal cell connectivity. - allocate(itemp(nvert)) + allocate (itemp(nvert)) do i = 1, nvert itemp(i) = 4 - enddo + end do call vertcellspm%init(nvert, ncpl, itemp) - deallocate(itemp) + deallocate (itemp) do j = 1, ncpl do i = iavert(j), iavert(j + 1) - 1 call vertcellspm%addconnection(javert(i), j, 1) - enddo - enddo + end do + end do ! ! -- Call routine to build a sparse matrix of the connections - call vertexconnect(this%nodes, nrsize, 6, nlay, ncpl, sparse, & + call vertexconnect(this%nodes, nrsize, 6, nlay, ncpl, sparse, & vertcellspm, cell1, cell2, nodereduced) this%nja = sparse%nnz this%njas = (this%nja - this%nodes) / 2 @@ -838,14 +839,14 @@ subroutine disvconnections(this, name_model, nodes, ncpl, nlay, nrsize, & call cell1%set_nodered(n) do ipos = this%ia(n) + 1, this%ia(n + 1) - 1 m = this%ja(ipos) - if(m < n) cycle + if (m < n) cycle call cell2%set_nodered(m) - call cell1%cprops(cell2, this%hwva(this%jas(ipos)), & - this%cl1(this%jas(ipos)), this%cl2(this%jas(ipos)), & - this%anglex(this%jas(ipos)), & + call cell1%cprops(cell2, this%hwva(this%jas(ipos)), & + this%cl1(this%jas(ipos)), this%cl2(this%jas(ipos)), & + this%anglex(this%jas(ipos)), & this%ihc(this%jas(ipos))) - enddo - enddo + end do + end do ! ! -- If reduced system, then need to build iausr and jausr, otherwise point ! them to ia and ja. @@ -887,10 +888,10 @@ subroutine disuconnections(this, name_model, nodes, nodesuser, nrsize, & real(DP), dimension(:), contiguous, intent(in) :: angldegxinp integer(I4B), intent(in) :: iangledegx ! -- local - integer(I4B),dimension(:),allocatable :: ihctemp - real(DP),dimension(:),allocatable :: cl12temp - real(DP),dimension(:),allocatable :: hwvatemp - real(DP),dimension(:),allocatable :: angldegxtemp + integer(I4B), dimension(:), allocatable :: ihctemp + real(DP), dimension(:), allocatable :: cl12temp + real(DP), dimension(:), allocatable :: hwvatemp + real(DP), dimension(:), allocatable :: angldegxtemp integer(I4B) :: nr, nu, mr, mu, ipos, iposr, ierror integer(I4B), dimension(:), allocatable :: rowmaxnnz type(sparsematrix) :: sparse @@ -925,11 +926,11 @@ subroutine disuconnections(this, name_model, nodes, nodesuser, nrsize, & ! -- reduced system requires more work ! ! -- Setup the sparse matrix object - allocate(rowmaxnnz(this%nodes)) + allocate (rowmaxnnz(this%nodes)) do nr = 1, this%nodes nu = nodeuser(nr) rowmaxnnz(nr) = iainp(nu + 1) - iainp(nu) - enddo + end do call sparse%init(this%nodes, this%nodes, rowmaxnnz) ! ! -- go through user connectivity and create sparse @@ -942,8 +943,8 @@ subroutine disuconnections(this, name_model, nodes, nodesuser, nrsize, & if (nr < 1) cycle if (mr < 1) cycle call sparse%addconnection(nr, mr, 1) - enddo - enddo + end do + end do this%nja = sparse%nnz this%njas = (this%nja - this%nodes) / 2 ! @@ -954,13 +955,13 @@ subroutine disuconnections(this, name_model, nodes, nodesuser, nrsize, & call sparse%sort() call sparse%filliaja(this%ia, this%ja, ierror) call sparse%destroy() - deallocate(rowmaxnnz) + deallocate (rowmaxnnz) ! ! -- At this point, need to reduce ihc, cl12, hwva, and angldegx - allocate(ihctemp(this%nja)) - allocate(cl12temp(this%nja)) - allocate(hwvatemp(this%nja)) - allocate(angldegxtemp(this%nja)) + allocate (ihctemp(this%nja)) + allocate (cl12temp(this%nja)) + allocate (hwvatemp(this%nja)) + allocate (angldegxtemp(this%nja)) ! ! -- Compress user arrays into reduced arrays iposr = 1 @@ -982,10 +983,10 @@ subroutine disuconnections(this, name_model, nodes, nodesuser, nrsize, & call this%con_finalize(ihctemp, cl12temp, hwvatemp, angldegxtemp) ! ! -- deallocate temporary arrays - deallocate(ihctemp) - deallocate(cl12temp) - deallocate(hwvatemp) - deallocate(angldegxtemp) + deallocate (ihctemp) + deallocate (cl12temp) + deallocate (hwvatemp) + deallocate (angldegxtemp) end if ! ! -- If reduced system, then need to build iausr and jausr, otherwise point @@ -1018,20 +1019,20 @@ subroutine iajausr(this, nrsize, nodesuser, nodereduced, nodeuser) ! ! -- If reduced system, then need to build iausr and jausr, otherwise point ! them to ia and ja. - if(nrsize > 0) then + if (nrsize > 0) then ! ! -- Create the iausr array of size nodesuser + 1. For excluded cells, ! iausr(n) and iausr(n + 1) should be equal to indicate no connections. - call mem_reallocate(this%iausr, nodesuser+1, 'IAUSR', this%memoryPath) + call mem_reallocate(this%iausr, nodesuser + 1, 'IAUSR', this%memoryPath) this%iausr(nodesuser + 1) = this%ia(this%nodes + 1) do n = nodesuser, 1, -1 nr = nodereduced(n) - if(nr < 1) then + if (nr < 1) then this%iausr(n) = this%iausr(n + 1) else this%iausr(n) = this%ia(nr) - endif - enddo + end if + end do ! ! -- Create the jausr array, which is the same size as ja, but it ! contains user node numbers instead of reduced node numbers @@ -1040,20 +1041,20 @@ subroutine iajausr(this, nrsize, nodesuser, nodereduced, nodeuser) nr = this%ja(ipos) n = nodeuser(nr) this%jausr(ipos) = n - enddo + end do else ! -- iausr and jausr will be pointers call mem_deallocate(this%iausr) call mem_deallocate(this%jausr) call mem_setptr(this%iausr, 'IA', this%memoryPath) call mem_setptr(this%jausr, 'JA', this%memoryPath) - endif + end if ! ! -- Return return end subroutine iajausr - function getjaindex(this,node1,node2) + function getjaindex(this, node1, node2) ! ****************************************************************************** ! Get the index in the JA array corresponding to the connection between ! two nodes of interest. Node1 is used as the index in the IA array, and @@ -1070,34 +1071,35 @@ function getjaindex(this,node1,node2) integer(I4B) :: getjaindex ! -- dummy class(ConnectionsType) :: this - integer(I4B), intent(in) :: node1, node2 ! nodes of interest + integer(I4B), intent(in) :: node1, node2 ! nodes of interest ! -- local integer(I4B) :: i ! ------------------------------------------------------------------------------ ! ! -- error checking - if (node1<1 .or. node1>this%nodes .or. node2<1 .or. node2>this%nodes) then - getjaindex = -1 ! indicates error (an invalid node number) + if (node1 < 1 .or. node1 > this%nodes .or. node2 < 1 .or. & + node2 > this%nodes) then + getjaindex = -1 ! indicates error (an invalid node number) return - endif + end if ! ! -- If node1==node2, just return the position for the diagonal. - if (node1==node2) then + if (node1 == node2) then getjaindex = this%ia(node1) return - endif + end if ! ! -- Look for connection among nonzero elements defined for row node1. - do i=this%ia(node1)+1,this%ia(node1+1)-1 - if (this%ja(i)==node2) then + do i = this%ia(node1) + 1, this%ia(node1 + 1) - 1 + if (this%ja(i) == node2) then getjaindex = i return - endif - enddo + end if + end do ! ! -- If execution reaches here, no connection exists ! between nodes of interest. - getjaindex = 0 ! indicates no connection exists + getjaindex = 0 ! indicates no connection exists return end function getjaindex @@ -1109,31 +1111,31 @@ subroutine fillisym(neq, nja, ia, ja, isym) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - integer(I4B),intent(in) :: neq - integer(I4B),intent(in) :: nja - integer(I4B),intent(inout),dimension(nja) :: isym + integer(I4B), intent(in) :: neq + integer(I4B), intent(in) :: nja + integer(I4B), intent(inout), dimension(nja) :: isym ! -- local - integer(I4B),intent(in),dimension(neq+1) :: ia - integer(I4B),intent(in),dimension(nja) :: ja + integer(I4B), intent(in), dimension(neq + 1) :: ia + integer(I4B), intent(in), dimension(nja) :: ja integer(I4B) :: n, m, ii, jj ! ------------------------------------------------------------------------------ ! - do n=1, neq + do n = 1, neq do ii = ia(n), ia(n + 1) - 1 m = ja(ii) - if(m /= n) then + if (m /= n) then isym(ii) = 0 search: do jj = ia(m), ia(m + 1) - 1 - if(ja(jj) == n) then + if (ja(jj) == n) then isym(ii) = jj exit search - endif - enddo search + end if + end do search else isym(ii) = ii - endif - enddo - enddo + end if + end do + end do ! ! -- Return return @@ -1147,12 +1149,12 @@ subroutine filljas(neq, nja, ia, ja, isym, jas) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - integer(I4B),intent(in) :: neq - integer(I4B),intent(in) :: nja - integer(I4B),intent(in),dimension(neq+1) :: ia - integer(I4B),intent(in),dimension(nja) :: ja - integer(I4B),intent(in),dimension(nja) :: isym - integer(I4B),intent(inout),dimension(nja) :: jas + integer(I4B), intent(in) :: neq + integer(I4B), intent(in) :: nja + integer(I4B), intent(in), dimension(neq + 1) :: ia + integer(I4B), intent(in), dimension(nja) :: ja + integer(I4B), intent(in), dimension(nja) :: isym + integer(I4B), intent(inout), dimension(nja) :: jas ! -- local integer(I4B) :: n, m, ii, ipos ! ------------------------------------------------------------------------------ @@ -1163,29 +1165,28 @@ subroutine filljas(neq, nja, ia, ja, isym, jas) jas(ia(n)) = 0 do ii = ia(n) + 1, ia(n + 1) - 1 m = ja(ii) - if(m > n) then + if (m > n) then jas(ii) = ipos ipos = ipos + 1 - endif - enddo - enddo + end if + end do + end do ! ! -- fill lower do n = 1, neq do ii = ia(n), ia(n + 1) - 1 m = ja(ii) - if(m < n) then + if (m < n) then jas(ii) = jas(isym(ii)) - endif - enddo - enddo + end if + end do + end do ! ! -- Return return end subroutine filljas - - subroutine vertexconnect(nodes, nrsize, maxnnz, nlay, ncpl, sparse, & + subroutine vertexconnect(nodes, nrsize, maxnnz, nlay, ncpl, sparse, & vertcellspm, cell1, cell2, nodereduced) ! ****************************************************************************** ! vertexconnect -- routine to make cell connections from vertices @@ -1213,49 +1214,49 @@ subroutine vertexconnect(nodes, nrsize, maxnnz, nlay, ncpl, sparse, & ! ------------------------------------------------------------------------------ ! ! -- Allocate and fill the ia and ja arrays - allocate(rowmaxnnz(nodes)) + allocate (rowmaxnnz(nodes)) do i = 1, nodes rowmaxnnz(i) = maxnnz - enddo + end do call sparse%init(nodes, nodes, rowmaxnnz) - deallocate(rowmaxnnz) + deallocate (rowmaxnnz) do k = 1, nlay do j = 1, ncpl ! ! -- Find the reduced node number and then cycle if the ! node is always inactive nr = get_node(k, 1, j, nlay, 1, ncpl) - if(nrsize > 0) nr = nodereduced(nr) - if(nr <= 0) cycle + if (nrsize > 0) nr = nodereduced(nr) + if (nr <= 0) cycle ! ! -- Process diagonal call sparse%addconnection(nr, nr, 1) ! ! -- Up direction - if(k > 1) then + if (k > 1) then do kk = k - 1, 1, -1 mr = get_node(kk, 1, j, nlay, 1, ncpl) - if(nrsize > 0) mr = nodereduced(mr) - if(mr >= 0) exit - enddo - if(mr > 0) then + if (nrsize > 0) mr = nodereduced(mr) + if (mr >= 0) exit + end do + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif + end if + end if ! ! -- Down direction - if(k < nlay) then + if (k < nlay) then do kk = k + 1, nlay mr = get_node(kk, 1, j, nlay, 1, ncpl) - if(nrsize > 0) mr = nodereduced(mr) - if(mr >= 0) exit - enddo - if(mr > 0) then + if (nrsize > 0) mr = nodereduced(mr) + if (mr >= 0) exit + end do + if (mr > 0) then call sparse%addconnection(nr, mr, 1) - endif - endif - enddo - enddo + end if + end if + end do + end do ! ! -- Go through each vertex and connect up all the cells that use ! this vertex in their definition and share an edge. @@ -1265,50 +1266,50 @@ subroutine vertexconnect(nodes, nrsize, maxnnz, nlay, ncpl, sparse, & j1 = vertcellspm%row(i)%icolarray(icol1) do k = 1, nlay nr = get_node(k, 1, j1, nlay, 1, ncpl) - if(nrsize > 0) nr = nodereduced(nr) - if(nr <= 0) cycle + if (nrsize > 0) nr = nodereduced(nr) + if (nr <= 0) cycle call cell1%set_nodered(nr) do icol2 = 1, vertcellspm%row(i)%nnz j2 = vertcellspm%row(i)%icolarray(icol2) - if(j1 == j2) cycle + if (j1 == j2) cycle mr = get_node(k, 1, j2, nlay, 1, ncpl) - if(nrsize > 0) mr = nodereduced(mr) - if(mr <= 0) cycle + if (nrsize > 0) mr = nodereduced(mr) + if (mr <= 0) cycle call cell2%set_nodered(mr) - if(cell1%shares_edge(cell2)) then + if (cell1%shares_edge(cell2)) then call sparse%addconnection(nr, mr, 1) - endif - enddo - enddo - enddo - enddo + end if + end do + end do + end do + end do ! ! -- return return end subroutine vertexconnect - + subroutine set_mask(this, ipos, maskval) ! ****************************************************************************** -! set_mask -- routine to set a value in the mask array +! set_mask -- routine to set a value in the mask array ! (which has the same shape as this%ja) ! ****************************************************************************** ! ! SPECIFICATIONS: -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ use MemoryManagerModule, only: mem_allocate class(ConnectionsType) :: this integer(I4B), intent(in) :: ipos integer(I4B), intent(in) :: maskval ! local integer(I4B) :: i -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! ! if we still point to this%ja, we first need to allocate space if (associated(this%mask, this%ja)) then call mem_allocate(this%mask, this%nja, 'MASK', this%memoryPath) ! and initialize with unmasked do i = 1, this%nja - this%mask(i) = 1 + this%mask(i) = 1 end do end if ! @@ -1318,28 +1319,34 @@ subroutine set_mask(this, ipos, maskval) ! -- return return end subroutine set_mask - - subroutine iac_to_ia(ia) + + subroutine iac_to_ia(iac, ia) ! ****************************************************************************** ! iac_to_ia -- convert an iac array into an ia array ! ****************************************************************************** ! ! SPECIFICATIONS: -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! -- dummy + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: iac integer(I4B), dimension(:), contiguous, intent(inout) :: ia ! -- local integer(I4B) :: n, nodes -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! ! -- Convert iac to ia - nodes = size(ia) - 1 - do n = 2, nodes + 1 - ia(n) = ia(n) + ia(n-1) - enddo + nodes = size(iac) + ia(1) = iac(1) + do n = 2, size(ia) ! size(ia) == size(iac) + 1 + if (n < size(ia)) then + ia(n) = iac(n) + ia(n - 1) + else + ia(n) = ia(n) + ia(n - 1) + end if + end do do n = nodes + 1, 2, -1 ia(n) = ia(n - 1) + 1 - enddo + end do ia(1) = 1 ! ! -- return diff --git a/src/Model/ModelUtilities/DiscretizationBase.f90 b/src/Model/ModelUtilities/DiscretizationBase.f90 index 2d954b0be08..c178a62caf0 100644 --- a/src/Model/ModelUtilities/DiscretizationBase.f90 +++ b/src/Model/ModelUtilities/DiscretizationBase.f90 @@ -1,51 +1,54 @@ module BaseDisModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMODELNAME, LENAUXNAME, LINELENGTH, & - DZERO, LENMEMPATH, DPIO180 - use SmoothingModule, only: sQuadraticSaturation - use ConnectionsModule, only: ConnectionsType - use InputOutputModule, only: URWORD, ubdsv1 - use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error, & - store_error_unit - use BlockParserModule, only: BlockParserType - use MemoryManagerModule, only: mem_allocate - use MemoryHelperModule, only: create_mem_path - use TdisModule, only: kstp, kper, pertim, totim, delt + + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMODELNAME, LENAUXNAME, LINELENGTH, & + DZERO, LENMEMPATH, DPIO180 + use SmoothingModule, only: sQuadraticSaturation + use ConnectionsModule, only: ConnectionsType + use InputOutputModule, only: URWORD, ubdsv1 + use SimVariablesModule, only: errmsg + use SimModule, only: count_errors, store_error, & + store_error_unit + use BlockParserModule, only: BlockParserType + use MemoryManagerModule, only: mem_allocate + use MemoryHelperModule, only: create_mem_path + use TdisModule, only: kstp, kper, pertim, totim, delt use TimeSeriesManagerModule, only: TimeSeriesManagerType implicit none - + private public :: DisBaseType + public :: dis_transform_xy type :: DisBaseType - character(len=LENMEMPATH) :: memoryPath !< path for memory allocation - character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model - integer(I4B), pointer :: inunit => null() !< unit number for input file - integer(I4B), pointer :: iout => null() !< unit number for output file - integer(I4B), pointer :: nodes => null() !< number of nodes in solution - integer(I4B), pointer :: nodesuser => null() !< number of user nodes (same as nodes for disu grid) - integer(I4B), pointer :: nja => null() !< number of connections plus number of nodes - integer(I4B), pointer :: njas => null() !< (nja-nodes)/2 - integer(I4B), pointer :: lenuni => null() !< length unit - integer(I4B), pointer :: ndim => null() !< number of spatial model dimensions (1 for disu grid) - integer(I4B), pointer :: icondir => null() !< flag indicating if grid has enough info to calculate connection vectors - logical, pointer :: writegrb => null() !< write binary grid file - real(DP), pointer :: yorigin => null() !< y-position of the lower-left grid corner (default is 0.) - real(DP), pointer :: xorigin => null() !< x-position of the lower-left grid corner (default is 0.) - real(DP), pointer :: angrot => null() !< counter-clockwise rotation angle of the lower-left corner (default is 0.0) - integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< shape of the model; (nodes) for DisBaseType - real(DP), dimension(:), pointer, contiguous :: top => null() !< (size:nodes) cell top elevation - real(DP), dimension(:), pointer, contiguous :: bot => null() !< (size:nodes) cell bottom elevation - real(DP), dimension(:), pointer, contiguous :: area => null() !< (size:nodes) cell area, in plan view - type(ConnectionsType), pointer :: con => null() !< connections object - type(BlockParserType) :: parser !< object to read blocks - real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< helper double array of size nodesuser - integer(I4B), dimension(:), pointer, contiguous :: ibuff => null() !< helper int array of size nodesuser - integer(I4B), dimension(:), pointer, contiguous :: nodereduced => null() !< (size:nodesuser)contains reduced nodenumber (size 0 if not reduced); -1 means vertical pass through, 0 is idomain = 0 - integer(I4B), dimension(:), pointer, contiguous :: nodeuser => null() !< (size:nodes) given a reduced nodenumber, provide the user nodenumber (size 0 if not reduced) + character(len=LENMEMPATH) :: memoryPath !< path for memory allocation + character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model + integer(I4B), pointer :: inunit => null() !< unit number for input file + integer(I4B), pointer :: iout => null() !< unit number for output file + integer(I4B), pointer :: nodes => null() !< number of nodes in solution + integer(I4B), pointer :: nodesuser => null() !< number of user nodes (same as nodes for disu grid) + integer(I4B), pointer :: nja => null() !< number of connections plus number of nodes + integer(I4B), pointer :: njas => null() !< (nja-nodes)/2 + integer(I4B), pointer :: lenuni => null() !< length unit + integer(I4B), pointer :: ndim => null() !< number of spatial model dimensions (1 for disu grid) + integer(I4B), pointer :: icondir => null() !< flag indicating if grid has enough info to calculate connection vectors + integer(I4B), pointer :: nogrb => null() !< don't write binary grid file + real(DP), dimension(:), pointer, contiguous :: xc => null() !< x-coordinate of the cell center + real(DP), dimension(:), pointer, contiguous :: yc => null() !< y-coordinate of the cell center + real(DP), pointer :: yorigin => null() !< y-position of the lower-left grid corner (default is 0.) + real(DP), pointer :: xorigin => null() !< x-position of the lower-left grid corner (default is 0.) + real(DP), pointer :: angrot => null() !< counter-clockwise rotation angle of the lower-left corner (default is 0.0) + integer(I4B), dimension(:), pointer, contiguous :: mshape => null() !< shape of the model; (nodes) for DisBaseType + real(DP), dimension(:), pointer, contiguous :: top => null() !< (size:nodes) cell top elevation + real(DP), dimension(:), pointer, contiguous :: bot => null() !< (size:nodes) cell bottom elevation + real(DP), dimension(:), pointer, contiguous :: area => null() !< (size:nodes) cell area, in plan view + type(ConnectionsType), pointer :: con => null() !< connections object + type(BlockParserType) :: parser !< object to read blocks + real(DP), dimension(:), pointer, contiguous :: dbuff => null() !< helper double array of size nodesuser + integer(I4B), dimension(:), pointer, contiguous :: ibuff => null() !< helper int array of size nodesuser + integer(I4B), dimension(:), pointer, contiguous :: nodereduced => null() !< (size:nodesuser)contains reduced nodenumber (size 0 if not reduced); -1 means vertical pass through, 0 is idomain = 0 + integer(I4B), dimension(:), pointer, contiguous :: nodeuser => null() !< (size:nodes) given a reduced nodenumber, provide the user nodenumber (size 0 if not reduced) contains procedure :: dis_df procedure :: dis_ac @@ -57,11 +60,11 @@ module BaseDisModule ! -- get_nodenumber is an overloaded integer function that will always ! return the reduced nodenumber. For all grids, get_nodenumber can ! be passed the user nodenumber. For some other grids, it can also - ! be passed an index. For dis3d the index is k, i, j, and for + ! be passed an index. For dis3d the index is k, i, j, and for ! disv the index is k, n. - generic :: get_nodenumber => get_nodenumber_idx1, & - get_nodenumber_idx2, & - get_nodenumber_idx3 + generic :: get_nodenumber => get_nodenumber_idx1, & + get_nodenumber_idx2, & + get_nodenumber_idx3 procedure :: get_nodenumber_idx1 procedure :: get_nodenumber_idx2 procedure :: get_nodenumber_idx3 @@ -74,7 +77,6 @@ module BaseDisModule procedure :: noder_from_cellid procedure :: connection_normal procedure :: connection_vector - procedure :: get_cellxy procedure :: get_dis_type procedure :: supports_layers procedure :: allocate_scalars @@ -83,30 +85,29 @@ module BaseDisModule procedure :: get_cell_volume procedure :: write_grb ! - procedure :: read_int_array - procedure :: read_dbl_array - generic, public :: read_grid_array => read_int_array, read_dbl_array - procedure, public :: read_layer_array - procedure :: fill_int_array - procedure :: fill_dbl_array - generic, public :: fill_grid_array => fill_int_array, fill_dbl_array - procedure, public :: read_list - ! - procedure, public :: record_array - procedure, public :: record_connection_array - procedure, public :: noder_to_string - procedure, public :: noder_to_array - procedure, public :: record_srcdst_list_header + procedure :: read_int_array + procedure :: read_dbl_array + generic, public :: read_grid_array => read_int_array, read_dbl_array + procedure, public :: read_layer_array + procedure :: fill_int_array + procedure :: fill_dbl_array + generic, public :: fill_grid_array => fill_int_array, fill_dbl_array + procedure, public :: read_list + ! + procedure, public :: record_array + procedure, public :: record_connection_array + procedure, public :: noder_to_string + procedure, public :: noder_to_array + procedure, public :: record_srcdst_list_header procedure, private :: record_srcdst_list_entry - generic, public :: record_mf6_list_entry => record_srcdst_list_entry - procedure, public :: nlarray_to_nodelist - procedure, public :: highest_active - procedure, public :: get_area - procedure, public :: transform_xy - + generic, public :: record_mf6_list_entry => record_srcdst_list_entry + procedure, public :: nlarray_to_nodelist + procedure, public :: highest_active + procedure, public :: get_area + end type DisBaseType - - contains + +contains subroutine dis_df(this) ! ****************************************************************************** @@ -144,13 +145,13 @@ subroutine dis_ac(this, moffset, sparse) ! ------------------------------------------------------------------------------ ! do i = 1, this%nodes - do ipos = this%con%ia(i), this%con%ia(i+1) - 1 + do ipos = this%con%ia(i), this%con%ia(i + 1) - 1 j = this%con%ja(ipos) iglo = i + moffset jglo = j + moffset call sparse%addconnection(iglo, jglo, 1) - enddo - enddo + end do + end do ! ! -- Return return @@ -181,13 +182,13 @@ subroutine dis_mc(this, moffset, idxglo, iasln, jasln) j = this%con%ja(ipos) jglo = j + moffset searchloop: do ipossln = iasln(iglo), iasln(iglo + 1) - 1 - if(jglo == jasln(ipossln)) then + if (jglo == jasln(ipossln)) then idxglo(ipos) = ipossln exit searchloop - endif - enddo searchloop - enddo - enddo + end if + end do searchloop + end do + end do ! ! -- Return return @@ -210,17 +211,17 @@ subroutine dis_ar(this, icelltype) ! ------------------------------------------------------------------------------ ! ! -- Expand icelltype to full grid; fill with 0 if cell is excluded - allocate(ict(this%nodesuser)) + allocate (ict(this%nodesuser)) do nu = 1, this%nodesuser nr = this%get_nodenumber(nu, 0) if (nr > 0) then ict(nu) = icelltype(nr) else ict(nu) = 0 - endif - enddo + end if + end do ! - if (this%writegrb) call this%write_grb(ict) + if (this%nogrb == 0) call this%write_grb(ict) ! ! -- Return return @@ -262,7 +263,7 @@ subroutine dis_da(this) ! ------------------------------------------------------------------------------ ! ! -- Strings - deallocate(this%name_model) + deallocate (this%name_model) ! ! -- Scalars call mem_deallocate(this%inunit) @@ -271,7 +272,7 @@ subroutine dis_da(this) call mem_deallocate(this%nodesuser) call mem_deallocate(this%ndim) call mem_deallocate(this%icondir) - call mem_deallocate(this%writegrb) + call mem_deallocate(this%nogrb) call mem_deallocate(this%xorigin) call mem_deallocate(this%yorigin) call mem_deallocate(this%angrot) @@ -281,6 +282,8 @@ subroutine dis_da(this) ! ! -- Arrays call mem_deallocate(this%mshape) + call mem_deallocate(this%xc) + call mem_deallocate(this%yc) call mem_deallocate(this%top) call mem_deallocate(this%bot) call mem_deallocate(this%area) @@ -289,7 +292,7 @@ subroutine dis_da(this) ! ! -- Connections call this%con%con_da() - deallocate(this%con) + deallocate (this%con) ! ! -- Return return @@ -320,7 +323,7 @@ end subroutine nodeu_to_string subroutine nodeu_to_array(this, nodeu, arr) ! ****************************************************************************** ! nodeu_to_array -- Convert user node number to cellid and fill array with -! (nodenumber) or (k,j) or (k,i,j) +! (nodenumber) or (k,j) or (k,i,j) ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -353,11 +356,11 @@ function get_nodeuser(this, noder) result(nodenumber) integer(I4B), intent(in) :: noder ! ------------------------------------------------------------------------------ ! - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then nodenumber = this%nodeuser(noder) else nodenumber = noder - endif + end if ! ! -- return return @@ -440,10 +443,10 @@ function get_nodenumber_idx3(this, k, i, j, icheck) result(nodenumber) return end function get_nodenumber_idx3 - subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & + subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ipos) ! ****************************************************************************** -! connection_normal -- calculate the normal vector components for reduced +! connection_normal -- calculate the normal vector components for reduced ! nodenumber cell (noden) and its shared face with cell nodem. ihc is the ! horizontal connection flag. ! ****************************************************************************** @@ -469,11 +472,11 @@ subroutine connection_normal(this, noden, nodem, ihc, xcomp, ycomp, zcomp, & ! -- return return end subroutine connection_normal - - subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & + + subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & xcomp, ycomp, zcomp, conlen) ! ****************************************************************************** -! connection_vector -- calculate the unit vector components from reduced +! connection_vector -- calculate the unit vector components from reduced ! nodenumber cell (noden) to its neighbor cell (nodem). The saturation for ! for these cells are also required so that the vertical position of the cell ! cell centers can be calculated. ihc is the horizontal flag. Also return @@ -500,68 +503,56 @@ subroutine connection_vector(this, noden, nodem, nozee, satn, satm, ihc, & ! ------------------------------------------------------------------------------ ! call store_error('Program error: connection_vector not implemented.', & - terminate=.TRUE.) + terminate=.TRUE.) ! ! -- return return end subroutine connection_vector - - ! return x,y coordinate for a node - subroutine get_cellxy(this, node, xcell, ycell) - class(DisBaseType), intent(in) :: this - integer(I4B), intent(in) :: node - real(DP), intent(out) :: xcell, ycell - - ! suppress warning - xcell = -999999.0 - ycell = -999999.0 - - call store_error('Program error: get_cellxy not implemented.', & - terminate=.TRUE.) - - end subroutine get_cellxy - + !> @brief get the x,y for a node transformed into !! 'global coordinates' using xorigin, yorigin, angrot, - !< analogously to how flopy does this. - subroutine transform_xy(this, x, y, xglo, yglo) - class(DisBaseType), intent(in) :: this !< this DIS - real(DP), intent(in) :: x !< the cell-x coordinate to transform - real(DP), intent(in) :: y !< the cell-y coordinate to transform - real(DP), intent(out) :: xglo !< the global cell-x coordinate - real(DP), intent(out) :: yglo !< the global cell-y coordinate + !< analogously to how flopy does this. + subroutine dis_transform_xy(x, y, xorigin, yorigin, angrot, xglo, yglo) + real(DP), intent(in) :: x !< the cell-x coordinate to transform + real(DP), intent(in) :: y !< the cell-y coordinate to transform + real(DP), intent(in) :: xorigin !< the cell-y coordinate to transform + real(DP), intent(in) :: yorigin !< the cell-y coordinate to transform + real(DP), intent(in) :: angrot !< the cell-y coordinate to transform + real(DP), intent(out) :: xglo !< the global cell-x coordinate + real(DP), intent(out) :: yglo !< the global cell-y coordinate ! local real(DP) :: ang - + xglo = x yglo = y ! first _rotate_ to 'real world' - ang = this%angrot*DPIO180 + ang = angrot * DPIO180 if (ang /= DZERO) then - xglo = x*cos(ang) - y*sin(ang) - yglo = x*sin(ang) + y*cos(ang) + xglo = x * cos(ang) - y * sin(ang) + yglo = x * sin(ang) + y * cos(ang) end if ! then _translate_ - xglo = xglo + this%xorigin - yglo = yglo + this%yorigin + xglo = xglo + xorigin + yglo = yglo + yorigin - end subroutine transform_xy - - ! return discretization type + end subroutine dis_transform_xy + + !> @brief return discretization type + !< subroutine get_dis_type(this, dis_type) - class(DisBaseType), intent(in) :: this - character(len=*), intent(out) :: dis_type - + class(DisBaseType), intent(in) :: this + character(len=*), intent(out) :: dis_type + ! suppress warning - dis_type = "Not implemented" - + dis_type = "Not implemented" + call store_error('Program error: get_dis_type not implemented.', & - terminate=.TRUE.) - + terminate=.TRUE.) + end subroutine get_dis_type - + subroutine allocate_scalars(this, name_model) ! ****************************************************************************** ! allocate_scalars -- Allocate and initialize scalar variables in this class @@ -581,7 +572,7 @@ subroutine allocate_scalars(this, name_model) this%memoryPath = create_mem_path(name_model, 'DIS') ! ! -- Allocate - allocate(this%name_model) + allocate (this%name_model) ! call mem_allocate(this%inunit, 'INUNIT', this%memoryPath) call mem_allocate(this%iout, 'IOUT', this%memoryPath) @@ -589,7 +580,7 @@ subroutine allocate_scalars(this, name_model) call mem_allocate(this%nodesuser, 'NODESUSER', this%memoryPath) call mem_allocate(this%ndim, 'NDIM', this%memoryPath) call mem_allocate(this%icondir, 'ICONDIR', this%memoryPath) - call mem_allocate(this%writegrb, 'WRITEGRB', this%memoryPath) + call mem_allocate(this%nogrb, 'NOGRB', this%memoryPath) call mem_allocate(this%xorigin, 'XORIGIN', this%memoryPath) call mem_allocate(this%yorigin, 'YORIGIN', this%memoryPath) call mem_allocate(this%angrot, 'ANGROT', this%memoryPath) @@ -605,10 +596,10 @@ subroutine allocate_scalars(this, name_model) this%nodesuser = 0 this%ndim = 1 this%icondir = 1 - this%writegrb = .true. + this%nogrb = 0 this%xorigin = DZERO this%yorigin = DZERO - this%angrot = DZERO + this%angrot = DZERO this%nja = 0 this%njas = 0 this%lenuni = 0 @@ -633,6 +624,8 @@ subroutine allocate_arrays(this) ! ! -- Allocate call mem_allocate(this%mshape, this%ndim, 'MSHAPE', this%memoryPath) + call mem_allocate(this%xc, this%nodes, 'XC', this%memoryPath) + call mem_allocate(this%yc, this%nodes, 'YC', this%memoryPath) call mem_allocate(this%top, this%nodes, 'TOP', this%memoryPath) call mem_allocate(this%bot, this%nodes, 'BOT', this%memoryPath) call mem_allocate(this%area, this%nodes, 'AREA', this%memoryPath) @@ -641,11 +634,11 @@ subroutine allocate_arrays(this) this%mshape(1) = this%nodes ! ! -- Determine size of buff memory - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then isize = this%nodesuser else isize = this%nodes - endif + end if ! ! -- Allocate the arrays call mem_allocate(this%dbuff, isize, 'DBUFF', this%name_model) ! TODO_MJR: is this correct?? @@ -660,42 +653,42 @@ function nodeu_from_string(this, lloc, istart, istop, in, iout, line, & ! ****************************************************************************** ! nodeu_from_string -- Receive a string and convert the string to a user ! nodenumber. The model is unstructured; just read user nodenumber. -! If flag_string argument is present and true, the first token in string +! If flag_string argument is present and true, the first token in string ! is allowed to be a string (e.g. boundary name). In this case, if a string ! is encountered, return value as -2. ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- dummy - class(DisBaseType) :: this - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout - character(len=*), intent(inout) :: line - logical, optional, intent(in) :: flag_string - logical, optional, intent(in) :: allow_zero - integer(I4B) :: nodeu - ! -- local + ! -- dummy + class(DisBaseType) :: this + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout + character(len=*), intent(inout) :: line + logical, optional, intent(in) :: flag_string + logical, optional, intent(in) :: allow_zero + integer(I4B) :: nodeu + ! -- local ! ------------------------------------------------------------------------------ - ! - ! - nodeu = 0 - call store_error('Program error: DisBaseType method nodeu_from_string & - ¬ implemented.', terminate=.TRUE.) - ! - ! -- return - return + ! + ! + nodeu = 0 + call store_error('Program error: DisBaseType method nodeu_from_string & + ¬ implemented.', terminate=.TRUE.) + ! + ! -- return + return end function nodeu_from_string - - function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & - allow_zero) result(nodeu) + + function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & + allow_zero) result(nodeu) ! ****************************************************************************** ! nodeu_from_cellid -- Receive cellid as a string and convert the string to a -! user nodenumber. -! If flag_string argument is present and true, the first token in string +! user nodenumber. +! If flag_string argument is present and true, the first token in string ! is allowed to be a string (e.g. boundary name). In this case, if a string ! is encountered, return value as -2. ! If allow_zero argument is present and true, if all indices equal zero, the @@ -706,12 +699,12 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType) :: this - character(len=*), intent(inout) :: cellid - integer(I4B), intent(in) :: inunit - integer(I4B), intent(in) :: iout - logical, optional, intent(in) :: flag_string - logical, optional, intent(in) :: allow_zero + class(DisBaseType) :: this + character(len=*), intent(inout) :: cellid + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout + logical, optional, intent(in) :: flag_string + logical, optional, intent(in) :: allow_zero integer(I4B) :: nodeu ! ------------------------------------------------------------------------------ ! @@ -722,13 +715,13 @@ function nodeu_from_cellid(this, cellid, inunit, iout, flag_string, & ! -- return return end function nodeu_from_cellid - - function noder_from_string(this, lloc, istart, istop, in, iout, line, & + + function noder_from_string(this, lloc, istart, istop, in, iout, line, & flag_string) result(noder) ! ****************************************************************************** ! noder_from_string -- Receive a string and convert the string to a reduced ! nodenumber. The model is unstructured; just read user nodenumber. -! If flag_string argument is present and true, the first token in string +! If flag_string argument is present and true, the first token in string ! is allowed to be a string (e.g. boundary name). In this case, if a string ! is encountered, return value as -2. ! ****************************************************************************** @@ -736,15 +729,15 @@ function noder_from_string(this, lloc, istart, istop, in, iout, line, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType) :: this - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout - character(len=*), intent(inout) :: line - logical, optional, intent(in) :: flag_string - integer(I4B) :: noder + class(DisBaseType) :: this + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout + character(len=*), intent(inout) :: line + logical, optional, intent(in) :: flag_string + integer(I4B) :: noder ! -- local integer(I4B) :: nodeu character(len=LINELENGTH) :: nodestr @@ -755,8 +748,8 @@ function noder_from_string(this, lloc, istart, istop, in, iout, line, & flag_string_local = flag_string else flag_string_local = .false. - endif - nodeu = this%nodeu_from_string(lloc, istart, istop, in, iout, line, & + end if + nodeu = this%nodeu_from_string(lloc, istart, istop, in, iout, line, & flag_string_local) ! ! -- Convert user-based nodenumber to reduced node number @@ -764,25 +757,25 @@ function noder_from_string(this, lloc, istart, istop, in, iout, line, & noder = this%get_nodenumber(nodeu, 0) else noder = nodeu - endif - if(noder <= 0 .and. .not. flag_string_local) then + end if + if (noder <= 0 .and. .not. flag_string_local) then call this%nodeu_to_string(nodeu, nodestr) - write(errmsg, *) & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif + end if ! ! -- return return end function noder_from_string - - function noder_from_cellid(this, cellid, inunit, iout, flag_string, & - allow_zero) result(noder) + + function noder_from_cellid(this, cellid, inunit, iout, flag_string, & + allow_zero) result(noder) ! ****************************************************************************** ! noder_from_cellid -- Receive cellid as a string and convert it to a reduced -! nodenumber. -! If flag_string argument is present and true, the first token in string +! nodenumber. +! If flag_string argument is present and true, the first token in string ! is allowed to be a string (e.g. boundary name). In this case, if a string ! is encountered, return value as -2. ! If allow_zero argument is present and true, if all indices equal zero, the @@ -795,12 +788,12 @@ function noder_from_cellid(this, cellid, inunit, iout, flag_string, & ! -- return integer(I4B) :: noder ! -- dummy - class(DisBaseType) :: this - character(len=*), intent(inout) :: cellid - integer(I4B), intent(in) :: inunit - integer(I4B), intent(in) :: iout - logical, optional, intent(in) :: flag_string - logical, optional, intent(in) :: allow_zero + class(DisBaseType) :: this + character(len=*), intent(inout) :: cellid + integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: iout + logical, optional, intent(in) :: flag_string + logical, optional, intent(in) :: allow_zero ! -- local integer(I4B) :: nodeu logical :: allowzerolocal @@ -812,14 +805,14 @@ function noder_from_cellid(this, cellid, inunit, iout, flag_string, & flag_string_local = flag_string else flag_string_local = .false. - endif + end if if (present(allow_zero)) then allowzerolocal = allow_zero else allowzerolocal = .false. - endif + end if ! - nodeu = this%nodeu_from_cellid(cellid, inunit, iout, flag_string_local, & + nodeu = this%nodeu_from_cellid(cellid, inunit, iout, flag_string_local, & allowzerolocal) ! ! -- Convert user-based nodenumber to reduced node number @@ -827,19 +820,19 @@ function noder_from_cellid(this, cellid, inunit, iout, flag_string, & noder = this%get_nodenumber(nodeu, 0) else noder = nodeu - endif - if(noder <= 0 .and. .not. flag_string_local) then + end if + if (noder <= 0 .and. .not. flag_string_local) then call this%nodeu_to_string(nodeu, nodestr) - write(errmsg, *) & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif + end if ! ! -- return return end function noder_from_cellid - + logical function supports_layers(this) ! ****************************************************************************** ! supports_layers @@ -881,7 +874,7 @@ function get_ncpl(this) ! -- Return return end function get_ncpl - + function get_cell_volume(this, n, x) ! ****************************************************************************** ! get_cell_volume -- Return volume of cell n based on x value passed. @@ -923,15 +916,15 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(DisBaseType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: iarray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! ! -- store error errmsg = 'Programmer error: read_int_array needs to be overridden & @@ -942,7 +935,7 @@ subroutine read_int_array(this, line, lloc, istart, istop, iout, in, & return end subroutine read_int_array - subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & + subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & darray, aname) ! ****************************************************************************** ! read_dbl_array -- Read a GWF double precision array @@ -951,15 +944,15 @@ subroutine read_dbl_array(this, line, lloc, istart, istop, iout, in, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType), intent(inout) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - integer(I4B), intent(in) :: in - integer(I4B), intent(in) :: iout + class(DisBaseType), intent(inout) :: this + character(len=*), intent(inout) :: line + integer(I4B), intent(inout) :: lloc + integer(I4B), intent(inout) :: istart + integer(I4B), intent(inout) :: istop + integer(I4B), intent(in) :: in + integer(I4B), intent(in) :: iout real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - character(len=*), intent(in) :: aname + character(len=*), intent(in) :: aname ! ! -- str=ore error message errmsg = 'Programmer error: read_dbl_array needs to be overridden & @@ -978,8 +971,8 @@ subroutine fill_int_array(this, ibuff1, ibuff2) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType), intent(inout) :: this - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ibuff1 + class(DisBaseType), intent(inout) :: this + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: ibuff1 integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: ibuff2 ! -- local integer(I4B) :: nodeu @@ -987,7 +980,7 @@ subroutine fill_int_array(this, ibuff1, ibuff2) ! ------------------------------------------------------------------------------ do nodeu = 1, this%nodesuser noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) cycle + if (noder <= 0) cycle ibuff2(noder) = ibuff1(nodeu) end do ! @@ -1003,8 +996,8 @@ subroutine fill_dbl_array(this, buff1, buff2) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType), intent(inout) :: this - real(DP), dimension(:), pointer, contiguous, intent(in) :: buff1 + class(DisBaseType), intent(inout) :: this + real(DP), dimension(:), pointer, contiguous, intent(in) :: buff1 real(DP), dimension(:), pointer, contiguous, intent(inout) :: buff2 ! -- local integer(I4B) :: nodeu @@ -1012,21 +1005,21 @@ subroutine fill_dbl_array(this, buff1, buff2) ! ------------------------------------------------------------------------------ do nodeu = 1, this%nodesuser noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) cycle + if (noder <= 0) cycle buff2(noder) = buff1(nodeu) end do ! ! -- return return end subroutine fill_dbl_array - - subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & - iauxmultcol, nodelist, rlist, auxvar, auxname, & - boundname, label, pkgname, tsManager, iscloc, & - indxconvertflux) + + subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & + iauxmultcol, nodelist, rlist, auxvar, auxname, & + boundname, label, pkgname, tsManager, iscloc, & + indxconvertflux) ! ****************************************************************************** ! read_list -- Read a list using the list reader object. -! Convert user node numbers to reduced numbers. +! Convert user node numbers to reduced numbers. ! Terminate if any nodenumbers are within an inactive domain. ! Set up time series and multiply by iauxmultcol if it exists. ! Write the list to iout if iprpak is set. @@ -1039,7 +1032,7 @@ subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & use ListReaderModule, only: ListReaderType use SimModule, only: store_error, store_error_unit, count_errors use InputOutputModule, only: urword - use TimeSeriesLinkModule, only: TimeSeriesLinkType + use TimeSeriesLinkModule, only: TimeSeriesLinkType use TimeSeriesManagerModule, only: read_value_or_time_series ! -- dummy class(DisBaseType) :: this @@ -1050,16 +1043,16 @@ subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & integer(I4B), intent(in) :: inamedbound integer(I4B), intent(in) :: iauxmultcol integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: nodelist - real(DP), dimension(:,:), pointer, contiguous, intent(inout) :: rlist - real(DP), dimension(:,:), pointer, contiguous, intent(inout) :: auxvar + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: rlist + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: auxvar character(len=LENAUXNAME), dimension(:), intent(inout) :: auxname - character(len=LENBOUNDNAME), dimension(:), pointer, contiguous, & - intent(inout) :: boundname + character(len=LENBOUNDNAME), dimension(:), pointer, contiguous, & + intent(inout) :: boundname !character(len=:), dimension(:), pointer, contiguous, intent(inout) :: auxname !character(len=:), dimension(:), pointer, contiguous, intent(inout) :: boundname character(len=*), intent(in) :: label - character(len=*), intent(in) :: pkgName - type(TimeSeriesManagerType) :: tsManager + character(len=*), intent(in) :: pkgName + type(TimeSeriesManagerType) :: tsManager integer(I4B), intent(in) :: iscloc integer(I4B), intent(in), optional :: indxconvertflux ! -- local @@ -1074,32 +1067,33 @@ subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & ! ------------------------------------------------------------------------------ ! ! -- Read the list - call lstrdobj%read_list(in, iout, nlist, inamedbound, this%mshape, & + call lstrdobj%read_list(in, iout, nlist, inamedbound, this%mshape, & nodelist, rlist, auxvar, auxname, boundname, label) ! ! -- Go through all locations where a text string was found instead of ! a double precision value and make time-series links to rlist - if(lstrdobj%ntxtrlist > 0) then + if (lstrdobj%ntxtrlist > 0) then do l = 1, lstrdobj%ntxtrlist ii = lstrdobj%idxtxtrow(l) jj = lstrdobj%idxtxtcol(l) tsLinkBnd => NULL() bndElem => rlist(jj, ii) - call read_value_or_time_series(lstrdobj%txtrlist(l), ii, jj, & - bndElem, pkgName, 'BND', tsManager, iprpak, tsLinkBnd) + call read_value_or_time_series(lstrdobj%txtrlist(l), ii, jj, bndElem, & + pkgName, 'BND', tsManager, iprpak, & + tsLinkBnd) if (associated(tsLinkBnd)) then ! ! -- If iauxmultcol is active and this column is the column - ! to be scaled, then assign tsLinkBnd%RMultiplier to auxvar + ! to be scaled, then assign tsLinkBnd%RMultiplier to auxvar ! multiplier if (iauxmultcol > 0 .and. jj == iscloc) then tsLinkBnd%RMultiplier => auxvar(iauxmultcol, ii) - endif + end if ! ! -- If boundaries are named, save the name in the link if (lstrdobj%inamedbound == 1) then tsLinkBnd%BndName = lstrdobj%boundname(tsLinkBnd%IRow) - endif + end if ! ! -- if the value is a flux and needs to be converted to a flow ! then set the tsLinkBnd appropriately @@ -1109,71 +1103,72 @@ subroutine read_list(this, in, iout, iprpak, nlist, inamedbound, & nodeu = nodelist(ii) noder = this%get_nodenumber(nodeu, 0) tsLinkBnd%CellArea = this%get_area(noder) - endif - endif + end if + end if ! - endif - enddo - endif + end if + end do + end if ! ! -- Make time-series substitutions for auxvar - if(lstrdobj%ntxtauxvar > 0) then + if (lstrdobj%ntxtauxvar > 0) then do l = 1, lstrdobj%ntxtauxvar ii = lstrdobj%idxtxtauxrow(l) jj = lstrdobj%idxtxtauxcol(l) tsLinkAux => NULL() bndElem => auxvar(jj, ii) - call read_value_or_time_series(lstrdobj%txtauxvar(l), ii, jj, & - bndElem, pkgName, 'AUX', tsManager, iprpak, tslinkAux) + call read_value_or_time_series(lstrdobj%txtauxvar(l), ii, jj, bndElem, & + pkgName, 'AUX', tsManager, iprpak, & + tslinkAux) if (lstrdobj%inamedbound == 1) then if (associated(tsLinkAux)) then tsLinkAux%BndName = lstrdobj%boundname(tsLinkAux%IRow) - endif - endif - enddo - endif + end if + end if + end do + end if ! ! -- Multiply rlist by the multiplier column in auxvar - if(iauxmultcol > 0) then + if (iauxmultcol > 0) then do l = 1, nlist rlist(iscloc, l) = rlist(iscloc, l) * auxvar(iauxmultcol, l) - enddo - endif + end do + end if ! ! -- Write the list to iout if requested - if(iprpak /= 0) then + if (iprpak /= 0) then call lstrdobj%write_list() - endif + end if ! ! -- Convert user nodenumbers to reduced nodenumbers, if necessary. ! Conversion to reduced nodenumbers must be done last, after the ! list is written so that correct indices are written to the list. - if(this%nodes < this%nodesuser) then + if (this%nodes < this%nodesuser) then do l = 1, nlist nodeu = nodelist(l) noder = this%get_nodenumber(nodeu, 0) - if(noder <= 0) then + if (noder <= 0) then call this%nodeu_to_string(nodeu, nodestr) - write(errmsg, *) & - ' Cell is outside active grid domain: ' // & - trim(adjustl(nodestr)) + write (errmsg, *) & + ' Cell is outside active grid domain: '// & + trim(adjustl(nodestr)) call store_error(errmsg) - endif + end if nodelist(l) = noder - enddo + end do ! ! -- Check for errors and terminate if encountered - if(count_errors() > 0) then - write(errmsg, *) count_errors(), ' errors encountered.' + if (count_errors() > 0) then + write (errmsg, *) count_errors(), ' errors encountered.' call store_error(errmsg) call store_error_unit(in) - endif - endif + end if + end if ! ! -- return end subroutine read_list - subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & + subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & icolbnd, aname, inunit, iout) ! ****************************************************************************** ! read_layer_array -- Read a 2d double array into col icolbnd of darray. @@ -1202,9 +1197,9 @@ subroutine read_layer_array(this, nodelist, darray, ncolbnd, maxbnd, & ! ! -- return end subroutine read_layer_array - - subroutine record_array(this, darray, iout, iprint, idataun, aname, & - cdatafmp, nvaluesp, nwidthp, editdesc, dinact) + + subroutine record_array(this, darray, iout, iprint, idataun, aname, & + cdatafmp, nvaluesp, nwidthp, editdesc, dinact) ! ****************************************************************************** ! record_array -- Record a double precision array. The array will be ! printed to an external file and/or written to an unformatted external file @@ -1226,19 +1221,19 @@ subroutine record_array(this, darray, iout, iprint, idataun, aname, & ! from the model domain ! ------------------------------------------------------------------------------ ! -- dummy - class(DisBaseType), intent(inout) :: this + class(DisBaseType), intent(inout) :: this real(DP), dimension(:), pointer, contiguous, intent(inout) :: darray - integer(I4B), intent(in) :: iout - integer(I4B), intent(in) :: iprint - integer(I4B), intent(in) :: idataun - character(len=*), intent(in) :: aname - character(len=*), intent(in) :: cdatafmp - integer(I4B), intent(in) :: nvaluesp - integer(I4B), intent(in) :: nwidthp - character(len=*), intent(in) :: editdesc - real(DP), intent(in) :: dinact - ! - ! -- + integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: iprint + integer(I4B), intent(in) :: idataun + character(len=*), intent(in) :: aname + character(len=*), intent(in) :: cdatafmp + integer(I4B), intent(in) :: nvaluesp + integer(I4B), intent(in) :: nwidthp + character(len=*), intent(in) :: editdesc + real(DP), intent(in) :: dinact + ! + ! -- errmsg = 'Programmer error: record_array needs to be overridden & &in any DIS type that extends DisBaseType' call store_error(errmsg, terminate=.TRUE.) @@ -1261,11 +1256,11 @@ subroutine record_connection_array(this, flowja, ibinun, iout) ! -- local character(len=16), dimension(1) :: text ! -- data - data text(1) /' FLOW-JA-FACE'/ + data text(1)/' FLOW-JA-FACE'/ ! ------------------------------------------------------------------------------ ! ! -- write full ja array - call ubdsv1(kstp, kper, text(1), ibinun, flowja, size(flowja), 1, 1, & + call ubdsv1(kstp, kper, text(1), ibinun, flowja, size(flowja), 1, 1, & iout, delt, pertim, totim) ! ! -- return @@ -1299,7 +1294,7 @@ end subroutine noder_to_string subroutine noder_to_array(this, noder, arr) ! ****************************************************************************** ! noder_to_array -- Convert reduced node number to cellid and fill array with -! (nodenumber) or (k,j) or (k,i,j) +! (nodenumber) or (k,j) or (k,i,j) ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -1320,8 +1315,8 @@ subroutine noder_to_array(this, noder, arr) return end subroutine noder_to_array - subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & - dstmodel, dstpackage, naux, auxtxt, & + subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & + dstmodel, dstpackage, naux, auxtxt, & ibdchn, nlist, iout) ! ****************************************************************************** ! record_srcdst_list_header -- Record list header for imeth=6 @@ -1342,7 +1337,7 @@ subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & integer(I4B), intent(in) :: nlist integer(I4B), intent(in) :: iout ! - ! -- + ! -- errmsg = 'Programmer error: record_srcdst_list_header needs to be & &overridden in any DIS type that extends DisBaseType' call store_error(errmsg, terminate=.TRUE.) @@ -1351,7 +1346,7 @@ subroutine record_srcdst_list_header(this, text, textmodel, textpackage, & return end subroutine record_srcdst_list_header - subroutine record_srcdst_list_entry(this, ibdchn, noder, noder2, q, & + subroutine record_srcdst_list_entry(this, ibdchn, noder, noder2, q, & naux, aux, olconv, olconv2) ! ****************************************************************************** ! record_srcdst_list_header -- Record list header @@ -1405,7 +1400,7 @@ subroutine record_srcdst_list_entry(this, ibdchn, noder, noder2, q, & return end subroutine record_srcdst_list_entry - subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & + subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & inunit, iout) ! ****************************************************************************** ! nlarray_to_nodelist -- Read an integer array into nodelist. For structured @@ -1427,7 +1422,7 @@ subroutine nlarray_to_nodelist(this, nodelist, maxbnd, nbound, aname, & integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout ! - ! -- + ! -- errmsg = 'Programmer error: nlarray_to_nodelist needs to be & &overridden in any DIS type that extends DisBaseType' call store_error(errmsg, terminate=.TRUE.) @@ -1448,36 +1443,36 @@ subroutine highest_active(this, n, ibound) integer(I4B), intent(inout) :: n integer(I4B), dimension(:), intent(in) :: ibound ! -- locals - integer(I4B) :: m,ii,iis + integer(I4B) :: m, ii, iis logical done, bottomcell ! ------------------------------------------------------------------------------ ! ! -- Loop through connected cells until the highest active one (including a ! constant head cell) is found. Return that cell as n. - done=.false. - do while(.not. done) + done = .false. + do while (.not. done) bottomcell = .true. - cloop: do ii = this%con%ia(n) + 1, this%con%ia(n+1)-1 + cloop: do ii = this%con%ia(n) + 1, this%con%ia(n + 1) - 1 m = this%con%ja(ii) iis = this%con%jas(ii) - if(this%con%ihc(iis) == 0 .and. m > n) then + if (this%con%ihc(iis) == 0 .and. m > n) then ! ! -- this cannot be a bottom cell bottomcell = .false. ! ! -- vertical down - if(ibound(m) /= 0) then + if (ibound(m) /= 0) then n = m done = .true. exit cloop else n = m exit cloop - endif - endif - enddo cloop - if(bottomcell) done = .true. - enddo + end if + end if + end do cloop + if (bottomcell) done = .true. + end do ! ! -- return return diff --git a/src/Model/ModelUtilities/DisvGeom.f90 b/src/Model/ModelUtilities/DisvGeom.f90 index c433f5f215f..581ad424b88 100644 --- a/src/Model/ModelUtilities/DisvGeom.f90 +++ b/src/Model/ModelUtilities/DisvGeom.f90 @@ -1,12 +1,12 @@ module DisvGeom - + use KindModule, only: DP, I4B use InputOutputModule, only: get_node, get_jk implicit none private public :: DisvGeomType public :: line_unit_vector - + type DisvGeomType integer(I4B) :: k integer(I4B) :: j @@ -15,7 +15,7 @@ module DisvGeom integer(I4B) :: nlay integer(I4B) :: ncpl logical :: reduced - integer(I4B) :: nodes ! number of reduced nodes; nodes = nlay *ncpl when grid is NOT reduced + integer(I4B) :: nodes ! number of reduced nodes; nodes = nlay *ncpl when grid is NOT reduced real(DP) :: top real(DP) :: bot real(DP), pointer, dimension(:) :: top_grid => null() @@ -24,8 +24,8 @@ module DisvGeom integer(I4B), pointer, dimension(:) :: javert => null() real(DP), pointer, dimension(:, :) :: vertex_grid => null() real(DP), pointer, dimension(:, :) :: cellxy_grid => null() - integer(I4B), pointer, dimension(:, :) :: nodereduced => null() ! nodered = nodereduced(nodeusr) - integer(I4B), pointer, dimension(:) :: nodeuser => null() ! nodeusr = nodesuser(nodered) + integer(I4B), pointer, dimension(:, :) :: nodereduced => null() ! nodered = nodereduced(nodeusr) + integer(I4B), pointer, dimension(:) :: nodeuser => null() ! nodeusr = nodesuser(nodered) contains procedure :: init generic :: set => set_kj, set_nodered @@ -38,10 +38,10 @@ module DisvGeom procedure :: shares_edge procedure :: get_area end type DisvGeomType - - contains - - subroutine init(this, nlay, ncpl, nodes, top_grid, bot_grid, iavert, & + +contains + + subroutine init(this, nlay, ncpl, nodes, top_grid, bot_grid, iavert, & javert, vertex_grid, cellxy_grid, nodereduced, nodeuser) class(DisvGeomType) :: this integer(I4B), intent(in) :: nlay @@ -69,13 +69,13 @@ subroutine init(this, nlay, ncpl, nodes, top_grid, bot_grid, iavert, & this%nodereduced => nodereduced this%nodeuser => nodeuser nodesuser = ncpl * nlay - if(nodes < nodesuser) then + if (nodes < nodesuser) then this%reduced = .true. else this%reduced = .false. - endif + end if end subroutine init - + subroutine set_kj(this, k, j) class(DisvGeomType) :: this integer(I4B), intent(in) :: k @@ -83,11 +83,11 @@ subroutine set_kj(this, k, j) this%k = k this%j = j this%nodeusr = get_node(k, 1, j, this%nlay, 1, this%ncpl) - if(this%reduced) then + if (this%reduced) then this%nodered = this%nodereduced(k, j) else this%nodered = this%nodeusr - endif + end if call this%cell_setup() return end subroutine set_kj @@ -96,11 +96,11 @@ subroutine set_nodered(this, nodered) class(DisvGeomType) :: this integer(I4B), intent(in) :: nodered this%nodered = nodered - if(this%reduced) then + if (this%reduced) then this%nodeusr = this%nodeuser(nodered) else this%nodeusr = nodered - endif + end if call get_jk(this%nodeusr, this%ncpl, this%nlay, this%j, this%k) call this%cell_setup() return @@ -111,7 +111,7 @@ subroutine cell_setup(this) this%top = this%top_grid(this%nodered) this%bot = this%bot_grid(this%nodered) end subroutine cell_setup - + subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc) ! -- module use ConstantsModule, only: DZERO, DHALF, DONE @@ -127,7 +127,7 @@ subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc) integer(I4B) :: istart1, istart2, istop1, istop2 real(DP) :: x0, y0, x1, y1, x2, y2 ! - if(this%j == cell2%j) then + if (this%j == cell2%j) then ! ! -- Cells share same j index, so must be a vertical connection ihc = 0 @@ -146,7 +146,7 @@ subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc) call shared_edge(this%javert(istart1:istop1), & this%javert(istart2:istop2), & ivert1, ivert2) - if(ivert1 == 0 .or. ivert2 == 0) then + if (ivert1 == 0 .or. ivert2 == 0) then ! ! -- Cells do not share an edge hwva = DZERO @@ -175,11 +175,11 @@ subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc) x2 = this%vertex_grid(1, ivert2) y2 = this%vertex_grid(2, ivert2) ax = anglex(x1, y1, x2, y2) - endif - endif - return + end if + end if + return end subroutine cprops - + subroutine edge_normal(this, cell2, xcomp, ycomp) ! return the x and y components of an outward normal ! facing vector @@ -200,19 +200,19 @@ subroutine edge_normal(this, cell2, xcomp, ycomp) istart2 = cell2%iavert(cell2%j) istop2 = this%iavert(cell2%j + 1) - 1 call shared_edge(this%javert(istart1:istop1), & - this%javert(istart2:istop2), & - ivert1, ivert2) + this%javert(istart2:istop2), & + ivert1, ivert2) x1 = this%vertex_grid(1, ivert1) y1 = this%vertex_grid(2, ivert1) x2 = this%vertex_grid(1, ivert2) y2 = this%vertex_grid(2, ivert2) ! call line_unit_normal(x1, y1, x2, y2, xcomp, ycomp) - return + return end subroutine edge_normal - - subroutine connection_vector(this, cell2, nozee, satn, satm, xcomp, & - ycomp, zcomp, conlen) + + subroutine connection_vector(this, cell2, nozee, satn, satm, xcomp, & + ycomp, zcomp, conlen) ! return the x y and z components of a unit vector that points ! from the center of this to the center of cell2, and the ! straight-line connection length @@ -243,11 +243,11 @@ subroutine connection_vector(this, cell2, nozee, satn, satm, xcomp, & z2 = cell2%bot + DHALF * satm * (cell2%top - cell2%bot) end if ! - call line_unit_vector(x1, y1, z1, x2, y2, z2, xcomp, ycomp, zcomp, & + call line_unit_vector(x1, y1, z1, x2, y2, z2, xcomp, ycomp, zcomp, & conlen) - return + return end subroutine connection_vector - + function shares_edge(this, cell2) result(l) ! ****************************************************************************** ! shares_edge -- Return true if this shares a horizontal edge with cell2 @@ -266,15 +266,15 @@ function shares_edge(this, cell2) result(l) istart2 = cell2%iavert(cell2%j) istop2 = this%iavert(cell2%j + 1) - 1 call shared_edge(this%javert(istart1:istop1), & - this%javert(istart2:istop2), & - ivert1, ivert2) + this%javert(istart2:istop2), & + ivert1, ivert2) l = .true. - if(ivert1 == 0 .or. ivert2 == 0) then + if (ivert1 == 0 .or. ivert2 == 0) then l = .false. - endif - return + end if + return end function shares_edge - + subroutine shared_edge(ivlist1, ivlist2, ivert1, ivert2) ! ****************************************************************************** ! shared_edge -- Find two common vertices shared by cell1 and cell2. @@ -304,22 +304,22 @@ subroutine shared_edge(ivlist1, ivlist2, ivert1, ivert2) ivert2 = 0 outerloop: do il1 = 1, nv1 - 1 do il2 = nv2, 2, -1 - if(ivlist1(il1) == ivlist2(il2) .and. & - ivlist1(il1 + 1) == ivlist2(il2 - 1)) then + if (ivlist1(il1) == ivlist2(il2) .and. & + ivlist1(il1 + 1) == ivlist2(il2 - 1)) then found = .true. ivert1 = ivlist1(il1) ivert2 = ivlist1(il1 + 1) exit outerloop - endif - enddo - if(found) exit - enddo outerloop + end if + end do + if (found) exit + end do outerloop end subroutine shared_edge - + function get_area(this) result(area) ! ****************************************************************************** ! get_cell2d_area -- Calculate and return the area of the cell -! a = 1/2 *[(x1*y2 + x2*y3 + x3*y4 + ... + xn*y1) - +! a = 1/2 *[(x1*y2 + x2*y3 + x3*y4 + ... + xn*y1) - ! (x2*y1 + x3*y2 + x4*y3 + ... + x1*yn)] ! ****************************************************************************** ! @@ -344,37 +344,37 @@ function get_area(this) result(area) icount = 1 do ivert = this%iavert(this%j), this%iavert(this%j + 1) - 1 x = this%vertex_grid(1, this%javert(ivert)) - if(icount < nvert) then + if (icount < nvert) then y = this%vertex_grid(2, this%javert(ivert + 1)) else y = this%vertex_grid(2, this%javert(this%iavert(this%j))) - endif + end if area = area + x * y icount = icount + 1 - enddo + end do ! icount = 1 do ivert = this%iavert(this%j), this%iavert(this%j + 1) - 1 y = this%vertex_grid(2, this%javert(ivert)) - if(icount < nvert) then + if (icount < nvert) then x = this%vertex_grid(1, this%javert(ivert + 1)) else x = this%vertex_grid(1, this%javert(this%iavert(this%j))) - endif + end if area = area - x * y icount = icount + 1 - enddo + end do ! area = abs(area) * DHALF ! ! -- return return end function get_area - + function anglex(x1, y1, x2, y2) result(ax) ! ****************************************************************************** -! anglex -- Calculate the angle that the x-axis makes with a line that is -! normal to the two points. This assumes that vertices are numbered +! anglex -- Calculate the angle that the x-axis makes with a line that is +! normal to the two points. This assumes that vertices are numbered ! clockwise so that the angle is for the normal outward of cell n. ! ****************************************************************************** ! @@ -392,10 +392,10 @@ function anglex(x1, y1, x2, y2) result(ax) dx = x2 - x1 dy = y2 - y1 ax = atan2(dx, -dy) - if(ax < DZERO) ax = DTWO * DPI + ax + if (ax < DZERO) ax = DTWO * DPI + ax return end function anglex - + function distance(x1, y1, x2, y2) result(d) ! ****************************************************************************** ! distance -- Calculate distance between two points @@ -409,11 +409,11 @@ function distance(x1, y1, x2, y2) result(d) real(DP), intent(in) :: y2 real(DP) :: d ! ------------------------------------------------------------------------------ - d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + d = (x1 - x2)**2 + (y1 - y2)**2 d = sqrt(d) return end function distance - + function distance_normal(x0, y0, x1, y1, x2, y2) result(d) ! ****************************************************************************** ! distance_normal -- Calculate normal distance from point (x0, y0) to line @@ -434,10 +434,10 @@ function distance_normal(x0, y0, x1, y1, x2, y2) result(d) d = d / distance(x1, y1, x2, y2) return end function distance_normal - + subroutine line_unit_normal(x0, y0, x1, y1, xcomp, ycomp) ! ****************************************************************************** -! line_unit_normal -- Calculate the normal vector components (xcomp and ycomp) +! line_unit_normal -- Calculate the normal vector components (xcomp and ycomp) ! for a line defined by two points, (x0, y0), (x1, y1) ! ****************************************************************************** ! @@ -453,16 +453,16 @@ subroutine line_unit_normal(x0, y0, x1, y1, xcomp, ycomp) ! ------------------------------------------------------------------------------ dx = x1 - x0 dy = y1 - y0 - vmag = sqrt(dx ** 2 + dy ** 2) + vmag = sqrt(dx**2 + dy**2) xcomp = -dy / vmag ycomp = dx / vmag return end subroutine line_unit_normal - - subroutine line_unit_vector(x0, y0, z0, x1, y1, z1, & - xcomp, ycomp, zcomp, vmag) + + subroutine line_unit_vector(x0, y0, z0, x1, y1, z1, & + xcomp, ycomp, zcomp, vmag) ! ****************************************************************************** -! line_unit_vector -- Calculate the vector components (xcomp, ycomp, and zcomp) +! line_unit_vector -- Calculate the vector components (xcomp, ycomp, and zcomp) ! for a line defined by two points, (x0, y0, z0), (x1, y1, z1). Also return ! the magnitude of the original vector, vmag. ! ****************************************************************************** @@ -483,12 +483,11 @@ subroutine line_unit_vector(x0, y0, z0, x1, y1, z1, & dx = x1 - x0 dy = y1 - y0 dz = z1 - z0 - vmag = sqrt(dx ** 2 + dy ** 2 + dz ** 2) + vmag = sqrt(dx**2 + dy**2 + dz**2) xcomp = dx / vmag ycomp = dy / vmag zcomp = dz / vmag return end subroutine line_unit_vector - - -end module DisvGeom \ No newline at end of file + +end module DisvGeom diff --git a/src/Model/ModelUtilities/GwfBuyInputData.f90 b/src/Model/ModelUtilities/GwfBuyInputData.f90 index b3c9944addb..6e35997a0f2 100644 --- a/src/Model/ModelUtilities/GwfBuyInputData.f90 +++ b/src/Model/ModelUtilities/GwfBuyInputData.f90 @@ -10,15 +10,15 @@ module GwfBuyInputDataModule type, public :: GwfBuyInputDataType ! options - integer(I4B) :: iform !< see BUY for description - real(DP) :: denseref !< see BUY for description + integer(I4B) :: iform !< see BUY for description + real(DP) :: denseref !< see BUY for description ! dim - integer(I4B) :: nrhospecies !< see BUY for description + integer(I4B) :: nrhospecies !< see BUY for description ! pkg data - real(DP), dimension(:), pointer, contiguous :: drhodc => null() !< see BUY for description - real(DP), dimension(:), pointer, contiguous :: crhoref => null() !< see BUY for description - character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< see BUY for description + real(DP), dimension(:), pointer, contiguous :: drhodc => null() !< see BUY for description + real(DP), dimension(:), pointer, contiguous :: crhoref => null() !< see BUY for description + character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< see BUY for description character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname !< see BUY for description contains @@ -32,12 +32,12 @@ module GwfBuyInputDataModule !< subroutine construct(this, nrhospecies) class(GwfBuyInputDataType) :: this !< the input data block - integer(I4B) :: nrhospecies !< the number of species + integer(I4B) :: nrhospecies !< the number of species - allocate(this%drhodc(nrhospecies)) - allocate(this%crhoref(nrhospecies)) - allocate(this%cmodelname(nrhospecies)) - allocate(this%cauxspeciesname(nrhospecies)) + allocate (this%drhodc(nrhospecies)) + allocate (this%crhoref(nrhospecies)) + allocate (this%cmodelname(nrhospecies)) + allocate (this%cauxspeciesname(nrhospecies)) end subroutine construct @@ -46,11 +46,11 @@ end subroutine construct subroutine destruct(this) class(GwfBuyInputDataType) :: this !< the input data block - deallocate(this%drhodc) - deallocate(this%crhoref) - deallocate(this%cmodelname) - deallocate(this%cauxspeciesname) + deallocate (this%drhodc) + deallocate (this%crhoref) + deallocate (this%cmodelname) + deallocate (this%cauxspeciesname) end subroutine destruct -end module GwfBuyInputDataModule \ No newline at end of file +end module GwfBuyInputDataModule diff --git a/src/Model/ModelUtilities/GwfMvrPeriodData.f90 b/src/Model/ModelUtilities/GwfMvrPeriodData.f90 new file mode 100644 index 00000000000..c65b6b55cb6 --- /dev/null +++ b/src/Model/ModelUtilities/GwfMvrPeriodData.f90 @@ -0,0 +1,177 @@ +!> @brief This module contains the GwfMvrPeriodDataModule Module +!! +!! This module contains the code for storing and reading +!! stress period data for the GwfMvr Package. +!! +!< +module GwfMvrPeriodDataModule + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMEMPATH, LENMODELNAME, LENPACKAGENAME, & + LINELENGTH + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use BlockParserModule, only: BlockParserType + + implicit none + private + public GwfMvrPeriodDataType + + !> @brief Derived type for GwfMvrPeriodDataType + !! + !! This derived type contains information and methods for + !! the data read for the GwfMvr Package. + !! + !< + type GwfMvrPeriodDataType + character(len=LENMODELNAME), & + dimension(:), pointer, contiguous :: mname1 => null() !< provider model name + character(len=LENPACKAGENAME), & + dimension(:), pointer, contiguous :: pname1 => null() !< provider package name + character(len=LENMODELNAME), & + dimension(:), pointer, contiguous :: mname2 => null() !< receiver model name + character(len=LENPACKAGENAME), & + dimension(:), pointer, contiguous :: pname2 => null() !< receiver package name + integer(I4B), dimension(:), pointer, contiguous :: id1 => null() !< provider reach number + integer(I4B), dimension(:), pointer, contiguous :: id2 => null() !< receiver reach number + integer(I4B), dimension(:), pointer, contiguous :: imvrtype => null() !< mover type (1, 2, 3, 4) corresponds to mvrtypes + real(DP), dimension(:), pointer, contiguous :: value => null() !< factor or rate depending on mvrtype + contains + procedure :: construct + procedure :: read_from_parser + procedure :: destroy + end type GwfMvrPeriodDataType + +contains + + !> @ brief Construct arrays + !! + !! Allocate maximum space for mover input. + !! + !< + subroutine construct(this, maxsize, memoryPath) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy + class(GwfMvrPeriodDataType) :: this !< GwfMvrPeriodDataType + integer(I4B), intent(in) :: maxsize !< size of arrays + character(len=LENMEMPATH), intent(in) :: memoryPath !< memory manager path + + ! -- character arrays + allocate (this%mname1(maxsize)) + allocate (this%pname1(maxsize)) + allocate (this%mname2(maxsize)) + allocate (this%pname2(maxsize)) + + ! -- integer and real + call mem_allocate(this%id1, maxsize, 'ID1', memoryPath) + call mem_allocate(this%id2, maxsize, 'ID2', memoryPath) + call mem_allocate(this%imvrtype, maxsize, 'IMVRTYPE', memoryPath) + call mem_allocate(this%value, maxsize, 'VALUE', memoryPath) + + return + end subroutine construct + + !> @ brief Fill the arrays from parser + !! + !! Use the provided block parser to fill the input arrays. + !! + !< + subroutine read_from_parser(this, parser, nmvr, modelname) + ! -- dummy + class(GwfMvrPeriodDataType) :: this !< GwfMvrPeriodDataType + type(BlockParserType), intent(inout) :: parser !< block parser + integer(I4B), intent(out) :: nmvr !< number of mover entries read + character(len=LENMODELNAME), intent(in) :: modelname !< name of model or empty string + ! -- local + integer(I4B) :: i + integer(I4B) :: maxmvr + logical :: endOfBlock + character(len=LINELENGTH) :: line + character(len=12) :: mvrtype_char + ! + ! -- Initialize + i = 1 + maxmvr = size(this%id1) + ! + ! -- Read each mover entry + do + call parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + ! + ! -- Raise error if movers exceeds maxmvr + if (i > maxmvr) then + call parser%GetCurrentLine(line) + write (errmsg, '(4x,a,a)') 'MOVERS EXCEED MAXMVR ON LINE: ', & + trim(adjustl(line)) + call store_error(errmsg) + call parser%StoreErrorUnit() + end if + ! + ! -- modelname, package name, id for provider + if (modelname == '') then + call parser%GetStringCaps(this%mname1(i)) + else + this%mname1(i) = modelname + end if + call parser%GetStringCaps(this%pname1(i)) + this%id1(i) = parser%GetInteger() + ! + ! -- modelname, package name, id for receiver + if (modelname == '') then + call parser%GetStringCaps(this%mname2(i)) + else + this%mname2(i) = modelname + end if + call parser%GetStringCaps(this%pname2(i)) + this%id2(i) = parser%GetInteger() + ! + ! -- Mover type and value + call parser%GetStringCaps(mvrtype_char) + select case (mvrtype_char) + case ('FACTOR') + this%imvrtype(i) = 1 + case ('EXCESS') + this%imvrtype(i) = 2 + case ('THRESHOLD') + this%imvrtype(i) = 3 + case ('UPTO') + this%imvrtype(i) = 4 + case default + call store_error('INVALID MOVER TYPE: '//trim(mvrtype_char)) + call parser%StoreErrorUnit() + end select + this%value(i) = parser%GetDouble() + i = i + 1 + end do + nmvr = i - 1 + return + end subroutine read_from_parser + + !> @ brief Destroy memory + !! + !! Deallocate memory from the memory manager. + !! + !< + subroutine destroy(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy + class(GwfMvrPeriodDataType) :: this !< GwfMvrPeriodDataType + + ! -- character arrays + deallocate (this%mname1) + deallocate (this%pname1) + deallocate (this%mname2) + deallocate (this%pname2) + + ! -- integer and real + call mem_deallocate(this%id1) + call mem_deallocate(this%id2) + call mem_deallocate(this%imvrtype) + call mem_deallocate(this%value) + + return + end subroutine destroy + +end module GwfMvrPeriodDataModule + diff --git a/src/Model/ModelUtilities/GwfNpfGridData.f90 b/src/Model/ModelUtilities/GwfNpfGridData.f90 deleted file mode 100644 index 2992b6294f8..00000000000 --- a/src/Model/ModelUtilities/GwfNpfGridData.f90 +++ /dev/null @@ -1,90 +0,0 @@ -module GwfNpfGridDataModule - use KindModule, only: I4B, DP - use ConstantsModule, only: DZERO - implicit none - private - - !> Data structure and helper methods for passing NPF grid data - !! into npf_ar, as an alternative to reading those from file. - !! As this is a temporary object, the variables are not - !! allocated inside the memory manager. - !< - type, public :: GwfNpfGridDataType - ! grid data - integer(I4B) :: ik22 !< flag equals 1 when present - integer(I4B) :: ik33 !< flag equals 1 when present - integer(I4B) :: iwetdry !< flag equals 1 when present - integer(I4B) :: iangle1 !< flag equals 1 when present - integer(I4B) :: iangle2 !< flag equals 1 when present - integer(I4B) :: iangle3 !< flag equals 1 when present - integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: k11 => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: k22 => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: k33 => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: wetdry => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: angle1 => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: angle2 => null() !< same as npf variable - real(DP), dimension(:), pointer, contiguous :: angle3 => null() !< same as npf variable - contains - procedure, pass(this) :: construct - procedure, pass(this) :: destroy - end type GwfNpfGridDataType - -contains - -!> @brief construct the input data object, allocating -!! the arrays at proper size and initializing the variables -!! at their defaults -!< -subroutine construct(this, nodes) - class(GwfNpfGridDataType), intent(inout) :: this !< the NPF grid data, as in the input GRIDDATA block - integer(I4B) :: nodes !< the number of nodes in the solution - ! local - integer(I4B) :: i - - this%ik22 = 0 - this%ik33 = 0 - this%iwetdry = 0 - this%iangle1 = 0 - this%iangle2 = 0 - this%iangle3 = 0 - - allocate(this%icelltype(nodes)) - allocate(this%k11(nodes)) - allocate(this%k22(nodes)) - allocate(this%k33(nodes)) - allocate(this%wetdry(nodes)) - allocate(this%angle1(nodes)) - allocate(this%angle2(nodes)) - allocate(this%angle3(nodes)) - - do i = 1, nodes - this%icelltype(i) = DZERO - this%k11(i) = DZERO - this%k22(i) = DZERO - this%k33(i) = DZERO - this%wetdry(i) = DZERO - this%angle1(i) = DZERO - this%angle2(i) = DZERO - this%angle3(i) = DZERO - end do - -end subroutine construct - -!> @brief clean up, deallocate, etc. -!< -subroutine destroy(this) - class(GwfNpfGridDataType), intent(inout) :: this !< the data structure - - deallocate(this%icelltype) - deallocate(this%k11) - deallocate(this%k22) - deallocate(this%k33) - deallocate(this%wetdry) - deallocate(this%angle1) - deallocate(this%angle2) - deallocate(this%angle3) - -end subroutine destroy - -end module GwfNpfGridDataModule \ No newline at end of file diff --git a/src/Model/ModelUtilities/GwfNpfOptions.f90 b/src/Model/ModelUtilities/GwfNpfOptions.f90 index 6567ea1b525..3f506655bbb 100644 --- a/src/Model/ModelUtilities/GwfNpfOptions.f90 +++ b/src/Model/ModelUtilities/GwfNpfOptions.f90 @@ -5,19 +5,19 @@ module GwfNpfOptionsModule implicit none private - !> Data structure and helper methods for passing NPF options + !> Data structure and helper methods for passing NPF options !! into npf_df, as an alternative to reading those from file !< type, public :: GwfNpfOptionsType - integer(I4B) :: icellavg !< same as npf variable - integer(I4B) :: ithickstrt !< same as npf variable - integer(I4B) :: iperched !< same as npf variable - integer(I4B) :: ivarcv !< same as npf variable - integer(I4B) :: idewatcv !< same as npf variable - integer(I4B) :: irewet !< same as npf variable - real(DP) :: wetfct !< same as npf variable - integer(I4B) :: iwetit !< same as npf variable - integer(I4B) :: ihdwet !< same as npf variable + integer(I4B) :: icellavg !< same as npf variable + integer(I4B) :: ithickstrt !< same as npf variable + integer(I4B) :: iperched !< same as npf variable + integer(I4B) :: ivarcv !< same as npf variable + integer(I4B) :: idewatcv !< same as npf variable + integer(I4B) :: irewet !< same as npf variable + real(DP) :: wetfct !< same as npf variable + integer(I4B) :: iwetit !< same as npf variable + integer(I4B) :: ihdwet !< same as npf variable contains procedure, pass(this) :: construct procedure, pass(this) :: destroy @@ -28,7 +28,7 @@ module GwfNpfOptionsModule !> @brief construct the input options, set variables to their defaults !< subroutine construct(this) - class(GwfNpfOptionsType), intent(inout) :: this !< the NPF options, as in the input OPTIONS block + class(GwfNpfOptionsType), intent(inout) :: this !< the NPF options, as in the input OPTIONS block this%icellavg = 0 this%ithickstrt = 0 @@ -45,10 +45,10 @@ end subroutine construct !> @brief cleans up !< subroutine destroy(this) - class(GwfNpfOptionsType), intent(inout) :: this !< the NPF options, as in the input OPTIONS block + class(GwfNpfOptionsType), intent(inout) :: this !< the NPF options, as in the input OPTIONS block ! nothing to be done here for now... end subroutine destroy -end module GwfNpfOptionsModule \ No newline at end of file +end module GwfNpfOptionsModule diff --git a/src/Model/ModelUtilities/GwfStorageUtils.f90 b/src/Model/ModelUtilities/GwfStorageUtils.f90 index d0cc034e90f..16a36cca0f3 100644 --- a/src/Model/ModelUtilities/GwfStorageUtils.f90 +++ b/src/Model/ModelUtilities/GwfStorageUtils.f90 @@ -24,7 +24,7 @@ module GwfStorageUtilsModule !> @brief Calculate the specific storage terms !! !! Subroutine to calculate the specific storage terms for a cell using - !! the cell geometry, current and previous specific storage capacity, + !! the cell geometry, current and previous specific storage capacity, !! current and previous cell saturation, and the current and previous head. !! Subroutine can optionally return the flow rate from specific storage. !! @@ -33,19 +33,19 @@ pure subroutine SsTerms(iconvert, iorig_ss, iconf_ss, top, bot, & rho1, rho1old, snnew, snold, hnew, hold, & aterm, rhsterm, rate) ! -- dummy variables - integer(I4B), intent(in) :: iconvert !< flag indicating if cell is convertible - integer(I4B), intent(in) :: iorig_ss !< flag indicating if the original MODFLOW 6 specific storage formulation is being used - integer(I4B), intent(in) :: iconf_ss !< flag indicating if specific storage only applies under confined conditions - real(DP), intent(in) :: top !< top of cell - real(DP), intent(in) :: bot !< bottom of cell - real(DP), intent(in) :: rho1 !< current specific storage capacity - real(DP), intent(in) :: rho1old !< previous specific storage capacity - real(DP), intent(in) :: snnew !< current cell saturation - real(DP), intent(in) :: snold !< previous cell saturation - real(DP), intent(in) :: hnew !< current head - real(DP), intent(in) :: hold !< previous head - real(DP), intent(inout) :: aterm !< coefficient matrix term - real(DP), intent(inout) :: rhsterm !< right-hand side term + integer(I4B), intent(in) :: iconvert !< flag indicating if cell is convertible + integer(I4B), intent(in) :: iorig_ss !< flag indicating if the original MODFLOW 6 specific storage formulation is being used + integer(I4B), intent(in) :: iconf_ss !< flag indicating if specific storage only applies under confined conditions + real(DP), intent(in) :: top !< top of cell + real(DP), intent(in) :: bot !< bottom of cell + real(DP), intent(in) :: rho1 !< current specific storage capacity + real(DP), intent(in) :: rho1old !< previous specific storage capacity + real(DP), intent(in) :: snnew !< current cell saturation + real(DP), intent(in) :: snold !< previous cell saturation + real(DP), intent(in) :: hnew !< current head + real(DP), intent(in) :: hold !< previous head + real(DP), intent(inout) :: aterm !< coefficient matrix term + real(DP), intent(inout) :: rhsterm !< right-hand side term real(DP), intent(inout), optional :: rate !< calculated specific storage rate ! -- local variables real(DP) :: tthk @@ -93,22 +93,22 @@ end subroutine SsTerms !> @brief Calculate the specific yield storage terms !! !! Subroutine to calculate the specific yield storage terms for a cell - !! using the cell geometry, current and previous specific yield storage - !! capacity, and the current and previous cell saturation. Subroutine + !! using the cell geometry, current and previous specific yield storage + !! capacity, and the current and previous cell saturation. Subroutine !! can optionally return the flow rate from specific yield. !! !< pure subroutine SyTerms(top, bot, rho2, rho2old, snnew, snold, & aterm, rhsterm, rate) ! -- dummy variables - real(DP), intent(in) :: top !< top of cell - real(DP), intent(in) :: bot !< bottom of cell - real(DP), intent(in) :: rho2 !< current specific yield storage capacity - real(DP), intent(in) :: rho2old !< previous specific yield storage capacity - real(DP), intent(in) :: snnew !< current cell saturation - real(DP), intent(in) :: snold !< previous cell saturation - real(DP), intent(inout) :: aterm !< coefficient matrix term - real(DP), intent(inout) :: rhsterm !< right-hand side term + real(DP), intent(in) :: top !< top of cell + real(DP), intent(in) :: bot !< bottom of cell + real(DP), intent(in) :: rho2 !< current specific yield storage capacity + real(DP), intent(in) :: rho2old !< previous specific yield storage capacity + real(DP), intent(in) :: snnew !< current cell saturation + real(DP), intent(in) :: snold !< previous cell saturation + real(DP), intent(inout) :: aterm !< coefficient matrix term + real(DP), intent(inout) :: rhsterm !< right-hand side term real(DP), intent(inout), optional :: rate !< calculated specific yield rate ! -- local variables real(DP) :: tthk @@ -125,7 +125,7 @@ pure subroutine SyTerms(top, bot, rho2, rho2old, snnew, snold, & else rhsterm = tthk * (DZERO - rho2old * snold) end if - ! -- known flow from specific yield + ! -- known flow from specific yield else rhsterm = tthk * (rho2 * snnew - rho2old * snold) end if @@ -148,11 +148,11 @@ end subroutine SyTerms !< pure function SsCapacity(istor_coef, top, bot, area, ss) result(sc1) ! -- dummy variables - integer(I4B), intent(in) :: istor_coef !< flag indicating if ss is the storage coefficient - real(DP), intent(in) :: top !< top of cell - real(DP), intent(in) :: bot !< bottom of cell - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: ss !< specific storage or storage coefficient + integer(I4B), intent(in) :: istor_coef !< flag indicating if ss is the storage coefficient + real(DP), intent(in) :: top !< top of cell + real(DP), intent(in) :: bot !< bottom of cell + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: ss !< specific storage or storage coefficient ! -- local variables real(DP) :: sc1 real(DP) :: thick @@ -162,7 +162,7 @@ pure function SsCapacity(istor_coef, top, bot, area, ss) result(sc1) else thick = DONE end if - sc1 = ss*thick*area + sc1 = ss * thick * area ! ! -- return return @@ -177,12 +177,12 @@ end function SsCapacity !< pure function SyCapacity(area, sy) result(sc2) ! -- dummy variables - real(DP), intent(in) :: area !< horizontal cell area - real(DP), intent(in) :: sy !< specific yield + real(DP), intent(in) :: area !< horizontal cell area + real(DP), intent(in) :: sy !< specific yield ! -- local variables real(DP) :: sc2 ! -- calculate specific yield capacity - sc2 = sy*area + sc2 = sy * area ! ! -- return return diff --git a/src/Model/ModelUtilities/GwfVscInputData.f90 b/src/Model/ModelUtilities/GwfVscInputData.f90 new file mode 100644 index 00000000000..fb39c0d1994 --- /dev/null +++ b/src/Model/ModelUtilities/GwfVscInputData.f90 @@ -0,0 +1,57 @@ +module GwfVscInputDataModule + use KindModule, only: I4B, DP + use ConstantsModule, only: LENMODELNAME, LENAUXNAME, DZERO + + implicit none + private + + !> Data structure to transfer input configuration to the + !< VSC package, as opposed to reading from file + type, public :: GwfVscInputDataType + + ! options + real(DP) :: viscref !< see VSC for description + ! dim + integer(I4B) :: nviscspecies !< see VSC for description + ! pkg data + integer(I4B), dimension(:), pointer :: ivisc => null() !< indicates if species uses linear or nonlinear relationship + real(DP), dimension(:), pointer, contiguous :: dviscdc => null() !< see VSC for description + real(DP), dimension(:), pointer, contiguous :: cviscref => null() !< see VSC for description + character(len=LENMODELNAME), dimension(:), allocatable :: cmodelname !< see VSC for description + character(len=LENAUXNAME), dimension(:), allocatable :: cauxspeciesname !< see VSC for description + + contains + procedure, pass(this) :: construct + procedure, pass(this) :: destruct + end type GwfVscInputDataType + +contains + +!> @brief Allocate the input data +!< + subroutine construct(this, nviscspecies) + class(GwfVscInputDataType) :: this !< the input data block + integer(I4B) :: nviscspecies !< the number of species + + allocate (this%ivisc(nviscspecies)) + allocate (this%dviscdc(nviscspecies)) + allocate (this%cviscref(nviscspecies)) + allocate (this%cmodelname(nviscspecies)) + allocate (this%cauxspeciesname(nviscspecies)) + + end subroutine construct + + !> @brief clean up + !< + subroutine destruct(this) + class(GwfVscInputDataType) :: this !< the input data block + + deallocate (this%ivisc) + deallocate (this%dviscdc) + deallocate (this%cviscref) + deallocate (this%cmodelname) + deallocate (this%cauxspeciesname) + + end subroutine destruct + +end module GwfVscInputDataModule diff --git a/src/Model/ModelUtilities/GwtAdvOptions.f90 b/src/Model/ModelUtilities/GwtAdvOptions.f90 index b4e612fd500..4e724a745d0 100644 --- a/src/Model/ModelUtilities/GwtAdvOptions.f90 +++ b/src/Model/ModelUtilities/GwtAdvOptions.f90 @@ -7,4 +7,4 @@ module GwtAdvOptionsModule integer(I4B) :: iAdvScheme !< the advection scheme: 0 = up, 1 = central, 2 = TVD end type GwtAdvOptionsType -end module GwtAdvOptionsModule \ No newline at end of file +end module GwtAdvOptionsModule diff --git a/src/Model/ModelUtilities/GwtDspGridData.f90 b/src/Model/ModelUtilities/GwtDspGridData.f90 deleted file mode 100644 index 8b463dbb7d9..00000000000 --- a/src/Model/ModelUtilities/GwtDspGridData.f90 +++ /dev/null @@ -1,51 +0,0 @@ -module GwtDspGridDataModule -use KindModule, only: DP, I4B -implicit none -private - -!> @brief data structure and helpers for passing dsp grid data -!< into the package, as opposed to reading from file -type, public :: GwtDspGridDataType - real(DP), dimension(:), pointer, contiguous :: diffc => null() !< molecular diffusion coefficient for each cell - real(DP), dimension(:), pointer, contiguous :: alh => null() !< longitudinal horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: alv => null() !< longitudinal vertical dispersivity - real(DP), dimension(:), pointer, contiguous :: ath1 => null() !< transverse horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: ath2 => null() !< transverse horizontal dispersivity - real(DP), dimension(:), pointer, contiguous :: atv => null() !< transverse vertical dispersivity -contains - procedure, pass(this) :: construct - procedure, pass(this) :: destroy -end type GwtDspGridDataType - -contains - -!> @brief allocate data structure -!< -subroutine construct(this, nodes) - class(GwtDspGridDataType) :: this - integer(I4B) :: nodes - - allocate(this%diffc(nodes)) - allocate(this%alh(nodes)) - allocate(this%alv(nodes)) - allocate(this%ath1(nodes)) - allocate(this%ath2(nodes)) - allocate(this%atv(nodes)) - -end subroutine construct - -!> @brief clean up -!< -subroutine destroy(this) - class(GwtDspGridDataType) :: this - - deallocate(this%diffc) - deallocate(this%alh) - deallocate(this%alv) - deallocate(this%ath1) - deallocate(this%ath2) - deallocate(this%atv) - -end subroutine destroy - -end module GwtDspGridDataModule \ No newline at end of file diff --git a/src/Model/ModelUtilities/GwtDspOptions.f90 b/src/Model/ModelUtilities/GwtDspOptions.f90 index 164beff134f..e4c25450244 100644 --- a/src/Model/ModelUtilities/GwtDspOptions.f90 +++ b/src/Model/ModelUtilities/GwtDspOptions.f90 @@ -9,4 +9,4 @@ module GwtDspOptionsModule integer(I4B) :: ixt3d !< flag indicating xt3d is active: 1 = enabled, 2 = rhs end type GwtDspOptionsType -end module GwtDspOptionsModule \ No newline at end of file +end module GwtDspOptionsModule diff --git a/src/Model/ModelUtilities/GwtSpc.f90 b/src/Model/ModelUtilities/GwtSpc.f90 index 8c19ca55f60..d28ac59ad3e 100644 --- a/src/Model/ModelUtilities/GwtSpc.f90 +++ b/src/Model/ModelUtilities/GwtSpc.f90 @@ -5,28 +5,29 @@ !! !< module GwtSpcModule - - use KindModule, only: DP, LGP, I4B - use ConstantsModule, only: LENPACKAGENAME, LENMODELNAME, & - LENMEMPATH, DZERO, LENFTYPE, & - LINELENGTH, TABLEFT, TABCENTER - use SimVariablesModule, only: errmsg - use SimModule, only: store_error, count_errors - use MemoryHelperModule, only: create_mem_path - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType - use TimeSeriesManagerModule, only: TimeSeriesManagerType, tsmanager_cr - use TimeArraySeriesManagerModule, only: TimeArraySeriesManagerType, tasmanager_cr - use TableModule, only: TableType, table_cr + + use KindModule, only: DP, LGP, I4B + use ConstantsModule, only: LENPACKAGENAME, LENMODELNAME, & + LENMEMPATH, DZERO, LENFTYPE, & + LINELENGTH, TABLEFT, TABCENTER + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, count_errors + use MemoryHelperModule, only: create_mem_path + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType + use TimeSeriesManagerModule, only: TimeSeriesManagerType, tsmanager_cr + use TimeArraySeriesManagerModule, only: TimeArraySeriesManagerType, & + tasmanager_cr + use TableModule, only: TableType, table_cr implicit none private public :: GwtSpcType - character(len=LENFTYPE) :: ftype = 'SPC' - character(len=LENPACKAGENAME) :: text = 'STRESS PACK CONC' + character(len=LENFTYPE) :: ftype = 'SPC' + character(len=LENPACKAGENAME) :: text = 'STRESS PACK CONC' - !> @brief Derived type for managing SPC input + !> @brief Derived type for managing SPC input !! !! This derived type will read and process an SPC input file, !! make time series interpolations, and provide concentrations to @@ -35,26 +36,26 @@ module GwtSpcModule !! !< type :: GwtSpcType - - character(len=LENMODELNAME) :: name_model = '' !< the name of the model that contains this package - character(len=LENPACKAGENAME) :: packName = '' !< name of the package - character(len=LENPACKAGENAME) :: packNameFlow = '' !< name of the corresponding flow package - character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored - integer(I4B), pointer :: id => null() !< id number for this spc package - integer(I4B), pointer :: inunit => null() !< unit number for input - integer(I4B), pointer :: iout => null() !< unit number for output - integer(I4B), pointer :: maxbound => null() !< length of dblvec - integer(I4B), pointer :: ionper => null() !< stress period for next data - integer(I4B), pointer :: lastonper => null() !< last value of ionper (for checking) - integer(I4B), pointer :: iprpak => null() !< flag for printing input - logical(LGP), pointer :: readasarrays => null() !< flag for reading concentrations as an array - real(DP), dimension(:), pointer, contiguous :: dblvec => null() !< vector of floats read from file - class(DisBaseType), pointer :: dis => null() !< model discretization object - type(BlockParserType) :: parser !< parser object for reading blocks of information - type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager - type(TimeArraySeriesManagerType), pointer :: TasManager => null() !< time array series manager - type(TableType), pointer :: inputtab => null() !< input table object - + + character(len=LENMODELNAME) :: name_model = '' !< the name of the model that contains this package + character(len=LENPACKAGENAME) :: packName = '' !< name of the package + character(len=LENPACKAGENAME) :: packNameFlow = '' !< name of the corresponding flow package + character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored + integer(I4B), pointer :: id => null() !< id number for this spc package + integer(I4B), pointer :: inunit => null() !< unit number for input + integer(I4B), pointer :: iout => null() !< unit number for output + integer(I4B), pointer :: maxbound => null() !< length of dblvec + integer(I4B), pointer :: ionper => null() !< stress period for next data + integer(I4B), pointer :: lastonper => null() !< last value of ionper (for checking) + integer(I4B), pointer :: iprpak => null() !< flag for printing input + logical(LGP), pointer :: readasarrays => null() !< flag for reading concentrations as an array + real(DP), dimension(:), pointer, contiguous :: dblvec => null() !< vector of floats read from file + class(DisBaseType), pointer :: dis => null() !< model discretization object + type(BlockParserType) :: parser !< parser object for reading blocks of information + type(TimeSeriesManagerType), pointer :: TsManager => null() !< time series manager + type(TimeArraySeriesManagerType), pointer :: TasManager => null() !< time array series manager + type(TableType), pointer :: inputtab => null() !< input table object + contains procedure :: initialize @@ -71,11 +72,11 @@ module GwtSpcModule procedure :: spc_da procedure :: read_check_ionper procedure :: check_flow_package - + end type GwtSpcType - - contains - + +contains + !> @ brief Initialize the SPC type !! !! Initialize the SPC object by setting up the parser, @@ -85,17 +86,17 @@ module GwtSpcModule !< subroutine initialize(this, dis, id, inunit, iout, name_model, packNameFlow) ! -- dummy variables - class(GwtSpcType) :: this !< GwtSpcType - class(DisBaseType), pointer, intent(in) :: dis !< discretization package - integer(I4B), intent(in) :: id !< id number for this spc package - integer(I4B), intent(in) :: inunit !< unit number for input - integer(I4B), intent(in) :: iout !< unit number for output - character(len=*), intent(in) :: name_model !< character string containing model name - character(len=*), intent(in) :: packNameflow !< character string containing name of corresponding flow package + class(GwtSpcType) :: this !< GwtSpcType + class(DisBaseType), pointer, intent(in) :: dis !< discretization package + integer(I4B), intent(in) :: id !< id number for this spc package + integer(I4B), intent(in) :: inunit !< unit number for input + integer(I4B), intent(in) :: iout !< unit number for output + character(len=*), intent(in) :: name_model !< character string containing model name + character(len=*), intent(in) :: packNameflow !< character string containing name of corresponding flow package ! -- local ! ! -- construct the memory path - write(this%packName,'(a, i0)') 'SPC' // '-', id + write (this%packName, '(a, i0)') 'SPC'//'-', id this%name_model = name_model this%memoryPath = create_mem_path(this%name_model, this%packName) ! @@ -138,17 +139,17 @@ subroutine initialize(this, dis, id, inunit, iout, name_model, packNameFlow) ! -- return return end subroutine initialize - + !> @ brief Allocate package scalars !! - !! Allocate and initialize package scalars. + !! Allocate and initialize package scalars. !! !< subroutine allocate_scalars(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(GwtSpcType) :: this !< GwtSpcType object + class(GwtSpcType) :: this !< GwtSpcType object ! ! -- allocate scalars in memory manager call mem_allocate(this%id, 'ID', this%memoryPath) @@ -161,8 +162,8 @@ subroutine allocate_scalars(this) call mem_allocate(this%readasarrays, 'READASARRAYS', this%memoryPath) ! ! -- allocate special derived types - allocate(this%TsManager) - allocate(this%TasManager) + allocate (this%TsManager) + allocate (this%TasManager) ! ! -- initialize this%id = 0 @@ -180,7 +181,7 @@ end subroutine allocate_scalars !> @ brief Read options for package !! - !! Read options for this package. + !! Read options for this package. !! !< subroutine read_options(this) @@ -192,15 +193,15 @@ subroutine read_options(this) integer(I4B) :: ierr logical :: isfound, endOfBlock ! -- formats - character(len=*), parameter :: fmtiprpak = & - "(4x,'SPC INFORMATION WILL BE PRINTED TO LISTING FILE.')" - character(len=*), parameter :: fmtreadasarrays = & + character(len=*), parameter :: fmtiprpak = & + &"(4x,'SPC INFORMATION WILL BE PRINTED TO LISTING FILE.')" + character(len=*), parameter :: fmtreadasarrays = & "(4x,'SPC INFORMATION WILL BE READ AS ARRAYS RATHER THAN IN LIST & &FORMAT.')" character(len=*), parameter :: fmtts = & - "(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" + &"(4x, 'TIME-SERIES DATA WILL BE READ FROM FILE: ', a)" character(len=*), parameter :: fmttas = & - "(4x, 'TIME-ARRAY SERIES DATA WILL BE READ FROM FILE: ', a)" + &"(4x, 'TIME-ARRAY SERIES DATA WILL BE READ FROM FILE: ', a)" ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, blockRequired=.false., & @@ -208,46 +209,46 @@ subroutine read_options(this) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(1x,a)')'PROCESSING SPC OPTIONS' + write (this%iout, '(1x,a)') 'PROCESSING SPC OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('PRINT_INPUT') - this%iprpak = 1 - write(this%iout, fmtiprpak) - case ('READASARRAYS') - this%readasarrays = .true. - write(this%iout, fmtreadasarrays) - case ('TS6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - endif - call this%parser%GetString(fname) - write(this%iout,fmtts)trim(fname) - call this%TsManager%add_tsfile(fname, this%inunit) - case ('TAS6') - call this%parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'TAS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - call this%parser%GetString(fname) - write(this%iout,fmttas)trim(fname) - call this%TasManager%add_tasfile(fname) - case default - write(errmsg,'(4x,a,a)') 'UNKNOWN SPC OPTION: ', trim(keyword) + case ('PRINT_INPUT') + this%iprpak = 1 + write (this%iout, fmtiprpak) + case ('READASARRAYS') + this%readasarrays = .true. + write (this%iout, fmtreadasarrays) + case ('TS6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' + call store_error(errmsg) + end if + call this%parser%GetString(fname) + write (this%iout, fmtts) trim(fname) + call this%TsManager%add_tsfile(fname, this%inunit) + case ('TAS6') + call this%parser%GetStringCaps(keyword) + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'TAS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' call store_error(errmsg) call this%parser%StoreErrorUnit() + end if + call this%parser%GetString(fname) + write (this%iout, fmttas) trim(fname) + call this%TasManager%add_tasfile(fname) + case default + write (errmsg, '(4x,a,a)') 'UNKNOWN SPC OPTION: ', trim(keyword) + call store_error(errmsg) + call this%parser%StoreErrorUnit() end select end do - write(this%iout,'(1x,a)')'END OF SPC OPTIONS' + write (this%iout, '(1x,a)') 'END OF SPC OPTIONS' end if ! ! -- Return @@ -256,12 +257,12 @@ end subroutine read_options !> @ brief Read dimensions for package !! - !! Read dimensions for this package. + !! Read dimensions for this package. !! !< subroutine read_dimensions(this) ! -- dummy variables - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object ! -- local variables character(len=LINELENGTH) :: keyword logical(LGP) :: isfound @@ -274,32 +275,32 @@ subroutine read_dimensions(this) ! ! -- parse dimensions block if detected if (isfound) then - write(this%iout,'(/1x,a)')'PROCESSING '//trim(adjustl(text))// & + write (this%iout, '(/1x,a)') 'PROCESSING '//trim(adjustl(text))// & ' DIMENSIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit call this%parser%GetStringCaps(keyword) select case (keyword) - case ('MAXBOUND') - this%maxbound = this%parser%GetInteger() - write(this%iout,'(4x,a,i7)') 'MAXBOUND = ', this%maxbound - case default - write(errmsg,'(a,3(1x,a))') & - 'UNKNOWN', trim(text), 'DIMENSION:', trim(keyword) - call store_error(errmsg) + case ('MAXBOUND') + this%maxbound = this%parser%GetInteger() + write (this%iout, '(4x,a,i7)') 'MAXBOUND = ', this%maxbound + case default + write (errmsg, '(a,3(1x,a))') & + 'UNKNOWN', trim(text), 'DIMENSION:', trim(keyword) + call store_error(errmsg) end select end do ! - write(this%iout,'(1x,a)')'END OF '//trim(adjustl(text))//' DIMENSIONS' + write (this%iout, '(1x,a)') 'END OF '//trim(adjustl(text))//' DIMENSIONS' else call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') call this%parser%StoreErrorUnit() end if ! ! -- verify dimensions were set - if(this%maxbound <= 0) then - write(errmsg, '(a)') 'MAXBOUND MUST BE AN INTEGER GREATER THAN ZERO.' + if (this%maxbound <= 0) then + write (errmsg, '(a)') 'MAXBOUND MUST BE AN INTEGER GREATER THAN ZERO.' call store_error(errmsg) end if ! @@ -314,14 +315,14 @@ end subroutine read_dimensions !> @ brief Allocate package arrays !! - !! Allocate and initialize package arrays. + !! Allocate and initialize package arrays. !! !< subroutine allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(GwtSpcType) :: this !< GwtSpcType object + class(GwtSpcType) :: this !< GwtSpcType object ! -- local integer(I4B) :: i ! @@ -336,15 +337,15 @@ subroutine allocate_arrays(this) ! -- return return end subroutine allocate_arrays - + !> @ brief Get the data value from this package !! - !! Get the floating point value from the dblvec array. + !! Get the floating point value from the dblvec array. !! !< function get_value(this, ientry) result(value) - class(GwtSpcType) :: this !< GwtSpcType object - integer(I4B), intent(in) :: ientry !< index of the data to return + class(GwtSpcType) :: this !< GwtSpcType object + integer(I4B), intent(in) :: ientry !< index of the data to return real(DP) :: value value = this%dblvec(ientry) return @@ -353,35 +354,36 @@ end function get_value !> @ brief Read and prepare !! !! Read and prepare the period data block and fill dblvec - !! if the next period block corresponds to this time step. + !! if the next period block corresponds to this time step. !! !< subroutine spc_rp(this) ! -- modules use TdisModule, only: kper, nper ! -- dummy - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object ! -- local character(len=LINELENGTH) :: line logical :: isfound integer(I4B) :: ierr ! -- formats - character(len=*),parameter :: fmtblkerr = & - "('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" - character(len=*),parameter :: fmtlsp = & - "(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" + character(len=*), parameter :: fmtblkerr = & + &"('Looking for BEGIN PERIOD iper. Found ', a, ' instead.')" + character(len=*), parameter :: fmtlsp = & + &"(1X,/1X,'REUSING ',A,'S FROM LAST STRESS PERIOD')" ! ! -- Set ionper to the stress period number for which a new block of data ! will be read. - if(this%inunit == 0) return + if (this%inunit == 0) return ! ! -- get stress period data if (this%ionper < kper) then ! ! -- get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) - if(isfound) then + supportOpenClose=.true., & + blockRequired=.false.) + if (isfound) then ! ! -- read ionper and check for increasing period numbers call this%read_check_ionper() @@ -394,14 +396,14 @@ subroutine spc_rp(this) else ! -- Found invalid block call this%parser%GetCurrentLine(line) - write(errmsg, fmtblkerr) adjustl(trim(line)) + write (errmsg, fmtblkerr) adjustl(trim(line)) call store_error(errmsg, terminate=.TRUE.) end if end if end if ! ! -- Read data if ionper == kper - if(this%ionper == kper) then + if (this%ionper == kper) then ! ! -- Remove all time-series and time-array-series links associated with ! this package. @@ -414,10 +416,10 @@ subroutine spc_rp(this) else call this%spc_rp_list() end if - ! - ! -- using data from the last stress period + ! + ! -- using data from the last stress period else - write(this%iout,fmtlsp) trim(ftype) + write (this%iout, fmtlsp) trim(ftype) end if ! ! -- write summary of maw well stress period error messages @@ -428,7 +430,7 @@ subroutine spc_rp(this) ! -- return return end subroutine spc_rp - + !> @ brief spc_rp_list !! !! Read the stress period data in list format @@ -438,7 +440,7 @@ subroutine spc_rp_list(this) ! -- modules use TdisModule, only: kper ! -- dummy - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object ! -- local character(len=LINELENGTH) :: line character(len=LINELENGTH) :: title @@ -451,16 +453,16 @@ subroutine spc_rp_list(this) if (this%iprpak /= 0) then ! ! -- reset the input table object - title = trim(adjustl(text)) // ' PACKAGE (' // & - 'SPC' //') DATA FOR PERIOD' - write(title, '(a,1x,i6)') trim(adjustl(title)), kper + title = trim(adjustl(text))//' PACKAGE ('// & + 'SPC'//') DATA FOR PERIOD' + write (title, '(a,1x,i6)') trim(adjustl(title)), kper call table_cr(this%inputtab, ftype, title) call this%inputtab%table_df(1, 3, this%iout, finalize=.FALSE.) tabletext = 'NUMBER' call this%inputtab%initialize_column(tabletext, 10, alignment=TABCENTER) tabletext = 'DATA TYPE' call this%inputtab%initialize_column(tabletext, 20, alignment=TABLEFT) - write(tabletext, '(a,1x,i6)') 'VALUE' + write (tabletext, '(a,1x,i6)') 'VALUE' call this%inputtab%initialize_column(tabletext, 15, alignment=TABCENTER) end if ! @@ -471,8 +473,8 @@ subroutine spc_rp_list(this) ival = this%parser%GetInteger() if (ival < 1 .or. ival > this%maxbound) then - write(errmsg,'(2(a,1x),i0,a)') & - 'IVAL must be greater than 0 and', & + write (errmsg, '(2(a,1x),i0,a)') & + 'IVAL must be greater than 0 and', & 'less than or equal to ', this%maxbound, '.' call store_error(errmsg) cycle @@ -496,7 +498,7 @@ subroutine spc_rp_list(this) ! -- return return end subroutine spc_rp_list - + !> @ brief spc_rp_array !! !! Read the stress period data in array format @@ -507,7 +509,7 @@ subroutine spc_rp_array(this, line) use SimModule, only: store_error use ArrayHandlersModule, only: ifind ! -- dummy - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object character(len=LINELENGTH), intent(inout) :: line ! -- local integer(I4B) :: n @@ -525,7 +527,7 @@ subroutine spc_rp_array(this, line) real(DP), dimension(:), pointer :: bndArrayPtr => null() ! -- formats ! -- data - data aname(1) /' CONCENTRATION'/ + data aname(1)/' CONCENTRATION'/ ! ! ------------------------------------------------------------------------------ ! @@ -533,7 +535,7 @@ subroutine spc_rp_array(this, line) jauxcol = 0 ivarsread = 0 ncolbnd = 1 - allocate(nodelist(this%maxbound)) + allocate (nodelist(this%maxbound)) do n = 1, size(nodelist) nodelist(n) = n end do @@ -541,7 +543,7 @@ subroutine spc_rp_array(this, line) ! -- Read CONCENTRATION variables as arrays call this%parser%GetNextLine(endOfBlock) if (endOfBlock) then - call store_error('LOOKING FOR CONCENTRATION. FOUND: ' // trim(line)) + call store_error('LOOKING FOR CONCENTRATION. FOUND: '//trim(line)) call this%parser%StoreErrorUnit() end if call this%parser%GetStringCaps(keyword) @@ -560,20 +562,20 @@ subroutine spc_rp_array(this, line) ! Make a time-array-series link and add it to the list of links ! contained in the TimeArraySeriesManagerType object. convertflux = .false. - call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & - this%iprpak, tasName, 'CONCENTRATION', & - convertFlux, nodelist, & - this%parser%iuactive) + call this%TasManager%MakeTasLink(this%packName, bndArrayPtr, & + this%iprpak, tasName, 'CONCENTRATION', & + convertFlux, nodelist, & + this%parser%iuactive) else ! ! -- Read the concentration array - call this%dis%read_layer_array(nodelist, this%dblvec, & - ncolbnd, this%maxbound, 1, aname(1), this%parser%iuactive, & - this%iout) - endif + call this%dis%read_layer_array(nodelist, this%dblvec, ncolbnd, & + this%maxbound, 1, aname(1), & + this%parser%iuactive, this%iout) + end if ! case default - call store_error('LOOKING FOR CONCENTRATION. FOUND: ' // trim(line)) + call store_error('LOOKING FOR CONCENTRATION. FOUND: '//trim(line)) call this%parser%StoreErrorUnit() end select ! @@ -589,7 +591,7 @@ end subroutine spc_rp_array subroutine spc_ad(this, nbound_flowpack, budtxt) ! -- modules ! -- dummy - class(GwtSpcType),intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object integer(I4B), intent(in) :: nbound_flowpack character(len=*), intent(in) :: budtxt ! -- local @@ -604,17 +606,17 @@ subroutine spc_ad(this, nbound_flowpack, budtxt) ! -- return return end subroutine spc_ad - + !> @ brief Deallocate variables !! - !! Deallocate and nullify package variables. + !! Deallocate and nullify package variables. !! !< subroutine spc_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy variables - class(GwtSpcType) :: this !< GwtSpcType object + class(GwtSpcType) :: this !< GwtSpcType object ! ! -- deallocate arrays in memory manager call mem_deallocate(this%dblvec) @@ -631,8 +633,8 @@ subroutine spc_da(this) ! ! -- deallocate derived types call this%TsManager%da() - deallocate(this%TsManager) - nullify(this%TsManager) + deallocate (this%TsManager) + nullify (this%TsManager) ! ! -- return return @@ -640,8 +642,8 @@ end subroutine spc_da !> @ brief Check ionper !! - !! Generic method to read and check ionperiod, which is used to determine - !! if new period data should be read from the input file. The check of + !! Generic method to read and check ionperiod, which is used to determine + !! if new period data should be read from the input file. The check of !! ionperiod also makes sure periods are increasing in subsequent period !! data blocks. Copied from NumericalPackage !! @@ -650,7 +652,7 @@ subroutine read_check_ionper(this) ! -- modules use TdisModule, only: kper ! -- dummy variables - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object ! ! -- save last value and read period number this%lastonper = this%ionper @@ -658,22 +660,22 @@ subroutine read_check_ionper(this) ! ! -- make check if (this%ionper <= this%lastonper) then - write(errmsg, '(a, i0)') & + write (errmsg, '(a, i0)') & 'ERROR IN STRESS PERIOD ', kper call store_error(errmsg) - write(errmsg, '(a, i0)') & + write (errmsg, '(a, i0)') & 'PERIOD NUMBERS NOT INCREASING. FOUND ', this%ionper call store_error(errmsg) - write(errmsg, '(a, i0)') & + write (errmsg, '(a, i0)') & 'BUT LAST PERIOD BLOCK WAS ASSIGNED ', this%lastonper call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- return return end subroutine read_check_ionper - + !> @ brief Set the data value from the input file !! !! Set the floating point value in the dblvec array using strings @@ -684,7 +686,7 @@ subroutine set_value(this, ival) ! -- modules use TimeSeriesManagerModule, only: read_value_or_time_series_adv ! -- dummy - class(GwtSpcType), intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object integer(I4B), intent(in) :: ival ! -- local character(len=LINELENGTH) :: keyword @@ -693,15 +695,15 @@ subroutine set_value(this, ival) ! ! -- read remainder of variables on the line call this%parser%GetStringCaps(keyword) - select case(keyword) - case('CONCENTRATION') + select case (keyword) + case ('CONCENTRATION') call this%parser%GetString(text) - jj = 1 ! For CONCENTRATION + jj = 1 ! For CONCENTRATION bndElem => this%dblvec(ival) - call read_value_or_time_series_adv(text, ival, jj, bndElem, this%packName, & - 'BND', this%tsManager, this%iprpak, & - 'CONCENTRATION') - + call read_value_or_time_series_adv(text, ival, jj, bndElem, this%packName, & + 'BND', this%tsManager, this%iprpak, & + 'CONCENTRATION') + end select return end subroutine set_value @@ -715,14 +717,14 @@ end subroutine set_value subroutine check_flow_package(this, nbound_flowpack, budtxt) ! -- modules ! -- dummy - class(GwtSpcType),intent(inout) :: this !< GwtSpcType object + class(GwtSpcType), intent(inout) :: this !< GwtSpcType object integer(I4B), intent(in) :: nbound_flowpack character(len=*), intent(in) :: budtxt ! -- local ! ! -- Check and make sure MAXBOUND is not less than nbound_flowpack if (this%maxbound < nbound_flowpack) then - write(errmsg, '(a, a, a, i0, a, i0, a)') & + write (errmsg, '(a, a, a, i0, a, i0, a)') & 'The SPC Package corresponding to flow package ', & trim(this%packNameFlow), & ' has MAXBOUND set less than the number of boundaries & @@ -737,19 +739,19 @@ subroutine check_flow_package(this, nbound_flowpack, budtxt) ! ! -- If budtxt is RCHA or EVTA, then readasarrays must be used, otherwise ! readasarrays cannot be used - select case(trim(adjustl(budtxt))) - case('RCHA') + select case (trim(adjustl(budtxt))) + case ('RCHA') if (.not. this%readasarrays) then - write(errmsg, '(a, a, a)') & + write (errmsg, '(a, a, a)') & 'Array-based recharge must be used with array-based stress package & &concentrations. GWF Package ', trim(this%packNameFlow), ' is being & &used with list-based SPC6 input. Use array-based SPC6 input instead.' call store_error(errmsg) call this%parser%StoreErrorUnit() end if - case('EVTA') + case ('EVTA') if (.not. this%readasarrays) then - write(errmsg, '(a, a, a)') & + write (errmsg, '(a, a, a)') & 'Array-based evapotranspiration must be used with array-based stress & &package concentrations. GWF Package ', trim(this%packNameFlow), & &' is being used with list-based SPC6 input. Use array-based SPC6 & @@ -759,7 +761,7 @@ subroutine check_flow_package(this, nbound_flowpack, budtxt) end if case default if (this%readasarrays) then - write(errmsg, '(a, a, a)') & + write (errmsg, '(a, a, a)') & 'List-based packages must be used with list-based stress & &package concentrations. GWF Package ', trim(this%packNameFlow), & &' is being used with array-based SPC6 input. Use list-based SPC6 & @@ -772,6 +774,5 @@ subroutine check_flow_package(this, nbound_flowpack, budtxt) ! -- return return end subroutine check_flow_package - - -end module GwtSpcModule \ No newline at end of file + +end module GwtSpcModule diff --git a/src/Model/ModelUtilities/Mover.f90 b/src/Model/ModelUtilities/Mover.f90 index d7973a20df6..0ff698fde01 100644 --- a/src/Model/ModelUtilities/Mover.f90 +++ b/src/Model/ModelUtilities/Mover.f90 @@ -1,147 +1,113 @@ +!> @brief This module contains the MvrModule Module +!! +!! This module contains the code for the low-level MvrType +!! object. +!! +!< module MvrModule - + use KindModule, only: DP, I4B - use ConstantsModule, only: LENMODELNAME, LINELENGTH, LENBUDTXT, & + use ConstantsModule, only: LENMODELNAME, LINELENGTH, LENBUDTXT, & LENAUXNAME, LENBOUNDNAME, DZERO, DONE, & LENMEMPATH + use SimVariablesModule, only: errmsg use PackageMoverModule, only: PackageMoverType - + implicit none private public :: MvrType - character(len=12), dimension(4) :: mvrtypes = & - [character(len=12) :: 'FACTOR', 'EXCESS', 'THRESHOLD', 'UPTO'] - + character(len=12), dimension(4) :: mvrtypes = & + &[character(len=12) :: 'FACTOR', 'EXCESS', 'THRESHOLD', 'UPTO'] + + !> @brief Derived type for MvrType + !! + !! This derived type contains information and methods for + !! moving water between packages. + !! + !< type MvrType - character(len=LENMEMPATH) :: pckNameSrc = '' !< provider package name - character(len=LENMEMPATH) :: pckNameTgt = '' !< receiver package name - integer(I4B) :: iRchNrSrc = 0 !< provider reach number - integer(I4B) :: iRchNrTgt = 0 !< receiver reach number - integer(I4B) :: imvrtype = 0 !< mover type (1, 2, 3, 4) corresponds to mvrtypes - real(DP) :: value = DZERO !< factor or rate depending on mvrtype - real(DP) :: qpactual = DZERO !< rate provided to the receiver - real(DP) :: qavailable = DZERO !< rate available at time of providing - real(DP), pointer :: qtformvr_ptr => null() !< pointer to total available flow (qtformvr) - real(DP), pointer :: qformvr_ptr => null() !< pointer to available flow after consumed (qformvr) - real(DP), pointer :: qtomvr_ptr => null() !< pointer to provider flow rate (qtomvr) - real(DP), pointer :: qfrommvr_ptr => null() !< pointer to receiver flow rate (qfrommvr) + character(len=LENMEMPATH) :: pckNameSrc = '' !< provider package name + character(len=LENMEMPATH) :: pckNameTgt = '' !< receiver package name + integer(I4B), pointer :: iRchNrSrc => null() !< provider reach number + integer(I4B), pointer :: iRchNrTgt => null() !< receiver reach number + integer(I4B), pointer :: imvrtype => null() !< mover type (1, 2, 3, 4) corresponds to mvrtypes + real(DP), pointer :: value => null() !< factor or rate depending on mvrtype + real(DP) :: qpactual = DZERO !< rate provided to the receiver + real(DP) :: qavailable = DZERO !< rate available at time of providing + real(DP), pointer :: qtformvr_ptr => null() !< pointer to total available flow (qtformvr) + real(DP), pointer :: qformvr_ptr => null() !< pointer to available flow after consumed (qformvr) + real(DP), pointer :: qtomvr_ptr => null() !< pointer to provider flow rate (qtomvr) + real(DP), pointer :: qfrommvr_ptr => null() !< pointer to receiver flow rate (qfrommvr) contains - procedure :: set + procedure :: set_values + procedure :: prepare procedure :: echo procedure :: advance procedure :: fc procedure :: qrcalc procedure :: writeflow end type MvrType - - contains - - subroutine set(this, line, inunit, iout, mname, pckMemPaths, pakmovers) -! ****************************************************************************** -! set -- Setup mvr object -! If mname == '', then read mname out of line. pckMemPaths is an array -! of strings which are the memory paths for those packages. They are composed -! of model names and package names. The mover entries must be in pckMemPaths, -! or this routine will terminate with an error. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ - ! -- modules - use InputOutputModule, only: urword, extract_idnum_or_bndname - use SimModule, only: store_error, store_error_unit, count_errors + +contains + + !> @ brief Set values from input data + !! + !! Set values and pointers for mover object. + !! + !< + subroutine set_values(this, mname1, pname1, id1, mname2, pname2, & + id2, imvrtype, value) use MemoryHelperModule, only: create_mem_path - ! -- dummy class(MvrType) :: this - character(len=*), intent(inout) :: line - integer(I4B), intent(in) :: inunit - integer(I4B), intent(in) :: iout - character(len=LENMODELNAME), intent(in) :: mname - character(len=LENMEMPATH), & - dimension(:), pointer, contiguous :: pckMemPaths - type(PackageMoverType), dimension(:), pointer, contiguous :: pakmovers + character(len=*), intent(in) :: mname1 + character(len=*), intent(in) :: pname1 + integer(I4B), intent(in), target :: id1 + character(len=*), intent(in) :: mname2 + character(len=*), intent(in) :: pname2 + integer(I4B), intent(in), target :: id2 + integer(I4B), intent(in), target :: imvrtype + real(DP), intent(in), target :: value + + this%pckNameSrc = create_mem_path(mname1, pname1) + this%iRchNrSrc => id1 + this%pckNameTgt = create_mem_path(mname2, pname2) + this%iRchNrTgt => id2 + this%imvrtype => imvrtype + this%value => value + + return + end subroutine set_values + + !> @ brief Prepare object + !! + !! Set values and pointers for mover object. + !! pckMemPaths is an array of strings which are the memory paths for those + !! packages. They are composed of model names and package names. The mover + !! entries must be in pckMemPaths, or this routine will terminate with an error. + !< + subroutine prepare(this, inunit, pckMemPaths, pakmovers) + ! -- modules + use SimModule, only: store_error, store_error_unit, count_errors + ! -- dummy + class(MvrType) :: this !< MvrType objec + integer(I4B), intent(in) :: inunit !< input file unit number + character(len=LENMEMPATH), & + dimension(:), pointer, contiguous :: pckMemPaths !< array of strings + type(PackageMoverType), dimension(:), pointer, contiguous :: pakmovers !< Array of package mover objects ! -- local - integer(I4B) :: lloc, istart, istop, ival - real(DP) :: rval real(DP), dimension(:), pointer, contiguous :: temp_ptr => null() - character(len=LINELENGTH) :: errmsg - character(len=LENBOUNDNAME) :: bndname - character(len=LINELENGTH) :: modelName - character(len=LINELENGTH) :: packageName - logical :: mnamel, found + logical :: found integer(I4B) :: i integer(I4B) :: ipakloc1, ipakloc2 -! ------------------------------------------------------------------------------ - ! - ! -- Check for valid mname and set logical mnamel flag - if(mname == '') then - mnamel = .false. - else - mnamel = .true. - endif - ! - ! -- Set lloc for line - lloc = 1 - ! - ! -- Construct provider name, which is the memory path for the package - if(mnamel) then - modelName = mname - else - call urword(line, lloc, istart, istop, 1, ival, rval, iout, inunit) - modelName = line(istart:istop) - endif - call urword(line, lloc, istart, istop, 1, ival, rval, iout, inunit) - packageName = line(istart:istop) - - this%pckNameSrc = create_mem_path(modelName, packageName) - - ! - ! -- Read id for the provider - call extract_idnum_or_bndname(line, lloc, istart, istop, ival, bndname) - this%iRchNrSrc = ival - ! - ! -- Construct receiver name, which is the memory path for the package - if(mnamel) then - modelName = mname - else - call urword(line, lloc, istart, istop, 1, ival, rval, iout, inunit) - modelName = line(istart:istop) - endif - call urword(line, lloc, istart, istop, 1, ival, rval, iout, inunit) - packageName = line(istart:istop) - this%pckNameTgt = create_mem_path(modelName, packageName) - ! - ! -- Read id for the receiver - call extract_idnum_or_bndname(line, lloc, istart, istop, ival, bndname) - this%iRchNrTgt = ival - ! - ! -- Read mover type - call urword(line, lloc, istart, istop, 1, ival, rval, iout, inunit) - select case(line(istart:istop)) - case('FACTOR') - this%imvrtype = 1 - case('EXCESS') - this%imvrtype = 2 - case('THRESHOLD') - this%imvrtype = 3 - case('UPTO') - this%imvrtype = 4 - case default - call store_error('INVALID MOVER TYPE: '//trim(line(istart:istop)) ) - call store_error_unit(inunit) - end select - ! - ! -- Read mover value - call urword(line, lloc, istart, istop, 3, ival, rval, iout, inunit) - this%value = rval ! ! -- Check to make sure provider and receiver are not the same - if(this%pckNameSrc == this%pckNameTgt .and. this%iRchNrSrc == this%iRchNrTgt) then - call store_error('PROVIDER AND RECEIVER ARE THE SAME: '// & - trim(line)) + if (this%pckNameSrc == this%pckNameTgt .and. & + this%iRchNrSrc == this%iRchNrTgt) then + call store_error('PROVIDER AND RECEIVER ARE THE SAME: '// & + trim(this%pckNameSrc)//' : '//trim(this%pckNameTgt)) call store_error_unit(inunit) - endif + end if ! ! -- Check to make sure pname1 and pname2 are both listed in pckMemPaths ! pname1 is the provider package; pname2 is the receiver package @@ -152,7 +118,7 @@ subroutine set(this, line, inunit, iout, mname, pckMemPaths, pakmovers) found = .true. ipakloc1 = i exit - endif + end if end do if (.not. found) then call store_error('MOVER CAPABILITY NOT ACTIVATED IN '//this%pckNameSrc) @@ -165,7 +131,7 @@ subroutine set(this, line, inunit, iout, mname, pckMemPaths, pakmovers) found = .true. ipakloc2 = i exit - endif + end if end do if (.not. found) then call store_error('MOVER CAPABILITY NOT ACTIVATED IN '//this%pckNameTgt) @@ -177,13 +143,13 @@ subroutine set(this, line, inunit, iout, mname, pckMemPaths, pakmovers) ! ! -- Set pointer to QTOMVR array in the provider boundary package temp_ptr => pakmovers(ipakloc1)%qtomvr - if(this%iRchNrSrc < 1 .or. this%iRchNrSrc > size(temp_ptr)) then + if (this%iRchNrSrc < 1 .or. this%iRchNrSrc > size(temp_ptr)) then call store_error('PROVIDER ID < 1 OR GREATER THAN PACKAGE SIZE ') - write(errmsg, '(4x,a,i0,a,i0)') 'PROVIDER ID = ', this%iRchNrSrc, & + write (errmsg, '(4x,a,i0,a,i0)') 'PROVIDER ID = ', this%iRchNrSrc, & '; PACKAGE SIZE = ', size(temp_ptr) call store_error(trim(errmsg)) call store_error_unit(inunit) - endif + end if this%qtomvr_ptr => temp_ptr(this%iRchNrSrc) ! ! -- Set pointer to QFORMVR array in the provider boundary package @@ -196,75 +162,68 @@ subroutine set(this, line, inunit, iout, mname, pckMemPaths, pakmovers) ! ! -- Set pointer to QFROMMVR array in the receiver boundary package temp_ptr => pakmovers(ipakloc2)%qfrommvr - if(this%iRchNrTgt < 1 .or. this%iRchNrTgt > size(temp_ptr)) then + if (this%iRchNrTgt < 1 .or. this%iRchNrTgt > size(temp_ptr)) then call store_error('RECEIVER ID < 1 OR GREATER THAN PACKAGE SIZE ') - write(errmsg, '(4x,a,i0,a,i0)') 'RECEIVER ID = ', this%iRchNrTgt, & + write (errmsg, '(4x,a,i0,a,i0)') 'RECEIVER ID = ', this%iRchNrTgt, & '; PACKAGE SIZE = ', size(temp_ptr) call store_error(trim(errmsg)) call store_error_unit(inunit) - endif + end if this%qfrommvr_ptr => temp_ptr(this%iRchNrTgt) ! ! -- return return - end subroutine set - + end subroutine prepare + + !> @ brief Echo data to list file + !! + !! Write mover values to output file. + !! + !< subroutine echo(this, iout) -! ****************************************************************************** -! echo -- Write the mover info that was read from file -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(MvrType) :: this - integer(I4B), intent(in) :: iout + class(MvrType) :: this !< MvrType + integer(I4B), intent(in) :: iout !< unit number for output file ! -- local -! ------------------------------------------------------------------------------ ! - write(iout, '(4x, a, a, a, i0)') 'FROM PACKAGE: ', trim(this%pckNameSrc), & + write (iout, '(4x, a, a, a, i0)') 'FROM PACKAGE: ', trim(this%pckNameSrc), & ' FROM ID: ', this%iRchNrSrc - write(iout, '(4x, a, a, a, i0)') 'TO PACKAGE: ', trim(this%pckNameTgt), & + write (iout, '(4x, a, a, a, i0)') 'TO PACKAGE: ', trim(this%pckNameTgt), & ' TO ID: ', this%iRchNrTgt - write(iout, '(4x, a, a, a, 1pg15.6,/)') 'MOVER TYPE: ', & + write (iout, '(4x, a, a, a, 1pg15.6,/)') 'MOVER TYPE: ', & trim(mvrtypes(this%imvrtype)), ' ', this%value ! ! -- return return end subroutine echo - + + !> @ brief Advance + !! + !! Advance mover object. Does nothing now. + !! + !< subroutine advance(this) -! ****************************************************************************** -! advance -- Advance the mover -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules ! -- dummy class(MvrType) :: this ! -- local -! ------------------------------------------------------------------------------ - ! ! ! -- return return end subroutine advance - + + !> @ brief Formulate coefficients + !! + !! Make mover calculations. + !! + !< subroutine fc(this) -! ****************************************************************************** -! fc -- formulate coefficients -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(MvrType) :: this + class(MvrType) :: this !< MvrType ! -- local real(DP) :: qavailable, qtanew, qpactual -! ------------------------------------------------------------------------------ ! ! -- Set qa and this%qavailable equal to available water in package (qtomvr) qavailable = this%qformvr_ptr @@ -279,10 +238,10 @@ subroutine fc(this) this%qpactual = qpactual ! ! -- Add the calculated qpactual term directly into the receiver package - ! qfrommvr array. + ! qfrommvr array. this%qfrommvr_ptr = this%qfrommvr_ptr + qpactual ! - ! -- Add the calculated qpactual term directly into the provider package + ! -- Add the calculated qpactual term directly into the provider package ! qtomvr array. this%qtomvr_ptr = this%qtomvr_ptr + qpactual ! @@ -294,82 +253,78 @@ subroutine fc(this) return end subroutine fc + !> @ brief Flow to receiver + !! + !! Calculate the rate of water provided to receiver. + !! + !< function qrcalc(this, qa, qta) result(qr) -! ****************************************************************************** -! qrcalc -- Calculate the rate of water provided to the receiver -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules ! -- return real(DP) :: qr ! -- dummy - class(MvrType) :: this - real(DP), intent(in) :: qa - real(DP), intent(in) :: qta + class(MvrType) :: this !< MvrType + real(DP), intent(in) :: qa !< actual flow + real(DP), intent(in) :: qta !< total available flow ! -- local -! ------------------------------------------------------------------------------ ! -- Using the mover rules, calculate how much of the available water will ! go to the receiver. qr = DZERO ! -- Calculate qr select case (this%imvrtype) - case(1) - ! -- FACTOR uses total available to make calculation, and then - ! limits qr by consumed available - if(qta > DZERO) qr = qta * this%value - qr = min(qr, qa) - case(2) - ! -- EXCESS - if(qa > this%value) then - qr = qa - this%value - else - qr = DZERO - endif - case(3) - ! -- THRESHOLD - if(this%value > qa) then - qr = DZERO - else - qr = this%value - endif - case(4) - ! -- UPTO - if(qa > this%value) then - qr = this%value - else - qr = qa - endif + case (1) + ! -- FACTOR uses total available to make calculation, and then + ! limits qr by consumed available + if (qta > DZERO) qr = qta * this%value + qr = min(qr, qa) + case (2) + ! -- EXCESS + if (qa > this%value) then + qr = qa - this%value + else + qr = DZERO + end if + case (3) + ! -- THRESHOLD + if (this%value > qa) then + qr = DZERO + else + qr = this%value + end if + case (4) + ! -- UPTO + if (qa > this%value) then + qr = this%value + else + qr = qa + end if end select ! ! -- return return end function qrcalc + !> @ brief Write flow + !! + !! Write a line of output for this mover object. + !! + !< subroutine writeflow(this, iout) -! ****************************************************************************** -! writeflow -- Write mover flow information -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class(MvrType) :: this - integer(I4B), intent(in) :: iout + class(MvrType) :: this !< MvrType + integer(I4B), intent(in) :: iout !< output file unit number ! -- local character(len=*), parameter :: fmt = & - "(1x, a, ' ID ', i0, ' AVAILABLE ', 1(1pg15.6), " // & - "' PROVIDED ', 1(1pg15.6), ' TO ', a, ' ID ', i0)" -! ------------------------------------------------------------------------------ + "(1x, a, ' ID ', i0, ' AVAILABLE ', 1(1pg15.6), & + &' PROVIDED ', 1(1pg15.6), ' TO ', a, ' ID ', i0)" ! - write(iout, fmt) trim(this%pckNameSrc), this%iRchNrSrc, this%qavailable, & + write (iout, fmt) trim(this%pckNameSrc), this%iRchNrSrc, this%qavailable, & this%qpactual, trim(this%pckNameTgt), this%iRchNrTgt ! ! -- return return end subroutine writeflow - + end module MvrModule - + diff --git a/src/Model/ModelUtilities/PackageMover.f90 b/src/Model/ModelUtilities/PackageMover.f90 index 5180a36d1be..b0c43187838 100644 --- a/src/Model/ModelUtilities/PackageMover.f90 +++ b/src/Model/ModelUtilities/PackageMover.f90 @@ -1,8 +1,8 @@ module PackageMoverModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMEMPATH, DZERO - use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & + + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMEMPATH, DZERO + use MemoryManagerModule, only: mem_allocate, mem_reallocate, mem_setptr, & mem_deallocate implicit none @@ -10,17 +10,17 @@ module PackageMoverModule public :: PackageMoverType public :: set_packagemover_pointer public :: nulllify_packagemover_pointer - + type PackageMoverType - - character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored - integer(I4B), pointer :: nproviders - integer(I4B), pointer :: nreceivers - integer(I4B), dimension(:), pointer, contiguous :: iprmap => null() !< map between id1 and feature (needed for lake to map from outlet to lake number) - real(DP), dimension(:), pointer, contiguous :: qtformvr => null() - real(DP), dimension(:), pointer, contiguous :: qformvr => null() - real(DP), dimension(:), pointer, contiguous :: qtomvr => null() - real(DP), dimension(:), pointer, contiguous :: qfrommvr => null() + + character(len=LENMEMPATH) :: memoryPath !< the location in the memory manager where the variables are stored + integer(I4B), pointer :: nproviders + integer(I4B), pointer :: nreceivers + integer(I4B), dimension(:), pointer, contiguous :: iprmap => null() !< map between id1 and feature (needed for lake to map from outlet to lake number) + real(DP), dimension(:), pointer, contiguous :: qtformvr => null() + real(DP), dimension(:), pointer, contiguous :: qformvr => null() + real(DP), dimension(:), pointer, contiguous :: qtomvr => null() + real(DP), dimension(:), pointer, contiguous :: qfrommvr => null() contains procedure :: ar @@ -33,17 +33,19 @@ module PackageMoverModule procedure :: get_qfrommvr procedure :: get_qtomvr procedure :: accumulate_qformvr - + end type PackageMoverType - - contains - + +contains + subroutine set_packagemover_pointer(packagemover, memPath) type(PackageMoverType), intent(inout) :: packagemover character(len=*), intent(in) :: memPath packagemover%memoryPath = memPath - call mem_setptr(packagemover%nproviders, 'NPROVIDERS', packagemover%memoryPath) - call mem_setptr(packagemover%nreceivers, 'NRECEIVERS', packagemover%memoryPath) + call mem_setptr(packagemover%nproviders, 'NPROVIDERS', & + packagemover%memoryPath) + call mem_setptr(packagemover%nreceivers, 'NRECEIVERS', & + packagemover%memoryPath) call mem_setptr(packagemover%iprmap, 'IPRMAP', packagemover%memoryPath) call mem_setptr(packagemover%qtformvr, 'QTFORMVR', packagemover%memoryPath) call mem_setptr(packagemover%qformvr, 'QFORMVR', packagemover%memoryPath) @@ -78,8 +80,8 @@ subroutine ar(this, nproviders, nreceivers, memoryPath) ! ! -- return return - end subroutine ar - + end subroutine ar + subroutine ad(this) class(PackageMoverType) :: this integer :: i @@ -88,12 +90,12 @@ subroutine ad(this) do i = 1, this%nproviders this%qtomvr(i) = DZERO this%qformvr(i) = DZERO - enddo + end do ! ! -- return return end subroutine ad - + subroutine cf(this) class(PackageMoverType) :: this integer :: i @@ -101,16 +103,16 @@ subroutine cf(this) ! -- set frommvr and qtomvr to zero do i = 1, this%nreceivers this%qfrommvr(i) = DZERO - enddo + end do do i = 1, this%nproviders this%qtomvr(i) = DZERO this%qtformvr(i) = this%qformvr(i) - enddo + end do ! ! -- return return end subroutine cf - + subroutine fc(this) class(PackageMoverType) :: this integer :: i @@ -118,12 +120,12 @@ subroutine fc(this) ! -- set formvr to zero do i = 1, this%nproviders this%qformvr(i) = DZERO - enddo + end do ! ! -- return return end subroutine fc - + subroutine da(this) class(PackageMoverType) :: this ! @@ -139,12 +141,12 @@ subroutine da(this) call mem_deallocate(this%nreceivers) ! ! -- pointers - nullify(this%iprmap) + nullify (this%iprmap) ! ! -- return return end subroutine da - + subroutine allocate_scalars(this) class(PackageMoverType) :: this ! @@ -156,8 +158,8 @@ subroutine allocate_scalars(this) ! ! -- return return - end subroutine allocate_scalars - + end subroutine allocate_scalars + subroutine allocate_arrays(this) class(PackageMoverType) :: this integer(I4B) :: i @@ -174,22 +176,22 @@ subroutine allocate_arrays(this) this%qtformvr(i) = DZERO this%qformvr(i) = DZERO this%qtomvr(i) = DZERO - enddo + end do do i = 1, this%nreceivers this%qfrommvr(i) = DZERO - enddo + end do ! ! -- return return end subroutine allocate_arrays - + function get_qfrommvr(this, ireceiver) result(qfrommvr) class(PackageMoverType) :: this real(DP) :: qfrommvr integer, intent(in) :: ireceiver qfrommvr = this%qfrommvr(ireceiver) end function get_qfrommvr - + function get_qtomvr(this, iprovider) result(qtomvr) class(PackageMoverType) :: this real(DP) :: qtomvr @@ -204,4 +206,4 @@ subroutine accumulate_qformvr(this, iprovider, qformvr) this%qformvr(iprovider) = this%qformvr(iprovider) + qformvr end subroutine accumulate_qformvr -end module PackageMoverModule \ No newline at end of file +end module PackageMoverModule diff --git a/src/Model/ModelUtilities/SfrCrossSectionManager.f90 b/src/Model/ModelUtilities/SfrCrossSectionManager.f90 index 0f2afdf73c3..87fdfc940a0 100644 --- a/src/Model/ModelUtilities/SfrCrossSectionManager.f90 +++ b/src/Model/ModelUtilities/SfrCrossSectionManager.f90 @@ -2,13 +2,13 @@ module sfrCrossSectionManager use KindModule, only: DP, I4B, LGP use ConstantsModule, only: DZERO, DONE, & - LINELENGTH + LINELENGTH use SimVariablesModule, only: errmsg, warnmsg use TableModule, only: TableType, table_cr implicit none - + public :: SfrCrossSection public :: cross_section_cr @@ -27,12 +27,12 @@ module sfrCrossSectionManager integer(I4B), pointer :: invalid => null() character(len=LINELENGTH), dimension(:), allocatable :: filenames integer(I4B), pointer, dimension(:), contiguous :: npoints => null() - type(SfrCrossSectionType), pointer, dimension(:), contiguous :: cross_sections => null() + type(SfrCrossSectionType), & + pointer, dimension(:), contiguous :: cross_sections => null() type(TableType), pointer :: inputtab => null() - - contains - + contains + ! ! -- public procedures procedure, public :: initialize @@ -46,8 +46,8 @@ module sfrCrossSectionManager procedure, private :: validate end type SfrCrossSection - - contains + +contains !> @brief Create a cross-section object !! @@ -56,20 +56,20 @@ module sfrCrossSectionManager !< subroutine cross_section_cr(this, iout, iprpak, nreaches) ! -- dummy variables - type(SfrCrossSection), pointer :: this !< SfrCrossSection object - integer(I4B), pointer, intent(in) :: iout !< model listing file - integer(I4B), pointer, intent(in) :: iprpak !< flag for printing table input data - integer(I4B), pointer, intent(in) :: nreaches !< number of reaches + type(SfrCrossSection), pointer :: this !< SfrCrossSection object + integer(I4B), pointer, intent(in) :: iout !< model listing file + integer(I4B), pointer, intent(in) :: iprpak !< flag for printing table input data + integer(I4B), pointer, intent(in) :: nreaches !< number of reaches ! ! -- check if table already associated and reset if necessary if (associated(this)) then call this%destroy() - deallocate(this) - nullify(this) + deallocate (this) + nullify (this) end if ! ! -- Create the object - allocate(this) + allocate (this) ! ! -- initialize scalars this%iout => iout @@ -82,20 +82,20 @@ end subroutine cross_section_cr !> @brief Initialize a cross-section object !! - !! Subroutine to inititialize the cross-section object with the current + !! Subroutine to inititialize the cross-section object with the current !! data. !! !< subroutine initialize(this, ncrossptstot, ncrosspts, iacross, & station, height, roughfraction) ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object - integer(I4B), intent(in) :: ncrossptstot !< total number of cross-section points - integer(I4B), dimension(this%nreaches), intent(in) :: ncrosspts !< pointers to cross-section data in data vector - integer(I4B), dimension(this%nreaches+1), intent(in) :: iacross !< pointers to cross-section data in data vector - real(DP), dimension(ncrossptstot), intent(in) :: station !< cross-section station data - real(DP), dimension(ncrossptstot), intent(in) :: height !< cross-section height data - real(DP), dimension(ncrossptstot), intent(in) :: roughfraction !< cross-section roughness fraction data + class(SfrCrossSection) :: this !< SfrCrossSection object + integer(I4B), intent(in) :: ncrossptstot !< total number of cross-section points + integer(I4B), dimension(this%nreaches), intent(in) :: ncrosspts !< pointers to cross-section data in data vector + integer(I4B), dimension(this%nreaches + 1), intent(in) :: iacross !< pointers to cross-section data in data vector + real(DP), dimension(ncrossptstot), intent(in) :: station !< cross-section station data + real(DP), dimension(ncrossptstot), intent(in) :: height !< cross-section height data + real(DP), dimension(ncrossptstot), intent(in) :: roughfraction !< cross-section roughness fraction data ! -- local variables integer(I4B) :: i integer(I4B) :: n @@ -105,22 +105,22 @@ subroutine initialize(this, ncrossptstot, ncrosspts, iacross, & integer(I4B) :: ipos ! ! -- allocate scalars - allocate(this%invalid) + allocate (this%invalid) ! ! -- initialize scalars this%invalid = 0 ! ! -- create cross-section container - allocate(this%filenames(this%nreaches)) - allocate(this%npoints(this%nreaches)) - allocate(this%cross_sections(this%nreaches)) + allocate (this%filenames(this%nreaches)) + allocate (this%npoints(this%nreaches)) + allocate (this%cross_sections(this%nreaches)) do n = 1, this%nreaches npoints = ncrosspts(n) - allocate(this%cross_sections(n)%npoints) - allocate(this%cross_sections(n)%station(npoints)) - allocate(this%cross_sections(n)%height(npoints)) - allocate(this%cross_sections(n)%roughfraction(npoints)) - allocate(this%cross_sections(n)%valid(npoints)) + allocate (this%cross_sections(n)%npoints) + allocate (this%cross_sections(n)%station(npoints)) + allocate (this%cross_sections(n)%height(npoints)) + allocate (this%cross_sections(n)%roughfraction(npoints)) + allocate (this%cross_sections(n)%valid(npoints)) end do ! ! -- fill cross-section container with current values @@ -155,10 +155,10 @@ subroutine read_table(this, irch, width, filename) use SimModule, only: store_error use BlockParserModule, only: BlockParserType ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object - integer(I4B), intent(in) :: irch !< current reach - real(DP), intent(in) :: width !< reach width - character(len=*), intent(in) :: filename !< table file with station height data + class(SfrCrossSection) :: this !< SfrCrossSection object + integer(I4B), intent(in) :: irch !< current reach + real(DP), intent(in) :: width !< reach width + character(len=*), intent(in) :: filename !< table file with station height data ! -- local variables character(len=LINELENGTH) :: tag character(len=LINELENGTH) :: keyword @@ -178,8 +178,8 @@ subroutine read_table(this, irch, width, filename) jmin = 2 ! ! -- create a tag with the file name and reach number - write(tag, "('Reach',1x,i0,1x,'(',a, ')')") & - irch, trim(adjustl(filename)) + write (tag, "('Reach',1x,i0,1x,'(',a, ')')") & + irch, trim(adjustl(filename)) ! ! -- open the table file iu = IUOC @@ -194,36 +194,37 @@ subroutine read_table(this, irch, width, filename) ! ! -- process the table dimension data if (this%iprpak /= 0) then - write(this%iout,'(/1x,a)') & - 'PROCESSING ' // trim(adjustl(tag)) // ' DIMENSIONS' + write (this%iout, '(/1x,a)') & + 'PROCESSING '//trim(adjustl(tag))//' DIMENSIONS' end if readdims: do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('NROW') - n = parser%GetInteger() - if (n < 1) then - write(errmsg,'(a)') 'TABLE NROW MUST BE > 0' - call store_error(errmsg) - end if - case ('NCOL') - j = parser%GetInteger() - jmin = 2 - if (j < jmin) then - write(errmsg,'(a,1x,i0)') 'TABLE NCOL MUST BE >= ', jmin - call store_error(errmsg) - end if - case default - write(errmsg,'(a,a)') & - 'UNKNOWN '//trim(adjustl(tag))//' DIMENSIONS KEYWORD: ', trim(keyword) + case ('NROW') + n = parser%GetInteger() + if (n < 1) then + write (errmsg, '(a)') 'TABLE NROW MUST BE > 0' + call store_error(errmsg) + end if + case ('NCOL') + j = parser%GetInteger() + jmin = 2 + if (j < jmin) then + write (errmsg, '(a,1x,i0)') 'TABLE NCOL MUST BE >= ', jmin call store_error(errmsg) + end if + case default + write (errmsg, '(a,a)') & + 'UNKNOWN '//trim(adjustl(tag))//' DIMENSIONS KEYWORD: ', & + trim(keyword) + call store_error(errmsg) end select end do readdims if (this%iprpak /= 0) then - write(this%iout,'(1x,a)') & - 'END OF ' // trim(adjustl(tag)) // ' DIMENSIONS' + write (this%iout, '(1x,a)') & + 'END OF '//trim(adjustl(tag))//' DIMENSIONS' end if else call store_error('REQUIRED DIMENSIONS BLOCK NOT FOUND.') @@ -231,12 +232,12 @@ subroutine read_table(this, irch, width, filename) ! ! -- check that ncol and nrow have been specified if (n < 1) then - write(errmsg,'(a)') & + write (errmsg, '(a)') & 'NROW NOT SPECIFIED IN THE TABLE DIMENSIONS BLOCK' call store_error(errmsg) end if if (j < 1) then - write(errmsg,'(a)') & + write (errmsg, '(a)') & 'NCOL NOT SPECIFIED IN THE TABLE DIMENSIONS BLOCK' call store_error(errmsg) end if @@ -247,21 +248,21 @@ subroutine read_table(this, irch, width, filename) ! ! -- set the filename and reset the number of points this%filenames(irch) = filename - this%npoints(irch) = n + this%npoints(irch) = n ! ! -- deallocate - deallocate(this%cross_sections(irch)%npoints) - deallocate(this%cross_sections(irch)%station) - deallocate(this%cross_sections(irch)%height) - deallocate(this%cross_sections(irch)%roughfraction) - deallocate(this%cross_sections(irch)%valid) + deallocate (this%cross_sections(irch)%npoints) + deallocate (this%cross_sections(irch)%station) + deallocate (this%cross_sections(irch)%height) + deallocate (this%cross_sections(irch)%roughfraction) + deallocate (this%cross_sections(irch)%valid) ! ! -- reallocate - allocate(this%cross_sections(irch)%npoints) - allocate(this%cross_sections(irch)%station(n)) - allocate(this%cross_sections(irch)%height(n)) - allocate(this%cross_sections(irch)%roughfraction(n)) - allocate(this%cross_sections(irch)%valid(n)) + allocate (this%cross_sections(irch)%npoints) + allocate (this%cross_sections(irch)%station(n)) + allocate (this%cross_sections(irch)%height(n)) + allocate (this%cross_sections(irch)%roughfraction(n)) + allocate (this%cross_sections(irch)%valid(n)) ! ! -- initialize this%cross_sections(irch)%npoints = n @@ -274,7 +275,7 @@ subroutine read_table(this, irch, width, filename) ! -- process the table data if (this%iprpak /= 0) then - write(this%iout,'(/1x,a)') & + write (this%iout, '(/1x,a)') & 'PROCESSING '//trim(adjustl(tag))//' TABLE' end if ipos = 0 @@ -294,9 +295,9 @@ subroutine read_table(this, irch, width, filename) end if this%cross_sections(irch)%valid(ipos) = .TRUE. end do readtabledata - + if (this%iprpak /= 0) then - write(this%iout,'(1x,a)') & + write (this%iout, '(1x,a)') & 'END OF '//trim(adjustl(tag))//' TABLE' end if else @@ -305,15 +306,15 @@ subroutine read_table(this, irch, width, filename) ! ! -- error condition if number of rows read are not equal to nrow if (ipos /= this%npoints(irch)) then - write(errmsg,'(a,1x,i0,1x,a,1x,i0,1x,a)') & + write (errmsg, '(a,1x,i0,1x,a,1x,i0,1x,a)') & 'NROW SET TO', this%npoints(irch), 'BUT', ipos, 'ROWS WERE READ' call store_error(errmsg) - end if + end if end if ! ! -- close the open table file if (iu > 0) then - close(iu) + close (iu) end if ! ! -- validate the table @@ -322,7 +323,7 @@ subroutine read_table(this, irch, width, filename) ! -- return return end subroutine read_table - + !> @brief Validate cross-section tables !! !! Subroutine to validate a cross-section table. @@ -335,14 +336,14 @@ subroutine validate(this, irch) use GwfSfrCrossSectionUtilsModule, only: get_cross_section_area, & get_hydraulic_radius ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object - integer(I4B), intent(in) :: irch !< current reach + class(SfrCrossSection) :: this !< SfrCrossSection object + integer(I4B), intent(in) :: irch !< current reach ! -- local variables logical(LGP) :: station_error logical(LGP) :: height_error logical(LGP) :: height_zero_error logical(LGP) :: roughness_error - character(len=LINELENGTH) :: filename + character(len=LINELENGTH) :: filename integer(I4B) :: npts integer(I4B) :: n integer(I4B) :: i @@ -392,25 +393,25 @@ subroutine validate(this, irch) height_zero_error .or. roughness_error) then filename = this%filenames(irch) if (station_error) then - write(errmsg, '(3a,1x,i0,1x,a)') & + write (errmsg, '(3a,1x,i0,1x,a)') & "All xfraction data in '", trim(adjustl(filename)), & "' for reach", irch, 'must be greater than or equal to zero.' call store_error(errmsg) end if if (height_error) then - write(errmsg, '(3a,1x,i0,1x,a)') & + write (errmsg, '(3a,1x,i0,1x,a)') & "All height data in '", trim(adjustl(filename)), & "' for reach", irch, 'must be greater than or equal to zero.' call store_error(errmsg) end if if (height_zero_error) then - write(errmsg, '(3a,1x,i0,1x,a)') & + write (errmsg, '(3a,1x,i0,1x,a)') & "At least one height data value in '", trim(adjustl(filename)), & "' for reach", irch, 'must be equal to zero.' call store_error(errmsg) end if if (roughness_error) then - write(errmsg, '(3a,1x,i0,1x,a)') & + write (errmsg, '(3a,1x,i0,1x,a)') & "All manfraction data in '", trim(adjustl(filename)), & "' for reach", irch, 'must be greater than zero.' call store_error(errmsg) @@ -418,7 +419,7 @@ subroutine validate(this, irch) end if ! ! -- initialize and fill heights - allocate(heights(npts)) + allocate (heights(npts)) do n = 1, npts heights(n) = this%cross_sections(irch)%height(n) end do @@ -426,7 +427,7 @@ subroutine validate(this, irch) ! -- get unique heights call unique_values(heights, unique_heights) ! - ! -- calculate the product of the area and the hydraulic radius to + ! -- calculate the product of the area and the hydraulic radius to ! the 2/3 power do n = 1, size(unique_heights) if (unique_heights(n) <= DZERO) cycle @@ -458,8 +459,8 @@ subroutine validate(this, irch) end do ! ! -- deallocate local storage - deallocate(heights) - deallocate(unique_heights) + deallocate (heights) + deallocate (unique_heights) ! ! -- return return @@ -475,15 +476,15 @@ subroutine output(this, widths, roughs, kstp, kper) use ConstantsModule, only: TABLEFT use SimModule, only: store_warning ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object - real(DP), dimension(this%nreaches), intent(in) :: widths !< reach widths - real(DP), dimension(this%nreaches), intent(in) :: roughs !< reach Manning's roughness coefficients - integer(I4B), intent(in), optional :: kstp !< time step - integer(I4B), intent(in), optional :: kper !< stress period + class(SfrCrossSection) :: this !< SfrCrossSection object + real(DP), dimension(this%nreaches), intent(in) :: widths !< reach widths + real(DP), dimension(this%nreaches), intent(in) :: roughs !< reach Manning's roughness coefficients + integer(I4B), intent(in), optional :: kstp !< time step + integer(I4B), intent(in), optional :: kper !< stress period ! -- local variables character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text - character(len=LINELENGTH) :: filename + character(len=LINELENGTH) :: filename character(len=10) :: cvalid logical(LGP) :: transient integer(I4B) :: kkstp @@ -551,7 +552,7 @@ subroutine output(this, widths, roughs, kstp, kper) end if ! ! -- reset the input table object - write(title, '(a,1x,i0,1x,3a)') & + write (title, '(a,1x,i0,1x,3a)') & 'CROSS_SECTION DATA FOR REACH', irch, "FROM TAB6 FILE ('", & trim(adjustl(filename)), "')" call table_cr(this%inputtab, trim(adjustl(filename)), title) @@ -587,7 +588,8 @@ subroutine output(this, widths, roughs, kstp, kper) call this%inputtab%add_term(xfraction) call this%inputtab%add_term(this%cross_sections(irch)%station(n)) call this%inputtab%add_term(this%cross_sections(irch)%height(n)) - call this%inputtab%add_term(this%cross_sections(irch)%roughfraction(n)) + call this%inputtab%add_term(& + &this%cross_sections(irch)%roughfraction(n)) call this%inputtab%add_term(r) if (reach_fail(irch) > 0) then if (this%cross_sections(irch)%valid(n)) then @@ -596,7 +598,7 @@ subroutine output(this, widths, roughs, kstp, kper) cvalid = 'TRUE' end if call this%inputtab%add_term(cvalid) - end if + end if end do ! ! -- finalize the table @@ -613,10 +615,10 @@ subroutine output(this, widths, roughs, kstp, kper) ninvalid_reaches = ninvalid_reaches + 1 end if end do - write(warnmsg, '(a,1x,i0,7(1x,a))') & + write (warnmsg, '(a,1x,i0,7(1x,a))') & 'Cross-section data for', ninvalid_reaches, & 'reaches include one or more points that result in a', & - 'non-unique depth-conveyance relation. This occurs when', & + 'non-unique depth-conveyance relation. This occurs when', & 'there are horizontal sections at non-zero heights', & '(for example, flat overbank sections). This can usually', & 'be resolved by adding a small slope to these flat', & @@ -651,7 +653,7 @@ function get_ncrossptstot(this) result(nptstot) ! -- return return end function get_ncrossptstot - + !> @brief Pack the cross-section object !! !! Subroutine to pack the cross-section object into vectors. @@ -660,13 +662,13 @@ end function get_ncrossptstot subroutine pack(this, ncrossptstot, ncrosspts, iacross, & station, height, roughfraction) ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object - integer(I4B), intent(in) :: ncrossptstot !< total number of cross-section points - integer(I4B), dimension(this%nreaches), intent(inout) :: ncrosspts !< pointers to cross-section data in data vector - integer(I4B), dimension(this%nreaches+1), intent(inout) :: iacross !< pointers to cross-section data in data vector - real(DP), dimension(ncrossptstot), intent(inout) :: station !< cross-section station data - real(DP), dimension(ncrossptstot), intent(inout) :: height !< cross-section height data - real(DP), dimension(ncrossptstot), intent(inout) :: roughfraction !< cross-section roughness fraction data + class(SfrCrossSection) :: this !< SfrCrossSection object + integer(I4B), intent(in) :: ncrossptstot !< total number of cross-section points + integer(I4B), dimension(this%nreaches), intent(inout) :: ncrosspts !< pointers to cross-section data in data vector + integer(I4B), dimension(this%nreaches + 1), intent(inout) :: iacross !< pointers to cross-section data in data vector + real(DP), dimension(ncrossptstot), intent(inout) :: station !< cross-section station data + real(DP), dimension(ncrossptstot), intent(inout) :: height !< cross-section height data + real(DP), dimension(ncrossptstot), intent(inout) :: roughfraction !< cross-section roughness fraction data ! -- local variables integer(I4B) :: i integer(I4B) :: n @@ -685,7 +687,7 @@ subroutine pack(this, ncrossptstot, ncrosspts, iacross, & roughfraction(ipos) = this%cross_sections(n)%roughfraction(i) ipos = ipos + 1 end do - iacross(n+1) = ipos + iacross(n + 1) = ipos end do ! ! -- return @@ -699,48 +701,46 @@ end subroutine pack !< subroutine destroy(this) ! -- dummy variables - class(SfrCrossSection) :: this !< SfrCrossSection object + class(SfrCrossSection) :: this !< SfrCrossSection object ! -- local variables integer(I4B) :: n ! ! -- deallocate and nullify pointers - deallocate(this%npoints) - nullify(this%npoints) + deallocate (this%npoints) + nullify (this%npoints) do n = 1, this%nreaches - deallocate(this%cross_sections(n)%npoints) - nullify(this%cross_sections(n)%npoints) - deallocate(this%cross_sections(n)%station) - nullify(this%cross_sections(n)%station) - deallocate(this%cross_sections(n)%height) - nullify(this%cross_sections(n)%height) - deallocate(this%cross_sections(n)%roughfraction) - nullify(this%cross_sections(n)%roughfraction) - deallocate(this%cross_sections(n)%valid) - nullify(this%cross_sections(n)%valid) + deallocate (this%cross_sections(n)%npoints) + nullify (this%cross_sections(n)%npoints) + deallocate (this%cross_sections(n)%station) + nullify (this%cross_sections(n)%station) + deallocate (this%cross_sections(n)%height) + nullify (this%cross_sections(n)%height) + deallocate (this%cross_sections(n)%roughfraction) + nullify (this%cross_sections(n)%roughfraction) + deallocate (this%cross_sections(n)%valid) + nullify (this%cross_sections(n)%valid) end do - deallocate(this%cross_sections) - nullify(this%cross_sections) + deallocate (this%cross_sections) + nullify (this%cross_sections) ! ! -- input table if (associated(this%inputtab)) then call this%inputtab%table_da() - deallocate(this%inputtab) - nullify(this%inputtab) + deallocate (this%inputtab) + nullify (this%inputtab) end if ! ! -- deallocate and nullify class scalars - deallocate(this%invalid) - nullify(this%invalid) + deallocate (this%invalid) + nullify (this%invalid) ! ! -- nullify scalars that are pointers to external variables - nullify(this%iout) - nullify(this%iprpak) - nullify(this%nreaches) + nullify (this%iout) + nullify (this%iprpak) + nullify (this%nreaches) ! ! -- return return end subroutine destroy - - -end module sfrCrossSectionManager \ No newline at end of file +end module sfrCrossSectionManager diff --git a/src/Model/ModelUtilities/SfrCrossSectionUtils.f90 b/src/Model/ModelUtilities/SfrCrossSectionUtils.f90 index 1f04f2e13a5..d4bd43250ca 100644 --- a/src/Model/ModelUtilities/SfrCrossSectionUtils.f90 +++ b/src/Model/ModelUtilities/SfrCrossSectionUtils.f90 @@ -2,9 +2,9 @@ !! !! This module contains the functions to calculate the wetted perimeter !! and cross-sectional area for a reach cross-section that are used in -!! the streamflow routing (SFR) package. It also contains subroutines to +!! the streamflow routing (SFR) package. It also contains subroutines to !! calculate the wetted perimeter and cross-sectional area for each -!! line segment in the cross-section. This module does not depend on the +!! line segment in the cross-section. This module does not depend on the !! SFR package. !! !< @@ -33,8 +33,8 @@ module GwfSfrCrossSectionUtilsModule !< function get_saturated_topwidth(npts, stations) result(w) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) ! -- local variables real(DP) :: w ! @@ -58,14 +58,14 @@ end function get_saturated_topwidth !< function get_wetted_topwidth(npts, stations, heights, d) result(w) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables integer(I4B) :: n real(DP) :: w - real(DP), dimension(npts-1) :: widths + real(DP), dimension(npts - 1) :: widths ! ! -- intitialize the wetted perimeter for the reach w = DZERO @@ -81,7 +81,7 @@ function get_wetted_topwidth(npts, stations, heights, d) result(w) ! -- return return end function get_wetted_topwidth - + !> @brief Calculate the wetted perimeter for a reach !! !! Function to calculate the wetted perimeter for a reach using the @@ -91,14 +91,14 @@ end function get_wetted_topwidth !< function get_wetted_perimeter(npts, stations, heights, d) result(p) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables integer(I4B) :: n real(DP) :: p - real(DP), dimension(npts-1) :: perimeters + real(DP), dimension(npts - 1) :: perimeters ! ! -- intitialize the wetted perimeter for the reach p = DZERO @@ -117,21 +117,21 @@ end function get_wetted_perimeter !> @brief Calculate the cross-sectional area for a reach !! - !! Function to calculate the cross-sectional area for a reach using + !! Function to calculate the cross-sectional area for a reach using !! the cross-section station-height data given a passed depth. !! !! @return a cross-sectional area !< function get_cross_section_area(npts, stations, heights, d) result(a) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables integer(I4B) :: n real(DP) :: a - real(DP), dimension(npts-1) :: areas + real(DP), dimension(npts - 1) :: areas ! ! -- intitialize the area a = DZERO @@ -150,24 +150,24 @@ end function get_cross_section_area !> @brief Calculate the hydraulic radius for a reach !! - !! Function to calculate the hydraulic radius for a reach using + !! Function to calculate the hydraulic radius for a reach using !! the cross-section station-height data given a passed depth. !! !! @return r hydraulic radius !< function get_hydraulic_radius(npts, stations, heights, d) result(r) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables integer(I4B) :: n real(DP) :: r real(DP) :: p real(DP) :: a - real(DP), dimension(npts-1) :: areas - real(DP), dimension(npts-1) :: perimeters + real(DP), dimension(npts - 1) :: areas + real(DP), dimension(npts - 1) :: perimeters ! ! -- intitialize the hydraulic radius, perimeter, and area r = DZERO @@ -212,14 +212,14 @@ end function get_hydraulic_radius function get_mannings_section(npts, stations, heights, roughfracs, & roughness, conv_fact, slope, d) result(q) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), dimension(npts), intent(in) :: roughfracs !< cross-section Mannings roughness fraction data - real(DP), intent(in) :: roughness !< base reach roughness - real(DP), intent(in) :: conv_fact !< unit conversion factor - real(DP), intent(in) :: slope !< reach slope - real(DP), intent(in) :: d !< depth to evaluate cross-section + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), dimension(npts), intent(in) :: roughfracs !< cross-section Mannings roughness fraction data + real(DP), intent(in) :: roughness !< base reach roughness + real(DP), intent(in) :: conv_fact !< unit conversion factor + real(DP), intent(in) :: slope !< reach slope + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables integer(I4B) :: n real(DP) :: q @@ -227,8 +227,8 @@ function get_mannings_section(npts, stations, heights, roughfracs, & real(DP) :: r real(DP) :: p real(DP) :: a - real(DP), dimension(npts-1) :: areas - real(DP), dimension(npts-1) :: perimeters + real(DP), dimension(npts - 1) :: areas + real(DP), dimension(npts - 1) :: perimeters ! ! -- intitialize the hydraulic radius, perimeter, and area q = DZERO @@ -272,17 +272,17 @@ end function get_mannings_section !> @brief Calculate the wetted perimeters for each line segment !! !! Subroutine to calculate the wetted perimeter for each line segment - !! that defines the reach using the cross-section station-height + !! that defines the reach using the cross-section station-height !! data given a passed depth. !! !< subroutine get_wetted_perimeters(npts, stations, heights, d, p) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section - real(DP), dimension(npts-1), intent(inout) :: p !< wetted perimeter for each line segment + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section + real(DP), dimension(npts - 1), intent(inout) :: p !< wetted perimeter for each line segment ! -- local variables integer(I4B) :: n real(DP) :: x0 @@ -302,9 +302,9 @@ subroutine get_wetted_perimeters(npts, stations, heights, d, p) ! ! -- initialize station-height data for segment x0 = stations(n) - x1 = stations(n+1) + x1 = stations(n + 1) d0 = heights(n) - d1 = heights(n+1) + d1 = heights(n + 1) ! ! -- get the start and end station position of the wetted segment call get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) @@ -335,17 +335,17 @@ end subroutine get_wetted_perimeters !> @brief Calculate the cross-sectional areas for each line segment !! !! Subroutine to calculate the cross-sectional area for each line segment - !! that defines the reach using the cross-section station-height + !! that defines the reach using the cross-section station-height !! data given a passed depth. !! !< subroutine get_cross_section_areas(npts, stations, heights, d, a) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section - real(DP), dimension(npts-1), intent(inout) :: a !< cross-sectional area for each line segment + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section + real(DP), dimension(npts - 1), intent(inout) :: a !< cross-sectional area for each line segment ! -- local variables integer(I4B) :: n real(DP) :: x0 @@ -364,9 +364,9 @@ subroutine get_cross_section_areas(npts, stations, heights, d, a) ! ! -- initialize station-height data for segment x0 = stations(n) - x1 = stations(n+1) + x1 = stations(n + 1) d0 = heights(n) - d1 = heights(n+1) + d1 = heights(n + 1) ! ! -- get the start and end station position of the wetted segment call get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) @@ -381,7 +381,7 @@ subroutine get_cross_section_areas(npts, stations, heights, d, a) end if ! ! -- add the area below dmax - if (dmax /= dmin .and. d > dmin) then + if (dmax /= dmin .and. d > dmin) then a(n) = a(n) + DHALF * (d - dmin) end if end if @@ -394,17 +394,17 @@ end subroutine get_cross_section_areas !> @brief Calculate the wetted top widths for each line segment !! !! Subroutine to calculate the wetted top width for each line segment - !! that defines the reach using the cross-section station-height + !! that defines the reach using the cross-section station-height !! data given a passed depth. !! !< subroutine get_wetted_topwidths(npts, stations, heights, d, w) ! -- dummy variables - integer(I4B), intent(in) :: npts !< number of station-height data for a reach - real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) - real(DP), dimension(npts), intent(in) :: heights !< cross-section height data - real(DP), intent(in) :: d !< depth to evaluate cross-section - real(DP), dimension(npts-1), intent(inout) :: w !< wetted top widths for each line segment + integer(I4B), intent(in) :: npts !< number of station-height data for a reach + real(DP), dimension(npts), intent(in) :: stations !< cross-section station distances (x-distance) + real(DP), dimension(npts), intent(in) :: heights !< cross-section height data + real(DP), intent(in) :: d !< depth to evaluate cross-section + real(DP), dimension(npts - 1), intent(inout) :: w !< wetted top widths for each line segment ! -- local variables integer(I4B) :: n real(DP) :: x0 @@ -419,9 +419,9 @@ subroutine get_wetted_topwidths(npts, stations, heights, d, w) ! ! -- initialize station-height data for segment x0 = stations(n) - x1 = stations(n+1) + x1 = stations(n + 1) d0 = heights(n) - d1 = heights(n+1) + d1 = heights(n + 1) ! ! -- get the start and end station position of the wetted segment call get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) @@ -434,27 +434,26 @@ subroutine get_wetted_topwidths(npts, stations, heights, d, w) return end subroutine get_wetted_topwidths - - !> @brief Calculate the station values for the wetted portion of the cross-section + !> @brief Calculate the station values for the wetted portion of the cross-section !! - !! Subroutine to calculate the station values that define the extent of the - !! wetted portion of the cross section for a line segment. The left (x0) and - !! right (x1) station positions are altered if the passed depth is less - !! than the maximum line segment depth. If the line segment is dry the left - !! and right station are equal. Otherwise the wetted station values are equal + !! Subroutine to calculate the station values that define the extent of the + !! wetted portion of the cross section for a line segment. The left (x0) and + !! right (x1) station positions are altered if the passed depth is less + !! than the maximum line segment depth. If the line segment is dry the left + !! and right station are equal. Otherwise the wetted station values are equal !! to the full line segment or smaller if the passed depth is less than - !! the maximum line segment depth. + !! the maximum line segment depth. !! !< pure subroutine get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) ! -- dummy variables - real(DP), intent(inout) :: x0 !< left station position - real(DP), intent(inout) :: x1 !< right station position - real(DP), intent(in) :: d0 !< depth at the left station - real(DP), intent(in) :: d1 !< depth at the right station - real(DP), intent(inout) :: dmax !< maximum depth - real(DP), intent(inout) :: dmin !< minimum depth - real(DP), intent(in) :: d !< depth to evaluate cross-section + real(DP), intent(inout) :: x0 !< left station position + real(DP), intent(inout) :: x1 !< right station position + real(DP), intent(in) :: d0 !< depth at the left station + real(DP), intent(in) :: d1 !< depth at the right station + real(DP), intent(inout) :: dmax !< maximum depth + real(DP), intent(inout) :: dmin !< minimum depth + real(DP), intent(in) :: d !< depth to evaluate cross-section ! -- local variables real(DP) :: xlen real(DP) :: dlen @@ -468,12 +467,12 @@ pure subroutine get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) dmin = min(d0, d1) dmax = max(d0, d1) ! - ! -- if d is less than or equal to the minimum value the + ! -- if d is less than or equal to the minimum value the ! station length (xlen) is zero if (d <= dmin) then x1 = x0 - ! -- if d is between dmin and dmax station length is less - ! than d1 - d0 + ! -- if d is between dmin and dmax station length is less + ! than d1 - d0 else if (d < dmax) then xlen = x1 - x0 dlen = d1 - d0 @@ -483,12 +482,12 @@ pure subroutine get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) slope = DZERO end if if (d0 > d1) then - dx = (d - d1) * slope + dx = (d - d1) * slope xt = x1 + dx xt0 = xt xt1 = x1 else - dx = (d - d0) * slope + dx = (d - d0) * slope xt = x0 + dx xt0 = x0 xt1 = xt @@ -501,5 +500,4 @@ pure subroutine get_wetted_station(x0, x1, d0, d1, dmax, dmin, d) return end subroutine get_wetted_station - -end module GwfSfrCrossSectionUtilsModule \ No newline at end of file +end module GwfSfrCrossSectionUtilsModule diff --git a/src/Model/ModelUtilities/UzfCellGroup.f90 b/src/Model/ModelUtilities/UzfCellGroup.f90 index 34fd6aaea50..5e8cc879535 100644 --- a/src/Model/ModelUtilities/UzfCellGroup.f90 +++ b/src/Model/ModelUtilities/UzfCellGroup.f90 @@ -1,8 +1,8 @@ module UzfCellGroupModule - + use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DEM30, DEM20, DEM15, DEM14, DEM12, DEM10, & - DEM9, DEM7, DEM6, DEM5, DEM4, DEM3, DHALF, DONE, & + use ConstantsModule, only: DZERO, DEM30, DEM20, DEM15, DEM14, DEM12, DEM10, & + DEM9, DEM7, DEM6, DEM5, DEM4, DEM3, DHALF, DONE, & DTWO, DTHREE, DEP20 use SmoothingModule use TdisModule, only: ITMUNI, delt, kper @@ -10,7 +10,7 @@ module UzfCellGroupModule implicit none private public :: UzfCellGroupType - + type :: UzfCellGroupType integer(I4B) :: imem_manager real(DP), pointer, dimension(:), contiguous :: thtr => null() @@ -54,43 +54,43 @@ module UzfCellGroupModule integer(I4B), pointer, dimension(:), contiguous :: landflag => null() integer(I4B), pointer, dimension(:), contiguous :: ivertcon => null() contains - procedure :: init - procedure :: setdata - procedure :: sethead - procedure :: setdatauzfarea - procedure :: setdatafinf - procedure :: setdataet - procedure :: setdataetwc - procedure :: setdataetha - procedure :: setwaves - procedure :: wave_shift - procedure :: routewaves - procedure :: uzflow - procedure :: addrech - procedure :: trailwav - procedure :: leadwav - procedure :: advance - procedure :: solve - procedure :: unsat_stor - procedure :: update_wav - procedure :: simgwet - procedure :: caph - procedure :: rate_et_z - procedure :: uzet - procedure :: uz_rise - procedure :: rejfinf - procedure :: gwseep - procedure :: setbelowpet - procedure :: setgwpet - procedure :: dealloc - procedure :: get_water_content_at_depth - procedure :: get_wcnew - end type UzfCellGroupType -! - contains + procedure :: init + procedure :: setdata + procedure :: sethead + procedure :: setdatauzfarea + procedure :: setdatafinf + procedure :: setdataet + procedure :: setdataetwc + procedure :: setdataetha + procedure :: setwaves + procedure :: wave_shift + procedure :: routewaves + procedure :: uzflow + procedure :: addrech + procedure :: trailwav + procedure :: leadwav + procedure :: advance + procedure :: solve + procedure :: unsat_stor + procedure :: update_wav + procedure :: simgwet + procedure :: caph + procedure :: rate_et_z + procedure :: uzet + procedure :: uz_rise + procedure :: rejfinf + procedure :: gwseep + procedure :: setbelowpet + procedure :: setgwpet + procedure :: dealloc + procedure :: get_water_content_at_depth + procedure :: get_wcnew + end type UzfCellGroupType +! +contains ! ! ------------------------------------------------------------------------------ - + subroutine init(this, ncells, nwav, memory_path) ! ****************************************************************************** ! init -- allocate and set uzf object variables @@ -98,15 +98,15 @@ subroutine init(this, ncells, nwav, memory_path) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- modules - use MemoryManagerModule, only: mem_allocate - ! -- dummy - class(UzfCellGroupType) :: this - integer(I4B), intent(in) :: nwav - integer(I4B), intent(in) :: ncells - character(len=*), intent(in), optional :: memory_path - ! -- local - integer(I4B) :: icell + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy + class(UzfCellGroupType) :: this + integer(I4B), intent(in) :: nwav + integer(I4B), intent(in) :: ncells + character(len=*), intent(in), optional :: memory_path + ! -- local + integer(I4B) :: icell ! ------------------------------------------------------------------------------ ! ! -- Use mem_allocate if memory path is passed in, otherwise it's a temp object @@ -150,50 +150,50 @@ subroutine init(this, ncells, nwav, memory_path) call mem_allocate(this%petmax, ncells, 'PETMAX', memory_path) call mem_allocate(this%extdp, ncells, 'EXTDP', memory_path) call mem_allocate(this%extdpuz, ncells, 'EXTDPUZ', memory_path) - call mem_allocate(this%landflag, ncells, 'LANDFLAG', memory_path) + call mem_allocate(this%landflag, ncells, 'LANDFLAG', memory_path) call mem_allocate(this%ivertcon, ncells, 'IVERTCON', memory_path) else this%imem_manager = 0 - allocate(this%uzdpst(nwav, ncells)) - allocate(this%uzthst(nwav, ncells)) - allocate(this%uzflst(nwav, ncells)) - allocate(this%uzspst(nwav, ncells)) - allocate(this%nwavst(ncells)) - allocate(this%thtr(ncells)) - allocate(this%thts(ncells)) - allocate(this%thti(ncells)) - allocate(this%eps(ncells)) - allocate(this%ha(ncells)) - allocate(this%hroot(ncells)) - allocate(this%rootact(ncells)) - allocate(this%extwc(ncells)) - allocate(this%etact(ncells)) - allocate(this%nwav(ncells)) - allocate(this%ntrail(ncells)) - allocate(this%totflux(ncells)) - allocate(this%sinf(ncells)) - allocate(this%finf(ncells)) - allocate(this%finf_rej(ncells)) - allocate(this%gwet(ncells)) - allocate(this%uzfarea(ncells)) - allocate(this%cellarea(ncells)) - allocate(this%celtop(ncells)) - allocate(this%celbot(ncells)) - allocate(this%landtop(ncells)) - allocate(this%watab(ncells)) - allocate(this%watabold(ncells)) - allocate(this%surfdep(ncells)) - allocate(this%vks(ncells)) - allocate(this%surflux(ncells)) - allocate(this%surfluxbelow(ncells)) - allocate(this%surfseep(ncells)) - allocate(this%gwpet(ncells)) - allocate(this%pet(ncells)) - allocate(this%petmax(ncells)) - allocate(this%extdp(ncells)) - allocate(this%extdpuz(ncells)) - allocate(this%landflag(ncells)) - allocate(this%ivertcon(ncells)) + allocate (this%uzdpst(nwav, ncells)) + allocate (this%uzthst(nwav, ncells)) + allocate (this%uzflst(nwav, ncells)) + allocate (this%uzspst(nwav, ncells)) + allocate (this%nwavst(ncells)) + allocate (this%thtr(ncells)) + allocate (this%thts(ncells)) + allocate (this%thti(ncells)) + allocate (this%eps(ncells)) + allocate (this%ha(ncells)) + allocate (this%hroot(ncells)) + allocate (this%rootact(ncells)) + allocate (this%extwc(ncells)) + allocate (this%etact(ncells)) + allocate (this%nwav(ncells)) + allocate (this%ntrail(ncells)) + allocate (this%totflux(ncells)) + allocate (this%sinf(ncells)) + allocate (this%finf(ncells)) + allocate (this%finf_rej(ncells)) + allocate (this%gwet(ncells)) + allocate (this%uzfarea(ncells)) + allocate (this%cellarea(ncells)) + allocate (this%celtop(ncells)) + allocate (this%celbot(ncells)) + allocate (this%landtop(ncells)) + allocate (this%watab(ncells)) + allocate (this%watabold(ncells)) + allocate (this%surfdep(ncells)) + allocate (this%vks(ncells)) + allocate (this%surflux(ncells)) + allocate (this%surfluxbelow(ncells)) + allocate (this%surfseep(ncells)) + allocate (this%gwpet(ncells)) + allocate (this%pet(ncells)) + allocate (this%petmax(ncells)) + allocate (this%extdp(ncells)) + allocate (this%extdpuz(ncells)) + allocate (this%landflag(ncells)) + allocate (this%ivertcon(ncells)) end if do icell = 1, ncells this%uzdpst(:, icell) = DZERO @@ -249,55 +249,55 @@ subroutine dealloc(this) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy - class(UzfCellGroupType) :: this - ! -- local + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy + class(UzfCellGroupType) :: this + ! -- local ! ------------------------------------------------------------------------------ ! ! -- deallocate based on whether or not memory manager was used if (this%imem_manager == 0) then - deallocate(this%uzdpst) - deallocate(this%uzthst) - deallocate(this%uzflst) - deallocate(this%uzspst) - deallocate(this%nwavst) - deallocate(this%thtr) - deallocate(this%thts) - deallocate(this%thti) - deallocate(this%eps) - deallocate(this%ha) - deallocate(this%hroot) - deallocate(this%rootact) - deallocate(this%extwc) - deallocate(this%etact) - deallocate(this%nwav) - deallocate(this%ntrail) - deallocate(this%totflux) - deallocate(this%sinf) - deallocate(this%finf) - deallocate(this%finf_rej) - deallocate(this%gwet) - deallocate(this%uzfarea) - deallocate(this%cellarea) - deallocate(this%celtop) - deallocate(this%celbot) - deallocate(this%landtop) - deallocate(this%watab) - deallocate(this%watabold) - deallocate(this%surfdep) - deallocate(this%vks) - deallocate(this%surflux) - deallocate(this%surfluxbelow) - deallocate(this%surfseep) - deallocate(this%gwpet) - deallocate(this%pet) - deallocate(this%petmax) - deallocate(this%extdp) - deallocate(this%extdpuz) - deallocate(this%landflag) - deallocate(this%ivertcon) + deallocate (this%uzdpst) + deallocate (this%uzthst) + deallocate (this%uzflst) + deallocate (this%uzspst) + deallocate (this%nwavst) + deallocate (this%thtr) + deallocate (this%thts) + deallocate (this%thti) + deallocate (this%eps) + deallocate (this%ha) + deallocate (this%hroot) + deallocate (this%rootact) + deallocate (this%extwc) + deallocate (this%etact) + deallocate (this%nwav) + deallocate (this%ntrail) + deallocate (this%totflux) + deallocate (this%sinf) + deallocate (this%finf) + deallocate (this%finf_rej) + deallocate (this%gwet) + deallocate (this%uzfarea) + deallocate (this%cellarea) + deallocate (this%celtop) + deallocate (this%celbot) + deallocate (this%landtop) + deallocate (this%watab) + deallocate (this%watabold) + deallocate (this%surfdep) + deallocate (this%vks) + deallocate (this%surflux) + deallocate (this%surfluxbelow) + deallocate (this%surfseep) + deallocate (this%gwpet) + deallocate (this%pet) + deallocate (this%petmax) + deallocate (this%extdp) + deallocate (this%extdpuz) + deallocate (this%landflag) + deallocate (this%ivertcon) else call mem_deallocate(this%uzdpst) call mem_deallocate(this%uzthst) @@ -337,15 +337,15 @@ subroutine dealloc(this) call mem_deallocate(this%petmax) call mem_deallocate(this%extdp) call mem_deallocate(this%extdpuz) - call mem_deallocate(this%landflag) - call mem_deallocate(this%ivertcon) + call mem_deallocate(this%landflag) + call mem_deallocate(this%ivertcon) end if ! ! -- return return end subroutine dealloc - subroutine setdata(this, icell, area, top, bot, surfdep, vks, thtr, thts, & + subroutine setdata(this, icell, area, top, bot, surfdep, vks, thtr, thts, & thti, eps, ntrail, landflag, ivertcon) ! ****************************************************************************** ! setdata -- set uzf object material properties @@ -395,7 +395,7 @@ subroutine setdata(this, icell, area, top, bot, surfdep, vks, thtr, thts, & this%ha(icell) = DZERO this%hroot(icell) = DZERO end subroutine setdata - + subroutine sethead(this, icell, hgwf) ! ****************************************************************************** ! sethead -- set uzf object material properties @@ -407,7 +407,7 @@ subroutine sethead(this, icell, hgwf) ! -- dummy class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell - real(DP), intent(in) :: hgwf + real(DP), intent(in) :: hgwf ! ------------------------------------------------------------------------------ ! ! -- set initial head @@ -417,7 +417,7 @@ subroutine sethead(this, icell, hgwf) this%watab(icell) = this%celtop(icell) this%watabold(icell) = this%watab(icell) end subroutine sethead - + subroutine setdatafinf(this, icell, finf) ! ****************************************************************************** ! setdatafinf -- set infiltration @@ -442,7 +442,7 @@ subroutine setdatafinf(this, icell, finf) this%finf_rej(icell) = DZERO this%surflux(icell) = DZERO this%surfluxbelow(icell) = DZERO - end subroutine setdatafinf + end subroutine setdatafinf subroutine setdatauzfarea(this, icell, areamult) ! ****************************************************************************** @@ -463,11 +463,11 @@ subroutine setdatauzfarea(this, icell, areamult) ! ! -- return return - end subroutine setdatauzfarea - + end subroutine setdatauzfarea + ! ------------------------------------------------------------------------------ -! - subroutine setdataet(this, icell, jbelow, pet, extdp) +! + subroutine setdataet(this, icell, jbelow, pet, extdp) ! ****************************************************************************** ! setdataet -- set unsat. et variables ! ****************************************************************************** @@ -494,8 +494,8 @@ subroutine setdataet(this, icell, jbelow, pet, extdp) thick = this%celtop(icell) - this%celbot(icell) this%extdp(icell) = extdp if (this%landflag(icell) > 0) then - this%landtop(icell) = this%celtop(icell) - this%petmax(icell) = this%pet(icell) + this%landtop(icell) = this%celtop(icell) + this%petmax(icell) = this%pet(icell) end if ! ! -- set uz extinction depth @@ -503,7 +503,7 @@ subroutine setdataet(this, icell, jbelow, pet, extdp) this%extdpuz(icell) = thick else this%extdpuz(icell) = this%celtop(icell) - & - (this%landtop(icell) - this%extdp(icell)) + (this%landtop(icell) - this%extdp(icell)) end if if (this%extdpuz(icell) < DZERO) this%extdpuz(icell) = DZERO if (this%extdpuz(icell) > DEM7 .and. this%extdp(icell) < DEM7) & @@ -517,12 +517,12 @@ subroutine setdataet(this, icell, jbelow, pet, extdp) ! ! -- return return - end subroutine setdataet - - subroutine setgwpet(this, icell) + end subroutine setdataet + + subroutine setgwpet(this, icell) ! ****************************************************************************** ! setgwpet -- subtract aet from pet to calculate residual et for gw -! +! ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -534,21 +534,21 @@ subroutine setgwpet(this, icell) integer(I4B), intent(in) :: icell ! -- dummy real(DP) :: pet -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ pet = DZERO ! ! -- reduce pet for gw by uzet pet = this%pet(icell) - this%etact(icell) / delt - if ( pet < DZERO ) pet = DZERO + if (pet < DZERO) pet = DZERO this%gwpet(icell) = pet ! ! -- return return - end subroutine setgwpet - + end subroutine setgwpet + subroutine setbelowpet(this, icell, jbelow) ! ****************************************************************************** -! setbelowpet -- subtract aet from pet to calculate residual et +! setbelowpet -- subtract aet from pet to calculate residual et ! for deeper cells ! ****************************************************************************** ! @@ -562,25 +562,25 @@ subroutine setbelowpet(this, icell, jbelow) integer(I4B), intent(in) :: jbelow ! -- dummy real(DP) :: pet -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ pet = DZERO ! ! -- transfer unmet pet to lower cell ! if (this%extdpuz(jbelow) > DEM3) then - pet = this%pet(icell) - this%etact(icell) / delt - & - this%gwet(icell)/this%uzfarea(icell) - if (pet < DZERO) pet = DZERO + pet = this%pet(icell) - this%etact(icell) / delt - & + this%gwet(icell) / this%uzfarea(icell) + if (pet < DZERO) pet = DZERO end if this%pet(jbelow) = pet ! ! -- return return - end subroutine setbelowpet - + end subroutine setbelowpet + subroutine setdataetwc(this, icell, jbelow, extwc) ! ****************************************************************************** -! setdataetwc -- set extinction water content +! setdataetwc -- set extinction water content ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -599,7 +599,7 @@ subroutine setdataetwc(this, icell, jbelow, extwc) ! -- return return end subroutine setdataetwc - + subroutine setdataetha(this, icell, jbelow, ha, hroot, rootact) ! ****************************************************************************** ! setdataetha -- set variables for head-based unsat. flow @@ -621,16 +621,16 @@ subroutine setdataetha(this, icell, jbelow, ha, hroot, rootact) this%hroot(icell) = hroot this%rootact(icell) = rootact if (jbelow > 0) then - this%ha(jbelow) = ha - this%hroot(jbelow) = hroot - this%rootact(jbelow) = rootact - end if + this%ha(jbelow) = ha + this%hroot(jbelow) = hroot + this%rootact(jbelow) = rootact + end if ! ! -- return return - end subroutine setdataetha - - subroutine advance(this, icell) + end subroutine setdataetha + + subroutine advance(this, icell) ! ****************************************************************************** ! advance -- set variables to advance to new time step. nothing yet. ! ****************************************************************************** @@ -649,12 +649,12 @@ subroutine advance(this, icell) return end subroutine advance - subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & - issflag, iseepflag, hgwf, qfrommvr, ierr, & + subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & + issflag, iseepflag, hgwf, qfrommvr, ierr, & reset_state, trhs, thcof, deriv, watercontent) ! ****************************************************************************** -! formulate -- formulate the unsaturated flow object, calculate terms for -! gwf equation +! formulate -- formulate the unsaturated flow object, calculate terms for +! gwf equation ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -663,18 +663,18 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & use TdisModule, only: delt ! -- dummy class(UzfCellGroupType) :: this - type(UzfCellGroupType) :: thiswork !< work object for resetting wave state - integer(I4B), intent(in) :: jbelow !< number of underlying uzf object or 0 if none - integer(I4B), intent(in) :: icell !< number of this uzf object - real(DP), intent(inout) :: totfluxtot !< - integer(I4B), intent(in) :: ietflag !< et is off (0) or based one water content (1) or pressure (2) - integer(I4B), intent(in) :: issflag !< steady state flag - integer(I4B), intent(in) :: iseepflag !< discharge to land is active (1) or not (0) - real(DP), intent(in) :: hgwf !< head for cell icell - real(DP), intent(in) :: qfrommvr !< water inflow from mover - integer(I4B), intent(inout) :: ierr !< flag indicating not enough waves - logical, intent(in) :: reset_state !< flag indicating that waves should be reset after solution - real(DP), intent(inout), optional :: trhs !< total uzf rhs contribution to GWF model + type(UzfCellGroupType) :: thiswork !< work object for resetting wave state + integer(I4B), intent(in) :: jbelow !< number of underlying uzf object or 0 if none + integer(I4B), intent(in) :: icell !< number of this uzf object + real(DP), intent(inout) :: totfluxtot !< + integer(I4B), intent(in) :: ietflag !< et is off (0) or based one water content (1) or pressure (2) + integer(I4B), intent(in) :: issflag !< steady state flag + integer(I4B), intent(in) :: iseepflag !< discharge to land is active (1) or not (0) + real(DP), intent(in) :: hgwf !< head for cell icell + real(DP), intent(in) :: qfrommvr !< water inflow from mover + integer(I4B), intent(inout) :: ierr !< flag indicating not enough waves + logical, intent(in) :: reset_state !< flag indicating that waves should be reset after solution + real(DP), intent(inout), optional :: trhs !< total uzf rhs contribution to GWF model real(DP), intent(inout), optional :: thcof !< total uzf hcof contribution to GWF model real(DP), intent(inout), optional :: deriv !< derivate term for contribution to GWF model real(DP), intent(inout), optional :: watercontent !< calculated water content @@ -699,7 +699,7 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & trhsseep = DZERO thcofseep = DZERO this%finf_rej(icell) = DZERO - this%surflux(icell) = this%finf(icell) + qfrommvr / this%uzfarea(icell) + this%surflux(icell) = this%finf(icell) + qfrommvr / this%uzfarea(icell) this%watab(icell) = hgwf this%surfseep(icell) = DZERO seep = DZERO @@ -708,9 +708,9 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & this%surfluxbelow(icell) = DZERO if (this%ivertcon(icell) > 0) then this%finf(jbelow) = DZERO - if (this%watab(icell) < this%celbot(icell)) & - this%watab(icell) = this%celbot(icell) end if + if (this%watab(icell) < this%celbot(icell)) & + this%watab(icell) = this%celbot(icell) ! ! -- initialize derivative variables deriv1 = DZERO @@ -721,7 +721,7 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & if (reset_state) then call thiswork%wave_shift(this, 1, icell, 0, 1, this%nwavst(icell), 1) end if - + if (this%watab(icell) > this%celtop(icell)) & this%watab(icell) = this%celtop(icell) ! @@ -730,20 +730,20 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & this%surflux(icell) = this%vks(icell) end if ! - ! -- saturation excess rejected infiltration + ! -- saturation excess rejected infiltration if (this%landflag(icell) == 1) then call this%rejfinf(icell, deriv1, hgwf, trhsfinf, thcoffinf, finfact) this%surflux(icell) = finfact end if ! ! -- calculate rejected infiltration - this%finf_rej(icell) = this%finf(icell) + & - (qfrommvr / this%uzfarea(icell)) - this%surflux(icell) + this%finf_rej(icell) = this%finf(icell) + & + (qfrommvr / this%uzfarea(icell)) - this%surflux(icell) ! ! -- calculate groundwater discharge if (iseepflag > 0 .and. this%landflag(icell) == 1) then call this%gwseep(icell, deriv2, scale, hgwf, trhsseep, thcofseep, seep) - this%surfseep(icell) = seep + this%surfseep(icell) = seep end if ! ! -- route water through unsat zone, calc. storage change and recharge @@ -751,13 +751,13 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & if (this%watabold(icell) - test < -DEM15) test = this%watabold(icell) if (this%celtop(icell) - test > DEM15) then if (issflag == 0) then - call this%routewaves(totfluxtot, delt, ietflag, icell, ierr) + call this%routewaves(totfluxtot, delt, ietflag, icell, ierr) if (ierr > 0) return call this%uz_rise(icell, totfluxtot) this%totflux(icell) = totfluxtot if (this%ivertcon(icell) > 0) then call this%addrech(icell, jbelow, hgwf, trhsfinf, thcoffinf, & - derivfinf, delt) + derivfinf, delt) end if else this%totflux(icell) = this%surflux(icell) * delt @@ -777,16 +777,16 @@ subroutine solve(this, thiswork, jbelow, icell, totfluxtot, ietflag, & end if ! ! -- If formulating, then these variables will be present - if (present(deriv)) deriv = deriv1 + deriv2 + derivfinf - if (present(trhs)) trhs = trhsfinf + trhsseep - if (present(thcof)) thcof = thcoffinf + thcofseep + if (present(deriv)) deriv = deriv1 + deriv2 + derivfinf + if (present(trhs)) trhs = trhsfinf + trhsseep + if (present(thcof)) thcof = thcoffinf + thcofseep ! ! -- Assign water content prior to resetting waves if (present(watercontent)) then watercontent = this%get_wcnew(icell) end if ! - ! -- reset waves to previous state for next iteration + ! -- reset waves to previous state for next iteration if (reset_state) then call this%wave_shift(thiswork, icell, 1, 0, 1, thiswork%nwavst(1), 1) end if @@ -814,7 +814,7 @@ subroutine addrech(this, icell, jbelow, hgwf, trhs, thcof, deriv, delt) ! -- local real(DP) :: fcheck real(DP) :: x, scale, range -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! ! -- initialize range = DEM5 @@ -824,11 +824,11 @@ subroutine addrech(this, icell, jbelow, hgwf, trhs, thcof, deriv, delt) if (this%totflux(icell) < DEM14) return scale = DONE ! - ! -- smoothly reduce flow between cells when head close to cell top - x = hgwf - (this%celbot(icell) - range) + ! -- smoothly reduce flow between cells when head close to cell top + x = hgwf - (this%celbot(icell) - range) call sSCurve(x, range, deriv, scale) deriv = this%uzfarea(icell) * deriv * this%totflux(icell) / delt - this%finf(jbelow) = (DONE - scale) * this%totflux(icell) / delt + this%finf(jbelow) = (DONE - scale) * this%totflux(icell) / delt fcheck = this%finf(jbelow) - this%vks(jbelow) ! ! -- reduce flow between cells when vks is too small @@ -859,7 +859,7 @@ subroutine rejfinf(this, icell, deriv, hgwf, trhs, thcof, finfact) real(DP), intent(inout) :: trhs real(DP), intent(in) :: hgwf ! -- local - real(DP) :: x, range, scale, q + real(DP) :: x, range, scale, q ! ------------------------------------------------------------------------------ range = this%surfdep(icell) q = this%surflux(icell) @@ -877,7 +877,7 @@ subroutine rejfinf(this, icell, deriv, hgwf, trhs, thcof, finfact) ! -- return return end subroutine rejfinf - + subroutine gwseep(this, icell, deriv, scale, hgwf, trhs, thcof, seep) ! ****************************************************************************** ! gwseep -- calc. groudwater discharge to land surface @@ -944,7 +944,7 @@ subroutine simgwet(this, igwetflag, icell, hgwf, trhs, thcof, det) real(DP), intent(inout) :: det ! -- local real(DP) :: s, x, c, b, et -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! this%gwet(icell) = DZERO trhs = DZERO @@ -954,18 +954,18 @@ subroutine simgwet(this, igwetflag, icell, hgwf, trhs, thcof, det) x = this%extdp(icell) c = this%gwpet(icell) b = this%celbot(icell) - if ( b > hgwf ) return + if (b > hgwf) return if (x < DEM6) return if (igwetflag == 1) then et = etfunc_lin(s, x, c, det, trhs, thcof, hgwf, & - this%celtop(icell), this%celbot(icell)) + this%celtop(icell), this%celbot(icell)) else if (igwetflag == 2) then et = etfunc_nlin(s, x, c, det, trhs, thcof, hgwf) end if ! this%gwet(icell) = et * this%uzfarea(icell) - trhs = trhs * this%uzfarea(icell) + trhs = trhs * this%uzfarea(icell) thcof = thcof * this%uzfarea(icell) - this%gwet(icell) = trhs - (thcof * hgwf) + this%gwet(icell) = trhs - (thcof * hgwf) ! write(99,*)'in group', icell, this%gwet(icell) ! ! -- return @@ -979,7 +979,7 @@ function etfunc_lin(s, x, c, det, trhs, thcof, hgwf, celtop, celbot) ! ****************************************************************************** ! ! SPECIFICATIONS: -! ------------------------------------------------------------------------------ +! ------------------------------------------------------------------------------ ! -- modules ! -- return real(DP) :: etfunc_lin @@ -1000,7 +1000,7 @@ function etfunc_lin(s, x, c, det, trhs, thcof, hgwf, celtop, celbot) ! ------------------------------------------------------------------------------ ! ! -- Between ET surface and extinction depth - if (hgwf > (s-x) .and. hgwf < s) THEN + if (hgwf > (s - x) .and. hgwf < s) THEN etgw = (c * (hgwf - (s - x)) / x) if (etgw > c) then etgw = c @@ -1009,13 +1009,13 @@ function etfunc_lin(s, x, c, det, trhs, thcof, hgwf, celtop, celbot) thcof = -c / x etgw = trhs - (thcof * hgwf) end if - ! - ! -- Above land surface - else if (hgwf >= s) then + ! + ! -- Above land surface + else if (hgwf >= s) then trhs = c etgw = c - ! - ! Below extinction depth + ! + ! Below extinction depth else etgw = DZERO end if @@ -1030,13 +1030,12 @@ function etfunc_lin(s, x, c, det, trhs, thcof, hgwf, celtop, celbot) trhs = scale * trhs thcof = scale * thcof etgw = trhs - (thcof * hgwf) - det = -det * etgw + det = -det * etgw etfunc_lin = etgw ! ! -- return return end function etfunc_lin - function etfunc_nlin(s, x, c, det, trhs, thcof, hgwf) ! ****************************************************************************** @@ -1135,7 +1134,7 @@ subroutine setwaves(this, icell) if (top < DZERO) top = DZERO bottom = this%thts(icell) - this%thtr(icell) if (bottom < DZERO) bottom = DZERO - this%uzflst(1, icell) = this%vks(icell) * (top / bottom) ** this%eps(icell) + this%uzflst(1, icell) = this%vks(icell) * (top / bottom)**this%eps(icell) if (this%uzthst(1, icell) < this%thtr(icell)) & this%uzthst(1, icell) = this%thtr(icell) ! @@ -1158,7 +1157,7 @@ subroutine setwaves(this, icell) ! -- return return end subroutine - + subroutine routewaves(this, totfluxtot, delt, ietflag, icell, ierr) ! ****************************************************************************** ! routewaves -- prepare and route waves over time step @@ -1197,8 +1196,8 @@ subroutine routewaves(this, totfluxtot, delt, ietflag, icell, ierr) end if idelt = 1 do ik = 1, idelt - call this%uzflow(thick, thickold, delt, ietflag, icell, ierr) - if (ierr > 0) return + call this%uzflow(thick, thickold, delt, ietflag, icell, ierr) + if (ierr > 0) return totfluxtot = totfluxtot + this%totflux(icell) end do ! @@ -1214,8 +1213,8 @@ subroutine wave_shift(this, this2, icell, icell2, shft, strt, stp, cntr) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class (UzfCellGroupType) :: this - type (UzfCellGroupType) :: this2 + class(UzfCellGroupType) :: this + type(UzfCellGroupType) :: this2 integer(I4B), intent(in) :: icell integer(I4B), intent(in) :: icell2 integer(I4B), intent(in) :: shft @@ -1238,7 +1237,7 @@ subroutine wave_shift(this, this2, icell, icell2, shft, strt, stp, cntr) ! -- return return end subroutine - + subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) ! ****************************************************************************** ! uzflow -- moc solution for kinematic wave equation @@ -1247,7 +1246,7 @@ subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this real(DP), intent(inout) :: thickold real(DP), intent(inout) :: thick real(DP), intent(in) :: delt @@ -1260,7 +1259,7 @@ subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) integer(I4B) :: itrailflg, itester ! ------------------------------------------------------------------------------ time = DZERO - this%totflux(icell) = DZERO + this%totflux(icell) = DZERO itrailflg = 0 oldsflx = this%uzflst(this%nwavst(icell), icell) call factors(feps1, feps2) @@ -1269,12 +1268,13 @@ subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) if ((thick - thickold) > feps1) then thetadif = abs(this%uzthst(1, icell) - this%thtr(icell)) if (thetadif > DEM6) then - call this%wave_shift(this, icell, icell, -1, this%nwavst(icell) + 1, 2, -1) + call this%wave_shift(this, icell, icell, -1, & + this%nwavst(icell) + 1, 2, -1) if (this%uzdpst(2, icell) < DEM30) & this%uzdpst(2, icell) = (this%ntrail(icell) + DTWO) * DEM6 if (this%uzthst(2, icell) > this%thtr(icell)) then this%uzspst(2, icell) = this%uzflst(2, icell) / & - (this%uzthst(2, icell) - this%thtr(icell)) + (this%uzthst(2, icell) - this%thtr(icell)) else this%uzspst(2, icell) = DZERO end if @@ -1296,7 +1296,7 @@ subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) fluxb = this%uzflst(1, icell) this%totflux(icell) = DZERO itester = 0 - ffcheck = (this%surflux(icell)-this%uzflst(this%nwavst(icell), icell)) + ffcheck = (this%surflux(icell) - this%uzflst(this%nwavst(icell), icell)) ! ! -- increase new waves in infiltration changes if (ffcheck > feps2 .OR. ffcheck < -feps2) then @@ -1316,12 +1316,12 @@ subroutine uzflow(this, thick, thickold, delt, ietflag, icell, ierr) if (ierr > 0) return itrailflg = 1 end if - call this%leadwav(time, itester, itrailflg, thetab, fluxb, ffcheck, & + call this%leadwav(time, itester, itrailflg, thetab, fluxb, ffcheck, & feps2, delt, icell) end if if (itester == 1) then this%totflux(icell) = this%totflux(icell) + & - (delt - time) * this%uzflst(1, icell) + (delt - time) * this%uzflst(1, icell) time = DZERO itester = 0 end if @@ -1359,10 +1359,10 @@ subroutine factors(feps1, feps2) else if (ITMUNI == 2) then factor1 = DONE / 1440.D0 else if (ITMUNI == 3) then - factor1 = DONE / 24.0D0 + factor1 = DONE / 24.0D0 else if (ITMUNI == 5) then factor1 = 365.0D0 - end if + end if factor2 = DONE / 0.3048 feps1 = feps1 * factor1 * factor2 feps2 = feps2 * factor1 * factor2 @@ -1380,7 +1380,7 @@ subroutine trailwav(this, icell, ierr) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell integer(I4B), intent(inout) :: ierr ! -- local @@ -1397,9 +1397,9 @@ subroutine trailwav(this, icell, ierr) nwavstm1 = this%nwavst(icell) - 1 ! ! -- initialize trailwaves - smoist = (((this%surflux(icell) / this%vks(icell)) ** & - (DONE / this%eps(icell))) * & - (this%thts(icell) - this%thtr(icell))) + this%thtr(icell) + smoist = (((this%surflux(icell) / this%vks(icell))** & + (DONE / this%eps(icell))) * & + (this%thts(icell) - this%thtr(icell))) + this%thtr(icell) if (this%uzthst(nwavstm1, icell) - smoist > DEM9) then fnuminc = DZERO do jk = 1, this%ntrail(icell) @@ -1415,27 +1415,28 @@ subroutine trailwav(this, icell, ierr) return end if if (j > this%nwavst(icell)) then - this%uzthst(j, icell) = this%uzthst(j - 1, icell) & - - ((ftrail - float(jj)) * smoistinc) + this%uzthst(j, icell) = this%uzthst(j - 1, icell) & + - ((ftrail - float(jj)) * smoistinc) else this%uzthst(j, icell) = this%uzthst(j - 1, icell) - DEM9 end if jj = jj - 1 if (this%uzthst(j, icell) <= this%thtr(icell) + DEM9) & this%uzthst(j, icell) = this%thtr(icell) + DEM9 - this%uzflst(j, icell) = this%vks(icell) * & - (((this%uzthst(j, icell) - this%thtr(icell)) * thtsrinv) ** & - this%eps(icell)) + this%uzflst(j, icell) = & + this%vks(icell) * (((this%uzthst(j, icell) - this%thtr(icell)) * & + thtsrinv)**this%eps(icell)) theta2 = this%uzthst(j - 1, icell) flux2 = this%uzflst(j - 1, icell) flux1 = this%uzflst(j, icell) theta1 = this%uzthst(j, icell) - this%uzspst(j, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(j, icell) = leadspeed(theta1, theta2, flux1, flux2, & + this%thts(icell), this%thtr(icell), & + this%eps(icell), this%vks(icell)) this%uzdpst(j, icell) = DZERO if (j == this%nwavst(icell)) then - this%uzdpst(j, icell) = this%uzdpst(j, icell) + (this%ntrail(icell) + 1) * DEM9 + this%uzdpst(j, icell) = this%uzdpst(j, icell) + & + (this%ntrail(icell) + 1) * DEM9 else this%uzdpst(j, icell) = this%uzdpst(j - 1, icell) - DEM9 end if @@ -1448,24 +1449,24 @@ subroutine trailwav(this, icell, ierr) end if else this%uzdpst(this%nwavst, icell) = DZERO - this%uzflst(this%nwavst, icell) = this%vks(icell) * & - (((this%uzthst(this%nwavst, icell) - this%thtr(icell)) * & - thtsrinv) ** this%eps(icell)) + this%uzflst(this%nwavst, icell) = & + this%vks(icell) * (((this%uzthst(this%nwavst, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) this%uzthst(this%nwavst, icell) = smoist theta2 = this%uzthst(this%nwavst(icell) - 1, icell) flux2 = this%uzflst(this%nwavst(icell) - 1, icell) flux1 = this%uzflst(this%nwavst(icell), icell) theta1 = this%uzthst(this%nwavst(icell), icell) - this%uzspst(this%nwavst(icell), icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(this%nwavst(icell), icell) = & + leadspeed(theta1, theta2, flux1, flux2, this%thts(icell), & + this%thtr(icell), this%eps(icell), this%vks(icell)) end if ! ! -- return return end subroutine trailwav - subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & + subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & ffcheck, feps2, delt, icell) ! ****************************************************************************** ! leadwav----create a lead wave and route over time step @@ -1475,7 +1476,7 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this real(DP), intent(inout) :: thetab real(DP), intent(inout) :: fluxb real(DP), intent(in) :: feps2 @@ -1495,8 +1496,8 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & integer(I4B) :: nwavp1, jshort integer(I4B), allocatable, dimension(:) :: more ! ------------------------------------------------------------------------------ - allocate(checktime(this%nwavst(icell))) - allocate(more(this%nwavst(icell))) + allocate (checktime(this%nwavst(icell))) + allocate (more(this%nwavst(icell))) ftest = DZERO eps_m1 = dble(this%eps(icell)) - DONE thtsrinv = DONE / (this%thts(icell) - this%thtr(icell)) @@ -1506,18 +1507,18 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & if (ffcheck > feps2) then this%uzflst(this%nwavst(icell), icell) = this%surflux(icell) if (this%uzflst(this%nwavst(icell), icell) < DEM30) & - this%uzflst(this%nwavst(icell), icell) = DZERO + this%uzflst(this%nwavst(icell), icell) = DZERO this%uzthst(this%nwavst(icell), icell) = & - (((this%uzflst(this%nwavst(icell), icell) / this%vks(icell)) ** & - (DONE / this%eps(icell))) * (this%thts(icell) - this%thtr(icell))) & - + this%thtr(icell) + (((this%uzflst(this%nwavst(icell), icell) / this%vks(icell))** & + (DONE / this%eps(icell))) * (this%thts(icell) - this%thtr(icell))) & + + this%thtr(icell) theta2 = this%uzthst(this%nwavst(icell), icell) flux2 = this%uzflst(this%nwavst(icell), icell) flux1 = this%uzflst(this%nwavst(icell) - 1, icell) theta1 = this%uzthst(this%nwavst(icell) - 1, icell) - this%uzspst(this%nwavst(icell), icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(this%nwavst(icell), icell) = & + leadspeed(theta1, theta2, flux1, flux2, this%thts(icell), & + this%thtr(icell), this%eps(icell), this%vks(icell)) this%uzdpst(this%nwavst(icell), icell) = DZERO end if end if @@ -1545,7 +1546,8 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & do while (j < nwavp1) ftest = this%uzspst(j - 1, icell) - this%uzspst(j, icell) if (abs(ftest) > DEM30) then - checktime(j) = (this%uzdpst(j, icell) - this%uzdpst(j - 1, icell)) / ftest + checktime(j) = (this%uzdpst(j, icell) - & + this%uzdpst(j - 1, icell)) / ftest if (checktime(j) < DEM30) checktime(j) = DEP20 end if j = j + 1 @@ -1574,7 +1576,7 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & end do do j = 3, this%nwavst(icell) if (shortest - checktime(j) < DEM9) then - if (j /= jshort) more(j) = 0 + if (j /= jshort) more(j) = 0 end if end do ! @@ -1588,14 +1590,15 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & do while (j < nwavp1) ! ! -- route waves - this%uzdpst(j, icell) = this%uzdpst(j, icell) + & - this%uzspst(j, icell) * bottomtime + this%uzdpst(j, icell) = this%uzdpst(j, icell) + & + this%uzspst(j, icell) * bottomtime j = j + 1 end do fluxb = this%uzflst(2, icell) thetab = this%uzthst(2, icell) iflx = 1 - call this%wave_shift(this, icell, icell, 1, 1, this%nwavst(icell) - 1, 1) + call this%wave_shift(this, icell, icell, 1, 1, & + this%nwavst(icell) - 1, 1) iremove = 1 timenew = time + bottomtime this%uzspst(1, icell) = DZERO @@ -1604,15 +1607,15 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & else if (fcheck < DZERO .AND. this%nwavst(icell) > 2) then j = 2 do while (j < nwavp1) - this%uzdpst(j, icell) = this%uzdpst(j, icell) + & - this%uzspst(j, icell) * shortest + this%uzdpst(j, icell) = this%uzdpst(j, icell) + & + this%uzspst(j, icell) * shortest j = j + 1 end do ! ! -- combine waves that intercept, remove a wave j = 3 l = j - do while (j < this%nwavst(icell) + 1) + do while (j < this%nwavst(icell) + 1) if (more(j) == 1) then l = j theta2 = this%uzthst(j, icell) @@ -1624,12 +1627,14 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & flux1 = this%uzflst(j - 2, icell) theta1 = this%uzthst(j - 2, icell) end if - this%uzspst(j, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(j, icell) = leadspeed(theta1, theta2, flux1, flux2, & + this%thts(icell), & + this%thtr(icell), & + this%eps(icell), this%vks(icell)) ! ! -- update waves - call this%wave_shift(this, icell, icell, 1, l - 1, this%nwavst(icell) - 1, 1) + call this%wave_shift(this, icell, icell, 1, l - 1, & + this%nwavst(icell) - 1, 1) l = this%nwavst(icell) + 1 iremove = iremove + 1 end if @@ -1641,8 +1646,8 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & else j = 2 do while (j < nwavp1) - this%uzdpst(j, icell) = this%uzdpst(j, icell) + & - this%uzspst(j, icell) * timedt + this%uzdpst(j, icell) = this%uzdpst(j, icell) + & + this%uzspst(j, icell) * timedt j = j + 1 end do timenew = delt @@ -1654,7 +1659,7 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & end if ! ! -- remove dead waves - this%nwavst(icell) = this%nwavst(icell) - iremove + this%nwavst(icell) = this%nwavst(icell) - iremove time = timenew diff = delt - Time if (this%nwavst(icell) == 1) then @@ -1663,8 +1668,8 @@ subroutine leadwav(this, time, itester, itrailflg, thetab, fluxb, & end if end do end if - deallocate(checktime) - deallocate(more) + deallocate (checktime) + deallocate (more) ! ! -- return return @@ -1702,11 +1707,11 @@ function leadspeed(theta1, theta2, flux1, flux2, thts, thtr, eps, vks) comp3 = theta1 - thtr if (comp2 < DEM15) flux2 = flux1 + DEM15 if (abs(comp1) < DEM30) then - if (comp3 > DEM30) fhold = (comp3 * thsrinv) ** eps + if (comp3 > DEM30) fhold = (comp3 * thsrinv)**eps if (fhold < DEM30) fhold = DEM30 - leadspeed = epsfksths * (fhold ** eps_m1) + leadspeed = epsfksths * (fhold**eps_m1) else - leadspeed = (flux2 - flux1) / (theta2 - theta1) + leadspeed = (flux2 - flux1) / (theta2 - theta1) end if if (leadspeed < DEM30) leadspeed = DEM30 ! @@ -1725,7 +1730,7 @@ function unsat_stor(this, icell, d1) ! -- return real(DP) :: unsat_stor ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell real(DP), intent(inout) :: d1 ! -- local @@ -1741,22 +1746,22 @@ function unsat_stor(this, icell, d1) ! -- find deepest wave above depth d1, counter held as j do while (k > 0) if (this%uzdpst(k, icell) - d1 < -DEM30) j = k - k = k - 1 + k = k - 1 end do if (j > this%nwavst(icell)) then fm = fm + (this%uzthst(this%nwavst(icell), icell) - this%thtr(icell)) * d1 elseif (this%nwavst(icell) > 1) then if (j > 1) then fm = fm + (this%uzthst(j - 1, icell) - this%thtr(icell)) & - * (d1 - this%uzdpst(j, icell)) + * (d1 - this%uzdpst(j, icell)) end if do jj = j, nwavm1 fm = fm + (this%uzthst(jj, icell) - this%thtr(icell)) & - * (this%uzdpst(jj, icell) & - - this%uzdpst(jj + 1, icell)) + * (this%uzdpst(jj, icell) & + - this%uzdpst(jj + 1, icell)) end do fm = fm + (this%uzthst(this%nwavst(icell), icell) - this%thtr(icell)) & - * (this%uzdpst(this%nwavst(icell), icell)) + * (this%uzdpst(this%nwavst(icell), icell)) else fm = fm + (this%uzthst(1, icell) - this%thtr(icell)) * d1 end if @@ -1772,7 +1777,7 @@ subroutine update_wav(this, icell, delt, iss, itest) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell integer(I4B), intent(in) :: itest integer(I4B), intent(in) :: iss @@ -1786,29 +1791,30 @@ subroutine update_wav(this, icell, delt, iss, itest) bot = this%watab(icell) top = this%celtop(icell) thick = top - bot - nwavhld = this%nwavst(icell) + nwavhld = this%nwavst(icell) if (itest == 1) then this%uzflst(1, icell) = DZERO this%uzthst(1, icell) = this%thtr(icell) return end if - if (iss == 1) then + if (iss == 1) then if (this%thts(icell) - this%thtr(icell) < DEM7) then thtsrinv = DONE / DEM7 else - thtsrinv = DONE / (this%thts(icell) - this%thtr(icell)) + thtsrinv = DONE / (this%thts(icell) - this%thtr(icell)) end if this%totflux(icell) = this%surflux(icell) * delt this%watabold(icell) = this%watab(icell) this%uzthst(1, icell) = this%thti(icell) - this%uzflst(1, icell) = this%vks(icell) * (((this%uzthst(1, icell) - this%thtr(icell)) & - * thtsrinv) ** this%eps(icell)) + this%uzflst(1, icell) = & + this%vks(icell) * (((this%uzthst(1, icell) - this%thtr(icell)) & + * thtsrinv)**this%eps(icell)) this%uzdpst(1, icell) = thick this%uzspst(1, icell) = thick this%nwavst(icell) = 1 else ! - ! -- water table rises through waves + ! -- water table rises through waves if (this%watab(icell) - this%watabold(icell) > DEM30) then depthsave = this%uzdpst(1, icell) j = 0 @@ -1818,21 +1824,22 @@ subroutine update_wav(this, icell, delt, iss, itest) k = k - 1 end do this%uzdpst(1, icell) = thick - if (j > 1) then + if (j > 1) then this%uzspst(1, icell) = DZERO this%nwavst(icell) = this%nwavst(icell) - j + 2 this%uzthst(1, icell) = this%uzthst(j - 1, icell) this%uzflst(1, icell) = this%uzflst(j - 1, icell) - if (j > 2) call this%wave_shift(this, icell, icell, j-2, 2, nwavhld - (j - 2), 1) + if (j > 2) call this%wave_shift(this, icell, icell, j - 2, 2, & + nwavhld - (j - 2), 1) elseif (j == 0) then this%uzspst(1, icell) = DZERO this%uzthst(1, icell) = this%uzthst(this%nwavst(icell), icell) - this%uzflst(1, icell) = this%uzflst(this%nwavst(icell), icell) + this%uzflst(1, icell) = this%uzflst(this%nwavst(icell), icell) this%nwavst(icell) = 1 end if - end if + end if ! - ! -- calculate new unsat. storage + ! -- calculate new unsat. storage if (thick <= DZERO) then this%uzspst(1, icell) = DZERO this%nwavst(icell) = 1 @@ -1842,7 +1849,7 @@ subroutine update_wav(this, icell, delt, iss, itest) this%watabold(icell) = this%watab(icell) end if end subroutine update_wav - + subroutine uzet(this, icell, delt, ietflag, ierr) ! ****************************************************************************** ! uzet -- remove water from uz due to et @@ -1852,7 +1859,7 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell real(DP), intent(in) :: delt integer(I4B), intent(in) :: ietflag @@ -1892,7 +1899,8 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! -- initialize this%etact(icell) = DZERO if (this%extdpuz(icell) < DEM7) return - petsub = this%rootact(icell) * this%pet(icell) * this%extdpuz(icell) / this%extdp(icell) + petsub = this%rootact(icell) * this%pet(icell) * & + this%extdpuz(icell) / this%extdp(icell) thetaout = delt * petsub / this%extdp(icell) if (ietflag == 1) thetaout = delt * this%pet(icell) / this%extdp(icell) if (thetaout < DEM10) return @@ -1912,7 +1920,7 @@ subroutine uzet(this, icell, delt, ietflag, ierr) if (this%thts(icell) - this%thtr(icell) < DEM7) then thtsrinv = 1.0 / DEM7 else - thtsrinv = DONE / (this%thts(icell) - this%thtr(icell)) + thtsrinv = DONE / (this%thts(icell) - this%thtr(icell)) end if epsfksthts = this%eps(icell) * this%vks(icell) * thtsrinv this%etact(icell) = DZERO @@ -1926,65 +1934,75 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! -- loop for reducing aet to pet when et is head dependent do while (itest == 0) k = k + 1 - if (k > 1 .AND. ABS(fmp - petsub) > DEM5 * petsub) factor = factor / (fm / petsub) + if (k > 1 .AND. ABS(fmp - petsub) > DEM5 * petsub) then + factor = factor / (fm / petsub) + end if ! ! -- one wave shallower than extdp - if (this%nwavst(icell) == 1 .AND. this%uzdpst(1, icell) <= this%extdpuz(icell)) then + if (this%nwavst(icell) == 1 .AND. & + this%uzdpst(1, icell) <= this%extdpuz(icell)) then if (ietflag == 2) then tho = this%uzthst(1, icell) fktho = this%uzflst(1, icell) hcap = this%caph(icell, tho) thetaout = this%rate_et_z(icell, factor, fktho, hcap) - end if + end if if ((this%uzthst(1, icell) - thetaout) > this%thtr(icell) + extwc1) then this%uzthst(1, icell) = this%uzthst(1, icell) - thetaout - this%uzflst(1, icell) = this%vks(icell) * (((this%uzthst(1, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell)) + this%uzflst(1, icell) = & + this%vks(icell) * (((this%uzthst(1, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) else if (this%uzthst(1, icell) > this%thtr(icell) + extwc1) then this%uzthst(1, icell) = this%thtr(icell) + extwc1 - this%uzflst(1, icell) = this%vks(icell) * (((this%uzthst(1, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell)) + this%uzflst(1, icell) = & + this%vks(icell) * (((this%uzthst(1, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) end if ! ! -- all waves shallower than extinction depth - else if (this%nwavst(icell) > 1 .AND. this%uzdpst(this%nwavst(icell), icell) > this%extdpuz(icell)) then + else if (this%nwavst(icell) > 1 .AND. & + this%uzdpst(this%nwavst(icell), icell) > this%extdpuz(icell)) then if (ietflag == 2) then tho = this%uzthst(this%nwavst(icell), icell) fktho = this%uzflst(this%nwavst(icell), icell) hcap = this%caph(icell, tho) thetaout = this%rate_et_z(icell, factor, fktho, hcap) - end if - if (this%uzthst(this%nwavst(icell), icell) - thetaout > this%thtr(icell) + extwc1) then - this%uzthst(this%nwavst(icell) + 1, icell) = this%uzthst(this%nwavst(icell), icell) - thetaout + end if + if (this%uzthst(this%nwavst(icell), icell) - thetaout > & + this%thtr(icell) + extwc1) then + this%uzthst(this%nwavst(icell) + 1, icell) = & + this%uzthst(this%nwavst(icell), icell) - thetaout numadd = 1 - else if (this%uzthst(this%nwavst(icell), icell) > this%thtr(icell) + extwc1) then + else if (this%uzthst(this%nwavst(icell), icell) > & + this%thtr(icell) + extwc1) then this%uzthst(this%nwavst(icell) + 1, icell) = this%thtr(icell) + extwc1 numadd = 1 end if if (numadd == 1) then - this%uzflst(this%nwavst(icell) + 1, icell) = this%vks(icell) * & - (((this%uzthst(this%nwavst(icell) + 1, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell)) + this%uzflst(this%nwavst(icell) + 1, icell) = & + this%vks(icell) * & + (((this%uzthst(this%nwavst(icell) + 1, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) theta2 = this%uzthst(this%nwavst(icell) + 1, icell) flux2 = this%uzflst(this%nwavst(icell) + 1, icell) flux1 = this%uzflst(this%nwavst(icell), icell) theta1 = this%uzthst(this%nwavst(icell), icell) - this%uzspst(this%nwavst(icell) + 1, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(this%nwavst(icell) + 1, icell) = & + leadspeed(theta1, theta2, flux1, flux2, this%thts(icell), & + this%thtr(icell), this%eps(icell), this%vks(icell)) this%uzdpst(this%nwavst(icell) + 1, icell) = this%extdpuz(icell) this%nwavst(icell) = this%nwavst(icell) + 1 if (this%nwavst(icell) > this%nwav(icell)) then - ! - ! -- too many waves error, deallocate temp arrays and return + ! + ! -- too many waves error, deallocate temp arrays and return ierr = 1 goto 500 end if else numadd = 0 end if - ! - ! -- one wave below extinction depth + ! + ! -- one wave below extinction depth else if (this%nwavst(icell) == 1) then if (ietflag == 2) then tho = this%uzthst(1, icell) @@ -1995,16 +2013,17 @@ subroutine uzet(this, icell, delt, ietflag, ierr) if ((this%uzthst(1, icell) - thetaout) > this%thtr(icell) + extwc1) then if (thetaout > DEM30) then this%uzthst(2, icell) = this%uzthst(1, icell) - thetaout - this%uzflst(2, icell) = this%vks(icell) * (((this%uzthst(2, icell) - this%thtr(icell)) * & - thtsrinv) ** this%eps(icell)) + this%uzflst(2, icell) = & + this%vks(icell) * (((this%uzthst(2, icell) - this%thtr(icell)) * & + thtsrinv)**this%eps(icell)) this%uzdpst(2, icell) = this%extdpuz(icell) theta2 = this%uzthst(2, icell) flux2 = this%uzflst(2, icell) flux1 = this%uzflst(1, icell) theta1 = this%uzthst(1, icell) - this%uzspst(2, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(2, icell) = & + leadspeed(theta1, theta2, flux1, flux2, this%thts(icell), & + this%thtr(icell), this%eps(icell), this%vks(icell)) this%nwavst(icell) = this%nwavst(icell) + 1 if (this%nwavst(icell) > this%nwav(icell)) then ! @@ -2016,16 +2035,17 @@ subroutine uzet(this, icell, delt, ietflag, ierr) else if (this%uzthst(1, icell) > this%thtr(icell) + extwc1) then if (thetaout > DEM30) then this%uzthst(2, icell) = this%thtr(icell) + extwc1 - this%uzflst(2, icell) = this%vks(icell) * (((this%uzthst(2, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell)) + this%uzflst(2, icell) = & + this%vks(icell) * (((this%uzthst(2, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) this%uzdpst(2, icell) = this%extdpuz(icell) theta2 = this%uzthst(2, icell) flux2 = this%uzflst(2, icell) flux1 = this%uzflst(1, icell) theta1 = this%uzthst(1, icell) - this%uzspst(2, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(2, icell) = & + leadspeed(theta1, theta2, flux1, flux2, this%thts(icell), & + this%thtr(icell), this%eps(icell), this%vks(icell)) this%nwavst(icell) = this%nwavst(icell) + 1 if (this%nwavst(icell) > this%nwav(icell)) then ! @@ -2056,7 +2076,8 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! ! -- create a wave at extinction depth if (abs(diff) > DEM5) then - call this%wave_shift(this, icell, icell, -1, this%nwavst(icell) + 1, j, -1) + call this%wave_shift(this, icell, icell, -1, & + this%nwavst(icell) + 1, j, -1) this%uzdpst(j, icell) = this%extdpuz(icell) this%nwavst(icell) = this%nwavst(icell) + 1 if (this%nwavst(icell) > this%nwav(icell)) then @@ -2064,7 +2085,7 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! -- too many waves error ierr = 1 goto 500 - end if + end if end if kk = j else @@ -2086,33 +2107,39 @@ subroutine uzet(this, icell, delt, ietflag, ierr) ! ! -- all waves above extinction depth do while (kk <= this%nwavst(icell)) - if (ietflag==2) then + if (ietflag == 2) then tho = this%uzthst(kk, icell) fktho = this%uzflst(kk, icell) hcap = this%caph(icell, tho) thetaout = this%rate_et_z(icell, factor, fktho, hcap) end if if (this%uzthst(kk, icell) > this%thtr(icell) + extwc1) then - if (this%uzthst(kk, icell) - thetaout > this%thtr(icell) + extwc1) then + if (this%uzthst(kk, icell) - thetaout > & + this%thtr(icell) + extwc1) then this%uzthst(kk, icell) = this%uzthst(kk, icell) - thetaout else if (this%uzthst(kk, icell) > this%thtr(icell) + extwc1) then this%uzthst(kk, icell) = this%thtr(icell) + extwc1 end if if (kk == 1) then - this%uzflst(kk, icell) = this%vks(icell) * (((this%uzthst(kk, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell)) + this%uzflst(kk, icell) = & + this%vks(icell) * & + (((this%uzthst(kk, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell)) end if if (kk > 1) then - flux1 = this%vks(icell) * ((this%uzthst(kk - 1, icell) - & - this%thtr(icell)) * thtsrinv) ** this%eps(icell) - flux2 = this%vks(icell) * ((this%uzthst(kk, icell) - this%thtr(icell)) * & - thtsrinv) ** this%eps(icell) + flux1 = & + this%vks(icell) * ((this%uzthst(kk - 1, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell) + flux2 = & + this%vks(icell) * ((this%uzthst(kk, icell) - & + this%thtr(icell)) * thtsrinv)**this%eps(icell) this%uzflst(kk, icell) = flux2 theta2 = this%uzthst(kk, icell) theta1 = this%uzthst(kk - 1, icell) - this%uzspst(kk, icell) = leadspeed(theta1, theta2, flux1, & - flux2, this%thts(icell), this%thtr(icell), this%eps(icell), & - this%vks(icell)) + this%uzspst(kk, icell) = leadspeed(theta1, theta2, flux1, flux2, & + this%thts(icell), & + this%thtr(icell), & + this%eps(icell), this%vks(icell)) end if end if kk = kk + 1 @@ -2123,7 +2150,8 @@ subroutine uzet(this, icell, delt, ietflag, ierr) kj = 1 do while (kj <= this%nwavst(icell) - 1) if (abs(this%uzthst(kj, icell) - this%uzthst(kj + 1, icell)) < DEM6) then - call this%wave_shift(this, icell, icell, 1, kj + 1, this%nwavst(icell) - 1, 1) + call this%wave_shift(this, icell, icell, 1, kj + 1, & + this%nwavst(icell) - 1, 1) kj = kj - 1 this%nwavst(icell) = this%nwavst(icell) - 1 end if @@ -2174,25 +2202,25 @@ function caph(this, icell, tho) ! ------------------------------------------------------------------------------ ! -- modules ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell real(DP), intent(in) :: tho ! -- local - real(DP) :: caph,lambda,star + real(DP) :: caph, lambda, star ! ------------------------------------------------------------------------------ caph = -DEM6 - star = (tho - this%thtr(icell)) / (this%thts(icell) - this%thtr(icell)) + star = (tho - this%thtr(icell)) / (this%thts(icell) - this%thtr(icell)) if (star < DEM15) star = DEM15 - lambda = DTWO / (this%eps(icell) - DTHREE) + lambda = DTWO / (this%eps(icell) - DTHREE) if (star > DEM15) then if (tho - this%thts(icell) < DEM15) then - caph = this%ha(icell) * star ** (-DONE / lambda) + caph = this%ha(icell) * star**(-DONE / lambda) else caph = DZERO end if end if end function caph - + function rate_et_z(this, icell, factor, fktho, h) ! ****************************************************************************** ! rate_et_z---- capillary pressure based uz et @@ -2204,7 +2232,7 @@ function rate_et_z(this, icell, factor, fktho, h) ! -- return real(DP) :: rate_et_z ! -- dummy - class (UzfCellGroupType) :: this + class(UzfCellGroupType) :: this integer(I4B), intent(in) :: icell real(DP), intent(in) :: factor, fktho, h ! -- local @@ -2215,8 +2243,8 @@ end function rate_et_z function get_water_content_at_depth(this, icell, depth) result(theta_at_depth) class(UzfCellGroupType) :: this - integer(I4B), intent(in) :: icell !< uzf cell containing depth - real(DP), intent(in) :: depth !< depth within the cell + integer(I4B), intent(in) :: icell !< uzf cell containing depth + real(DP), intent(in) :: depth !< depth within the cell real(DP) :: theta_at_depth real(DP) :: d1 real(DP) :: d2 @@ -2229,7 +2257,7 @@ function get_water_content_at_depth(this, icell, depth) result(theta_at_depth) f1 = this%unsat_stor(icell, d1) f2 = this%unsat_stor(icell, d2) theta_at_depth = this%thtr(icell) + (f2 - f1) / (d2 - d1) - else + else theta_at_depth = this%thts(icell) end if else @@ -2237,10 +2265,10 @@ function get_water_content_at_depth(this, icell, depth) result(theta_at_depth) end if return end function get_water_content_at_depth - + function get_wcnew(this, icell) result(watercontent) class(UzfCellGroupType) :: this - integer(I4B), intent(in) :: icell !< uzf cell containing depth + integer(I4B), intent(in) :: icell !< uzf cell containing depth ! real(DP) :: watercontent real(DP) :: top @@ -2252,7 +2280,7 @@ function get_wcnew(this, icell) result(watercontent) real(DP) :: d ! hgwf = this%watab(icell) - top = this%celtop(icell) + top = this%celtop(icell) bot = this%celbot(icell) thk = top - max(bot, hgwf) if (thk > DZERO) then @@ -2266,5 +2294,5 @@ function get_wcnew(this, icell) result(watercontent) end if return end function get_wcnew - -end module UzfCellGroupModule \ No newline at end of file + +end module UzfCellGroupModule diff --git a/src/Model/ModelUtilities/Xt3dAlgorithm.f90 b/src/Model/ModelUtilities/Xt3dAlgorithm.f90 index d31a60ec689..19bbb70191e 100644 --- a/src/Model/ModelUtilities/Xt3dAlgorithm.f90 +++ b/src/Model/ModelUtilities/Xt3dAlgorithm.f90 @@ -7,11 +7,11 @@ module Xt3dAlgorithmModule use ConstantsModule, only: DPREC, DONE implicit none - contains - - subroutine qconds(nnbrmx,nnbr0,inbr0,il01,vc0,vn0,dl0,dl0n,ck0, & - nnbr1,inbr1,il10,vc1,vn1,dl1,dl1n,ck1,ar01,ar10, & - vcthresh,allhc0,allhc1,chat01,chati0,chat1j) +contains + + subroutine qconds(nnbrmx, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, & + nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! ****************************************************************************** ! !.....Compute the "conductances" in the normal-flux expression for an @@ -101,40 +101,40 @@ subroutine qconds(nnbrmx,nnbr0,inbr0,il01,vc0,vn0,dl0,dl0n,ck0, & !.....If area ar01 is zero (in which case ar10 is also zero, since ! this can only happen here in the case of Newton), then the ! "conductances" are all zero. - if (ar01.eq.0d0) then + if (ar01 .eq. 0d0) then chat01 = 0d0 - do i=1,nnbrmx - chati0(i) = 0d0 - chat1j(i) = 0d0 - enddo + do i = 1, nnbrmx + chati0(i) = 0d0 + chat1j(i) = 0d0 + end do !.....Else compute "conductances." else !........Compute contributions from cell 0. - call abhats(nnbrmx,nnbr0,inbr0,il01,vc0,vn0,dl0,dl0n,ck0, & - vcthresh,allhc0,ar01,ahat0,bhat0) + call abhats(nnbrmx, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, & + vcthresh, allhc0, ar01, ahat0, bhat0) !........Compute contributions from cell 1. - call abhats(nnbrmx,nnbr1,inbr1,il10,vc1,vn1,dl1,dl1n,ck1, & - vcthresh,allhc1,ar10,ahat1,bhat1) + call abhats(nnbrmx, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, & + vcthresh, allhc1, ar10, ahat1, bhat1) !........Compute "conductances" based on the two flux estimates. denom = (ahat0 + ahat1) if (abs(denom) > DPREC) then - wght1 = ahat0/(ahat0 + ahat1) + wght1 = ahat0 / (ahat0 + ahat1) else wght1 = DONE end if wght0 = 1d0 - wght1 - chat01 = wght1*ahat1 - do i=1,nnbrmx - chati0(i) = wght0*bhat0(i) - chat1j(i) = wght1*bhat1(i) - enddo + chat01 = wght1 * ahat1 + do i = 1, nnbrmx + chati0(i) = wght0 * bhat0(i) + chat1j(i) = wght1 * bhat1(i) + end do end if ! return - end subroutine qconds + end subroutine qconds - subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & - vcthresh,allhc,ar01,ahat,bhat) + subroutine abhats(nnbrmx, nnbr, inbr, il01, vc, vn, dl0, dln, ck, & + vcthresh, allhc, ar01, ahat, bhat) ! ****************************************************************************** !.....Compute "ahat" and "bhat" coefficients for one side of an ! interface. @@ -151,7 +151,7 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & real(DP), dimension(nnbrmx, 3) :: vn real(DP), dimension(nnbrmx) :: dl0 real(DP), dimension(nnbrmx) :: dln - real(DP), dimension(3, 3) :: ck + real(DP), dimension(3, 3) :: ck real(DP) :: vcthresh logical :: allhc real(DP) :: ar01 @@ -160,9 +160,9 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & ! -- local logical :: iscomp real(DP), dimension(nnbrmx, 3) :: vccde - real(DP), dimension(3, 3) :: rmat - real(DP), dimension(3) :: sigma - real(DP), dimension(nnbrmx) :: bd + real(DP), dimension(3, 3) :: rmat + real(DP), dimension(3) :: sigma + real(DP), dimension(nnbrmx) :: bd real(DP), dimension(nnbrmx) :: be real(DP), dimension(nnbrmx) :: betad real(DP), dimension(nnbrmx) :: betae @@ -187,13 +187,13 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & ! coordinates to (c, d, e) coordinates. (If no active ! connection is found that has a non-negligible component ! perpendicular to the primary connection, ilmo=0 is returned.) - call getrot(nnbrmx,nnbr,inbr,vc,il01,rmat,iml0) + call getrot(nnbrmx, nnbr, inbr, vc, il01, rmat, iml0) ! !.....If no active connection with a non-negligible perpendicular ! component, assume no perpendicular gradient and base gradient ! solely on the primary connection. Otherwise, proceed with ! basing weights on information from neighboring connections. - if (iml0.eq.0) then + if (iml0 .eq. 0) then ! !........Compute ahat and bhat coefficients assuming perpendicular ! components of gradient are zero. @@ -206,11 +206,11 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & !........Transform local connection unit-vectors from model coordinates ! to "(c, d, e)" coordinates associated with the connection ! between cells 0 and 1. - call tranvc(nnbrmx,nnbr,rmat,vc,vccde) + call tranvc(nnbrmx, nnbr, rmat, vc, vccde) ! !........Get "a" and "b" weights for first perpendicular direction. - call abwts(nnbrmx,nnbr,inbr,il01,2,vccde, & - vcthresh,dl0,dln,acd,add,aed,bd) + call abwts(nnbrmx, nnbr, inbr, il01, 2, vccde, & + vcthresh, dl0, dln, acd, add, aed, bd) ! !........If all neighboring connections are user-designated as ! horizontal, or if none have a non-negligible component in @@ -234,8 +234,8 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & end if end do if (iscomp) then - call abwts(nnbrmx,nnbr,inbr,il01,3,vccde, & - vcthresh,dl0,dln,ace,aee,ade,be) + call abwts(nnbrmx, nnbr, inbr, il01, 3, vccde, & + vcthresh, dl0, dln, ace, aee, ade, be) else ace = 0d0 aee = 1d0 @@ -245,36 +245,36 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & end if ! !........Compute alpha and beta coefficients. - determ = add * aee - ade * aed - oodet = 1d0 / determ - alphad = (acd * aee - ace * aed) * oodet - alphae = (ace * add - acd * ade) * oodet - betad = 0d0 - betae = 0d0 - do il = 1, nnbr + determ = add * aee - ade * aed + oodet = 1d0 / determ + alphad = (acd * aee - ace * aed) * oodet + alphae = (ace * add - acd * ade) * oodet + betad = 0d0 + betae = 0d0 + do il = 1, nnbr !...........If this is connection (0,1) or inactive, skip. - if ((il == il01) .or. (inbr(il) == 0)) cycle - betad(il) = (bd(il) * aee - be(il) * aed) * oodet - betae(il) = (be(il) * add - bd(il) * ade) * oodet - end do + if ((il == il01) .or. (inbr(il) == 0)) cycle + betad(il) = (bd(il) * aee - be(il) * aed) * oodet + betae(il) = (be(il) * add - bd(il) * ade) * oodet + end do ! !........Compute sigma coefficients. - sigma = matmul(vn(il01, :), matmul(ck, rmat)) + sigma = matmul(vn(il01, :), matmul(ck, rmat)) ! !........Compute ahat and bhat coefficients. - ahat = (sigma(1) - sigma(2) * alphad - sigma(3) * alphae) / dl0(il01) - bhat = 0d0 - do il = 1, nnbr + ahat = (sigma(1) - sigma(2) * alphad - sigma(3) * alphae) / dl0(il01) + bhat = 0d0 + do il = 1, nnbr !...........If this is connection (0,1) or inactive, skip. - if ((il == il01) .or. (inbr(il) == 0)) cycle - dl0il = dl0(il) + dln(il) - bhat(il) = (sigma(2) * betad(il) + sigma(3) * betae(il)) / dl0il - end do + if ((il == il01) .or. (inbr(il) == 0)) cycle + dl0il = dl0(il) + dln(il) + bhat(il) = (sigma(2) * betad(il) + sigma(3) * betae(il)) / dl0il + end do !........Set the bhat for connection (0,1) to zero here, since we have ! been skipping it in our do loops to avoiding explicitly ! computing it. This will carry through to the corresponding ! chati0 and chat1j value, so that they too are zero. - bhat(il01) = 0d0 + bhat(il01) = 0d0 ! end if ! @@ -285,7 +285,7 @@ subroutine abhats(nnbrmx,nnbr,inbr,il01,vc,vn,dl0,dln,ck, & return end subroutine abhats - subroutine getrot(nnbrmx,nnbr,inbr,vc,il01,rmat,iml0) + subroutine getrot(nnbrmx, nnbr, inbr, vc, il01, rmat, iml0) ! ****************************************************************************** !.....Compute the matrix that rotates the model-coordinate axes to ! the "(c, d, e)-coordinate" axes associated with a connection. @@ -329,7 +329,7 @@ subroutine getrot(nnbrmx,nnbr,inbr,vc,il01,rmat,iml0) ! ------------------------------------------------------------------------------ ! !.....set vcc. - vcc(:) = vc(il01,:) + vcc(:) = vc(il01, :) ! !.....Set vcmax. (If no connection has a perpendicular component ! greater than some tiny threshold, return with iml0=0 and @@ -338,23 +338,23 @@ subroutine getrot(nnbrmx,nnbr,inbr,vc,il01,rmat,iml0) acmpmn = 1d0 - 1d-10 iml0 = 0 do il = 1, nnbr - if ((il.eq.il01).or.(inbr(il).eq.0)) then + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) then cycle else - cmp = dot_product(vc(il,:), vcc) + cmp = dot_product(vc(il, :), vcc) acmp = dabs(cmp) - if (acmp.lt.acmpmn) then + if (acmp .lt. acmpmn) then cmpmn = cmp acmpmn = acmp iml0 = il end if end if - enddo + end do if (iml0 == 0) then - rmat(:,1) = vcc(:) - goto 999 + rmat(:, 1) = vcc(:) + goto 999 else - vcmax(:) = vc(iml0,:) + vcmax(:) = vc(iml0, :) end if ! !.....Set the first perpendicular direction as the direction that is @@ -364,20 +364,20 @@ subroutine getrot(nnbrmx,nnbr,inbr,vc,il01,rmat,iml0) ! !.....Set the second perpendicular direction as the cross product of ! the primary and first-perpendicular directions. - vce(1) = vcc(2)*vcd(3) - vcc(3)*vcd(2) - vce(2) = vcc(3)*vcd(1) - vcc(1)*vcd(3) - vce(3) = vcc(1)*vcd(2) - vcc(2)*vcd(1) + vce(1) = vcc(2) * vcd(3) - vcc(3) * vcd(2) + vce(2) = vcc(3) * vcd(1) - vcc(1) * vcd(3) + vce(3) = vcc(1) * vcd(2) - vcc(2) * vcd(1) ! !.....Set the rotation matrix as the matrix with vcc, vcd, and vce ! as its columns. - rmat(:,1) = vcc(:) - rmat(:,2) = vcd(:) - rmat(:,3) = vce(:) + rmat(:, 1) = vcc(:) + rmat(:, 2) = vcd(:) + rmat(:, 3) = vce(:) ! 999 return end subroutine getrot - subroutine tranvc(nnbrmx,nnbrs,rmat,vc,vccde) + subroutine tranvc(nnbrmx, nnbrs, rmat, vc, vccde) ! ****************************************************************************** !.....Transform local connection unit-vectors from model coordinates ! to "(c, d, e)" coordinates associated with a connection. @@ -408,14 +408,14 @@ subroutine tranvc(nnbrmx,nnbrs,rmat,vc,vccde) ! rotation matrix so that the transformation is from model ! to (c, d, e) coordinates. do il = 1, nnbrs - vccde(il,:) = matmul(transpose(rmat), vc(il,:)) - enddo + vccde(il, :) = matmul(transpose(rmat), vc(il, :)) + end do ! return end subroutine tranvc - subroutine abwts(nnbrmx,nnbr,inbr,il01,nde1,vccde, & - vcthresh,dl0,dln,acd,add,aed,bd) + subroutine abwts(nnbrmx, nnbr, inbr, il01, nde1, vccde, & + vcthresh, dl0, dln, acd, add, aed, bd) ! ****************************************************************************** !.....Compute "a" and "b" weights for the local connections with respect ! to the perpendicular direction of primary interest. @@ -463,76 +463,76 @@ subroutine abwts(nnbrmx,nnbr,inbr,il01,nde1,vccde, & ! ------------------------------------------------------------------------------ ! !.....Set the perpendicular direction of secondary interest. - nde2 = 5 - nde1 + nde2 = 5 - nde1 ! !.....Begin computing "omega" weights. - omwt = 0d0 - dsum = 0d0 - vcmx = 0d0 - do il = 1, nnbr + omwt = 0d0 + dsum = 0d0 + vcmx = 0d0 + do il = 1, nnbr !........if this is connection (0,1) or inactive, skip. - if ((il.eq.il01).or.(inbr(il).eq.0)) cycle - vcmx = max(dabs(vccde(il,nde1)), vcmx) - dlm = 5d-1*(dl0(il) + dln(il)) + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle + vcmx = max(dabs(vccde(il, nde1)), vcmx) + dlm = 5d-1 * (dl0(il) + dln(il)) !...........Distance-based weighting. dl4wt is the distance between ! the point supplying the gradient information and the ! point at which the flux is being estimated. Could be ! coded as a special case of resistance-based weighting ! (by setting the conductivity matrix to be the identity ! matrix), but this is more efficient. - cosang = vccde(il,1) - dl4wt = dsqrt(dlm*dlm + dl0(il01)*dl0(il01) & - - 2d0*dlm*dl0(il01)*cosang) - omwt(il) = dabs(vccde(il,nde1))*dl4wt - dsum = dsum + omwt(il) - end do + cosang = vccde(il, 1) + dl4wt = dsqrt(dlm * dlm + dl0(il01) * dl0(il01) & + - 2d0 * dlm * dl0(il01) * cosang) + omwt(il) = dabs(vccde(il, nde1)) * dl4wt + dsum = dsum + omwt(il) + end do ! !.....Finish computing non-normalized "omega" weights. [Add a ! tiny bit to dsum so that the normalized omega weight later ! evaluates to (essentially) 1 in the case of a single relevant ! connection, avoiding 0/0.] - dsum = dsum + 1d-10*dsum - do il = 1, nnbr + dsum = dsum + 1d-10 * dsum + do il = 1, nnbr !........If this is connection (0,1) or inactive, skip. - if ((il.eq.il01).or.(inbr(il).eq.0)) cycle - fact = dsum - omwt(il) - omwt(il) = fact*dabs(vccde(il,nde1)) - end do + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle + fact = dsum - omwt(il) + omwt(il) = fact * dabs(vccde(il, nde1)) + end do ! !.....Compute "b" weights. - bd = 0d0 - dsum = 0d0 - do il = 1, nnbr + bd = 0d0 + dsum = 0d0 + do il = 1, nnbr !........If this is connection (0,1) or inactive, skip. - if ((il.eq.il01).or.(inbr(il).eq.0)) cycle - bd(il) = omwt(il)*sign(1d0,vccde(il,nde1)) - dsum = dsum + omwt(il)*dabs(vccde(il,nde1)) - end do - oodsum = 1d0/dsum - do il = 1, nnbr + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle + bd(il) = omwt(il) * sign(1d0, vccde(il, nde1)) + dsum = dsum + omwt(il) * dabs(vccde(il, nde1)) + end do + oodsum = 1d0 / dsum + do il = 1, nnbr !........If this is connection (0,1) or inactive, skip. - if ((il.eq.il01).or.(inbr(il).eq.0)) cycle - bd(il) = bd(il)*oodsum - end do + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle + bd(il) = bd(il) * oodsum + end do ! !.....Compute "a" weights. - add = 1d0 - acd = 0d0 - aed = 0d0 - do il = 1, nnbr + add = 1d0 + acd = 0d0 + aed = 0d0 + do il = 1, nnbr !........If this is connection (0,1) or inactive, skip. - if ((il.eq.il01).or.(inbr(il).eq.0)) cycle - acd = acd + bd(il)*vccde(il,1) - aed = aed + bd(il)*vccde(il,nde2) - end do + if ((il .eq. il01) .or. (inbr(il) .eq. 0)) cycle + acd = acd + bd(il) * vccde(il, 1) + aed = aed + bd(il) * vccde(il, nde2) + end do ! !.....Apply attenuation function to acd, aed, and bd. - if (vcmx.lt.vcthresh) then - fatten = vcmx/vcthresh - acd = acd*fatten - aed = aed*fatten - bd = bd*fatten - end if + if (vcmx .lt. vcthresh) then + fatten = vcmx / vcthresh + acd = acd * fatten + aed = aed * fatten + bd = bd * fatten + end if ! end subroutine abwts ! diff --git a/src/Model/ModelUtilities/Xt3dInterface.f90 b/src/Model/ModelUtilities/Xt3dInterface.f90 index 68b307d8ddc..9e57db4443e 100644 --- a/src/Model/ModelUtilities/Xt3dInterface.f90 +++ b/src/Model/ModelUtilities/Xt3dInterface.f90 @@ -1,50 +1,52 @@ module Xt3dModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DHALF, DONE, LENMEMPATH - use BaseDisModule, only: DisBaseType - use MemoryHelperModule, only: create_mem_path + + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, DHALF, DONE, LENMEMPATH + use BaseDisModule, only: DisBaseType + use MemoryHelperModule, only: create_mem_path implicit none public Xt3dType public :: xt3d_cr - - type Xt3dType - character(len=LENMEMPATH) :: memoryPath !< location in memory manager for storing package variables - integer(I4B), pointer :: inunit => null() !< unit number from where xt3d was read - integer(I4B), pointer :: iout => null() !< unit number for output - integer(I4B), pointer :: inewton => null() !< Newton flag - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound - integer(I4B),dimension(:), pointer, contiguous :: iax => null() !< ia array for extended neighbors used by xt3d - integer(I4B),dimension(:), pointer, contiguous :: jax => null() !< ja array for extended neighbors used by xt3d - integer(I4B),dimension(:), pointer, contiguous :: idxglox => null() !< mapping array for extended neighbors used by xt3d - integer(I4B), pointer :: numextnbrs => null() !< dimension of jax array - integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs) - logical, pointer :: nozee => null() !< nozee flag - real(DP), pointer :: vcthresh => null() !< attenuation function threshold - real(DP), dimension(:,:), pointer, contiguous :: rmatck => null() !< rotation matrix for the conductivity tensor - real(DP), dimension(:), pointer, contiguous :: qsat => null() !< saturated flow saved for Newton - integer(I4B), pointer :: nbrmax => null() !< maximum number of neighbors for any cell - real(DP), dimension(:), pointer, contiguous :: amatpc => null() !< saved contributions to amat from permanently confined connections, direct neighbors - real(DP), dimension(:), pointer, contiguous :: amatpcx => null() !< saved contributions to amat from permanently confined connections, extended neighbors - integer(I4B), dimension(:), pointer, contiguous :: iallpc => null() !< indicates for each node whether all connections processed by xt3d are permanently confined (0 no, 1 yes) - logical, pointer :: lamatsaved => null() !< indicates whether amat has been saved for permanently confined connections - class(DisBaseType), pointer :: dis => null() !< discretization object + + type Xt3dType + character(len=LENMEMPATH) :: memoryPath !< location in memory manager for storing package variables + integer(I4B), pointer :: inunit => null() !< unit number from where xt3d was read + integer(I4B), pointer :: iout => null() !< unit number for output + integer(I4B), pointer :: inewton => null() !< Newton flag + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !< pointer to model ibound + integer(I4B), dimension(:), pointer, contiguous :: iax => null() !< ia array for extended neighbors used by xt3d + integer(I4B), dimension(:), pointer, contiguous :: jax => null() !< ja array for extended neighbors used by xt3d + integer(I4B), dimension(:), pointer, contiguous :: idxglox => null() !< mapping array for extended neighbors used by xt3d + integer(I4B), dimension(:), pointer, contiguous :: ia_xt3d => null() !< ia array for local extended xt3d connections (no diagonal) + integer(I4B), dimension(:), pointer, contiguous :: ja_xt3d => null() !< ja array for local extended xt3d connections (no diagonal) + integer(I4B), pointer :: numextnbrs => null() !< dimension of jax array + integer(I4B), pointer :: ixt3d => null() !< xt3d flag (0 is off, 1 is lhs, 2 is rhs) + logical, pointer :: nozee => null() !< nozee flag + real(DP), pointer :: vcthresh => null() !< attenuation function threshold + real(DP), dimension(:, :), pointer, contiguous :: rmatck => null() !< rotation matrix for the conductivity tensor + real(DP), dimension(:), pointer, contiguous :: qsat => null() !< saturated flow saved for Newton + integer(I4B), pointer :: nbrmax => null() !< maximum number of neighbors for any cell + real(DP), dimension(:), pointer, contiguous :: amatpc => null() !< saved contributions to amat from permanently confined connections, direct neighbors + real(DP), dimension(:), pointer, contiguous :: amatpcx => null() !< saved contributions to amat from permanently confined connections, extended neighbors + integer(I4B), dimension(:), pointer, contiguous :: iallpc => null() !< indicates for each node whether all connections processed by xt3d are permanently confined (0 no, 1 yes) + logical, pointer :: lamatsaved => null() !< indicates whether amat has been saved for permanently confined connections + class(DisBaseType), pointer :: dis => null() !< discretization object ! pointers to npf variables - real(DP), dimension(:), pointer, contiguous :: k11 => null() !< horizontal hydraulic conductivity - real(DP), dimension(:),pointer, contiguous :: k22 => null() !< minor axis of horizontal hydraulic conductivity ellipse - real(DP), dimension(:), pointer, contiguous :: k33 => null() !< vertical hydraulic conductivity - integer(I4B), pointer :: ik22 => null() !< flag indicates K22 was read - integer(I4B), pointer :: ik33 => null() !< flag indicates K33 was read - real(DP), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell - integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< cell type (confined or unconfined) - integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read - integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read - integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read - real(DP), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw) - real(DP), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch) - real(DP), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll) - logical, pointer :: ldispersion => null() !< flag to indicate dispersion + real(DP), dimension(:), pointer, contiguous :: k11 => null() !< horizontal hydraulic conductivity + real(DP), dimension(:), pointer, contiguous :: k22 => null() !< minor axis of horizontal hydraulic conductivity ellipse + real(DP), dimension(:), pointer, contiguous :: k33 => null() !< vertical hydraulic conductivity + integer(I4B), pointer :: ik22 => null() !< flag indicates K22 was read + integer(I4B), pointer :: ik33 => null() !< flag indicates K33 was read + real(DP), dimension(:), pointer, contiguous :: sat => null() !< saturation (0. to 1.) for each cell + integer(I4B), dimension(:), pointer, contiguous :: icelltype => null() !< cell type (confined or unconfined) + integer(I4B), pointer :: iangle1 => null() !< flag to indicate angle1 was read + integer(I4B), pointer :: iangle2 => null() !< flag to indicate angle2 was read + integer(I4B), pointer :: iangle3 => null() !< flag to indicate angle3 was read + real(DP), dimension(:), pointer, contiguous :: angle1 => null() !< k ellipse rotation in xy plane around z axis (yaw) + real(DP), dimension(:), pointer, contiguous :: angle2 => null() !< k ellipse rotation up from xy plane around y axis (pitch) + real(DP), dimension(:), pointer, contiguous :: angle3 => null() !< k tensor rotation around x axis (roll) + logical, pointer :: ldispersion => null() !< flag to indicate dispersion contains procedure :: xt3d_df procedure :: xt3d_ac @@ -74,8 +76,8 @@ module Xt3dModule procedure, private :: xt3d_fillrmatck procedure, private :: xt3d_qnbrs end type Xt3dType - - contains + +contains subroutine xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt) ! ****************************************************************************** @@ -93,9 +95,9 @@ subroutine xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(xt3dobj) + allocate (xt3dobj) ! - + ! -- assign the memory path xt3dobj%memoryPath = create_mem_path(name_model, 'XT3D') ! @@ -104,7 +106,7 @@ subroutine xt3d_cr(xt3dobj, name_model, inunit, iout, ldispopt) ! ! -- Set variables xt3dobj%inunit = inunit - xt3dobj%iout = iout + xt3dobj%iout = iout if (present(ldispopt)) xt3dobj%ldispersion = ldispopt ! ! -- Return @@ -129,7 +131,7 @@ subroutine xt3d_df(this, dis) ! -- Return return end subroutine xt3d_df - + subroutine xt3d_ac(this, moffset, sparse) ! ****************************************************************************** ! xt3d_ac -- Add connections for extended neighbors to the sparse matrix @@ -139,37 +141,73 @@ subroutine xt3d_ac(this, moffset, sparse) ! ------------------------------------------------------------------------------ ! -- modules use SparseModule, only: sparsematrix + use MemoryManagerModule, only: mem_allocate ! -- dummy class(Xt3dType) :: this integer(I4B), intent(in) :: moffset type(sparsematrix), intent(inout) :: sparse ! -- local + type(sparsematrix) :: sparse_xt3d integer(I4B) :: i, j, k, jj, kk, iglo, kglo, iadded + integer(I4B) :: nnz + integer(I4B) :: ierror ! ------------------------------------------------------------------------------ ! ! -- If not rhs, add connections if (this%ixt3d == 1) then - ! -- loop over nodes - do i = 1, this%dis%nodes - iglo = i + moffset - ! -- loop over neighbors - do jj = this%dis%con%ia(i), this%dis%con%ia(i+1) - 1 - j = this%dis%con%ja(jj) - ! -- loop over neighbors of neighbors - do kk = this%dis%con%ia(j), this%dis%con%ia(j+1) - 1 - k = this%dis%con%ja(kk) - kglo = k + moffset - call sparse%addconnection(iglo, kglo, 1, iadded) - this%numextnbrs = this%numextnbrs + iadded - enddo - enddo - enddo - endif + + ! -- assume nnz is 19, which is an approximate value + ! based on a 3d structured grid + nnz = 19 + call sparse_xt3d%init(this%dis%nodes, this%dis%nodes, nnz) + + ! -- loop over nodes and store extended xt3d neighbors + ! temporarily in sparse_xt3d; this will be converted to + ! ia_xt3d and ja_xt3d next + do i = 1, this%dis%nodes + iglo = i + moffset + ! -- loop over neighbors + do jj = this%dis%con%ia(i) + 1, this%dis%con%ia(i + 1) - 1 + j = this%dis%con%ja(jj) + ! -- loop over neighbors of neighbors + do kk = this%dis%con%ia(j) + 1, this%dis%con%ia(j + 1) - 1 + k = this%dis%con%ja(kk) + kglo = k + moffset + call sparse_xt3d%addconnection(i, k, 1) + end do + end do + end do + + ! -- calculate ia_xt3d and ja_xt3d from sparse_xt3d and + ! then destroy sparse + call mem_allocate(this%ia_xt3d, this%dis%nodes + 1, 'IA_XT3D', & + trim(this%memoryPath)) + call mem_allocate(this%ja_xt3d, sparse_xt3d%nnz, 'JA_XT3D', & + trim(this%memoryPath)) + call sparse_xt3d%filliaja(this%ia_xt3d, this%ja_xt3d, ierror) + call sparse_xt3d%destroy() + ! + ! -- add extended neighbors to sparse and count number of + ! extended neighbors + do i = 1, this%dis%nodes + iglo = i + moffset + do kk = this%ia_xt3d(i), this%ia_xt3d(i + 1) - 1 + k = this%ja_xt3d(kk) + kglo = k + moffset + call sparse%addconnection(iglo, kglo, 1, iadded) + this%numextnbrs = this%numextnbrs + 1 + end do + end do + else + ! -- Arrays not needed; set to size zero + call mem_allocate(this%ia_xt3d, 0, 'IA_XT3D', trim(this%memoryPath)) + call mem_allocate(this%ja_xt3d, 0, 'JA_XT3D', trim(this%memoryPath)) + end if ! ! -- Return return end subroutine xt3d_ac - + subroutine xt3d_mc(this, moffset, iasln, jasln) ! ****************************************************************************** ! xt3d_mc -- Map connections and construct iax, jax, and idxglox @@ -185,7 +223,8 @@ subroutine xt3d_mc(this, moffset, iasln, jasln) integer(I4B), dimension(:), intent(in) :: iasln integer(I4B), dimension(:), intent(in) :: jasln ! -- local - integer(I4B) :: i, j, jj, iglo, jglo, jjg, niax, njax, ipos + integer(I4B) :: i, j, iglo, jglo, jjg, niax, njax, ipos + integer(I4B) :: jj_xt3d integer(I4B) :: igfirstnod, iglastnod logical :: isextnbr ! ------------------------------------------------------------------------------ @@ -224,32 +263,30 @@ subroutine xt3d_mc(this, moffset, iasln, jasln) jglo = jasln(jjg) if (jglo < igfirstnod .or. jglo > iglastnod) then cycle - endif + end if ! - ! -- determine whether this neighbor is an extended neighbor - ! by searching the original neighbors - isextnbr = .true. - searchloop: do jj = this%dis%con%ia(i), this%dis%con%ia(i+1) - 1 - j = this%dis%con%ja(jj) - jglo = j + moffset - ! - ! -- if an original neighbor, note that and end the search - if(jglo == jasln(jjg)) then - isextnbr = .false. - exit searchloop - endif - enddo searchloop + ! -- Check to see if this local connection was added by + ! xt3d. If not, then this connection was added by + ! something else, such as an interface model. + j = jglo - moffset + isextnbr = .false. + do jj_xt3d = this%ia_xt3d(i), this%ia_xt3d(i + 1) - 1 + if (j == this%ja_xt3d(jj_xt3d)) then + isextnbr = .true. + exit + end if + end do ! ! -- if an extended neighbor, add it to jax and idxglox if (isextnbr) then this%jax(ipos) = jasln(jjg) - moffset this%idxglox(ipos) = jjg ipos = ipos + 1 - endif - enddo + end if + end do ! -- load next iax entry - this%iax(i+1) = ipos - enddo + this%iax(i + 1) = ipos + end do ! else ! @@ -257,14 +294,14 @@ subroutine xt3d_mc(this, moffset, iasln, jasln) call mem_allocate(this%jax, 0, 'JAX', trim(this%memoryPath)) call mem_allocate(this%idxglox, 0, 'IDXGLOX', trim(this%memoryPath)) ! - endif + end if ! ! -- Return return end subroutine xt3d_mc - - subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, & - iangle1, iangle2, iangle3, angle1, angle2, angle3, inewton, icelltype) + + subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, iangle1, & + iangle2, iangle3, angle1, angle2, angle3, inewton, icelltype) ! ****************************************************************************** ! xt3d_ar -- Allocate and Read ! ****************************************************************************** @@ -294,18 +331,18 @@ subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, & ! -- local integer(I4B) :: n, nnbrs ! -- formats - character(len=*), parameter :: fmtheader = & - "(1x, /1x, 'XT3D is active.'//)" + character(len=*), parameter :: fmtheader = & + "(1x, /1x, 'XT3D is active.'//)" ! -- data ! ------------------------------------------------------------------------------ ! ! -- Print a message identifying the xt3d module. if (this%iout > 0) then - write(this%iout, fmtheader) + write (this%iout, fmtheader) end if ! ! -- Store pointers to arguments that were passed in - this%ibound => ibound + this%ibound => ibound this%k11 => k11 this%ik33 => ik33 this%k33 => k33 @@ -324,44 +361,44 @@ subroutine xt3d_ar(this, ibound, k11, ik33, k33, sat, ik22, k22, & end if if (present(icelltype)) then ! -- icelltype is not needed for transport, so it's optional. - ! It is only needed to determine if cell connections are permanently + ! It is only needed to determine if cell connections are permanently ! confined, which means that some matrix terms can be precalculated this%icelltype => icelltype end if ! ! -- If angle1 and angle2 were not specified, then there is no z ! component in the xt3d formulation for horizontal connections. - if(this%iangle2 == 0) this%nozee = .true. + if (this%iangle2 == 0) this%nozee = .true. ! ! -- Determine the maximum number of neighbors for any cell. this%nbrmax = 0 do n = 1, this%dis%nodes - nnbrs = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbrs = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 this%nbrmax = max(nnbrs, this%nbrmax) end do ! ! -- Check to make sure dis package can calculate connection direction info if (this%dis%icondir == 0) then - call store_error('Vertices not specified for discretization ' // & - 'package, but XT3D is active: '// trim(adjustl(this%memoryPath)) // & - '. Vertices must be specified in discretization package in order ' // & - 'to use XT3D.', terminate=.TRUE.) - endif + call store_error('Vertices not specified for discretization package, '// & + 'but XT3D is active: '//trim(adjustl(this%memoryPath))// & + '. Vertices must be specified in discretization '// & + 'package in order to use XT3D.', terminate=.TRUE.) + end if ! ! -- Check to make sure ANGLEDEGX is available for interface normals if (this%dis%con%ianglex == 0) then - call store_error('ANGLDEGX is not specified in the DIS ' // & - 'package, but XT3D is active: '// trim(adjustl(this%memoryPath)) // & - '. ANGLDEGX must be provided in discretization package in order ' // & - 'to use XT3D.', terminate=.TRUE.) - endif + call store_error('ANGLDEGX is not specified in the DIS package, '// & + 'but XT3D is active: '//trim(adjustl(this%memoryPath))// & + '. ANGLDEGX must be provided in discretization '// & + 'package in order to use XT3D.', terminate=.TRUE.) + end if ! ! -- allocate arrays call this%allocate_arrays() ! - ! -- If not Newton and not rhs, precalculate amatpc and amatpcx for + ! -- If not Newton and not rhs, precalculate amatpc and amatpcx for ! -- permanently confined connections - if(this%lamatsaved .and. .not. this%ldispersion) & + if (this%lamatsaved .and. .not. this%ldispersion) & call this%xt3d_fcpc(this%dis%nodes, .true.) ! ! -- Return @@ -380,11 +417,11 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! -- dummy class(Xt3dType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(:) :: idxglo - real(DP),intent(inout),dimension(:) :: rhs - real(DP),intent(inout),dimension(:) :: hnew + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(:) :: idxglo + real(DP), intent(inout), dimension(:) :: rhs + real(DP), intent(inout), dimension(:) :: hnew ! -- local integer(I4B) :: nodes, nja integer(I4B) :: n, m, ipos @@ -393,13 +430,13 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) integer(I4B) :: nnbr0, nnbr1 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10 integer(I4B) :: i - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 real(DP) :: ar01, ar10 - real(DP),dimension(this%nbrmax,3) :: vc0, vn0, vc1, vn1 - real(DP),dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n - real(DP),dimension(3,3) :: ck0, ck1 + real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1 + real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n + real(DP), dimension(3, 3) :: ck0, ck1 real(DP) :: chat01 - real(DP),dimension(this%nbrmax) :: chati0, chat1j + real(DP), dimension(this%nbrmax) :: chati0, chat1j real(DP) :: qnm, qnbrs ! ------------------------------------------------------------------------------ ! @@ -419,31 +456,31 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) ! do n = 1, nodes ! -- Skip if inactive. - if (this%ibound(n).eq.0) cycle + if (this%ibound(n) .eq. 0) cycle ! -- Skip if all connections are permanently confined if (this%lamatsaved) then if (this%iallpc(n) == 1) cycle end if - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load conductivity and connection info for cell 0. - call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & - ck0, allhc0) + call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & + ck0, allhc0) ! -- Loop over active neighbors of cell 0 that have a higher ! -- cell number (taking advantage of reciprocity). - do il0 = 1,nnbr0 + do il0 = 1, nnbr0 ipos = this%dis%con%ia(n) + il0 if (this%dis%con%mask(ipos) == 0) cycle - + m = inbr0(il0) ! -- Skip if neighbor is inactive or has lower cell number. - if ((m.eq.0).or.(m.lt.n)) cycle - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 - ! -- Load conductivity and connection info for cell 1. - call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & - ck1, allhc1) + if ((m .eq. 0) .or. (m .lt. n)) cycle + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 + ! -- Load conductivity and connection info for cell 1. + call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & + ck1, allhc1) ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! -- Compute areas. if (this%inewton /= 0) then ar01 = DONE @@ -453,15 +490,15 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) end if ! -- Compute "conductances" for interface between ! -- cells 0 and 1. - call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & - ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & - this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) + call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, & + nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! -- If Newton, compute and save saturated flow, then scale ! -- conductance-like coefficients by the actual area for ! -- subsequent amat and rhs assembly. if (this%inewton /= 0) then ! -- Contribution to flow from primary connection. - qnm = chat01*(hnew(m) - hnew(n)) + qnm = chat01 * (hnew(m) - hnew(n)) ! -- Contribution from immediate neighbors of node 0. call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs) qnm = qnm + qnbrs @@ -470,12 +507,12 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) qnm = qnm - qnbrs ! -- Multiply by saturated area and save in qsat. call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew) - this%qsat(ii01) = qnm*ar01 + this%qsat(ii01) = qnm * ar01 ! -- Scale coefficients by actual area. call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew) - chat01 = chat01*ar01 - chati0 = chati0*ar01 - chat1j = chat1j*ar01 + chat01 = chat01 * ar01 + chati0 = chati0 * ar01 + chat1j = chat1j * ar01 end if ! -- Contribute to rows for cells 0 and 1. amat(idxglo(ii00)) = amat(idxglo(ii00)) - chat01 @@ -483,21 +520,21 @@ subroutine xt3d_fc(this, kiter, njasln, amat, idxglo, rhs, hnew) amat(idxglo(ii11)) = amat(idxglo(ii11)) - chat01 amat(idxglo(ii10)) = amat(idxglo(ii10)) + chat01 if (this%ixt3d == 1) then - call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, njasln, & - inbr0, amat, idxglo, chati0) - call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, njasln, & - inbr1, amat, idxglo, chat1j) - call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, njasln, & - inbr1, amat, idxglo, chat1j) - call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, njasln, & - inbr0, amat, idxglo, chati0) + call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, njasln, & + inbr0, amat, idxglo, chati0) + call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, njasln, & + inbr1, amat, idxglo, chat1j) + call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, njasln, & + inbr1, amat, idxglo, chat1j) + call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, njasln, & + inbr0, amat, idxglo, chati0) else - call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs) - call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs) - endif + call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs) + call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs) + end if ! - enddo - enddo + end do + end do ! ! -- Return return @@ -516,29 +553,29 @@ subroutine xt3d_fcpc(this, nodes, lsat) ! -- dummy class(Xt3dType) :: this integer(I4B), intent(in) :: nodes - logical, intent(in) :: lsat !< if true, then calculations made with saturated areas (should be false for dispersion) + logical, intent(in) :: lsat !< if true, then calculations made with saturated areas (should be false for dispersion) ! -- local integer(I4B) :: n, m, ipos ! logical :: allhc0, allhc1 integer(I4B) :: nnbr0, nnbr1 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10 - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 real(DP) :: ar01, ar10 - real(DP),dimension(this%nbrmax,3) :: vc0, vn0, vc1, vn1 - real(DP),dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n - real(DP),dimension(3,3) :: ck0, ck1 + real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1 + real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n + real(DP), dimension(3, 3) :: ck0, ck1 real(DP) :: chat01 - real(DP),dimension(this%nbrmax) :: chati0, chat1j + real(DP), dimension(this%nbrmax) :: chati0, chat1j ! ------------------------------------------------------------------------------ ! ! -- Initialize amatpc and amatpcx to zero do n = 1, size(this%amatpc) this%amatpc(n) = DZERO - enddo + end do do n = 1, size(this%amatpcx) this%amatpcx(n) = DZERO - enddo + end do ! ! -- Calculate xt3d conductance-like coefficients for permanently confined ! -- connections and put into amatpc and amatpcx as appropriate @@ -546,33 +583,33 @@ subroutine xt3d_fcpc(this, nodes, lsat) ! -- Skip if not iallpc. if (this%iallpc(n) == 0) cycle if (this%ibound(n) == 0) cycle - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load conductivity and connection info for cell 0. - call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & - ck0, allhc0) + call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & + ck0, allhc0) ! -- Loop over active neighbors of cell 0 that have a higher ! -- cell number (taking advantage of reciprocity). - do il0 = 1,nnbr0 + do il0 = 1, nnbr0 ipos = this%dis%con%ia(n) + il0 if (this%dis%con%mask(ipos) == 0) cycle - + m = inbr0(il0) ! -- Skip if neighbor has lower cell number. - if (m.lt.n) cycle - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 + if (m .lt. n) cycle + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 ! -- Load conductivity and connection info for cell 1. - call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & - ck1, allhc1) + call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & + ck1, allhc1) ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! -- Compute confined areas. call this%xt3d_areas(nodes, n, m, jjs01, lsat, ar01, ar10) ! -- Compute "conductances" for interface between ! -- cells 0 and 1. - call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & - ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & - this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) + call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, & + nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! -- Contribute to rows for cells 0 and 1. this%amatpc(ii00) = this%amatpc(ii00) - chat01 this%amatpc(ii01) = this%amatpc(ii01) + chat01 @@ -582,15 +619,15 @@ subroutine xt3d_fcpc(this, nodes, lsat) call this%xt3d_amatpcx_nbrnbrs(nodes, n, m, ii01, nnbr1, inbr1, chat1j) call this%xt3d_amatpc_nbrs(nodes, m, ii11, nnbr1, inbr1, chat1j) call this%xt3d_amatpcx_nbrnbrs(nodes, m, n, ii10, nnbr0, inbr0, chati0) - enddo - enddo + end do + end do ! ! -- Return return end subroutine xt3d_fcpc subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & - n, m, condhfb) + n, m, condhfb) ! ****************************************************************************** ! xt3d_fhfb -- Formulate HFB correction ! ****************************************************************************** @@ -602,27 +639,27 @@ subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & ! -- dummy class(Xt3dType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: nodes - integer(I4B),intent(in) :: nja - integer(I4B),intent(in) :: njasln + integer(I4B), intent(in) :: nodes + integer(I4B), intent(in) :: nja + integer(I4B), intent(in) :: njasln integer(I4B) :: n, m - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(nja) :: idxglo - real(DP),intent(inout),dimension(nodes) :: rhs - real(DP),intent(inout),dimension(nodes) :: hnew + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(nja) :: idxglo + real(DP), intent(inout), dimension(nodes) :: rhs + real(DP), intent(inout), dimension(nodes) :: hnew real(DP) :: condhfb ! -- local ! logical :: allhc0, allhc1 integer(I4B) :: nnbr0, nnbr1 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10, il - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 real(DP) :: ar01, ar10 - real(DP),dimension(this%nbrmax,3) :: vc0, vn0, vc1, vn1 - real(DP),dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n - real(DP),dimension(3,3) :: ck0, ck1 + real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1 + real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n + real(DP), dimension(3, 3) :: ck0, ck1 real(DP) :: chat01 - real(DP),dimension(this%nbrmax) :: chati0, chat1j + real(DP), dimension(this%nbrmax) :: chati0, chat1j real(DP) :: qnm, qnbrs real(DP) :: term ! ------------------------------------------------------------------------------ @@ -630,24 +667,24 @@ subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & ! -- Calculate hfb corrections to xt3d conductance-like coefficients and ! -- put into amat and rhs as appropriate ! - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load conductivity and connection info for cell 0. - call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & - ck0, allhc0) + call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & + ck0, allhc0) ! -- Find local neighbor number of cell 1. - do il = 1,nnbr0 - if (inbr0(il).eq.m) then + do il = 1, nnbr0 + if (inbr0(il) .eq. m) then il0 = il exit end if end do - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 ! -- Load conductivity and connection info for cell 1. - call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & - ck1, allhc1) + call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & + ck1, allhc1) ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! -- Compute areas. if (this%inewton /= 0) then ar01 = DONE @@ -657,24 +694,24 @@ subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & end if ! -- Compute "conductances" for interface between ! -- cells 0 and 1. - call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & - ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & - this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) + call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & + ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! -- Apply scale factor to compute "conductances" for hfb correction - if(condhfb > DZERO) then - term = chat01/(chat01 + condhfb) + if (condhfb > DZERO) then + term = chat01 / (chat01 + condhfb) else term = -condhfb - endif - chat01 = -chat01*term - chati0 = -chati0*term - chat1j = -chat1j*term + end if + chat01 = -chat01 * term + chati0 = -chati0 * term + chat1j = -chat1j * term ! -- If Newton, compute and save saturated flow, then scale ! -- conductance-like coefficients by the actual area for ! -- subsequent amat and rhs assembly. if (this%inewton /= 0) then ! -- Contribution to flow from primary connection. - qnm = chat01*(hnew(m) - hnew(n)) + qnm = chat01 * (hnew(m) - hnew(n)) ! -- Contribution from immediate neighbors of node 0. call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs) qnm = qnm + qnbrs @@ -683,12 +720,12 @@ subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & qnm = qnm - qnbrs ! -- Multiply by saturated area and add correction to qsat. call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew) - this%qsat(ii01) = this%qsat(ii01) + qnm*ar01 + this%qsat(ii01) = this%qsat(ii01) + qnm * ar01 ! -- Scale coefficients by actual area. call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew) - chat01 = chat01*ar01 - chati0 = chati0*ar01 - chat1j = chat1j*ar01 + chat01 = chat01 * ar01 + chati0 = chati0 * ar01 + chat1j = chat1j * ar01 end if ! -- Contribute to rows for cells 0 and 1. amat(idxglo(ii00)) = amat(idxglo(ii00)) - chat01 @@ -696,18 +733,18 @@ subroutine xt3d_fhfb(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew, & amat(idxglo(ii11)) = amat(idxglo(ii11)) - chat01 amat(idxglo(ii10)) = amat(idxglo(ii10)) + chat01 if (this%ixt3d == 1) then - call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, njasln, & - inbr0, amat, idxglo, chati0) - call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, njasln, & - inbr1, amat, idxglo, chat1j) - call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, njasln, & - inbr1, amat, idxglo, chat1j) - call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, njasln, & - inbr0, amat, idxglo, chati0) + call this%xt3d_amat_nbrs(nodes, n, ii00, nnbr0, nja, njasln, & + inbr0, amat, idxglo, chati0) + call this%xt3d_amat_nbrnbrs(nodes, n, m, ii01, nnbr1, nja, njasln, & + inbr1, amat, idxglo, chat1j) + call this%xt3d_amat_nbrs(nodes, m, ii11, nnbr1, nja, njasln, & + inbr1, amat, idxglo, chat1j) + call this%xt3d_amat_nbrnbrs(nodes, m, n, ii10, nnbr0, nja, njasln, & + inbr0, amat, idxglo, chati0) else - call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs) - call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs) - endif + call this%xt3d_rhs(nodes, n, m, nnbr0, inbr0, chati0, hnew, rhs) + call this%xt3d_rhs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, rhs) + end if ! ! -- Return return @@ -725,19 +762,19 @@ subroutine xt3d_fn(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) ! -- dummy class(Xt3dType) :: this integer(I4B) :: kiter - integer(I4B),intent(in) :: nodes - integer(I4B),intent(in) :: nja - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amat - integer(I4B),intent(in),dimension(nja) :: idxglo - real(DP),intent(inout),dimension(nodes) :: rhs - real(DP),intent(inout),dimension(nodes) :: hnew + integer(I4B), intent(in) :: nodes + integer(I4B), intent(in) :: nja + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amat + integer(I4B), intent(in), dimension(nja) :: idxglo + real(DP), intent(inout), dimension(nodes) :: rhs + real(DP), intent(inout), dimension(nodes) :: hnew ! -- local integer(I4B) :: n, m, ipos ! integer(I4B) :: nnbr0 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10 - integer(I4B),dimension(this%nbrmax) :: inbr0 + integer(I4B), dimension(this%nbrmax) :: inbr0 integer(I4B) :: iups, idn real(DP) :: topup, botup, derv, term ! ------------------------------------------------------------------------------ @@ -745,28 +782,28 @@ subroutine xt3d_fn(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) ! -- Update amat and rhs with Newton terms do n = 1, nodes ! -- Skip if inactive. - if (this%ibound(n).eq.0) cycle + if (this%ibound(n) .eq. 0) cycle ! -- No Newton correction if amat saved (which implies no rhs option) ! -- and all connections for the cell are permanently confined. if (this%lamatsaved) then if (this%iallpc(n) == 1) cycle end if - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load neighbors of cell. Set cell numbers for inactive ! -- neighbors to zero. call this%xt3d_load_inbr(n, nnbr0, inbr0) ! -- Loop over active neighbors of cell 0 that have a higher ! -- cell number (taking advantage of reciprocity). - do il0 = 1,nnbr0 + do il0 = 1, nnbr0 ipos = this%dis%con%ia(n) + il0 if (this%dis%con%mask(ipos) == 0) cycle - + m = inbr0(il0) ! -- Skip if neighbor is inactive or has lower cell number. - if ((inbr0(il0).eq.0).or.(m.lt.n)) cycle + if ((inbr0(il0) .eq. 0) .or. (m .lt. n)) cycle ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! determine upstream node iups = m if (hnew(m) < hnew(n)) iups = n @@ -774,15 +811,15 @@ subroutine xt3d_fn(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) if (iups == n) idn = m ! -- no Newton terms if upstream cell is confined ! -- and no rhs option - if ((this%icelltype(iups) == 0).and.(this%ixt3d.eq.1)) cycle + if ((this%icelltype(iups) == 0) .and. (this%ixt3d .eq. 1)) cycle ! -- Set the upstream top and bot, and then recalculate for a ! vertically staggered horizontal connection topup = this%dis%top(iups) botup = this%dis%bot(iups) - if(this%dis%con%ihc(jjs01) == 2) then + if (this%dis%con%ihc(jjs01) == 2) then topup = min(this%dis%top(n), this%dis%top(m)) botup = max(this%dis%bot(n), this%dis%bot(m)) - endif + end if ! derivative term derv = sQuadraticSaturationDerivative(topup, botup, hnew(iups)) term = this%qsat(ii01) * derv @@ -794,7 +831,7 @@ subroutine xt3d_fn(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) ! fill in row of m amat(idxglo(ii10)) = amat(idxglo(ii10)) - term rhs(m) = rhs(m) - term * hnew(n) - ! fill Jacobian for m being the upstream node + ! fill Jacobian for m being the upstream node else ! fill in row of n amat(idxglo(ii01)) = amat(idxglo(ii01)) + term @@ -803,8 +840,8 @@ subroutine xt3d_fn(this, kiter, nodes, nja, njasln, amat, idxglo, rhs, hnew) amat(idxglo(ii11)) = amat(idxglo(ii11)) - term rhs(m) = rhs(m) - term * hnew(m) end if - enddo - enddo + end do + end do ! ! -- Return return @@ -820,56 +857,56 @@ subroutine xt3d_flowja(this, hnew, flowja) use Xt3dAlgorithmModule, only: qconds ! -- dummy class(Xt3dType) :: this - real(DP),intent(inout),dimension(:) :: hnew - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(inout), dimension(:) :: hnew + real(DP), intent(inout), dimension(:) :: flowja ! -- local integer(I4B) :: n, ipos, m, nodes real(DP) :: qnm, qnbrs logical :: allhc0, allhc1 integer(I4B) :: nnbr0, nnbr1 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10 - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 real(DP) :: ar01, ar10 - real(DP),dimension(this%nbrmax,3) :: vc0, vn0, vc1, vn1 - real(DP),dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n - real(DP),dimension(3,3) :: ck0, ck1 + real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1 + real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n + real(DP), dimension(3, 3) :: ck0, ck1 real(DP) :: chat01 - real(DP),dimension(this%nbrmax) :: chati0, chat1j + real(DP), dimension(this%nbrmax) :: chati0, chat1j ! ------------------------------------------------------------------------------ ! ! -- Calculate the flow across each cell face and store in flowja nodes = this%dis%nodes do n = 1, nodes ! -- Skip if inactive. - if (this%ibound(n).eq.0) cycle - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + if (this%ibound(n) .eq. 0) cycle + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load conductivity and connection info for cell 0. - call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & - ck0, allhc0) + call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & + ck0, allhc0) ! -- Loop over active neighbors of cell 0 that have a higher ! -- cell number (taking advantage of reciprocity). - do il0 = 1,nnbr0 + do il0 = 1, nnbr0 m = inbr0(il0) ! -- Skip if neighbor is inactive or has lower cell number. - if ((inbr0(il0).eq.0).or.(m.lt.n)) cycle - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 + if ((inbr0(il0) .eq. 0) .or. (m .lt. n)) cycle + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 ! -- Load conductivity and connection info for cell 1. - call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & - ck1, allhc1) + call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & + ck1, allhc1) ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! -- Compute areas. - if (this%inewton /= 0) & + if (this%inewton /= 0) & call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew) call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew) ! -- Compute "conductances" for interface between ! -- cells 0 and 1. - call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & - ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & - this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) + call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, ck0, & + nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! -- Contribution to flow from primary connection. - qnm = chat01*(hnew(m) - hnew(n)) + qnm = chat01 * (hnew(m) - hnew(n)) ! -- Contribution from immediate neighbors of node 0. call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs) qnm = qnm + qnbrs @@ -878,9 +915,9 @@ subroutine xt3d_flowja(this, hnew, flowja) qnm = qnm - qnbrs ipos = ii01 flowja(ipos) = flowja(ipos) + qnm - flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - qnm - enddo - enddo + flowja(this%dis%con%isym(ipos)) = flowja(this%dis%con%isym(ipos)) - qnm + end do + end do ! ! -- Return return @@ -898,8 +935,8 @@ subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb) ! -- dummy class(Xt3dType) :: this integer(I4B) :: n, m - real(DP),intent(inout),dimension(:) :: hnew - real(DP),intent(inout),dimension(:) :: flowja + real(DP), intent(inout), dimension(:) :: hnew + real(DP), intent(inout), dimension(:) :: flowja real(DP) :: condhfb ! -- local ! @@ -908,14 +945,14 @@ subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb) !!! integer(I4B), parameter :: nbrmax = 10 integer(I4B) :: nnbr0, nnbr1 integer(I4B) :: il0, ii01, jjs01, il01, il10, ii00, ii11, ii10, il - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 integer(I4B) :: ipos real(DP) :: ar01, ar10 - real(DP),dimension(this%nbrmax,3) :: vc0, vn0, vc1, vn1 - real(DP),dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n - real(DP),dimension(3,3) :: ck0, ck1 + real(DP), dimension(this%nbrmax, 3) :: vc0, vn0, vc1, vn1 + real(DP), dimension(this%nbrmax) :: dl0, dl0n, dl1, dl1n + real(DP), dimension(3, 3) :: ck0, ck1 real(DP) :: chat01 - real(DP),dimension(this%nbrmax) :: chati0, chat1j + real(DP), dimension(this%nbrmax) :: chati0, chat1j real(DP) :: qnm, qnbrs real(DP) :: term ! ------------------------------------------------------------------------------ @@ -924,24 +961,24 @@ subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb) ! -- put into amat and rhs as appropriate ! nodes = this%dis%nodes - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 ! -- Load conductivity and connection info for cell 0. - call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & - ck0, allhc0) + call this%xt3d_load(nodes, n, nnbr0, inbr0, vc0, vn0, dl0, dl0n, & + ck0, allhc0) ! -- Find local neighbor number of cell 1. - do il = 1,nnbr0 - if (inbr0(il).eq.m) then + do il = 1, nnbr0 + if (inbr0(il) .eq. m) then il0 = il exit end if end do - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 ! -- Load conductivity and connection info for cell 1. - call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & - ck1, allhc1) + call this%xt3d_load(nodes, m, nnbr1, inbr1, vc1, vn1, dl1, dl1n, & + ck1, allhc1) ! -- Set various indices. - call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + call this%xt3d_indices(n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! -- Compute areas. if (this%inewton /= 0) then ar01 = DONE @@ -951,32 +988,32 @@ subroutine xt3d_flowjahfb(this, n, m, hnew, flowja, condhfb) end if ! -- Compute "conductances" for interface between ! -- cells 0 and 1. - call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & - ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & - this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) + call qconds(this%nbrmax, nnbr0, inbr0, il01, vc0, vn0, dl0, dl0n, & + ck0, nnbr1, inbr1, il10, vc1, vn1, dl1, dl1n, ck1, ar01, ar10, & + this%vcthresh, allhc0, allhc1, chat01, chati0, chat1j) ! -- Apply scale factor to compute "conductances" for hfb correction - if(condhfb > DZERO) then - term = chat01/(chat01 + condhfb) + if (condhfb > DZERO) then + term = chat01 / (chat01 + condhfb) else term = -condhfb - endif - chat01 = -chat01*term - chati0 = -chati0*term - chat1j = -chat1j*term + end if + chat01 = -chat01 * term + chati0 = -chati0 * term + chat1j = -chat1j * term ! -- Contribution to flow from primary connection. - qnm = chat01*(hnew(m) - hnew(n)) + qnm = chat01 * (hnew(m) - hnew(n)) ! -- Contribution from immediate neighbors of node 0. call this%xt3d_qnbrs(nodes, n, m, nnbr0, inbr0, chati0, hnew, qnbrs) qnm = qnm + qnbrs ! -- Contribution from immediate neighbors of node 1. call this%xt3d_qnbrs(nodes, m, n, nnbr1, inbr1, chat1j, hnew, qnbrs) qnm = qnm - qnbrs - ! -- If Newton, scale conductance-like coefficients by the + ! -- If Newton, scale conductance-like coefficients by the ! -- actual area. if (this%inewton /= 0) then call this%xt3d_areas(nodes, n, m, jjs01, .true., ar01, ar10, hnew) call this%xt3d_areas(nodes, n, m, jjs01, .false., ar01, ar10, hnew) - qnm = qnm*ar01 + qnm = qnm * ar01 end if ipos = ii01 flowja(ipos) = flowja(ipos) + qnm @@ -998,18 +1035,20 @@ subroutine xt3d_da(this) ! -- dummy class(Xt3dType) :: this ! ------------------------------------------------------------------------------ - ! + ! ! -- Deallocate arrays if (this%ixt3d /= 0) then call mem_deallocate(this%iax) call mem_deallocate(this%jax) call mem_deallocate(this%idxglox) + call mem_deallocate(this%ia_xt3d) + call mem_deallocate(this%ja_xt3d) call mem_deallocate(this%rmatck) call mem_deallocate(this%qsat) call mem_deallocate(this%amatpc) call mem_deallocate(this%amatpcx) call mem_deallocate(this%iallpc) - endif + end if ! ! -- Scalars call mem_deallocate(this%ixt3d) @@ -1051,7 +1090,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%vcthresh, 'VCTHRESH', this%memoryPath) call mem_allocate(this%lamatsaved, 'LAMATSAVED', this%memoryPath) call mem_allocate(this%ldispersion, 'LDISPERSION', this%memoryPath) - ! + ! ! -- Initialize value this%ixt3d = 0 this%nbrmax = 0 @@ -1109,7 +1148,7 @@ subroutine allocate_arrays(this) ! permanently confined and precalculate matrix terms case where ! conductances do not depend on head call this%xt3d_iallpc() - endif + end if ! ! -- Allocate space for precalculated matrix terms if (this%lamatsaved) then @@ -1151,10 +1190,10 @@ subroutine xt3d_iallpc(this) ! -- local integer(I4B) :: n, m, mm, il0, il1 integer(I4B) :: nnbr0, nnbr1 - integer(I4B),dimension(this%nbrmax) :: inbr0, inbr1 + integer(I4B), dimension(this%nbrmax) :: inbr0, inbr1 ! ------------------------------------------------------------------------------ ! - if(this%ixt3d == 2) then + if (this%ixt3d == 2) then this%lamatsaved = .false. call mem_allocate(this%iallpc, 0, 'IALLPC', this%memoryPath) else @@ -1172,28 +1211,28 @@ subroutine xt3d_iallpc(this) this%iallpc(n) = 0 cycle end if - nnbr0 = this%dis%con%ia(n+1) - this%dis%con%ia(n) - 1 + nnbr0 = this%dis%con%ia(n + 1) - this%dis%con%ia(n) - 1 call this%xt3d_load_inbr(n, nnbr0, inbr0) - do il0 = 1,nnbr0 + do il0 = 1, nnbr0 m = inbr0(il0) - if (m.lt.n) cycle + if (m .lt. n) cycle if (this%icelltype(m) /= 0) then this%iallpc(n) = 0 this%iallpc(m) = 0 cycle end if - nnbr1 = this%dis%con%ia(m+1) - this%dis%con%ia(m) - 1 + nnbr1 = this%dis%con%ia(m + 1) - this%dis%con%ia(m) - 1 call this%xt3d_load_inbr(m, nnbr1, inbr1) - do il1 = 1,nnbr1 + do il1 = 1, nnbr1 mm = inbr1(il1) if (this%icelltype(mm) /= 0) then this%iallpc(n) = 0 this%iallpc(m) = 0 this%iallpc(mm) = 0 end if - enddo - enddo - enddo + end do + end do + end do ! ! -- If any cells have all permanently confined connections then ! performance can be improved by precalculating coefficients @@ -1204,10 +1243,10 @@ subroutine xt3d_iallpc(this) this%lamatsaved = .true. exit end if - enddo + end do end if ! - if (.not.this%lamatsaved) then + if (.not. this%lamatsaved) then call mem_deallocate(this%iallpc) call mem_allocate(this%iallpc, 0, 'IALLPC', this%memoryPath) end if @@ -1215,9 +1254,9 @@ subroutine xt3d_iallpc(this) ! -- Return return end subroutine xt3d_iallpc - - subroutine xt3d_indices(this, n, m, il0, ii01, jjs01, il01, il10, & - ii00, ii11, ii10) + + subroutine xt3d_indices(this, n, m, il0, ii01, jjs01, il01, il10, & + ii00, ii11, ii10) ! ****************************************************************************** ! xt3d_indices -- Set various indices for XT3D. ! ****************************************************************************** @@ -1266,12 +1305,12 @@ subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc) ! -- dummy class(Xt3dType) :: this logical :: allhc - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr - real(DP),dimension(this%nbrmax,3) :: vc, vn - real(DP),dimension(this%nbrmax) :: dl, dln - real(DP),dimension(3,3) :: ck + integer(I4B), dimension(this%nbrmax) :: inbr + real(DP), dimension(this%nbrmax, 3) :: vc, vn + real(DP), dimension(this%nbrmax) :: dl, dln + real(DP), dimension(3, 3) :: ck ! -- local integer(I4B) :: il, ii, jj, jjs integer(I4B) :: ihcnjj @@ -1281,17 +1320,9 @@ subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc) ! ! -- Set conductivity tensor for cell. ck = DZERO - ck(1,1) = this%k11(n) - if(this%ik22 == 0) then - ck(2,2) = ck(1,1) - else - ck(2,2) = this%k22(n) - end if - if(this%ik33 == 0) then - ck(3,3) = ck(1,1) - else - ck(3,3) = this%k33(n) - endif + ck(1, 1) = this%k11(n) + ck(2, 2) = this%k22(n) + ck(3, 3) = this%k33(n) call this%xt3d_fillrmatck(n) ck = matmul(this%rmatck, ck) ck = matmul(ck, transpose(this%rmatck)) @@ -1302,31 +1333,31 @@ subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc) ! -- lengths. Also determine if all active connections are ! -- horizontal. allhc = .true. - do il = 1,nnbr + do il = 1, nnbr ii = il + this%dis%con%ia(n) jj = this%dis%con%ja(ii) jjs = this%dis%con%jas(ii) - if (this%ibound(jj).ne.0) then + if (this%ibound(jj) .ne. 0) then inbr(il) = jj satn = this%sat(n) satjj = this%sat(jj) ! -- DISV and DIS ihcnjj = this%dis%con%ihc(jjs) - call this%dis%connection_normal(n, jj, ihcnjj, & - vn(il, 1), vn(il, 2), vn(il, 3), ii) - call this%dis%connection_vector(n, jj, this%nozee, satn, satjj, & - ihcnjj, vc(il, 1), vc(il, 2), vc(il, 3), dltot) - if(jj > n) then + call this%dis%connection_normal(n, jj, ihcnjj, vn(il, 1), vn(il, 2), & + vn(il, 3), ii) + call this%dis%connection_vector(n, jj, this%nozee, satn, satjj, ihcnjj, & + vc(il, 1), vc(il, 2), vc(il, 3), dltot) + if (jj > n) then cl1njj = this%dis%con%cl1(jjs) cl2njj = this%dis%con%cl2(jjs) else cl1njj = this%dis%con%cl2(jjs) cl2njj = this%dis%con%cl1(jjs) - endif - ooclsum = 1d0/(cl1njj + cl2njj) - dl(il) = dltot*cl1njj*ooclsum - dln(il) = dltot*cl2njj*ooclsum - if (this%dis%con%ihc(jjs).eq.0) allhc = .false. + end if + ooclsum = 1d0 / (cl1njj + cl2njj) + dl(il) = dltot * cl1njj * ooclsum + dln(il) = dltot * cl2njj * ooclsum + if (this%dis%con%ihc(jjs) .eq. 0) allhc = .false. else inbr(il) = 0 end if @@ -1334,7 +1365,7 @@ subroutine xt3d_load(this, nodes, n, nnbr, inbr, vc, vn, dl, dln, ck, allhc) ! return end subroutine xt3d_load - + subroutine xt3d_load_inbr(this, n, nnbr, inbr) ! ****************************************************************************** ! xt3d_load_inbr -- Load neighbor list for a cell. @@ -1346,17 +1377,17 @@ subroutine xt3d_load_inbr(this, n, nnbr, inbr) ! -- dummy class(Xt3dType) :: this integer(I4B) :: n, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr + integer(I4B), dimension(this%nbrmax) :: inbr ! -- local integer(I4B) :: il, ii, jj ! ------------------------------------------------------------------------------ ! ! -- Load neighbors of cell. Set cell numbers for inactive ! -- neighbors to zero so xt3d knows to ignore them. - do il = 1,nnbr + do il = 1, nnbr ii = il + this%dis%con%ia(n) jj = this%dis%con%ja(ii) - if (this%ibound(jj).ne.0) then + if (this%ibound(jj) .ne. 0) then inbr(il) = jj else inbr(il) = 0 @@ -1404,7 +1435,7 @@ subroutine xt3d_areas(this, nodes, n, m, jjs01, lsat, ar01, ar10, hnew) botm = this%dis%bot(m) thksatn = topn - botn thksatm = topm - botm - if (this%dis%con%ihc(jjs01).eq.2) then + if (this%dis%con%ihc(jjs01) .eq. 2) then ! -- vertically staggered sill_top = min(topn, topm) sill_bot = max(botn, botm) @@ -1424,7 +1455,7 @@ subroutine xt3d_areas(this, nodes, n, m, jjs01, lsat, ar01, ar10, hnew) else satups = this%sat(m) end if - ar01 = ar01*satups + ar01 = ar01 * satups end if ar10 = ar01 else @@ -1451,13 +1482,13 @@ subroutine xt3d_areas(this, nodes, n, m, jjs01, lsat, ar01, ar10, hnew) end if ar01 = this%dis%con%hwva(jjs01) * thksatn ar10 = this%dis%con%hwva(jjs01) * thksatm - endif + end if ! return end subroutine xt3d_areas - subroutine xt3d_amat_nbrs(this, nodes, n, idiag, nnbr, nja, & - njasln, inbr, amat, idxglo, chat) + subroutine xt3d_amat_nbrs(this, nodes, n, idiag, nnbr, nja, & + njasln, inbr, amat, idxglo, chat) ! ****************************************************************************** ! xt3d_amat_nbrs -- Add contributions from neighbors to amat. ! ****************************************************************************** @@ -1467,29 +1498,29 @@ subroutine xt3d_amat_nbrs(this, nodes, n, idiag, nnbr, nja, & ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, idiag, nnbr, nja, njasln - integer(I4B),dimension(this%nbrmax) :: inbr - integer(I4B),intent(in),dimension(nja) :: idxglo - real(DP),dimension(njasln),intent(inout) :: amat - real(DP),dimension(this%nbrmax) :: chat + integer(I4B), dimension(this%nbrmax) :: inbr + integer(I4B), intent(in), dimension(nja) :: idxglo + real(DP), dimension(njasln), intent(inout) :: amat + real(DP), dimension(this%nbrmax) :: chat ! -- local integer(I4B) :: iil, iii ! ------------------------------------------------------------------------------ ! - do iil = 1,nnbr - if (inbr(iil).ne.0) then + do iil = 1, nnbr + if (inbr(iil) .ne. 0) then iii = this%dis%con%ia(n) + iil amat(idxglo(idiag)) = amat(idxglo(idiag)) - chat(iil) - amat(idxglo(iii)) = amat(idxglo(iii)) + chat(iil) - endif - enddo + amat(idxglo(iii)) = amat(idxglo(iii)) + chat(iil) + end if + end do ! return end subroutine xt3d_amat_nbrs - subroutine xt3d_amat_nbrnbrs(this, nodes, n, m, ii01, nnbr, nja, & - njasln, inbr, amat, idxglo, chat) + subroutine xt3d_amat_nbrnbrs(this, nodes, n, m, ii01, nnbr, nja, & + njasln, inbr, amat, idxglo, chat) ! ****************************************************************************** ! xt3d_amat_nbrnbrs -- Add contributions from neighbors of neighbor to amat. ! ****************************************************************************** @@ -1499,30 +1530,30 @@ subroutine xt3d_amat_nbrnbrs(this, nodes, n, m, ii01, nnbr, nja, & ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, m, ii01, nnbr, nja, njasln - integer(I4B),dimension(this%nbrmax) :: inbr - integer(I4B),intent(in),dimension(nja) :: idxglo - real(DP),dimension(njasln),intent(inout) :: amat - real(DP),dimension(this%nbrmax) :: chat + integer(I4B), dimension(this%nbrmax) :: inbr + integer(I4B), intent(in), dimension(nja) :: idxglo + real(DP), dimension(njasln), intent(inout) :: amat + real(DP), dimension(this%nbrmax) :: chat ! -- local integer(I4B) :: iil, iii, jjj, iixjjj, iijjj ! ------------------------------------------------------------------------------ ! - do iil = 1,nnbr - if (inbr(iil).ne.0) then + do iil = 1, nnbr + if (inbr(iil) .ne. 0) then amat(idxglo(ii01)) = amat(idxglo(ii01)) + chat(iil) iii = this%dis%con%ia(m) + iil jjj = this%dis%con%ja(iii) call this%xt3d_get_iinmx(n, jjj, iixjjj) - if (iixjjj.ne.0) then + if (iixjjj .ne. 0) then amat(this%idxglox(iixjjj)) = amat(this%idxglox(iixjjj)) - chat(iil) else call this%xt3d_get_iinm(n, jjj, iijjj) amat(idxglo(iijjj)) = amat(idxglo(iijjj)) - chat(iil) - endif - endif - enddo + end if + end if + end do ! return end subroutine xt3d_amat_nbrnbrs @@ -1537,19 +1568,19 @@ subroutine xt3d_amatpc_nbrs(this, nodes, n, idiag, nnbr, inbr, chat) ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, idiag, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr - real(DP),dimension(this%nbrmax) :: chat + integer(I4B), dimension(this%nbrmax) :: inbr + real(DP), dimension(this%nbrmax) :: chat ! -- local integer(I4B) :: iil, iii ! ------------------------------------------------------------------------------ ! - do iil = 1,nnbr + do iil = 1, nnbr iii = this%dis%con%ia(n) + iil this%amatpc(idiag) = this%amatpc(idiag) - chat(iil) - this%amatpc(iii) = this%amatpc(iii) + chat(iil) - enddo + this%amatpc(iii) = this%amatpc(iii) + chat(iil) + end do ! return end subroutine xt3d_amatpc_nbrs @@ -1565,26 +1596,26 @@ subroutine xt3d_amatpcx_nbrnbrs(this, nodes, n, m, ii01, nnbr, inbr, chat) ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, m, ii01, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr - real(DP),dimension(this%nbrmax) :: chat + integer(I4B), dimension(this%nbrmax) :: inbr + real(DP), dimension(this%nbrmax) :: chat ! -- local integer(I4B) :: iil, iii, jjj, iixjjj, iijjj ! ------------------------------------------------------------------------------ ! - do iil = 1,nnbr + do iil = 1, nnbr this%amatpc(ii01) = this%amatpc(ii01) + chat(iil) iii = this%dis%con%ia(m) + iil jjj = this%dis%con%ja(iii) call this%xt3d_get_iinmx(n, jjj, iixjjj) - if (iixjjj.ne.0) then + if (iixjjj .ne. 0) then this%amatpcx(iixjjj) = this%amatpcx(iixjjj) - chat(iil) else call this%xt3d_get_iinm(n, jjj, iijjj) this%amatpc(iijjj) = this%amatpc(iijjj) - chat(iil) - endif - enddo + end if + end do ! return end subroutine xt3d_amatpcx_nbrnbrs @@ -1606,13 +1637,13 @@ subroutine xt3d_get_iinm(this, n, m, iinm) ! ------------------------------------------------------------------------------ ! iinm = 0 - do ii = this%dis%con%ia(n), this%dis%con%ia(n+1)-1 + do ii = this%dis%con%ia(n), this%dis%con%ia(n + 1) - 1 jj = this%dis%con%ja(ii) - if (jj.eq.m) then + if (jj .eq. m) then iinm = ii exit - endif - enddo + end if + end do ! return end subroutine xt3d_get_iinm @@ -1634,19 +1665,19 @@ subroutine xt3d_get_iinmx(this, n, m, iinmx) ! ------------------------------------------------------------------------------ ! iinmx = 0 - do iix = this%iax(n), this%iax(n+1)-1 + do iix = this%iax(n), this%iax(n + 1) - 1 jjx = this%jax(iix) - if (jjx.eq.m) then + if (jjx .eq. m) then iinmx = iix exit - endif - enddo + end if + end do ! return end subroutine xt3d_get_iinmx - subroutine xt3d_rhs(this, nodes, n, m, nnbr, inbr, chat, hnew, & - rhs) + subroutine xt3d_rhs(this, nodes, n, m, nnbr, inbr, chat, hnew, & + rhs) ! ****************************************************************************** ! xt3d_rhs -- Add contributions to rhs. ! ****************************************************************************** @@ -1656,31 +1687,31 @@ subroutine xt3d_rhs(this, nodes, n, m, nnbr, inbr, chat, hnew, & ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, m, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr - real(DP),dimension(this%nbrmax) :: chat - real(DP),intent(inout),dimension(nodes) :: hnew, rhs + integer(I4B), dimension(this%nbrmax) :: inbr + real(DP), dimension(this%nbrmax) :: chat + real(DP), intent(inout), dimension(nodes) :: hnew, rhs ! -- local integer(I4B) :: iil, iii, jjj real(DP) :: term ! ------------------------------------------------------------------------------ ! - do iil = 1,nnbr - if (inbr(iil).ne.0) then + do iil = 1, nnbr + if (inbr(iil) .ne. 0) then iii = iil + this%dis%con%ia(n) jjj = this%dis%con%ja(iii) - term = chat(iil)*(hnew(jjj)-hnew(n)) + term = chat(iil) * (hnew(jjj) - hnew(n)) rhs(n) = rhs(n) - term rhs(m) = rhs(m) + term - endif - enddo + end if + end do ! return end subroutine xt3d_rhs - subroutine xt3d_qnbrs(this, nodes, n, m, nnbr, inbr, chat, hnew, & - qnbrs) + subroutine xt3d_qnbrs(this, nodes, n, m, nnbr, inbr, chat, hnew, & + qnbrs) ! ****************************************************************************** ! xt3d_qnbrs -- Add contributions to flow from neighbors. ! ****************************************************************************** @@ -1690,26 +1721,26 @@ subroutine xt3d_qnbrs(this, nodes, n, m, nnbr, inbr, chat, hnew, & ! -- module ! -- dummy class(Xt3dType) :: this - integer(I4B),intent(in) :: nodes + integer(I4B), intent(in) :: nodes integer(I4B) :: n, m, nnbr - integer(I4B),dimension(this%nbrmax) :: inbr + integer(I4B), dimension(this%nbrmax) :: inbr real(DP) :: qnbrs - real(DP),dimension(this%nbrmax) :: chat - real(DP),intent(inout),dimension(nodes) :: hnew + real(DP), dimension(this%nbrmax) :: chat + real(DP), intent(inout), dimension(nodes) :: hnew ! -- local integer(I4B) :: iil, iii, jjj real(DP) :: term ! ------------------------------------------------------------------------------ ! qnbrs = 0d0 - do iil = 1,nnbr - if (inbr(iil).ne.0) then + do iil = 1, nnbr + if (inbr(iil) .ne. 0) then iii = iil + this%dis%con%ia(n) jjj = this%dis%con%ja(iii) - term = chat(iil)*(hnew(jjj)-hnew(n)) + term = chat(iil) * (hnew(jjj) - hnew(n)) qnbrs = qnbrs + term - endif - enddo + end if + end do ! return end subroutine xt3d_qnbrs @@ -1741,24 +1772,24 @@ subroutine xt3d_fillrmatck(this, n) ang1 = this%angle1(n) ang2 = this%angle2(n) ang3 = this%angle3(n) - endif + end if s1 = sin(ang1) c1 = cos(ang1) s2 = sin(ang2) c2 = cos(ang2) s3 = sin(ang3) c3 = cos(ang3) - this%rmatck(1,1) = c1*c2 - this%rmatck(1,2) = c1*s2*s3 - s1*c3 - this%rmatck(1,3) = -c1*s2*c3 - s1*s3 - this%rmatck(2,1) = s1*c2 - this%rmatck(2,2) = s1*s2*s3 + c1*c3 - this%rmatck(2,3) = -s1*s2*c3 + c1*s3 - this%rmatck(3,1) = s2 - this%rmatck(3,2) = -c2*s3 - this%rmatck(3,3) = c2*c3 + this%rmatck(1, 1) = c1 * c2 + this%rmatck(1, 2) = c1 * s2 * s3 - s1 * c3 + this%rmatck(1, 3) = -c1 * s2 * c3 - s1 * s3 + this%rmatck(2, 1) = s1 * c2 + this%rmatck(2, 2) = s1 * s2 * s3 + c1 * c3 + this%rmatck(2, 3) = -s1 * s2 * c3 + c1 * s3 + this%rmatck(3, 1) = s2 + this%rmatck(3, 2) = -c2 * s3 + this%rmatck(3, 3) = c2 * c3 ! return end subroutine xt3d_fillrmatck - + end module Xt3dModule diff --git a/src/Model/NumericalModel.f90 b/src/Model/NumericalModel.f90 index b8b3cbe206e..ecbebe9b515 100644 --- a/src/Model/NumericalModel.f90 +++ b/src/Model/NumericalModel.f90 @@ -14,24 +14,24 @@ module NumericalModelModule GetNumericalModelFromList type, extends(BaseModelType) :: NumericalModelType - character(len=LINELENGTH), pointer :: filename => null() !input file name - integer(I4B), pointer :: neq => null() !number of equations - integer(I4B), pointer :: nja => null() !number of connections - integer(I4B), pointer :: moffset => null() !offset of this model in the solution - integer(I4B), pointer :: icnvg => null() !convergence flag - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !csr row pointer - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !csr columns - real(DP), dimension(:), pointer, contiguous :: x => null() !dependent variable (head, conc, etc) - real(DP), dimension(:), pointer, contiguous :: rhs => null() !right-hand side vector - real(DP), dimension(:), pointer, contiguous :: cond => null() !conductance matrix - integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() !pointer to position in solution matrix - real(DP), dimension(:), pointer, contiguous :: xold => null() !dependent variable for previous timestep - real(DP), dimension(:), pointer, contiguous :: flowja => null() !intercell flows - integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !ibound array + character(len=LINELENGTH), pointer :: filename => null() !input file name + integer(I4B), pointer :: neq => null() !number of equations + integer(I4B), pointer :: nja => null() !number of connections + integer(I4B), pointer :: moffset => null() !offset of this model in the solution + integer(I4B), pointer :: icnvg => null() !convergence flag + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !csr row pointer + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !csr columns + real(DP), dimension(:), pointer, contiguous :: x => null() !dependent variable (head, conc, etc) + real(DP), dimension(:), pointer, contiguous :: rhs => null() !right-hand side vector + real(DP), dimension(:), pointer, contiguous :: cond => null() !conductance matrix + integer(I4B), dimension(:), pointer, contiguous :: idxglo => null() !pointer to position in solution matrix + real(DP), dimension(:), pointer, contiguous :: xold => null() !dependent variable for previous timestep + real(DP), dimension(:), pointer, contiguous :: flowja => null() !intercell flows + integer(I4B), dimension(:), pointer, contiguous :: ibound => null() !ibound array ! ! -- Derived types - type(ListType), pointer :: bndlist => null() !array of boundary packages for this model - class(DisBaseType), pointer :: dis => null() !discretization object + type(ListType), pointer :: bndlist => null() !array of boundary packages for this model + class(DisBaseType), pointer :: dis => null() !discretization object contains ! @@ -74,7 +74,7 @@ module NumericalModelModule procedure :: get_iasym end type NumericalModelType - contains +contains ! ! -- Type-bound procedures for a numerical model ! @@ -104,17 +104,17 @@ end subroutine model_rp subroutine model_ad(this) class(NumericalModelType) :: this end subroutine model_ad - - subroutine model_cf(this,kiter) + + subroutine model_cf(this, kiter) class(NumericalModelType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter end subroutine model_cf subroutine model_fc(this, kiter, amatsln, njasln, inwtflag) class(NumericalModelType) :: this - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amatsln + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amatsln integer(I4B), intent(in) :: inwtflag end subroutine model_fc @@ -127,32 +127,32 @@ end subroutine model_ptcchk subroutine model_ptc(this, kiter, neqsln, njasln, & ia, ja, x, rhs, amatsln, iptc, ptcf) class(NumericalModelType) :: this - integer(I4B),intent(in) :: kiter + integer(I4B), intent(in) :: kiter integer(I4B), intent(in) :: neqsln - integer(I4B),intent(in) :: njasln - integer(I4B), dimension(neqsln+1), intent(in) :: ia - integer(I4B),dimension(njasln),intent(in) :: ja + integer(I4B), intent(in) :: njasln + integer(I4B), dimension(neqsln + 1), intent(in) :: ia + integer(I4B), dimension(njasln), intent(in) :: ja real(DP), dimension(neqsln), intent(in) :: x real(DP), dimension(neqsln), intent(in) :: rhs - real(DP),dimension(njasln),intent(in) :: amatsln + real(DP), dimension(njasln), intent(in) :: amatsln integer(I4B), intent(inout) :: iptc - real(DP),intent(inout) :: ptcf + real(DP), intent(inout) :: ptcf end subroutine model_ptc subroutine model_nr(this, kiter, amatsln, njasln, inwtflag) class(NumericalModelType) :: this - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: njasln - real(DP),dimension(njasln),intent(inout) :: amatsln + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: njasln + real(DP), dimension(njasln), intent(inout) :: amatsln integer(I4B), intent(in) :: inwtflag end subroutine model_nr subroutine model_cc(this, innertot, kiter, iend, icnvgmod, cpak, ipak, dpak) class(NumericalModelType) :: this - integer(I4B),intent(in) :: innertot - integer(I4B),intent(in) :: kiter - integer(I4B),intent(in) :: iend - integer(I4B),intent(in) :: icnvgmod + integer(I4B), intent(in) :: innertot + integer(I4B), intent(in) :: kiter + integer(I4B), intent(in) :: iend + integer(I4B), intent(in) :: icnvgmod character(len=LENPAKLOC), intent(inout) :: cpak integer(I4B), intent(inout) :: ipak real(DP), intent(inout) :: dpak @@ -171,24 +171,24 @@ end subroutine model_nur subroutine model_cq(this, icnvg, isuppress_output) class(NumericalModelType) :: this - integer(I4B),intent(in) :: icnvg + integer(I4B), intent(in) :: icnvg integer(I4B), intent(in) :: isuppress_output end subroutine model_cq subroutine model_bd(this, icnvg, isuppress_output) class(NumericalModelType) :: this - integer(I4B),intent(in) :: icnvg + integer(I4B), intent(in) :: icnvg integer(I4B), intent(in) :: isuppress_output end subroutine model_bd subroutine model_bdcalc(this, icnvg) class(NumericalModelType) :: this - integer(I4B),intent(in) :: icnvg + integer(I4B), intent(in) :: icnvg end subroutine model_bdcalc subroutine model_bdsave(this, icnvg) class(NumericalModelType) :: this - integer(I4B),intent(in) :: icnvg + integer(I4B), intent(in) :: icnvg end subroutine model_bdsave subroutine model_ot(this) @@ -216,7 +216,7 @@ subroutine model_da(this) call mem_deallocate(this%nja) call mem_deallocate(this%icnvg) call mem_deallocate(this%moffset) - deallocate(this%filename) + deallocate (this%filename) ! ! -- Arrays call mem_deallocate(this%xold) @@ -225,7 +225,7 @@ subroutine model_da(this) ! ! -- derived types call this%bndlist%Clear() - deallocate(this%bndlist) + deallocate (this%bndlist) ! ! -- nullify pointers call mem_deallocate(this%x, 'X', this%memoryPath) @@ -263,7 +263,7 @@ end subroutine set_idsoln subroutine allocate_scalars(this, modelname) use MemoryManagerModule, only: mem_allocate class(NumericalModelType) :: this - character(len=*), intent(in) :: modelname + character(len=*), intent(in) :: modelname ! ! -- allocate basetype members call this%BaseModelType%allocate_scalars(modelname) @@ -273,8 +273,8 @@ subroutine allocate_scalars(this, modelname) call mem_allocate(this%nja, 'NJA', this%memoryPath) call mem_allocate(this%icnvg, 'ICNVG', this%memoryPath) call mem_allocate(this%moffset, 'MOFFSET', this%memoryPath) - allocate(this%filename) - allocate(this%bndlist) + allocate (this%filename) + allocate (this%bndlist) ! this%filename = '' this%neq = 0 @@ -341,7 +341,8 @@ subroutine set_iboundptr(this, iboundsln, varNameTgt, memPathTgt) ! -- local ! -- code this%ibound => iboundsln(this%moffset + 1:this%moffset + this%neq) - call mem_checkin(this%ibound, 'IBOUND', this%memoryPath, varNameTgt, memPathTgt) + call mem_checkin(this%ibound, 'IBOUND', this%memoryPath, varNameTgt, & + memPathTgt) end subroutine set_iboundptr subroutine get_mcellid(this, node, mcellid) @@ -353,10 +354,10 @@ subroutine get_mcellid(this, node, mcellid) character(len=20) :: cellid integer(I4B) :: ip, ipaknode, istart, istop class(BndType), pointer :: packobj - + if (node < 1) then cellid = '' - else if(node <= this%dis%nodes) then + else if (node <= this%dis%nodes) then call this%dis%noder_to_string(node, cellid) else cellid = '***ERROR***' @@ -364,18 +365,18 @@ subroutine get_mcellid(this, node, mcellid) istart = 1 do ip = 1, this%bndlist%Count() packobj => GetBndFromList(this%bndlist, ip) - if(packobj%npakeq == 0) cycle + if (packobj%npakeq == 0) cycle istop = istart + packobj%npakeq - 1 - if(istart <= ipaknode .and. ipaknode <= istop) then - write(cellid, '(a, a, a, i0, a, i0, a)') '(', & - trim(packobj%filtyp), '_', & + if (istart <= ipaknode .and. ipaknode <= istop) then + write (cellid, '(a, a, a, i0, a, i0, a)') '(', & + trim(packobj%filtyp), '_', & packobj%ibcnum, '-', ipaknode - packobj%ioffset, ')' exit - endif + end if istart = istop + 1 - enddo - endif - write(mcellid, '(i0, a, a, a, a)') this%id, '_', this%macronym, '-', & + end do + end if + write (mcellid, '(i0, a, a, a, a)') this%id, '_', this%macronym, '-', & trim(adjustl(cellid)) return end subroutine get_mcellid @@ -386,21 +387,21 @@ subroutine get_mnodeu(this, node, nodeu) integer(I4B), intent(in) :: node integer(I4B), intent(inout) :: nodeu ! -- local - if(node <= this%dis%nodes) then + if (node <= this%dis%nodes) then nodeu = this%dis%get_nodeuser(node) else nodeu = -(node - this%dis%nodes) - endif + end if return end subroutine get_mnodeu - - function get_iasym(this) result (iasym) + + function get_iasym(this) result(iasym) class(NumericalModelType) :: this integer(I4B) :: iasym iasym = 0 end function get_iasym - function CastAsNumericalModelClass(obj) result (res) + function CastAsNumericalModelClass(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(NumericalModelType), pointer :: res @@ -418,7 +419,7 @@ end function CastAsNumericalModelClass subroutine AddNumericalModelToList(list, model) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(NumericalModelType), pointer, intent(inout) :: model ! -- local class(*), pointer :: obj @@ -428,13 +429,13 @@ subroutine AddNumericalModelToList(list, model) ! return end subroutine AddNumericalModelToList - - function GetNumericalModelFromList(list, idx) result (res) + + function GetNumericalModelFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(NumericalModelType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(NumericalModelType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Model/NumericalPackage.f90 b/src/Model/NumericalPackage.f90 index 804224e9406..e451d272c24 100644 --- a/src/Model/NumericalPackage.f90 +++ b/src/Model/NumericalPackage.f90 @@ -1,4 +1,4 @@ -!> @brief This module contains the base numerical package type +!> @brief This module contains the base numerical package type !! !! This module contains the base model package class that is extended !! by all model packages. @@ -7,14 +7,14 @@ module NumericalPackageModule ! -- modules use KindModule, only: DP, I4B - use ConstantsModule, only: LENPACKAGENAME, LENMODELNAME, & - LENMEMPATH, LENFTYPE, LINELENGTH, & - LENVARNAME - use SimVariablesModule, only: errmsg - use SimModule, only: store_error - use BlockParserModule, only: BlockParserType - use BaseDisModule, only: DisBaseType - use MemoryHelperModule, only: create_mem_path + use ConstantsModule, only: LENPACKAGENAME, LENMODELNAME, & + LENMEMPATH, LENFTYPE, LINELENGTH, & + LENVARNAME + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use BlockParserModule, only: BlockParserType + use BaseDisModule, only: DisBaseType + use MemoryHelperModule, only: create_mem_path implicit none private @@ -23,29 +23,30 @@ module NumericalPackageModule type :: NumericalPackageType ! -- strings - character(len=LENMODELNAME) :: name_model = '' !< the name of the model that contains this package - character(len=LENPACKAGENAME) :: packName = '' !< name of the package - character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored - character(len=LENMEMPATH) :: memoryPathModel = '' !< the location in the memory manager where the variables + character(len=LENMODELNAME) :: name_model = '' !< the name of the model that contains this package + character(len=LENPACKAGENAME) :: packName = '' !< name of the package + character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored + character(len=LENMEMPATH) :: memoryPathModel = '' !< the location in the memory manager where the variables !! of the parent model are stored - character(len=LENFTYPE) :: filtyp = '' !< file type (CHD, DRN, RIV, etc.) - + character(len=LENFTYPE) :: filtyp = '' !< file type (CHD, DRN, RIV, etc.) + character(len=LENFTYPE), pointer :: package_type => null() !< package type (same as filtyp) stored in memory manager + ! -- integers - integer(I4B), pointer :: id => null() !< consecutive package number in model - integer(I4B), pointer :: inunit => null() !< unit number for input file - integer(I4B), pointer :: iout => null() !< unit number for writing package output - integer(I4B), pointer :: inewton => null() !< newton flag - integer(I4B), pointer :: iasym => null() !< package causes matrix asymmetry - integer(I4B), pointer :: iprpak => null() !< integer flag to echo input - integer(I4B), pointer :: iprflow => null() !< flag to print simulated flows - integer(I4B), pointer :: ipakcb => null() !< output flows (-1, 0, 1) - save_flows - integer(I4B), pointer :: ionper => null() !< stress period for next data - integer(I4B), pointer :: lastonper => null() !< last value of ionper (for checking) + integer(I4B), pointer :: id => null() !< consecutive package number in model + integer(I4B), pointer :: inunit => null() !< unit number for input file + integer(I4B), pointer :: iout => null() !< unit number for writing package output + integer(I4B), pointer :: inewton => null() !< newton flag + integer(I4B), pointer :: iasym => null() !< package causes matrix asymmetry + integer(I4B), pointer :: iprpak => null() !< integer flag to echo input + integer(I4B), pointer :: iprflow => null() !< flag to print simulated flows + integer(I4B), pointer :: ipakcb => null() !< output flows (-1, 0, 1) - save_flows + integer(I4B), pointer :: ionper => null() !< stress period for next data + integer(I4B), pointer :: lastonper => null() !< last value of ionper (for checking) ! ! -- derived types - type(BlockParserType) :: parser !< parser object for reading blocks of information - class(DisBaseType), pointer :: dis => null() !< model discretization object - + type(BlockParserType) :: parser !< parser object for reading blocks of information + class(DisBaseType), pointer :: dis => null() !< model discretization object + contains procedure :: set_names procedure :: allocate_scalars @@ -54,192 +55,196 @@ module NumericalPackageModule procedure :: get_block_data end type NumericalPackageType ! - contains +contains ! - !> @ brief Set package names + !> @ brief Set package names !! - !! Method to assign the filtyp (ftype), the model name, and package name for + !! Method to assign the filtyp (ftype), the model name, and package name for !! a package. This method also creates the memoryPath and memoryPathModel that - !! is used by the memory manager when variables are allocated. + !! is used by the memory manager when variables are allocated. !! - !< - subroutine set_names(this, ibcnum, name_model, pakname, ftype) - ! -- dummy variables - class(NumericalPackageType),intent(inout) :: this !< NumericalPackageType object - integer(I4B), intent(in) :: ibcnum !< unique package number - character(len=*), intent(in) :: name_model !< name of the model - character(len=*), intent(in) :: pakname !< name of the package - character(len=*), intent(in) :: ftype !< package type + !< + subroutine set_names(this, ibcnum, name_model, pakname, ftype) + ! -- dummy variables + class(NumericalPackageType), intent(inout) :: this !< NumericalPackageType object + integer(I4B), intent(in) :: ibcnum !< unique package number + character(len=*), intent(in) :: name_model !< name of the model + character(len=*), intent(in) :: pakname !< name of the package + character(len=*), intent(in) :: ftype !< package type + ! + ! -- set names + this%filtyp = ftype + this%name_model = name_model + if (pakname == '') then + write (this%packName, '(a, i0)') trim(ftype)//'-', ibcnum + else ! - ! -- set names - this%filtyp = ftype - this%name_model = name_model - if(pakname == '') then - write(this%packName,'(a, i0)') trim(ftype) // '-', ibcnum - else - ! - ! -- Ensure pakname has no spaces - if(index(trim(pakname), ' ') > 0) then - errmsg = 'Package name contains spaces: ' // trim(pakname) - call store_error(errmsg) - errmsg = 'Remove spaces from name.' - call store_error(errmsg, terminate=.TRUE.) - endif - ! - this%packName = pakname - endif - this%memoryPath = create_mem_path(name_model, this%packName) - this%memoryPathModel = create_mem_path(name_model) + ! -- Ensure pakname has no spaces + if (index(trim(pakname), ' ') > 0) then + errmsg = 'Package name contains spaces: '//trim(pakname) + call store_error(errmsg) + errmsg = 'Remove spaces from name.' + call store_error(errmsg, terminate=.TRUE.) + end if ! - ! -- return - return - end subroutine set_names - - !> @ brief Allocate package scalars + this%packName = pakname + end if + this%memoryPath = create_mem_path(name_model, this%packName) + this%memoryPathModel = create_mem_path(name_model) + ! + ! -- return + return + end subroutine set_names + + !> @ brief Allocate package scalars !! - !! Allocate and initialize base numerical package scalars. + !! Allocate and initialize base numerical package scalars. !! - !< - subroutine allocate_scalars(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate, mem_setptr - ! -- dummy variables - class(NumericalPackageType) :: this !< NumericalPackageType object - ! -- local variables - integer(I4B), pointer :: imodelnewton => null() - integer(I4B), pointer :: imodelprpak => null() - integer(I4B), pointer :: imodelprflow => null() - integer(I4B), pointer :: imodelpakcb => null() - ! - ! -- allocate scalars - call mem_allocate(this%id, 'ID', this%memoryPath) - call mem_allocate(this%inunit, 'INUNIT', this%memoryPath) - call mem_allocate(this%iout, 'IOUT', this%memoryPath) - call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) - call mem_allocate(this%iasym, 'IASYM', this%memoryPath) - call mem_allocate(this%iprpak, 'IPRPAK', this%memoryPath) - call mem_allocate(this%iprflow, 'IPRFLOW', this%memoryPath) - call mem_allocate(this%ipakcb, 'IPAKCB', this%memoryPath) - ! - call mem_allocate(this%ionper, 'IONPER', this%memoryPath) - call mem_allocate(this%lastonper, 'LASTONPER', this%memoryPath) - ! - ! -- set pointer to model variables - call mem_setptr(imodelnewton, 'INEWTON', this%memoryPathModel) - call mem_setptr(imodelprpak, 'IPRPAK', this%memoryPathModel) - call mem_setptr(imodelprflow, 'IPRFLOW', this%memoryPathModel) - call mem_setptr(imodelpakcb, 'IPAKCB', this%memoryPathModel) - ! - ! -- initialize - this%id = 0 - this%inunit = 0 - this%iout = 0 - this%inewton = imodelnewton - this%iasym = 0 - this%iprpak = imodelprpak - this%iprflow = imodelprflow - this%ipakcb = imodelpakcb - this%ionper = 0 - this%lastonper = 0 - ! - ! -- nullify unneeded pointers - imodelnewton => null() - imodelprpak => null() - imodelprflow => null() - imodelpakcb => null() - ! - ! -- return - return - end subroutine allocate_scalars + !< + subroutine allocate_scalars(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate, mem_setptr + ! -- dummy variables + class(NumericalPackageType) :: this !< NumericalPackageType object + ! -- local variables + integer(I4B), pointer :: imodelnewton => null() + integer(I4B), pointer :: imodelprpak => null() + integer(I4B), pointer :: imodelprflow => null() + integer(I4B), pointer :: imodelpakcb => null() + ! + ! -- allocate scalars + call mem_allocate(this%package_type, LENFTYPE, 'PACKAGE_TYPE', & + this%memoryPath) + call mem_allocate(this%id, 'ID', this%memoryPath) + call mem_allocate(this%inunit, 'INUNIT', this%memoryPath) + call mem_allocate(this%iout, 'IOUT', this%memoryPath) + call mem_allocate(this%inewton, 'INEWTON', this%memoryPath) + call mem_allocate(this%iasym, 'IASYM', this%memoryPath) + call mem_allocate(this%iprpak, 'IPRPAK', this%memoryPath) + call mem_allocate(this%iprflow, 'IPRFLOW', this%memoryPath) + call mem_allocate(this%ipakcb, 'IPAKCB', this%memoryPath) + ! + call mem_allocate(this%ionper, 'IONPER', this%memoryPath) + call mem_allocate(this%lastonper, 'LASTONPER', this%memoryPath) + ! + ! -- set pointer to model variables + call mem_setptr(imodelnewton, 'INEWTON', this%memoryPathModel) + call mem_setptr(imodelprpak, 'IPRPAK', this%memoryPathModel) + call mem_setptr(imodelprflow, 'IPRFLOW', this%memoryPathModel) + call mem_setptr(imodelpakcb, 'IPAKCB', this%memoryPathModel) + ! + ! -- initialize + this%package_type = this%filtyp + this%id = 0 + this%inunit = 0 + this%iout = 0 + this%inewton = imodelnewton + this%iasym = 0 + this%iprpak = imodelprpak + this%iprflow = imodelprflow + this%ipakcb = imodelpakcb + this%ionper = 0 + this%lastonper = 0 + ! + ! -- nullify unneeded pointers + imodelnewton => null() + imodelprpak => null() + imodelprflow => null() + imodelpakcb => null() + ! + ! -- return + return + end subroutine allocate_scalars - !> @ brief Deallocate package scalars + !> @ brief Deallocate package scalars !! - !! Deallocate and initialize base numerical package scalars. + !! Deallocate and initialize base numerical package scalars. !! - !< - subroutine da(this) - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy variables - class(NumericalPackageType) :: this !< NumericalPackageType object - ! - ! -- deallocate - call mem_deallocate(this%id) - call mem_deallocate(this%inunit) - call mem_deallocate(this%iout) - call mem_deallocate(this%inewton) - call mem_deallocate(this%iasym) - call mem_deallocate(this%iprpak) - call mem_deallocate(this%iprflow) - call mem_deallocate(this%ipakcb) - call mem_deallocate(this%ionper) - call mem_deallocate(this%lastonper) - ! - ! -- return - return - end subroutine da + !< + subroutine da(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy variables + class(NumericalPackageType) :: this !< NumericalPackageType object + ! + ! -- deallocate + call mem_deallocate(this%package_type, 'PACKAGE_TYPE', this%memoryPath) + call mem_deallocate(this%id) + call mem_deallocate(this%inunit) + call mem_deallocate(this%iout) + call mem_deallocate(this%inewton) + call mem_deallocate(this%iasym) + call mem_deallocate(this%iprpak) + call mem_deallocate(this%iprflow) + call mem_deallocate(this%ipakcb) + call mem_deallocate(this%ionper) + call mem_deallocate(this%lastonper) + ! + ! -- return + return + end subroutine da - !> @ brief Check ionper + !> @ brief Check ionper !! - !! Generic method to read and check ionperiod, which is used to determine - !! if new period data should be read from the input file. The check of + !! Generic method to read and check ionperiod, which is used to determine + !! if new period data should be read from the input file. The check of !! ionperiod also makes sure periods are increasing in subsequent period !! data blocks. !! - !< - subroutine read_check_ionper(this) - ! -- modules - use TdisModule, only: kper - ! -- dummy variables - class(NumericalPackageType), intent(inout) :: this !< NumericalPackageType object - ! - ! -- save last value and read period number - this%lastonper = this%ionper - this%ionper = this%parser%GetInteger() - ! - ! -- make check - if (this%ionper <= this%lastonper) then - write(errmsg, '(a, i0)') & - 'ERROR IN STRESS PERIOD ', kper - call store_error(errmsg) - write(errmsg, '(a, i0)') & - 'PERIOD NUMBERS NOT INCREASING. FOUND ', this%ionper - call store_error(errmsg) - write(errmsg, '(a, i0)') & - 'BUT LAST PERIOD BLOCK WAS ASSIGNED ', this%lastonper - call store_error(errmsg) - call this%parser%StoreErrorUnit() - endif - ! - ! -- return - return - end subroutine read_check_ionper + !< + subroutine read_check_ionper(this) + ! -- modules + use TdisModule, only: kper + ! -- dummy variables + class(NumericalPackageType), intent(inout) :: this !< NumericalPackageType object + ! + ! -- save last value and read period number + this%lastonper = this%ionper + this%ionper = this%parser%GetInteger() + ! + ! -- make check + if (this%ionper <= this%lastonper) then + write (errmsg, '(a, i0)') & + 'ERROR IN STRESS PERIOD ', kper + call store_error(errmsg) + write (errmsg, '(a, i0)') & + 'PERIOD NUMBERS NOT INCREASING. FOUND ', this%ionper + call store_error(errmsg) + write (errmsg, '(a, i0)') & + 'BUT LAST PERIOD BLOCK WAS ASSIGNED ', this%lastonper + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end if + ! + ! -- return + return + end subroutine read_check_ionper - !> @ brief Read griddata block for a package + !> @ brief Read griddata block for a package !! !! Generic method to read data in the GRIDDATA block for a package. !! - !< - subroutine get_block_data(this, tags, lfound, varinames) + !< + subroutine get_block_data(this, tags, lfound, varinames) ! -- modules use MemoryManagerModule, only: mem_setptr ! -- dummy variables - class(NumericalPackageType) :: this !< NumericalPackageType object - character(len=24), dimension(:), intent(in) :: tags !< vector with variable tags - logical, dimension(:), intent(inout) :: lfound !< boolean vector indicating of a variable tag was found - character(len=24), dimension(:), intent(in), optional :: varinames !< optional vector of variable names + class(NumericalPackageType) :: this !< NumericalPackageType object + character(len=24), dimension(:), intent(in) :: tags !< vector with variable tags + logical, dimension(:), intent(inout) :: lfound !< boolean vector indicating of a variable tag was found + character(len=24), dimension(:), intent(in), optional :: varinames !< optional vector of variable names ! -- local variables logical :: lkeyword logical :: endOfBlock integer(I4B) :: nsize integer(I4B) :: j - character(len=24) :: tmpvar + character(len=24) :: tmpvar character(len=LENVARNAME) :: varname character(len=LINELENGTH) :: keyword character(len=:), allocatable :: line integer(I4B) :: istart, istop, lloc integer(I4B), dimension(:), pointer, contiguous :: aint - real(DP), dimension(:), pointer, contiguous :: adbl + real(DP), dimension(:), pointer, contiguous :: adbl ! ! -- initialize nsize nsize = size(tags) @@ -262,19 +267,19 @@ subroutine get_block_data(this, tags, lfound, varinames) varname = tmpvar(1:LENVARNAME) if (keyword(1:1) == 'I') then call mem_setptr(aint, trim(varname), trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, aint, tags(j)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, aint, tags(j)) else call mem_setptr(adbl, trim(varname), trim(this%memoryPath)) - call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & - this%parser%iuactive, adbl, tags(j)) + call this%dis%read_grid_array(line, lloc, istart, istop, this%iout, & + this%parser%iuactive, adbl, tags(j)) end if exit tag_iter end if end do tag_iter - if (.not.lkeyword) then - write(errmsg,'(4x,a,a)')'ERROR. UNKNOWN GRIDDATA TAG: ', & - trim(keyword) + if (.not. lkeyword) then + write (errmsg, '(4x,a,a)') 'ERROR. UNKNOWN GRIDDATA TAG: ', & + trim(keyword) call store_error(errmsg) call this%parser%StoreErrorUnit() end if @@ -285,4 +290,4 @@ subroutine get_block_data(this, tags, lfound, varinames) end subroutine get_block_data end module NumericalPackageModule - + diff --git a/src/Model/TransportModel.f90 b/src/Model/TransportModel.f90 new file mode 100644 index 00000000000..f37082cc3cb --- /dev/null +++ b/src/Model/TransportModel.f90 @@ -0,0 +1,25 @@ +!> @brief This module contains the base transport model type +!! +!! This module contains the base class for transport models. +!! +!< + +module TransportModelModule + use KindModule, only: DP, I4B + use ConstantsModule, only: LENFTYPE + use SimVariablesModule, only: errmsg + use NumericalModelModule, only: NumericalModelType + + implicit none + + private + + public :: TransportModelType + + type, extends(NumericalModelType) :: TransportModelType + + contains + + end type TransportModelType + +end module TransportModelModule diff --git a/src/SimulationCreate.f90 b/src/SimulationCreate.f90 index 0145033aaab..f5d70a1a057 100644 --- a/src/SimulationCreate.f90 +++ b/src/SimulationCreate.f90 @@ -1,24 +1,25 @@ module SimulationCreateModule - use KindModule, only: DP, I4B, write_kindinfo - use ConstantsModule, only: LINELENGTH, LENMODELNAME, LENBIGLINE, DZERO - use SimVariablesModule, only: simfile, simlstfile, iout + use KindModule, only: DP, I4B, LGP, write_kindinfo + use ConstantsModule, only: LINELENGTH, LENMODELNAME, LENBIGLINE, DZERO + use SimVariablesModule, only: simfile, simlstfile, iout use GenericUtilitiesModule, only: sim_message, write_centered - use SimModule, only: store_error, count_errors, & - store_error_unit, MaxErrors - use VersionModule, only: write_listfile_header - use InputOutputModule, only: getunit, urword, openfile - use ArrayHandlersModule, only: expandarray, ifind - use BaseModelModule, only: BaseModelType - use BaseSolutionModule, only: BaseSolutionType, AddBaseSolutionToList, & - GetBaseSolutionFromList - use SolutionGroupModule, only: SolutionGroupType, AddSolutionGroupToList - use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList - use ListsModule, only: basesolutionlist, basemodellist, & - solutiongrouplist, baseexchangelist - use BaseModelModule, only: GetBaseModelFromList - use BlockParserModule, only: BlockParserType - use ListModule, only: ListType + use SimModule, only: store_error, count_errors, & + store_error_unit, MaxErrors + use VersionModule, only: write_listfile_header + use InputOutputModule, only: getunit, urword, openfile + use ArrayHandlersModule, only: expandarray, ifind + use BaseModelModule, only: BaseModelType + use BaseSolutionModule, only: BaseSolutionType, AddBaseSolutionToList, & + GetBaseSolutionFromList + use SolutionGroupModule, only: SolutionGroupType, AddSolutionGroupToList + use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList + use DistributedModelModule, only: add_dist_model + use ListsModule, only: basesolutionlist, basemodellist, & + solutiongrouplist, baseexchangelist + use BaseModelModule, only: GetBaseModelFromList + use BlockParserModule, only: BlockParserType + use ListModule, only: ListType implicit none private @@ -29,7 +30,7 @@ module SimulationCreateModule character(len=LENMODELNAME), allocatable, dimension(:) :: modelname type(BlockParserType) :: parser - contains +contains !> @brief Read the simulation name file and initialize the models, exchanges !< @@ -39,7 +40,7 @@ subroutine simulation_cr() character(len=LINELENGTH) :: line ! ------------------------------------------------------------------------------ ! - ! -- initialize iout + ! -- initialize iout iout = 0 ! ! -- Open simulation list file @@ -47,8 +48,8 @@ subroutine simulation_cr() call openfile(iout, 0, simlstfile, 'LIST', filstat_opt='REPLACE') ! ! -- write simlstfile to stdout - write(line,'(2(1x,A))') 'Writing simulation list file:', & - trim(adjustl(simlstfile)) + write (line, '(2(1x,A))') 'Writing simulation list file:', & + trim(adjustl(simlstfile)) call sim_message(line) call write_listfile_header(iout) ! @@ -58,7 +59,7 @@ subroutine simulation_cr() ! -- Return return end subroutine simulation_cr - + !> @brief Deallocate simulation variables !< subroutine simulation_da() @@ -67,7 +68,7 @@ subroutine simulation_da() ! ------------------------------------------------------------------------------ ! ! -- variables - deallocate(modelname) + deallocate (modelname) ! ! -- Return return @@ -82,7 +83,7 @@ end subroutine simulation_da !< subroutine read_simulation_namefile(namfile) ! -- dummy - character(len=*),intent(in) :: namfile !< simulation name file + character(len=*), intent(in) :: namfile !< simulation name file ! -- local character(len=LINELENGTH) :: line ! ------------------------------------------------------------------------------ @@ -92,7 +93,7 @@ subroutine read_simulation_namefile(namfile) call openfile(inunit, iout, namfile, 'NAM') ! ! -- write name of namfile to stdout - write(line,'(2(1x,a))') 'Using Simulation name file:', namfile + write (line, '(2(1x,a))') 'Using Simulation name file:', namfile call sim_message(line, skipafter=1) ! ! -- Initialize block parser @@ -121,7 +122,7 @@ subroutine read_simulation_namefile(namfile) call parser%Clear() ! ! -- Go through each solution and assign exchanges accordingly - call assign_exchanges() + call assign_exchanges() ! ! -- Return return @@ -143,44 +144,44 @@ subroutine options_create() ! ! -- Process OPTIONS block call parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) if (isfound) then - write(iout,'(/1x,a)')'READING SIMULATION OPTIONS' + write (iout, '(/1x,a)') 'READING SIMULATION OPTIONS' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('CONTINUE') - isimcontinue = 1 - write(iout, '(4x, a)') & - 'SIMULATION WILL CONTINUE EVEN IF THERE IS NONCONVERGENCE.' - case ('NOCHECK') - isimcheck = 0 - write(iout, '(4x, a)') & - 'MODEL DATA WILL NOT BE CHECKED FOR ERRORS.' - case ('MEMORY_PRINT_OPTION') - errmsg = '' - call parser%GetStringCaps(keyword) - call mem_set_print_option(iout, keyword, errmsg) - if (errmsg /= ' ') then - call store_error(errmsg) - call parser%StoreErrorUnit() - endif - case ('MAXERRORS') - imax = parser%GetInteger() - call MaxErrors(imax) - write(iout, '(4x, a, i0)') & - 'MAXIMUM NUMBER OF ERRORS THAT WILL BE STORED IS ', imax - case default - write(errmsg, '(4x,a,a)') & - '****ERROR. UNKNOWN SIMULATION OPTION: ', & - trim(keyword) + case ('CONTINUE') + isimcontinue = 1 + write (iout, '(4x, a)') & + 'SIMULATION WILL CONTINUE EVEN IF THERE IS NONCONVERGENCE.' + case ('NOCHECK') + isimcheck = 0 + write (iout, '(4x, a)') & + 'MODEL DATA WILL NOT BE CHECKED FOR ERRORS.' + case ('MEMORY_PRINT_OPTION') + errmsg = '' + call parser%GetStringCaps(keyword) + call mem_set_print_option(iout, keyword, errmsg) + if (errmsg /= ' ') then call store_error(errmsg) call parser%StoreErrorUnit() + end if + case ('MAXERRORS') + imax = parser%GetInteger() + call MaxErrors(imax) + write (iout, '(4x, a, i0)') & + 'MAXIMUM NUMBER OF ERRORS THAT WILL BE STORED IS ', imax + case default + write (errmsg, '(4x,a,a)') & + '****ERROR. UNKNOWN SIMULATION OPTION: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)')'END OF SIMULATION OPTIONS' + write (iout, '(1x,a)') 'END OF SIMULATION OPTIONS' end if ! ! -- return @@ -206,27 +207,27 @@ subroutine timing_create() ! ! -- Process TIMING block call parser%GetBlock('TIMING', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) if (isfound) then - write(iout,'(/1x,a)')'READING SIMULATION TIMING' + write (iout, '(/1x,a)') 'READING SIMULATION TIMING' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('TDIS6') - found_tdis = .true. - call parser%GetString(line) - call tdis_cr(line) - case default - write(errmsg, '(4x,a,a)') & - '****ERROR. UNKNOWN SIMULATION TIMING: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case ('TDIS6') + found_tdis = .true. + call parser%GetString(line) + call tdis_cr(line) + case default + write (errmsg, '(4x,a,a)') & + '****ERROR. UNKNOWN SIMULATION TIMING: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)')'END OF SIMULATION TIMING' + write (iout, '(1x,a)') 'END OF SIMULATION TIMING' else call store_error('****ERROR. Did not find TIMING block in simulation'// & ' control file.') @@ -234,10 +235,10 @@ subroutine timing_create() end if ! ! -- Ensure that TDIS was found - if(.not. found_tdis) then + if (.not. found_tdis) then call store_error('****ERROR. TDIS not found in TIMING block.') call parser%StoreErrorUnit() - endif + end if ! ! -- return return @@ -247,9 +248,9 @@ end subroutine timing_create !< subroutine models_create() ! -- modules - use GwfModule, only: gwf_cr - use GwtModule, only: gwt_cr - use ConstantsModule, only: LENMODELNAME + use GwfModule, only: gwf_cr + use GwtModule, only: gwt_cr + use ConstantsModule, only: LENMODELNAME ! -- dummy ! -- local integer(I4B) :: ierr @@ -262,32 +263,34 @@ subroutine models_create() ! ! -- Process MODELS block call parser%GetBlock('MODELS', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) if (isfound) then - write(iout,'(/1x,a)')'READING SIMULATION MODELS' + write (iout, '(/1x,a)') 'READING SIMULATION MODELS' im = 0 do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('GWF6') - call parser%GetString(fname) - call add_model(im, 'GWF6', mname) - call gwf_cr(fname, im, modelname(im)) - case ('GWT6') - call parser%GetString(fname) - call add_model(im, 'GWT6', mname) - call gwt_cr(fname, im, modelname(im)) - case default - write(errmsg, '(4x,a,a)') & - '****ERROR. UNKNOWN SIMULATION MODEL: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case ('GWF6') + call parser%GetString(fname) + call add_model(im, 'GWF6', mname) + call gwf_cr(fname, im, modelname(im)) + call add_dist_model(im) + case ('GWT6') + call parser%GetString(fname) + call add_model(im, 'GWT6', mname) + call gwt_cr(fname, im, modelname(im)) + call add_dist_model(im) + case default + write (errmsg, '(4x,a,a)') & + '****ERROR. UNKNOWN SIMULATION MODEL: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)')'END OF SIMULATION MODELS' + write (iout, '(1x,a)') 'END OF SIMULATION MODELS' else call store_error('****ERROR. Did not find MODELS block in simulation'// & ' control file.') @@ -302,9 +305,9 @@ end subroutine models_create !< subroutine exchanges_create() ! -- modules - use GwfGwfExchangeModule, only: gwfexchange_create - use GwfGwtExchangeModule, only: gwfgwt_cr - use GwtGwtExchangeModule, only: gwtexchange_create + use GwfGwfExchangeModule, only: gwfexchange_create + use GwfGwtExchangeModule, only: gwfgwt_cr + use GwtGwtExchangeModule, only: gwtexchange_create ! -- dummy ! -- local integer(I4B) :: ierr @@ -320,9 +323,9 @@ subroutine exchanges_create() &'file. Could not find model: ', a)" ! ------------------------------------------------------------------------------ call parser%GetBlock('EXCHANGES', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) if (isfound) then - write(iout,'(/1x,a)')'READING SIMULATION EXCHANGES' + write (iout, '(/1x,a)') 'READING SIMULATION EXCHANGES' id = 0 do call parser%GetNextLine(endOfBlock) @@ -337,39 +340,39 @@ subroutine exchanges_create() ! find model index in list m1 = ifind(modelname, name1) - if(m1 < 0) then - write(errmsg, fmtmerr) trim(name1) + if (m1 < 0) then + write (errmsg, fmtmerr) trim(name1) call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if m2 = ifind(modelname, name2) - if(m2 < 0) then - write(errmsg, fmtmerr) trim(name2) + if (m2 < 0) then + write (errmsg, fmtmerr) trim(name2) call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if - write(iout, '(4x,a,a,i0,a,i0,a,i0)') trim(keyword), ' exchange ', & - id, ' will be created to connect model ', m1, ' with model ', m2 + write (iout, '(4x,a,a,i0,a,i0,a,i0)') trim(keyword), ' exchange ', & + id, ' will be created to connect model ', m1, ' with model ', m2 select case (keyword) - case ('GWF6-GWF6') - call gwfexchange_create(fname, id, m1, m2) - case ('GWF6-GWT6') - call gwfgwt_cr(fname, id, m1, m2) - case ('GWT6-GWT6') - call gwtexchange_create(fname, id, m1, m2) - case default - write(errmsg, '(4x,a,a)') & - '****ERROR. UNKNOWN SIMULATION EXCHANGES: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case ('GWF6-GWF6') + call gwfexchange_create(fname, id, m1, m2) + case ('GWF6-GWT6') + call gwfgwt_cr(fname, id, m1, m2) + case ('GWT6-GWT6') + call gwtexchange_create(fname, id, m1, m2) + case default + write (errmsg, '(4x,a,a)') & + '****ERROR. UNKNOWN SIMULATION EXCHANGES: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)')'END OF SIMULATION EXCHANGES' + write (iout, '(1x,a)') 'END OF SIMULATION EXCHANGES' else - call store_error('****ERROR. Did not find EXCHANGES block in '// & + call store_error('****ERROR. Did not find EXCHANGES block in '// & 'simulation control file.') call parser%StoreErrorUnit() end if @@ -382,17 +385,17 @@ end subroutine exchanges_create !< subroutine solution_groups_create() ! -- modules - use SolutionGroupModule, only: SolutionGroupType, & - solutiongroup_create - use BaseSolutionModule, only: BaseSolutionType - use BaseModelModule, only: BaseModelType - use BaseExchangeModule, only: BaseExchangeType - use NumericalSolutionModule, only: solution_create + use SolutionGroupModule, only: SolutionGroupType, & + solutiongroup_create + use BaseSolutionModule, only: BaseSolutionType + use BaseModelModule, only: BaseModelType + use BaseExchangeModule, only: BaseExchangeType + use NumericalSolutionModule, only: solution_create ! -- dummy ! -- local - type(SolutionGroupType), pointer :: sgp - class(BaseSolutionType), pointer :: sp - class(BaseModelType), pointer :: mp + type(SolutionGroupType), pointer :: sgp + class(BaseSolutionType), pointer :: sp + class(BaseModelType), pointer :: mp integer(I4B) :: ierr logical :: isfound, endOfBlock integer(I4B) :: isoln @@ -400,14 +403,15 @@ subroutine solution_groups_create() integer(I4B) :: isgpsoln integer(I4B) :: sgid integer(I4B) :: mid + logical(LGP) :: blockRequired character(len=LINELENGTH) :: errmsg character(len=LENBIGLINE) :: keyword character(len=LINELENGTH) :: fname, mname ! -- formats character(len=*), parameter :: fmterrmxiter = & - "('ERROR. MXITER IS SET TO ', i0, ' BUT THERE IS ONLY ONE SOLUTION', & - &' IN SOLUTION GROUP ', i0, '. SET MXITER TO 1 IN SIMULATION CONTROL', & - &' FILE.')" + "('ERROR. MXITER IS SET TO ', i0, ' BUT THERE IS ONLY ONE SOLUTION', & + &' IN SOLUTION GROUP ', i0, '. SET MXITER TO 1 IN SIMULATION CONTROL', & + &' FILE.')" ! ------------------------------------------------------------------------------ ! ! -- isoln is the cumulative solution number, isgp is the cumulative @@ -418,28 +422,31 @@ subroutine solution_groups_create() !Read through the simulation name file and process each SOLUTION_GROUP sgploop: do ! + blockRequired = .false. + if (isgp == 0) blockRequired = .true. call parser%GetBlock('SOLUTIONGROUP', isfound, ierr, & - supportOpenClose=.true.) - if(ierr /= 0) exit sgploop + supportOpenClose=.true., & + blockRequired=blockRequired) + if (ierr /= 0) exit sgploop if (.not. isfound) exit sgploop isgp = isgp + 1 ! ! -- Get the solutiongroup id and check that it is listed consecutively. sgid = parser%GetInteger() - if(isgp /= sgid) then - write(errmsg, '(a)') 'Solution groups are not listed consecutively.' + if (isgp /= sgid) then + write (errmsg, '(a)') 'Solution groups are not listed consecutively.' call store_error(errmsg) - write(errmsg, '(a,i0,a,i0)' ) 'Found ', sgid, ' when looking for ',isgp + write (errmsg, '(a,i0,a,i0)') 'Found ', sgid, ' when looking for ', isgp call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if ! ! -- Create the solutiongroup and add it to the solutiongrouplist call solutiongroup_create(sgp, sgid) call AddSolutionGroupToList(solutiongrouplist, sgp) ! ! -- Begin processing the solution group - write(iout,'(/1x,a)')'READING SOLUTIONGROUP' + write (iout, '(/1x,a)') 'READING SOLUTIONGROUP' ! ! -- Initialize isgpsoln to 0. isgpsoln is the solution counter for this ! particular solution group. It goes from 1 to the number of solutions @@ -451,126 +458,126 @@ subroutine solution_groups_create() call parser%GetStringCaps(keyword) select case (keyword) ! - case ('MXITER') - sgp%mxiter = parser%GetInteger() + case ('MXITER') + sgp%mxiter = parser%GetInteger() + ! + case ('IMS6') + ! + ! -- Initialize and increment counters + isoln = isoln + 1 + isgpsoln = isgpsoln + 1 ! - case ('IMS6') + ! -- Create the solution, retrieve from the list, and add to sgp + call parser%GetString(fname) + call solution_create(fname, isoln) + sp => GetBaseSolutionFromList(basesolutionlist, isoln) + call sgp%add_solution(isoln, sp) + ! + ! -- Add all of the models that are listed on this line to + ! the current solution (sp) + do + ! + ! -- Set istart and istop to encompass model name. Exit this + ! loop if there are no more models. + call parser%GetStringCaps(mname) + if (mname == '') exit ! - ! -- Initialize and increment counters - isoln = isoln + 1 - isgpsoln = isgpsoln + 1 + ! -- Find the model id, and then get model + mid = ifind(modelname, mname) + if (mid <= 0) then + write (errmsg, '(a,a)') 'Error. Invalid modelname: ', & + trim(mname) + call store_error(errmsg) + call parser%StoreErrorUnit() + end if + mp => GetBaseModelFromList(basemodellist, mid) ! - ! -- Create the solution, retrieve from the list, and add to sgp - call parser%GetString(fname) - call solution_create(fname, isoln) - sp => GetBaseSolutionFromList(basesolutionlist, isoln) - call sgp%add_solution(isoln, sp) + ! -- Add the model to the solution + call sp%add_model(mp) + mp%idsoln = isoln ! - ! -- Add all of the models that are listed on this line to - ! the current solution (sp) - do - ! - ! -- Set istart and istop to encompass model name. Exit this - ! loop if there are no more models. - call parser%GetStringCaps(mname) - if (mname == '') exit - ! - ! -- Find the model id, and then get model - mid = ifind(modelname, mname) - if(mid <= 0) then - write(errmsg, '(a,a)') 'Error. Invalid modelname: ', & - trim(mname) - call store_error(errmsg) - call parser%StoreErrorUnit() - endif - mp => GetBaseModelFromList(basemodellist, mid) - ! - ! -- Add the model to the solution - call sp%add_model(mp) - mp%idsoln = isoln - ! - enddo + end do ! - case default - write(errmsg, '(4x,a,a)') & - '****ERROR. UNKNOWN SOLUTIONGROUP ENTRY: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case default + write (errmsg, '(4x,a,a)') & + '****ERROR. UNKNOWN SOLUTIONGROUP ENTRY: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do ! ! -- Make sure there is a solution in this solution group - if(isgpsoln == 0) then - write(errmsg, '(4x,a,i0)') & + if (isgpsoln == 0) then + write (errmsg, '(4x,a,i0)') & 'ERROR. THERE ARE NO SOLUTIONS FOR SOLUTION GROUP ', isgp call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if ! ! -- If there is only one solution then mxiter should be 1. - if(isgpsoln == 1 .and. sgp%mxiter > 1) then - write(errmsg, fmterrmxiter) sgp%mxiter, isgpsoln + if (isgpsoln == 1 .and. sgp%mxiter > 1) then + write (errmsg, fmterrmxiter) sgp%mxiter, isgpsoln call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if ! ! -- todo: more error checking? ! - write(iout,'(1x,a)')'END OF SIMULATION SOLUTIONGROUP' + write (iout, '(1x,a)') 'END OF SIMULATION SOLUTIONGROUP' ! - enddo sgploop + end do sgploop ! ! -- Check and make sure at least one solution group was found - if(solutiongrouplist%Count() == 0) then + if (solutiongrouplist%Count() == 0) then call store_error('ERROR. THERE ARE NO SOLUTION GROUPS.') call parser%StoreErrorUnit() - endif + end if ! ! -- return return end subroutine solution_groups_create - !> @brief Check for dangling models, and break with + !> @brief Check for dangling models, and break with !! error when found !< - subroutine check_model_assignment() + subroutine check_model_assignment() character(len=LINELENGTH) :: errmsg class(BaseModelType), pointer :: mp integer(I4B) :: im - + do im = 1, basemodellist%Count() mp => GetBaseModelFromList(basemodellist, im) if (mp%idsoln == 0) then - write(errmsg, '(a,a)') & + write (errmsg, '(a,a)') & '****ERROR. Model was not assigned to a solution: ', mp%name call store_error(errmsg) - endif - enddo + end if + end do if (count_errors() > 0) then call store_error_unit(inunit) - endif + end if end subroutine check_model_assignment !> @brief Assign exchanges to solutions - !! - !! This assigns NumericalExchanges to NumericalSolutions, + !! + !! This assigns NumericalExchanges to NumericalSolutions, !! based on the link between the models in the solution and - !! those exchanges. The BaseExchange%connects_model() function + !! those exchanges. The BaseExchange%connects_model() function !! should be overridden to indicate if such a link exists. !< subroutine assign_exchanges() ! -- local - class(BaseSolutionType), pointer :: sp + class(BaseSolutionType), pointer :: sp class(BaseExchangeType), pointer :: ep - class(BaseModelType), pointer :: mp + class(BaseModelType), pointer :: mp type(ListType), pointer :: models_in_solution integer(I4B) :: is, ie, im do is = 1, basesolutionlist%Count() sp => GetBaseSolutionFromList(basesolutionlist, is) - ! + ! ! -- now loop over exchanges do ie = 1, baseexchangelist%Count() ep => GetBaseExchangeFromList(baseexchangelist, ie) @@ -580,14 +587,14 @@ subroutine assign_exchanges() do im = 1, models_in_solution%Count() mp => GetBaseModelFromList(models_in_solution, im) if (ep%connects_model(mp)) then - ! + ! ! -- add to solution (and only once) call sp%add_exchange(ep) exit end if end do end do - enddo + end do end subroutine assign_exchanges !> @brief Add the model to the list of modelnames, check that the model name is valid @@ -601,35 +608,35 @@ subroutine add_model(im, mtype, mname) integer :: ilen integer :: i character(len=LINELENGTH) :: errmsg - ! ------------------------------------------------------------------------------ + ! ------------------------------------------------------------------------------ im = im + 1 call expandarray(modelname) call parser%GetStringCaps(mname) ilen = len_trim(mname) if (ilen > LENMODELNAME) then - write(errmsg, '(4x,a,a)') & - 'ERROR. INVALID MODEL NAME: ', trim(mname) + write (errmsg, '(4x,a,a)') & + 'ERROR. INVALID MODEL NAME: ', trim(mname) call store_error(errmsg) - write(errmsg, '(4x,a,i0,a,i0)') & - 'NAME LENGTH OF ', ilen, ' EXCEEDS MAXIMUM LENGTH OF ', & - LENMODELNAME + write (errmsg, '(4x,a,i0,a,i0)') & + 'NAME LENGTH OF ', ilen, ' EXCEEDS MAXIMUM LENGTH OF ', & + LENMODELNAME call store_error(errmsg) call parser%StoreErrorUnit() - endif + end if do i = 1, ilen if (mname(i:i) == ' ') then - write(errmsg, '(4x,a,a)') & - 'ERROR. INVALID MODEL NAME: ', trim(mname) + write (errmsg, '(4x,a,a)') & + 'ERROR. INVALID MODEL NAME: ', trim(mname) call store_error(errmsg) - write(errmsg, '(4x,a)') & - 'MODEL NAME CANNOT HAVE SPACES WITHIN IT.' + write (errmsg, '(4x,a)') & + 'MODEL NAME CANNOT HAVE SPACES WITHIN IT.' call store_error(errmsg) call parser%StoreErrorUnit() - endif - enddo + end if + end do modelname(im) = mname - write(iout, '(4x,a,i0)') mtype // ' model ' // trim(mname) // & - ' will be created as model ', im + write (iout, '(4x,a,i0)') mtype//' model '//trim(mname)// & + ' will be created as model ', im ! ! -- return return diff --git a/src/Solution/BaseSolution.f90 b/src/Solution/BaseSolution.f90 index bcc5ac2b2f8..69a16ada697 100644 --- a/src/Solution/BaseSolution.f90 +++ b/src/Solution/BaseSolution.f90 @@ -5,7 +5,7 @@ module BaseSolutionModule use ConstantsModule, only: LENSOLUTIONNAME use BaseModelModule, only: BaseModelType use BaseExchangeModule, only: BaseExchangeType - use ListModule, only: ListType + use ListModule, only: ListType implicit none private @@ -15,23 +15,23 @@ module BaseSolutionModule type, abstract :: BaseSolutionType character(len=LENSOLUTIONNAME) :: name contains - procedure (sln_df), deferred :: sln_df - procedure (sln_ar), deferred :: sln_ar - procedure (sln_calculate_delt), deferred :: sln_calculate_delt - procedure (sln_ad), deferred :: sln_ad - procedure (sln_ca), deferred :: sln_ca - procedure (sln_ot), deferred :: sln_ot - procedure (sln_fp), deferred :: sln_fp - procedure (sln_da), deferred :: sln_da - procedure (slnsave), deferred :: save - procedure (slnaddmodel), deferred :: add_model - procedure (slnaddexchange), deferred :: add_exchange - procedure (slngetmodels), deferred :: get_models - procedure (slngetexchanges), deferred :: get_exchanges + procedure(sln_df), deferred :: sln_df + procedure(sln_ar), deferred :: sln_ar + procedure(sln_calculate_delt), deferred :: sln_calculate_delt + procedure(sln_ad), deferred :: sln_ad + procedure(sln_ca), deferred :: sln_ca + procedure(sln_ot), deferred :: sln_ot + procedure(sln_fp), deferred :: sln_fp + procedure(sln_da), deferred :: sln_da + procedure(slnsave), deferred :: save + procedure(slnaddmodel), deferred :: add_model + procedure(slnaddexchange), deferred :: add_exchange + procedure(slngetmodels), deferred :: get_models + procedure(slngetexchanges), deferred :: get_exchanges end type BaseSolutionType abstract interface - + subroutine sln_df(this) import BaseSolutionType class(BaseSolutionType) :: this @@ -48,7 +48,7 @@ subroutine assignConnectionsIFace(this) import BaseSolutionType class(BaseSolutionType) :: this end subroutine - + subroutine sln_ar(this) import BaseSolutionType class(BaseSolutionType) :: this @@ -58,12 +58,12 @@ subroutine sln_rp(this) import BaseSolutionType class(BaseSolutionType) :: this end subroutine - + subroutine sln_calculate_delt(this) import BaseSolutionType class(BaseSolutionType) :: this end subroutine - + subroutine sln_ad(this) import BaseSolutionType class(BaseSolutionType) :: this @@ -78,21 +78,21 @@ subroutine sln_ca(this, isgcnvg, isuppress_output) use KindModule, only: DP, I4B import BaseSolutionType class(BaseSolutionType) :: this - integer(I4B),intent(in) :: isuppress_output + integer(I4B), intent(in) :: isuppress_output integer(I4B), intent(inout) :: isgcnvg end subroutine - subroutine slnsave(this,filename) + subroutine slnsave(this, filename) import BaseSolutionType class(BaseSolutionType) :: this character(len=*), intent(in) :: filename end subroutine - subroutine slnaddmodel(this,mp) + subroutine slnaddmodel(this, mp) import BaseSolutionType import BaseModelType class(BaseSolutionType) :: this - class(BaseModelType),pointer,intent(in) :: mp + class(BaseModelType), pointer, intent(in) :: mp end subroutine function slngetmodels(this) result(models) @@ -123,7 +123,7 @@ subroutine sln_da(this) contains - function CastAsBaseSolutionClass(obj) result (res) + function CastAsBaseSolutionClass(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(BaseSolutionType), pointer :: res @@ -141,7 +141,7 @@ end function CastAsBaseSolutionClass subroutine AddBaseSolutionToList(list, solution) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(BaseSolutionType), pointer, intent(in) :: solution ! -- local class(*), pointer :: obj @@ -151,13 +151,13 @@ subroutine AddBaseSolutionToList(list, solution) ! return end subroutine AddBaseSolutionToList - - function GetBaseSolutionFromList(list, idx) result (res) + + function GetBaseSolutionFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(BaseSolutionType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(BaseSolutionType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Solution/LinearMethods/ims8base.f90 b/src/Solution/LinearMethods/ims8base.f90 new file mode 100644 index 00000000000..a78ebccaf5e --- /dev/null +++ b/src/Solution/LinearMethods/ims8base.f90 @@ -0,0 +1,1319 @@ + +!> @brief This module contains the IMS linear accelerator subroutines +!! +!! This module contains the IMS linear accelerator subroutines used by a +!! MODFLOW 6 solution. +!< +MODULE IMSLinearBaseModule + ! -- modules + use KindModule, only: DP, I4B + use ConstantsModule, only: LINELENGTH, IZERO, & + DZERO, DPREC, DEM6, DEM3, DHALF, DONE + use GenericUtilitiesModule, only: sim_message, is_same + use BlockParserModule, only: BlockParserType + use IMSReorderingModule, only: ims_odrv + + IMPLICIT NONE + + type(BlockParserType), private :: parser + +contains + + !> @ brief Preconditioned Conjugate Gradient linear accelerator + !! + !! Apply the Preconditioned Conjugate Gradient linear accelerator to + !! the current coefficient matrix, right-hand side, using the current + !! dependent-variable. + !! + !< + SUBROUTINE ims_base_cg(ICNVG, ITMAX, INNERIT, & + NEQ, NJA, NIAPC, NJAPC, & + IPC, NITERC, ICNVGOPT, NORTH, & + DVCLOSE, RCLOSE, L2NORM0, EPFACT, & + IA0, JA0, A0, IAPC, JAPC, APC, & + X, B, D, P, Q, Z, & + NJLU, IW, JLU, & + NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & + CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & + DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) + ! -- dummy variables + integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) + integer(I4B), INTENT(IN) :: ITMAX !< maximum number of inner iterations + integer(I4B), INTENT(INOUT) :: INNERIT !< inner iteration count + integer(I4B), INTENT(IN) :: NEQ !< number of equations + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows + integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries + integer(I4B), INTENT(IN) :: IPC !< preconditioner option + integer(I4B), INTENT(INOUT) :: NITERC !< total number of inner iterations + integer(I4B), INTENT(IN) :: ICNVGOPT !< flow convergence criteria option + integer(I4B), INTENT(IN) :: NORTH !< orthogonalization frequency + real(DP), INTENT(IN) :: DVCLOSE !< dependent-variable closure criteria + real(DP), INTENT(IN) :: RCLOSE !< flow closure criteria + real(DP), INTENT(IN) :: L2NORM0 !< initial L-2 norm for system of equations + real(DP), INTENT(IN) :: EPFACT !< factor for decreasing flow convergence criteria for subsequent Picard iterations + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA0 !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA0 !< CRS column pointers + real(DP), DIMENSION(NJA), INTENT(IN) :: A0 !< coefficient matrix + integer(I4B), DIMENSION(NIAPC + 1), INTENT(IN) :: IAPC !< preconditioner CRS row pointers + integer(I4B), DIMENSION(NJAPC), INTENT(IN) :: JAPC !< preconditioner CRS column pointers + real(DP), DIMENSION(NJAPC), INTENT(IN) :: APC !< preconditioner matrix + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent-variable vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: B !< right-hand side vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: P !< working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Q !< working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Z !< working vector + ! -- ILUT dummy variables + integer(I4B), INTENT(IN) :: NJLU !< preconditioner length of JLU vector + integer(I4B), DIMENSION(NIAPC), INTENT(IN) :: IW !< preconditioner integer working vector + integer(I4B), DIMENSION(NJLU), INTENT(IN) :: JLU !< preconditioner JLU working vector + ! -- convergence information dummy variables dummy variables + integer(I4B), INTENT(IN) :: NCONV !< maximum number of inner iterations in a time step (maxiter * maxinner) + integer(I4B), INTENT(IN) :: CONVNMOD !< number of models in the solution + integer(I4B), DIMENSION(CONVNMOD + 1), INTENT(INOUT) :: CONVMODSTART !< pointer to the start of each model in the convmod* arrays + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< location of the maximum dependent-variable change in the solution + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< location of the maximum flow change in the solution + character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< convergence string + integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< actual number of inner iterations in each Picard iteration + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< location of the maximum dependent-variable change in each model in the solution + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< location of the maximum flow change in each model in the solution + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< maximum dependent-variable change in the solution + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< maximum flow change in the solution + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< maximum dependent-variable change in each model in the solution + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< maximum flow change in each model in the solution + ! -- local variables + LOGICAL :: lorth + logical :: lsame + character(len=31) :: cval + integer(I4B) :: n + integer(I4B) :: iiter + integer(I4B) :: xloc, rloc + integer(I4B) :: im, im0, im1 + real(DP) :: ddot + real(DP) :: tv + real(DP) :: deltax + real(DP) :: rmax + real(DP) :: l2norm + real(DP) :: rcnvg + real(DP) :: denom + real(DP) :: alpha, beta + real(DP) :: rho, rho0 + ! + ! -- initialize local variables + rho0 = DZERO + rho = DZERO + INNERIT = 0 + ! + ! -- INNER ITERATION + INNER: DO iiter = 1, itmax + INNERIT = INNERIT + 1 + NITERC = NITERC + 1 + ! + ! -- APPLY PRECONDITIONER + SELECT CASE (IPC) + ! + ! -- ILU0 AND MILU0 + CASE (1, 2) + CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, D, Z) + ! + ! -- ILUT AND MILUT + CASE (3, 4) + CALL lusol(NEQ, D, Z, APC, JLU, IW) + END SELECT + rho = ddot(NEQ, D, 1, Z, 1) + ! + ! -- COMPUTE DIRECTIONAL VECTORS + IF (IITER == 1) THEN + DO n = 1, NEQ + P(n) = Z(n) + END DO + ELSE + beta = rho / rho0 + DO n = 1, NEQ + P(n) = Z(n) + beta * P(n) + END DO + END IF + ! + ! -- COMPUTE ITERATES + ! + ! -- UPDATE Q + call amux(NEQ, P, Q, A0, JA0, IA0) + denom = ddot(NEQ, P, 1, Q, 1) + denom = denom + SIGN(DPREC, denom) + alpha = rho / denom + ! + ! -- UPDATE X AND RESIDUAL + deltax = DZERO + rmax = DZERO + l2norm = DZERO + DO im = 1, CONVNMOD + DVMAX(im) = DZERO + DRMAX(im) = DZERO + END DO + im = 1 + im0 = CONVMODSTART(1) + im1 = CONVMODSTART(2) + DO n = 1, NEQ + ! + ! -- determine current model index + if (n == im1) then + im = im + 1 + im0 = CONVMODSTART(im) + im1 = CONVMODSTART(im + 1) + end if + ! + ! -- identify deltax and rmax + tv = alpha * P(n) + X(n) = X(n) + tv + IF (ABS(tv) > ABS(deltax)) THEN + deltax = tv + xloc = n + END IF + IF (ABS(tv) > ABS(DVMAX(im))) THEN + DVMAX(im) = tv + LOCDV(im) = n + END IF + tv = D(n) + tv = tv - alpha * Q(n) + D(n) = tv + IF (ABS(tv) > ABS(rmax)) THEN + rmax = tv + rloc = n + END IF + IF (ABS(tv) > ABS(DRMAX(im))) THEN + DRMAX(im) = tv + LOCDR(im) = n + END IF + l2norm = l2norm + tv * tv + END DO + l2norm = SQRT(l2norm) + ! + ! -- SAVE SOLVER convergence information dummy variables + IF (NCONV > 1) THEN !< + n = NITERC + WRITE (cval, '(g15.7)') alpha + CACCEL(n) = cval + ITINNER(n) = iiter + DO im = 1, CONVNMOD + CONVLOCDV(im, n) = LOCDV(im) + CONVLOCDR(im, n) = LOCDR(im) + CONVDVMAX(im, n) = DVMAX(im) + CONVDRMAX(im, n) = DRMAX(im) + END DO + END IF + ! + ! -- TEST FOR SOLVER CONVERGENCE + IF (ICNVGOPT == 2 .OR. ICNVGOPT == 3 .OR. ICNVGOPT == 4) THEN + rcnvg = l2norm + ELSE + rcnvg = rmax + END IF + CALL ims_base_testcnvg(ICNVGOPT, ICNVG, INNERIT, & + deltax, rcnvg, & + L2NORM0, EPFACT, DVCLOSE, RCLOSE) + ! + ! -- CHECK FOR EXACT SOLUTION + IF (rcnvg == DZERO) ICNVG = 1 + ! + ! -- CHECK FOR STANDARD CONVERGENCE + IF (ICNVG .NE. 0) EXIT INNER + ! + ! -- CHECK THAT CURRENT AND PREVIOUS rho ARE DIFFERENT + lsame = is_same(rho, rho0) + IF (lsame) THEN + EXIT INNER + END IF + ! + ! -- RECALCULATE THE RESIDUAL + IF (NORTH > 0) THEN + lorth = mod(iiter + 1, NORTH) == 0 + IF (lorth) THEN + call ims_base_residual(NEQ, NJA, X, B, D, A0, IA0, JA0) + END IF + END IF + ! + ! -- exit inner if rho is zero + if (rho == DZERO) then + exit inner + end if + ! + ! -- SAVE CURRENT INNER ITERATES + rho0 = rho + END DO INNER + ! + ! -- RESET ICNVG + IF (ICNVG < 0) ICNVG = 0 + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_cg + + !> @ brief Preconditioned BiConjugate Gradient Stabilized linear accelerator + !! + !! Apply the Preconditioned BiConjugate Gradient Stabilized linear + !! accelerator to the current coefficient matrix, right-hand side, using + !! the currentdependent-variable. + !! + !< + SUBROUTINE ims_base_bcgs(ICNVG, ITMAX, INNERIT, & + NEQ, NJA, NIAPC, NJAPC, & + IPC, NITERC, ICNVGOPT, NORTH, ISCL, DSCALE, & + DVCLOSE, RCLOSE, L2NORM0, EPFACT, & + IA0, JA0, A0, IAPC, JAPC, APC, & + X, B, D, P, Q, & + T, V, DHAT, PHAT, QHAT, & + NJLU, IW, JLU, & + NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & + CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & + DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) + ! -- dummy variables + integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) + integer(I4B), INTENT(IN) :: ITMAX !< maximum number of inner iterations + integer(I4B), INTENT(INOUT) :: INNERIT !< inner iteration count + integer(I4B), INTENT(IN) :: NEQ !< number of equations + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows + integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries + integer(I4B), INTENT(IN) :: IPC !< preconditioner option + integer(I4B), INTENT(INOUT) :: NITERC !< total number of inner iterations + integer(I4B), INTENT(IN) :: ICNVGOPT !< flow convergence criteria option + integer(I4B), INTENT(IN) :: NORTH !< orthogonalization frequency + integer(I4B), INTENT(IN) :: ISCL !< scaling option + real(DP), DIMENSION(NEQ), INTENT(IN) :: DSCALE !< scaling vector + real(DP), INTENT(IN) :: DVCLOSE !< dependent-variable closure criteria + real(DP), INTENT(IN) :: RCLOSE !< flow closure criteria + real(DP), INTENT(IN) :: L2NORM0 !< initial L-2 norm for system of equations + real(DP), INTENT(IN) :: EPFACT !< factor for decreasing flow convergence criteria for subsequent Picard iterations + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA0 !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA0 !< CRS column pointers + real(DP), DIMENSION(NJA), INTENT(IN) :: A0 !< coefficient matrix + integer(I4B), DIMENSION(NIAPC + 1), INTENT(IN) :: IAPC !< preconditioner CRS row pointers + integer(I4B), DIMENSION(NJAPC), INTENT(IN) :: JAPC !< preconditioner CRS column pointers + real(DP), DIMENSION(NJAPC), INTENT(IN) :: APC !< preconditioner matrix + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent-variable vector + real(DP), DIMENSION(NEQ), INTENT(IN) :: B !< right-hand side vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: P !< preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Q !< preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: T !< preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: V !< preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DHAT !< BCGS preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: PHAT !< BCGS preconditioner working vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: QHAT !< BCGS preconditioner working vector + ! -- ILUT dummy variables + integer(I4B), INTENT(IN) :: NJLU !< preconditioner length of JLU vector + integer(I4B), DIMENSION(NIAPC), INTENT(IN) :: IW !< preconditioner integer working vector + integer(I4B), DIMENSION(NJLU), INTENT(IN) :: JLU !< preconditioner JLU working vector + ! -- convergence information dummy variables + integer(I4B), INTENT(IN) :: NCONV !< maximum number of inner iterations in a time step (maxiter * maxinner) + integer(I4B), INTENT(IN) :: CONVNMOD !< number of models in the solution + integer(I4B), DIMENSION(CONVNMOD + 1), INTENT(INOUT) :: CONVMODSTART !< pointer to the start of each model in the convmod* arrays + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< location of the maximum dependent-variable change in the solution + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< location of the maximum flow change in the solution + character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< convergence string + integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< actual number of inner iterations in each Picard iteration + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< location of the maximum dependent-variable change in each model in the solution + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< location of the maximum flow change in each model in the solution + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< maximum dependent-variable change in the solution + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< maximum flow change in the solution + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< maximum dependent-variable change in each model in the solution + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< maximum flow change in each model in the solution + ! -- local variables + LOGICAL :: LORTH + logical :: lsame + character(len=15) :: cval1, cval2 + integer(I4B) :: n + integer(I4B) :: iiter + integer(I4B) :: xloc, rloc + integer(I4B) :: im, im0, im1 + real(DP) :: ddot + real(DP) :: tv + real(DP) :: deltax + real(DP) :: rmax + real(DP) :: l2norm + real(DP) :: rcnvg + real(DP) :: alpha, alpha0 + real(DP) :: beta + real(DP) :: rho, rho0 + real(DP) :: omega, omega0 + real(DP) :: numer, denom + ! + ! -- initialize local variables + INNERIT = 0 + alpha = DZERO + alpha0 = DZERO + beta = DZERO + rho = DZERO + rho0 = DZERO + omega = DZERO + omega0 = DZERO + ! + ! -- SAVE INITIAL RESIDUAL + DO n = 1, NEQ + DHAT(n) = D(n) + END DO + ! + ! -- INNER ITERATION + INNER: DO iiter = 1, itmax + INNERIT = INNERIT + 1 + NITERC = NITERC + 1 + ! + ! -- CALCULATE rho + rho = ddot(NEQ, DHAT, 1, D, 1) + ! + ! -- COMPUTE DIRECTIONAL VECTORS + IF (IITER == 1) THEN + DO n = 1, NEQ + P(n) = D(n) + END DO + ELSE + beta = (rho / rho0) * (alpha0 / omega0) + DO n = 1, NEQ + P(n) = D(n) + beta * (P(n) - omega0 * V(n)) + END DO + END IF + ! + ! -- APPLY PRECONDITIONER TO UPDATE PHAT + SELECT CASE (IPC) + ! + ! -- ILU0 AND MILU0 + CASE (1, 2) + CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, P, PHAT) + ! + ! -- ILUT AND MILUT + CASE (3, 4) + CALL lusol(NEQ, P, PHAT, APC, JLU, IW) + END SELECT + ! + ! -- COMPUTE ITERATES + ! + ! -- UPDATE V WITH A AND PHAT + call amux(NEQ, PHAT, V, A0, JA0, IA0) + ! + ! -- UPDATE alpha WITH DHAT AND V + denom = ddot(NEQ, DHAT, 1, V, 1) + denom = denom + SIGN(DPREC, denom) + alpha = rho / denom + ! + ! -- UPDATE Q + DO n = 1, NEQ + Q(n) = D(n) - alpha * V(n) + END DO + ! + ! ! -- CALCULATE INFINITY NORM OF Q - TEST FOR TERMINATION + ! ! TERMINATE IF rmax IS LESS THAN MACHINE PRECISION (DPREC) + ! rmax = DZERO + ! DO n = 1, NEQ + ! tv = Q(n) + ! IF (ISCL.NE.0 ) tv = tv / DSCALE(n) + ! IF (ABS(tv) > ABS(rmax) ) rmax = tv + ! END DO + ! IF (ABS(rmax).LE.DPREC) THEN + ! deltax = DZERO + ! DO n = 1, NEQ + ! tv = alpha * PHAT(n) + ! IF (ISCL.NE.0) THEN + ! tv = tv * DSCALE(n) + ! END IF + ! X(n) = X(n) + tv + ! IF (ABS(tv) > ABS(deltax) ) deltax = tv + ! END DO + ! CALL IMSLINEARSUB_TESTCNVG(ICNVGOPT, ICNVG, INNERIT, & + ! deltax, rmax, & + ! rmax, EPFACT, DVCLOSE, RCLOSE ) + ! IF (ICNVG.NE.0 ) EXIT INNER + ! END IF + ! + ! -- APPLY PRECONDITIONER TO UPDATE QHAT + SELECT CASE (IPC) + ! + ! -- ILU0 AND MILU0 + CASE (1, 2) + CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, Q, QHAT) + ! + ! -- ILUT AND MILUT + CASE (3, 4) + CALL lusol(NEQ, Q, QHAT, APC, JLU, IW) + END SELECT + ! + ! -- UPDATE T WITH A AND QHAT + call amux(NEQ, QHAT, T, A0, JA0, IA0) + ! + ! -- UPDATE omega + numer = ddot(NEQ, T, 1, Q, 1) + denom = ddot(NEQ, T, 1, T, 1) + denom = denom + SIGN(DPREC, denom) + omega = numer / denom + ! + ! -- UPDATE X AND RESIDUAL + deltax = DZERO + rmax = DZERO + l2norm = DZERO + DO im = 1, CONVNMOD + DVMAX(im) = DZERO + DRMAX(im) = DZERO + END DO + im = 1 + im0 = CONVMODSTART(1) + im1 = CONVMODSTART(2) + DO n = 1, NEQ + ! + ! -- determine current model index + if (n == im1) then + im = im + 1 + im0 = CONVMODSTART(im) + im1 = CONVMODSTART(im + 1) + end if + ! + ! -- X AND DX + tv = alpha * PHAT(n) + omega * QHAT(n) + X(n) = X(n) + tv + IF (ISCL .NE. 0) THEN + tv = tv * DSCALE(n) + END IF + IF (ABS(tv) > ABS(deltax)) THEN + deltax = tv + xloc = n + END IF + IF (ABS(tv) > ABS(DVMAX(im))) THEN + DVMAX(im) = tv + LOCDV(im) = n + END IF + ! + ! -- RESIDUAL + tv = Q(n) - omega * T(n) + D(n) = tv + IF (ISCL .NE. 0) THEN + tv = tv / DSCALE(n) + END IF + IF (ABS(tv) > ABS(rmax)) THEN + rmax = tv + rloc = n + END IF + IF (ABS(tv) > ABS(DRMAX(im))) THEN + DRMAX(im) = tv + LOCDR(im) = n + END IF + l2norm = l2norm + tv * tv + END DO + l2norm = sqrt(l2norm) + ! + ! -- SAVE SOLVER convergence information dummy variables + IF (NCONV > 1) THEN !< + n = NITERC + WRITE (cval1, '(g15.7)') alpha + WRITE (cval2, '(g15.7)') omega + CACCEL(n) = trim(adjustl(cval1))//','//trim(adjustl(cval2)) + ITINNER(n) = iiter + DO im = 1, CONVNMOD + CONVLOCDV(im, n) = LOCDV(im) + CONVLOCDR(im, n) = LOCDR(im) + CONVDVMAX(im, n) = DVMAX(im) + CONVDRMAX(im, n) = DRMAX(im) + END DO + END IF + ! + ! -- TEST FOR SOLVER CONVERGENCE + IF (ICNVGOPT == 2 .OR. ICNVGOPT == 3 .OR. ICNVGOPT == 4) THEN + rcnvg = l2norm + ELSE + rcnvg = rmax + END IF + CALL ims_base_testcnvg(ICNVGOPT, ICNVG, INNERIT, & + deltax, rcnvg, & + L2NORM0, EPFACT, DVCLOSE, RCLOSE) + ! + ! -- CHECK FOR EXACT SOLUTION + IF (rcnvg == DZERO) ICNVG = 1 + ! + ! -- CHECK FOR STANDARD CONVERGENCE + IF (ICNVG .NE. 0) EXIT INNER + ! + ! -- CHECK THAT CURRENT AND PREVIOUS rho, alpha, AND omega ARE + ! DIFFERENT + lsame = is_same(rho, rho0) + IF (lsame) THEN + EXIT INNER + END IF + lsame = is_same(alpha, alpha0) + IF (lsame) THEN + EXIT INNER + END IF + lsame = is_same(omega, omega0) + IF (lsame) THEN + EXIT INNER + END IF + ! + ! -- RECALCULATE THE RESIDUAL + IF (NORTH > 0) THEN + LORTH = mod(iiter + 1, NORTH) == 0 + IF (LORTH) THEN + call ims_base_residual(NEQ, NJA, X, B, D, A0, IA0, JA0) + END IF + END IF + ! + ! -- exit inner if rho or omega are zero + if (rho * omega == DZERO) then + exit inner + end if + ! + ! -- SAVE CURRENT INNER ITERATES + rho0 = rho + alpha0 = alpha + omega0 = omega + END DO INNER + ! + ! -- RESET ICNVG + IF (ICNVG < 0) ICNVG = 0 + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_bcgs + + !> @ brief Calculate LORDER AND IORDER + !! + !! Calculate LORDER and IORDER for reordering. + !! + !< + SUBROUTINE ims_base_calc_order(IORD, NEQ, NJA, IA, JA, LORDER, IORDER) + ! -- modules + use SimModule, only: store_error, count_errors + ! -- dummy variables + integer(I4B), INTENT(IN) :: IORD !< reordering optionn + integer(I4B), INTENT(IN) :: NEQ !< number of rows + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< row pointer + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< column pointer + integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: LORDER !< reorder vector + integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: IORDER !< inverse of reorder vector + ! -- local variables + character(len=LINELENGTH) :: errmsg + integer(I4B) :: n + integer(I4B) :: nsp + integer(I4B), DIMENSION(:), ALLOCATABLE :: iwork0 + integer(I4B), DIMENSION(:), ALLOCATABLE :: iwork1 + integer(I4B) :: iflag + ! + ! -- initialize lorder and iorder + DO n = 1, NEQ + LORDER(n) = IZERO + IORDER(n) = IZERO + END DO + ! ALLOCATE (iwork0(NEQ)) + SELECT CASE (IORD) + CASE (1) + CALL genrcm(NEQ, NJA, IA, JA, LORDER) + CASE (2) + nsp = 3 * NEQ + 4 * NJA + allocate (iwork0(NEQ)) + allocate (iwork1(nsp)) + CALL ims_odrv(NEQ, NJA, nsp, IA, JA, LORDER, iwork0, & + iwork1, iflag) + IF (iflag .NE. 0) THEN + write (errmsg, '(A,1X,A)') & + 'IMSLINEARSUB_CALC_ORDER ERROR CREATING MINIMUM DEGREE ', & + 'ORDER PERMUTATION ' + call store_error(errmsg) + END IF + ! + ! -- DEALLOCATE TEMPORARY STORAGE + deallocate (iwork0, iwork1) + END SELECT + ! + ! -- GENERATE INVERSE OF LORDER + DO n = 1, NEQ + IORDER(LORDER(n)) = n + END DO + ! + ! -- terminate if errors occured + if (count_errors() > 0) then + call parser%StoreErrorUnit() + end if + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_calc_order + + ! + !> @ brief Scale the coefficient matrix + !! + !! Scale the coefficient matrix (AMAT), the right-hand side (B), + !! and the estimate of the dependent variable (X). + !! + !< + SUBROUTINE ims_base_scale(IOPT, ISCL, NEQ, NJA, IA, JA, AMAT, X, B, & + DSCALE, DSCALE2) + ! -- dummy variables + integer(I4B), INTENT(IN) :: IOPT !< flag to scale (0) or unscale the system of equations + integer(I4B), INTENT(IN) :: ISCL !< scaling option (1) symmetric (2) L-2 norm + integer(I4B), INTENT(IN) :: NEQ !< number of equations + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointer + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointer + real(DP), DIMENSION(NJA), INTENT(INOUT) :: AMAT !< coefficient matrix + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent variable + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: B !< right-hand side + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DSCALE !< first scaling vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DSCALE2 !< second scaling vector + ! -- local variables + integer(I4B) :: i, n + integer(I4B) :: id, jc + integer(I4B) :: i0, i1 + real(DP) :: v, c1, c2 + ! + ! -- SCALE SCALE AMAT, X, AND B + IF (IOPT == 0) THEN + ! + ! -- SYMMETRIC SCALING + SELECT CASE (ISCL) + CASE (1) + DO n = 1, NEQ + id = IA(n) + v = AMAT(id) + c1 = DONE / SQRT(ABS(v)) + DSCALE(n) = c1 + DSCALE2(n) = c1 + END DO + ! + ! -- SCALE AMAT -- AMAT = DSCALE(row) * AMAT(i) * DSCALE2(col) + DO n = 1, NEQ + c1 = DSCALE(n) + i0 = IA(n) + i1 = IA(n + 1) - 1 + DO i = i0, i1 + jc = JA(i) + c2 = DSCALE2(jc) + AMAT(i) = c1 * AMAT(i) * c2 + END DO + END DO + ! + ! -- L-2 NORM SCALING + CASE (2) + ! + ! -- SCALE EACH ROW SO THAT THE L-2 NORM IS 1 + DO n = 1, NEQ + c1 = DZERO + i0 = IA(n) + i1 = IA(n + 1) - 1 + DO i = i0, i1 + c1 = c1 + AMAT(i) * AMAT(i) + END DO + c1 = SQRT(c1) + IF (c1 == DZERO) THEN + c1 = DONE + ELSE + c1 = DONE / c1 + END IF + DSCALE(n) = c1 + ! + ! -- INITIAL SCALING OF AMAT -- AMAT = DSCALE(row) * AMAT(i) + DO i = i0, i1 + AMAT(i) = c1 * AMAT(i) + END DO + END DO + ! + ! -- SCALE EACH COLUMN SO THAT THE L-2 NORM IS 1 + DO n = 1, NEQ + DSCALE2(n) = DZERO + END DO + c2 = DZERO + DO n = 1, NEQ + i0 = IA(n) + i1 = IA(n + 1) - 1 + DO i = i0, i1 + jc = JA(i) + c2 = AMAT(i) + DSCALE2(jc) = DSCALE2(jc) + c2 * c2 + END DO + END DO + DO n = 1, NEQ + c2 = DSCALE2(n) + IF (c2 == DZERO) THEN + c2 = DONE + ELSE + c2 = DONE / SQRT(c2) + END IF + DSCALE2(n) = c2 + END DO + ! + ! -- FINAL SCALING OF AMAT -- AMAT = DSCALE2(col) * AMAT(i) + DO n = 1, NEQ + i0 = IA(n) + i1 = IA(n + 1) - 1 + DO i = i0, i1 + jc = JA(i) + c2 = DSCALE2(jc) + AMAT(i) = c2 * AMAT(i) + END DO + END DO + END SELECT + ! + ! -- SCALE X AND B + DO n = 1, NEQ + c1 = DSCALE(n) + c2 = DSCALE2(n) + X(n) = X(n) / c2 + B(n) = B(n) * c1 + END DO + ! + ! -- UNSCALE SCALE AMAT, X, AND B + ELSE + DO n = 1, NEQ + c1 = DSCALE(n) + i0 = IA(n) + i1 = IA(n + 1) - 1 + ! + ! -- UNSCALE AMAT + DO i = i0, i1 + jc = JA(i) + c2 = DSCALE2(jc) + AMAT(i) = (DONE / c1) * AMAT(i) * (DONE / c2) + END DO + ! + ! -- UNSCALE X AND B + c2 = DSCALE2(n) + X(n) = X(n) * c2 + B(n) = B(n) / c1 + END DO + END IF + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_scale + + !> @ brief Update the preconditioner + !! + !! Update the preconditioner using the current coefficient matrix. + !! + !< + SUBROUTINE ims_base_pcu(IOUT, NJA, NEQ, NIAPC, NJAPC, IPC, RELAX, & + AMAT, IA, JA, APC, IAPC, JAPC, IW, W, & + LEVEL, DROPTOL, NJLU, NJW, NWLU, JLU, JW, WLU) + ! -- modules + use SimModule, only: store_error, count_errors + ! -- dummy variables + integer(I4B), INTENT(IN) :: IOUT !< simulation listing file unit + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NEQ !< number of equations + integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows + integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries + integer(I4B), INTENT(IN) :: IPC !< precoditioner (1) ILU0 (2) MILU0 (3) ILUT (4) MILUT + real(DP), INTENT(IN) :: RELAX !< preconditioner relaxation factor for MILU0 and MILUT + real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers + real(DP), DIMENSION(NJAPC), INTENT(INOUT) :: APC !< preconditioner matrix + integer(I4B), DIMENSION(NIAPC + 1), INTENT(INOUT) :: IAPC !< preconditioner CRS row pointers + integer(I4B), DIMENSION(NJAPC), INTENT(INOUT) :: JAPC !< preconditioner CRS column pointers + integer(I4B), DIMENSION(NIAPC), INTENT(INOUT) :: IW !< preconditioner integed work vector + real(DP), DIMENSION(NIAPC), INTENT(INOUT) :: W !< preconditioner work verctor + ! -- ILUT dummy variables + integer(I4B), INTENT(IN) :: LEVEL !< number of levels of fill for ILUT and MILUT + real(DP), INTENT(IN) :: DROPTOL !< drop tolerance + integer(I4B), INTENT(IN) :: NJLU !< length of JLU working vector + integer(I4B), INTENT(IN) :: NJW !< length of JW working vector + integer(I4B), INTENT(IN) :: NWLU !< length of WLU working vector + integer(I4B), DIMENSION(NJLU), INTENT(INOUT) :: JLU !< ILUT/MILUT JLU working vector + integer(I4B), DIMENSION(NJW), INTENT(INOUT) :: JW !< ILUT/MILUT JW working vector + real(DP), DIMENSION(NWLU), INTENT(INOUT) :: WLU !< ILUT/MILUT WLU working vector + ! -- local variables + character(len=LINELENGTH) :: errmsg + character(len=100), dimension(5), parameter :: cerr = & + ["Elimination process has generated a row in L or U whose length is > n.", & + &"The matrix L overflows the array al. ", & + &"The matrix U overflows the array alu. ", & + &"Illegal value for lfil. ", & + &"Zero row encountered. "] + integer(I4B) :: ipcflag + integer(I4B) :: icount + integer(I4B) :: ierr + real(DP) :: delta + ! -- formats +2000 FORMAT(/, ' MATRIX IS SEVERELY NON-DIAGONALLY DOMINANT.', & + /, ' ADDED SMALL VALUE TO PIVOT ', i0, ' TIMES IN', & + ' IMSLINEARSUB_PCU.') + ! + ! -- initialize local variables + ipcflag = 0 + icount = 0 + delta = DZERO + PCSCALE: DO + SELECT CASE (IPC) + ! + ! -- ILU0 AND MILU0 + CASE (1, 2) + CALL ims_base_pcilu0(NJA, NEQ, AMAT, IA, JA, & + APC, IAPC, JAPC, IW, W, & + RELAX, ipcflag, delta) + ! + ! -- ILUT AND MILUT + CASE (3, 4) + ierr = 0 + CALL ilut(NEQ, AMAT, JA, IA, LEVEL, DROPTOL, & + APC, JLU, IW, NJAPC, WLU, JW, ierr, & + relax, ipcflag, delta) + if (ierr /= 0) then + if (ierr > 0) then + write (errmsg, '(a,1x,i0,1x,a)') & + 'ILUT: zero pivot encountered at step number', ierr, '.' + else + write (errmsg, '(a,1x,a)') 'ILUT:', cerr(-ierr) + end if + call store_error(errmsg) + call parser%StoreErrorUnit() + end if + ! + ! -- ADDITIONAL PRECONDITIONERS + CASE DEFAULT + ipcflag = 0 + END SELECT + IF (ipcflag < 1) THEN + EXIT PCSCALE + END IF + delta = 1.5d0 * delta + DEM3 + ipcflag = 0 + IF (delta > DHALF) THEN + delta = DHALF + ipcflag = 2 + END IF + icount = icount + 1 + ! + ! -- terminate pcscale loop if not making progress + if (icount > 10) then + exit PCSCALE + end if + + END DO PCSCALE + ! + ! -- write error message if small value added to pivot + if (icount > 0) then + write (IOUT, 2000) icount + end if + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_pcu + + !> @ brief Jacobi preconditioner + !! + !! Calculate the Jacobi preconditioner (inverse of the diagonal) using + !! the current coefficient matrix. + !! + !< + SUBROUTINE ims_base_pcjac(NJA, NEQ, AMAT, APC, IA, JA) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NEQ !< number of equations + real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: APC !< preconditioner matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers + ! -- local variables + integer(I4B) :: i, n + integer(I4B) :: ic0, ic1 + integer(I4B) :: id + real(DP) :: tv + ! -- code + DO n = 1, NEQ + ic0 = IA(n) + ic1 = IA(n + 1) - 1 + id = IA(n) + DO i = ic0, ic1 + IF (JA(i) == n) THEN + id = i + EXIT + END IF + END DO + tv = AMAT(id) + IF (ABS(tv) > DZERO) tv = DONE / tv + APC(n) = tv + END DO + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_pcjac + + !> @ brief Apply the Jacobi preconditioner + !! + !! Apply the Jacobi preconditioner and return the resultant vector. + !! + !< + SUBROUTINE ims_base_jaca(NEQ, A, D1, D2) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NEQ !< number of equations + real(DP), DIMENSION(NEQ), INTENT(IN) :: A !< Jacobi preconditioner + real(DP), DIMENSION(NEQ), INTENT(IN) :: D1 !< input vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D2 !< resultant vector + ! -- local variables + integer(I4B) :: n + real(DP) :: tv + ! -- code + DO n = 1, NEQ + tv = A(n) * D1(n) + D2(n) = tv + END DO + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_jaca + + !> @ brief Update the ILU0 preconditioner + !! + !! Update the ILU0 preconditioner using the current coefficient matrix. + !! + !< + SUBROUTINE ims_base_pcilu0(NJA, NEQ, AMAT, IA, JA, & + APC, IAPC, JAPC, IW, W, & + RELAX, IPCFLAG, DELTA) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NEQ !< number of equations + real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers + real(DP), DIMENSION(NJA), INTENT(INOUT) :: APC !< preconditioned matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(INOUT) :: IAPC !< preconditioner CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(INOUT) :: JAPC !< preconditioner CRS column pointers + integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: IW !< preconditioner integer work vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: W !< preconditioner work vector + real(DP), INTENT(IN) :: RELAX !< MILU0 preconditioner relaxation factor + integer(I4B), INTENT(INOUT) :: IPCFLAG !< preconditioner error flag + real(DP), INTENT(IN) :: DELTA !< factor used to correct non-diagonally dominant matrices + ! -- local variables + integer(I4B) :: ic0, ic1 + integer(I4B) :: iic0, iic1 + integer(I4B) :: iu, iiu + integer(I4B) :: j, n + integer(I4B) :: jj + integer(I4B) :: jcol, jw + integer(I4B) :: jjcol + real(DP) :: drelax + real(DP) :: sd1 + real(DP) :: tl + real(DP) :: rs + real(DP) :: d + ! + ! -- initialize local variables + drelax = RELAX + DO n = 1, NEQ + IW(n) = 0 + W(n) = DZERO + END DO + MAIN: DO n = 1, NEQ + ic0 = IA(n) + ic1 = IA(n + 1) - 1 + DO j = ic0, ic1 + jcol = JA(j) + IW(jcol) = 1 + W(jcol) = W(jcol) + AMAT(j) + END DO + ic0 = IAPC(n) + ic1 = IAPC(n + 1) - 1 + iu = JAPC(n) + rs = DZERO + LOWER: DO j = ic0, iu - 1 + jcol = JAPC(j) + iic0 = IAPC(jcol) + iic1 = IAPC(jcol + 1) - 1 + iiu = JAPC(jcol) + tl = W(jcol) * APC(jcol) + W(jcol) = tl + DO jj = iiu, iic1 + jjcol = JAPC(jj) + jw = IW(jjcol) + IF (jw .NE. 0) THEN + W(jjcol) = W(jjcol) - tl * APC(jj) + ELSE + rs = rs + tl * APC(jj) + END IF + END DO + END DO LOWER + ! + ! -- DIAGONAL - CALCULATE INVERSE OF DIAGONAL FOR SOLUTION + d = W(n) + tl = (DONE + DELTA) * d - (drelax * rs) + ! + ! -- ENSURE THAT THE SIGN OF THE DIAGONAL HAS NOT CHANGED AND IS + sd1 = SIGN(d, tl) + IF (sd1 .NE. d) THEN + ! + ! -- USE SMALL VALUE IF DIAGONAL SCALING IS NOT EFFECTIVE FOR + ! PIVOTS THAT CHANGE THE SIGN OF THE DIAGONAL + IF (IPCFLAG > 1) THEN + tl = SIGN(DEM6, d) + ! + ! -- DIAGONAL SCALING CONTINUES TO BE EFFECTIVE + ELSE + IPCFLAG = 1 + EXIT MAIN + END IF + END IF + IF (ABS(tl) == DZERO) THEN + ! + ! -- USE SMALL VALUE IF DIAGONAL SCALING IS NOT EFFECTIVE FOR + ! ZERO PIVOTS + IF (IPCFLAG > 1) THEN + tl = SIGN(DEM6, d) + ! + ! -- DIAGONAL SCALING CONTINUES TO BE EFFECTIVE FOR ELIMINATING + ELSE + IPCFLAG = 1 + EXIT MAIN + END IF + END IF + APC(n) = DONE / tl + ! + ! -- RESET POINTER FOR IW TO ZERO + IW(n) = 0 + W(n) = DZERO + DO j = ic0, ic1 + jcol = JAPC(j) + APC(j) = W(jcol) + IW(jcol) = 0 + W(jcol) = DZERO + END DO + END DO MAIN + ! + ! -- RESET IPCFLAG IF SUCCESSFUL COMPLETION OF MAIN + IPCFLAG = 0 + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_pcilu0 + + !> @ brief Apply the ILU0 and MILU0 preconditioners + !! + !! Apply the ILU0 and MILU0 preconditioners to the passed vector (R). + !! + !< + SUBROUTINE ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, R, D) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries + integer(I4B), INTENT(IN) :: NEQ !< number of equations + real(DP), DIMENSION(NJA), INTENT(IN) :: APC !< ILU0/MILU0 preconditioner matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IAPC !< ILU0/MILU0 preconditioner CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JAPC !< ILU0/MILU0 preconditioner CRS column pointers + real(DP), DIMENSION(NEQ), INTENT(IN) :: R !< input vector + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< output vector after applying APC to R + ! -- local variables + integer(I4B) :: ic0, ic1 + integer(I4B) :: iu + integer(I4B) :: jcol + integer(I4B) :: j, n + real(DP) :: tv + ! + ! -- FORWARD SOLVE - APC * D = R + FORWARD: DO n = 1, NEQ + tv = R(n) + ic0 = IAPC(n) + ic1 = IAPC(n + 1) - 1 + iu = JAPC(n) - 1 + LOWER: DO j = ic0, iu + jcol = JAPC(j) + tv = tv - APC(j) * D(jcol) + END DO LOWER + D(n) = tv + END DO FORWARD + ! + ! -- BACKWARD SOLVE - D = D / U + BACKWARD: DO n = NEQ, 1, -1 + ic0 = IAPC(n) + ic1 = IAPC(n + 1) - 1 + iu = JAPC(n) + tv = D(n) + UPPER: DO j = iu, ic1 + jcol = JAPC(j) + tv = tv - APC(j) * D(jcol) + END DO UPPER + ! + ! -- COMPUTE D FOR DIAGONAL - D = D / U + D(n) = tv * APC(n) + END DO BACKWARD + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_ilu0a + + !> @ brief Test for solver convergence + !! + !! General routine for testing for solver convergence based on the + !! user-specified convergence option (Icnvgopt). + !< + ! + ! -- TEST FOR SOLVER CONVERGENCE + SUBROUTINE ims_base_testcnvg(Icnvgopt, Icnvg, Iiter, & + Dvmax, Rmax, & + Rmax0, Epfact, Dvclose, Rclose) + ! -- dummy variables + integer(I4B), INTENT(IN) :: Icnvgopt !< convergence option - see documentation for option + integer(I4B), INTENT(INOUT) :: Icnvg !< flag indicating if convergence achieved (1) or not (0) + integer(I4B), INTENT(IN) :: Iiter !< inner iteration number (used for strict convergence option) + real(DP), INTENT(IN) :: Dvmax !< maximum dependent-variable change + real(DP), INTENT(IN) :: Rmax !< maximum flow change + real(DP), INTENT(IN) :: Rmax0 !< initial flow change (initial L2-norm) + real(DP), INTENT(IN) :: Epfact !< factor for reducing convergence criteria in subsequent Picard iterations + real(DP), INTENT(IN) :: Dvclose !< Maximum depenendent-variable change allowed + real(DP), INTENT(IN) :: Rclose !< Maximum flow change alowed + ! -- code + IF (Icnvgopt == 0) THEN + IF (ABS(Dvmax) <= Dvclose .AND. ABS(Rmax) <= Rclose) THEN + Icnvg = 1 + END IF + ELSE IF (Icnvgopt == 1) THEN + IF (ABS(Dvmax) <= Dvclose .AND. ABS(Rmax) <= Rclose) THEN + IF (iiter == 1) THEN + Icnvg = 1 + ELSE + Icnvg = -1 + END IF + END IF + ELSE IF (Icnvgopt == 2) THEN + IF (ABS(Dvmax) <= Dvclose .OR. Rmax <= Rclose) THEN + Icnvg = 1 + ELSE IF (Rmax <= Rmax0 * Epfact) THEN + Icnvg = -1 + END IF + ELSE IF (Icnvgopt == 3) THEN + IF (ABS(Dvmax) <= Dvclose) THEN + Icnvg = 1 + ELSE IF (Rmax <= Rmax0 * Rclose) THEN + Icnvg = -1 + END IF + ELSE IF (Icnvgopt == 4) THEN + IF (ABS(Dvmax) <= Dvclose .AND. Rmax <= Rclose) THEN + Icnvg = 1 + ELSE IF (Rmax <= Rmax0 * Epfact) THEN + Icnvg = -1 + END IF + END IF + ! + ! -- return + RETURN + END SUBROUTINE ims_base_testcnvg + + !> @ brief Generate CRS pointers for the preconditioner + !! + !! Generate the CRS row and column pointers for the preconditioner. + !! JAPC(1:NEQ) hHas the position of the upper entry for a row, + !! JAPC(NEQ+1:NJA) is the column position for entry, + !! APC(1:NEQ) is the preconditioned inverse of the diagonal, and + !! APC(NEQ+1:NJA) are the preconditioned entries for off diagonals. + !< + SUBROUTINE ims_base_pccrs(NEQ, NJA, IA, JA, & + IAPC, JAPC) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NEQ !< + integer(I4B), INTENT(IN) :: NJA !< + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< + integer(I4B), DIMENSION(NEQ + 1), INTENT(INOUT) :: IAPC !< + integer(I4B), DIMENSION(NJA), INTENT(INOUT) :: JAPC !< + ! -- local variables + integer(I4B) :: n, j + integer(I4B) :: i0, i1 + integer(I4B) :: nlen + integer(I4B) :: ic, ip + integer(I4B) :: jcol + integer(I4B), DIMENSION(:), ALLOCATABLE :: iarr + ! -- code + ip = NEQ + 1 + DO n = 1, NEQ + i0 = IA(n) + i1 = IA(n + 1) - 1 + nlen = i1 - i0 + ALLOCATE (iarr(nlen)) + ic = 0 + DO j = i0, i1 + jcol = JA(j) + IF (jcol == n) CYCLE + ic = ic + 1 + iarr(ic) = jcol + END DO + CALL ims_base_isort(nlen, iarr) + IAPC(n) = ip + DO j = 1, nlen + jcol = iarr(j) + JAPC(ip) = jcol + ip = ip + 1 + END DO + DEALLOCATE (iarr) + END DO + IAPC(NEQ + 1) = NJA + 1 + ! + ! -- POSITION OF THE FIRST UPPER ENTRY FOR ROW + DO n = 1, NEQ + i0 = IAPC(n) + i1 = IAPC(n + 1) - 1 + JAPC(n) = IAPC(n + 1) + DO j = i0, i1 + jcol = JAPC(j) + IF (jcol > n) THEN + JAPC(n) = j + EXIT + END IF + END DO + END DO + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_pccrs + + !> @brief In-place sorting for an integer array + !! + !! Subroutine sort an integer array in-place. + !! + !< + SUBROUTINE ims_base_isort(NVAL, IARRAY) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NVAL !< length of the interger array + integer(I4B), DIMENSION(NVAL), INTENT(INOUT) :: IARRAY !< integer array to be sorted + ! -- local variables + integer(I4B) :: i, j, itemp + ! -- code + DO i = 1, NVAL - 1 + DO j = i + 1, NVAL + if (IARRAY(i) > IARRAY(j)) then + itemp = IARRAY(j) + IARRAY(j) = IARRAY(i) + IARRAY(i) = itemp + END IF + END DO + END DO + ! + ! -- RETURN + RETURN + END SUBROUTINE ims_base_isort + + !> @brief Calculate residual + !! + !! Subroutine to calculate the residual. + !! + !< + SUBROUTINE ims_base_residual(NEQ, NJA, X, B, D, A, IA, JA) + ! -- dummy variables + integer(I4B), INTENT(IN) :: NEQ !< length of vectors + integer(I4B), INTENT(IN) :: NJA !< length of coefficient matrix + real(DP), DIMENSION(NEQ), INTENT(IN) :: X !< dependent variable + real(DP), DIMENSION(NEQ), INTENT(IN) :: B !< right-hand side + real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< residual + real(DP), DIMENSION(NJA), INTENT(IN) :: A !< coefficient matrix + integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers + integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers + ! -- local variables + integer(I4B) :: n + ! -- code + ! + ! -- calculate matrix-vector product + call amux(NEQ, X, D, A, JA, IA) + ! + ! -- subtract matrix-vector product from right-hand side + DO n = 1, NEQ + D(n) = B(n) - D(n) + END DO + ! + ! -- return + RETURN + END SUBROUTINE ims_base_residual + +END MODULE IMSLinearBaseModule diff --git a/src/Solution/LinearMethods/ims8linear.f90 b/src/Solution/LinearMethods/ims8linear.f90 new file mode 100644 index 00000000000..c1015d69dfe --- /dev/null +++ b/src/Solution/LinearMethods/ims8linear.f90 @@ -0,0 +1,1016 @@ +MODULE IMSLinearModule + + use KindModule, only: DP, I4B + use ConstantsModule, only: LINELENGTH, LENSOLUTIONNAME, LENMEMPATH, & + IZERO, DZERO, DPREC, DSAME, & + DEM8, DEM6, DEM5, DEM4, DEM3, DEM2, DEM1, & + DHALF, DONE, DTWO, & + VDEBUG + use GenericUtilitiesModule, only: sim_message + use IMSLinearBaseModule, only: ims_base_cg, ims_base_bcgs, & + ims_base_pccrs, ims_base_calc_order, & + ims_base_scale, ims_base_pcu, & + ims_base_residual + use BlockParserModule, only: BlockParserType + + IMPLICIT NONE + private + + TYPE, PUBLIC :: ImsLinearDataType + character(len=LENMEMPATH) :: memoryPath !< the path for storing variables in the memory manager + integer(I4B), POINTER :: iout => NULL() !< simulation listing file unit + integer(I4B), POINTER :: IPRIMS => NULL() !< print flag + integer(I4B), POINTER :: ILINMETH => NULL() !< linear accelerator (1) cg, (2) bicgstab + integer(I4B), POINTER :: ITER1 => NULL() !< maximum inner iterations + integer(I4B), POINTER :: IPC => NULL() !< preconditioner flag + integer(I4B), POINTER :: ISCL => NULL() !< scaling flag + integer(I4B), POINTER :: IORD => NULL() !< reordering flag + integer(I4B), POINTER :: NORTH => NULL() !< orthogonalization interval + integer(I4B), POINTER :: ICNVGOPT => NULL() !< rclose convergence option flag + integer(I4B), POINTER :: IACPC => NULL() !< preconditioner CRS row pointers + integer(I4B), POINTER :: NITERC => NULL() !< + integer(I4B), POINTER :: NIABCGS => NULL() !< size of working vectors for BCGS linear accelerator + integer(I4B), POINTER :: NIAPC => NULL() !< preconditioner number of rows + integer(I4B), POINTER :: NJAPC => NULL() !< preconditioner number of non-zero entries + real(DP), POINTER :: DVCLOSE => NULL() !< dependent variable convergence criteria + real(DP), POINTER :: RCLOSE => NULL() !< flow convergence criteria + real(DP), POINTER :: RELAX => NULL() !< preconditioner MILU0/MILUT relaxation factor + real(DP), POINTER :: EPFACT => NULL() !< factor for decreasing convergence criteria in seubsequent Picard iterations + real(DP), POINTER :: L2NORM0 => NULL() !< initial L2 norm + ! -- ilut variables + integer(I4B), POINTER :: LEVEL => NULL() !< preconditioner number of levels + real(DP), POINTER :: DROPTOL => NULL() !< preconditioner drop tolerance + integer(I4B), POINTER :: NJLU => NULL() !< length of jlu work vector + integer(I4B), POINTER :: NJW => NULL() !< length of jw work vector + integer(I4B), POINTER :: NWLU => NULL() !< length of wlu work vector + ! -- pointers to solution variables + integer(I4B), POINTER :: NEQ => NULL() !< number of equations (rows in matrix) + integer(I4B), POINTER :: NJA => NULL() !< number of non-zero values in amat + integer(I4B), dimension(:), pointer, contiguous :: IA => NULL() !< position of start of each row + integer(I4B), dimension(:), pointer, contiguous :: JA => NULL() !< column pointer + real(DP), dimension(:), pointer, contiguous :: AMAT => NULL() !< coefficient matrix + real(DP), dimension(:), pointer, contiguous :: RHS => NULL() !< right-hand side of equation + real(DP), dimension(:), pointer, contiguous :: X => NULL() !< dependent variable + ! VECTORS + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DSCALE => NULL() !< scaling factor + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DSCALE2 => NULL() !< unscaling factor + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IAPC => NULL() !< position of start of each row in preconditioner matrix + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JAPC => NULL() !< preconditioner matrix column pointer + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: APC => NULL() !< preconditioner coefficient matrix + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: LORDER => NULL() !< reordering mapping + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IORDER => NULL() !< mapping to restore reordered matrix + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IARO => NULL() !< position of start of each row in reordered matrix + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JARO => NULL() !< reordered matrix column pointer + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: ARO => NULL() !< reordered coefficient matrix + ! WORKING ARRAYS + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IW => NULL() !< integer working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: W => NULL() !< real working array + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: ID => NULL() !< integer working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: D => NULL() !< real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: P => NULL() !< real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: Q => NULL() !< real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: Z => NULL() !< real working array + ! BICGSTAB WORKING ARRAYS + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: T => NULL() !< BICGSTAB real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: V => NULL() !< BICGSTAB real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DHAT => NULL() !< BICGSTAB real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: PHAT => NULL() !< BICGSTAB real working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: QHAT => NULL() !< rBICGSTAB eal working array + ! POINTERS FOR USE WITH BOTH ORIGINAL AND RCM ORDERINGS + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IA0 => NULL() !< pointer to current CRS row pointers + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JA0 => NULL() !< pointer to current CRS column pointers + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: A0 => NULL() !< pointer to current coefficient matrix + ! ILUT WORKING ARRAYS + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JLU => NULL() !< ilut integer working array + integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JW => NULL() !< ilut integer working array + real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: WLU => NULL() !< ilut real working array + + ! PROCEDURES (METHODS) + CONTAINS + PROCEDURE :: IMSLINEAR_ALLOCATE => imslinear_ar + procedure :: imslinear_summary + PROCEDURE :: IMSLINEAR_APPLY => imslinear_ap + procedure :: IMSLINEAR_DA => imslinear_da + procedure, private :: allocate_scalars + ! -- PRIVATE PROCEDURES + PROCEDURE, PRIVATE :: SET_IMSLINEAR_INPUT => imslinear_set_input + END TYPE ImsLinearDataType + +CONTAINS + + !> @ brief Allocate storage and read data + !! + !! Allocate storage for linear accelerators and read data + !! + !< + SUBROUTINE imslinear_ar(this, NAME, parser, IOUT, IPRIMS, MXITER, IFDPARAM, & + IMSLINEARM, NEQ, NJA, IA, JA, AMAT, RHS, X, & + NINNER, LFINDBLOCK) + ! -- modules + use MemoryManagerModule, only: mem_allocate + use MemoryHelperModule, only: create_mem_path + use SimModule, only: store_error, count_errors, & + deprecation_warning + ! -- dummy variables + CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance + CHARACTER(LEN=LENSOLUTIONNAME), INTENT(IN) :: NAME !< solution name + type(BlockParserType) :: parser !< block parser + integer(I4B), INTENT(IN) :: IOUT !< simulation listing file unit + integer(I4B), TARGET, INTENT(IN) :: IPRIMS !< print option + integer(I4B), INTENT(IN) :: MXITER !< maximum outer iterations + integer(I4B), INTENT(IN) :: IFDPARAM !< complexity option + integer(I4B), INTENT(INOUT) :: IMSLINEARM !< linear method option (1) CG (2) BICGSTAB + integer(I4B), TARGET, INTENT(IN) :: NEQ !< number of equations + integer(I4B), TARGET, INTENT(IN) :: NJA !< number of non-zero entries in the coefficient matrix + integer(I4B), DIMENSION(NEQ + 1), TARGET, INTENT(IN) :: IA !< pointer to the start of a row in the coefficient matrix + integer(I4B), DIMENSION(NJA), TARGET, INTENT(IN) :: JA !< column pointer + real(DP), DIMENSION(NJA), TARGET, INTENT(IN) :: AMAT !< coefficient matrix + real(DP), DIMENSION(NEQ), TARGET, INTENT(INOUT) :: RHS !< right-hand side + real(DP), DIMENSION(NEQ), TARGET, INTENT(INOUT) :: X !< dependent variables + integer(I4B), TARGET, INTENT(INOUT) :: NINNER !< maximum number of inner iterations + integer(I4B), INTENT(IN), OPTIONAL :: LFINDBLOCK !< flag indicating if the linear block is present (1) or missing (0) + + ! -- local variables + LOGICAL :: lreaddata + character(len=LINELENGTH) :: errmsg + character(len=LINELENGTH) :: warnmsg + character(len=LINELENGTH) :: keyword + integer(I4B) :: i, n + integer(I4B) :: i0 + integer(I4B) :: iscllen, iolen + integer(I4B) :: ierr + real(DP) :: r + logical :: isfound, endOfBlock + integer(I4B) :: ijlu + integer(I4B) :: ijw + integer(I4B) :: iwlu + integer(I4B) :: iwk + ! + ! -- SET LREADDATA + IF (PRESENT(LFINDBLOCK)) THEN + IF (LFINDBLOCK < 1) THEN + lreaddata = .FALSE. + ELSE + lreaddata = .TRUE. + END IF + ELSE + lreaddata = .TRUE. + END IF + ! + ! -- DEFINE NAME + this%memoryPath = create_mem_path(name, 'IMSLINEAR') + ! + ! -- SET POINTERS TO SOLUTION STORAGE + this%IPRIMS => IPRIMS + this%NEQ => NEQ + this%NJA => NJA + this%IA => IA + this%JA => JA + this%AMAT => AMAT + this%RHS => RHS + this%X => X + ! + ! -- ALLOCATE SCALAR VARIABLES + call this%allocate_scalars() + ! + ! -- initialize iout + this%iout = iout + ! + ! -- DEFAULT VALUES + this%IORD = 0 + this%ISCL = 0 + this%IPC = 0 + this%LEVEL = 0 + ! + ! -- TRANSFER COMMON VARIABLES FROM IMS TO IMSLINEAR + this%ILINMETH = 0 + + this%IACPC = 0 + this%RELAX = DZERO !0.97 + + this%DROPTOL = DZERO + + this%NORTH = 0 + + this%ICNVGOPT = 0 + ! + ! -- PRINT A MESSAGE IDENTIFYING IMSLINEAR SOLVER PACKAGE + write (iout, 2000) +02000 FORMAT(1X, /1X, 'IMSLINEAR -- UNSTRUCTURED LINEAR SOLUTION', & + ' PACKAGE, VERSION 8, 04/28/2017') + ! + ! -- SET DEFAULT IMSLINEAR PARAMETERS + CALL this%SET_IMSLINEAR_INPUT(IFDPARAM) + NINNER = this%iter1 + ! + ! -- get IMSLINEAR block + if (lreaddata) then + call parser%GetBlock('LINEAR', isfound, ierr, & + supportOpenClose=.true., blockRequired=.FALSE.) + else + isfound = .FALSE. + end if + ! + ! -- parse IMSLINEAR block if detected + if (isfound) then + write (iout, '(/1x,a)') 'PROCESSING LINEAR DATA' + do + call parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + call parser%GetStringCaps(keyword) + ! -- parse keyword + select case (keyword) + case ('INNER_DVCLOSE') + this%DVCLOSE = parser%GetDouble() + case ('INNER_RCLOSE') + this%rclose = parser%GetDouble() + ! -- look for additional key words + call parser%GetStringCaps(keyword) + if (keyword == 'STRICT') then + this%ICNVGOPT = 1 + else if (keyword == 'L2NORM_RCLOSE') then + this%ICNVGOPT = 2 + else if (keyword == 'RELATIVE_RCLOSE') then + this%ICNVGOPT = 3 + else if (keyword == 'L2NORM_RELATIVE_RCLOSE') then + this%ICNVGOPT = 4 + end if + case ('INNER_MAXIMUM') + i = parser%GetInteger() + this%iter1 = i + NINNER = i + case ('LINEAR_ACCELERATION') + call parser%GetStringCaps(keyword) + if (keyword .eq. 'CG') then + this%ILINMETH = 1 + else if (keyword .eq. 'BICGSTAB') then + this%ILINMETH = 2 + else + this%ILINMETH = 0 + write (errmsg, '(3a)') & + 'UNKNOWN IMSLINEAR LINEAR_ACCELERATION METHOD (', & + trim(keyword), ').' + call store_error(errmsg) + end if + case ('SCALING_METHOD') + call parser%GetStringCaps(keyword) + i = 0 + if (keyword .eq. 'NONE') then + i = 0 + else if (keyword .eq. 'DIAGONAL') then + i = 1 + else if (keyword .eq. 'L2NORM') then + i = 2 + else + write (errmsg, '(3a)') & + 'UNKNOWN IMSLINEAR SCALING_METHOD (', trim(keyword), ').' + call store_error(errmsg) + end if + this%ISCL = i + case ('RED_BLACK_ORDERING') + i = 0 + case ('REORDERING_METHOD') + call parser%GetStringCaps(keyword) + i = 0 + if (keyword == 'NONE') then + i = 0 + else if (keyword == 'RCM') then + i = 1 + else if (keyword == 'MD') then + i = 2 + else + write (errmsg, '(3a)') & + 'UNKNOWN IMSLINEAR REORDERING_METHOD (', trim(keyword), ').' + call store_error(errmsg) + end if + this%IORD = i + case ('NUMBER_ORTHOGONALIZATIONS') + this%north = parser%GetInteger() + case ('RELAXATION_FACTOR') + this%relax = parser%GetDouble() + case ('PRECONDITIONER_LEVELS') + i = parser%GetInteger() + this%level = i + if (i < 0) then + write (errmsg, '(a,1x,a)') & + 'IMSLINEAR PRECONDITIONER_LEVELS MUST BE GREATER THAN', & + 'OR EQUAL TO ZERO' + call store_error(errmsg) + end if + case ('PRECONDITIONER_DROP_TOLERANCE') + r = parser%GetDouble() + this%DROPTOL = r + if (r < DZERO) then + write (errmsg, '(a,1x,a)') & + 'IMSLINEAR PRECONDITIONER_DROP_TOLERANCE', & + 'MUST BE GREATER THAN OR EQUAL TO ZERO' + call store_error(errmsg) + end if + ! + ! -- deprecated variables + case ('INNER_HCLOSE') + this%DVCLOSE = parser%GetDouble() + ! + ! -- create warning message + write (warnmsg, '(a)') & + 'SETTING INNER_DVCLOSE TO INNER_HCLOSE VALUE' + ! + ! -- create deprecation warning + call deprecation_warning('LINEAR', 'INNER_HCLOSE', '6.1.1', & + warnmsg, parser%GetUnit()) + ! + ! -- default + case default + write (errmsg, '(3a)') & + 'UNKNOWN IMSLINEAR KEYWORD (', trim(keyword), ').' + call store_error(errmsg) + end select + end do + write (iout, '(1x,a)') 'END OF LINEAR DATA' + else + if (IFDPARAM == 0) THEN + write (errmsg, '(a)') 'NO LINEAR BLOCK DETECTED.' + call store_error(errmsg) + end if + end if + + IMSLINEARM = this%ILINMETH + ! + ! -- DETERMINE PRECONDITIONER + IF (this%LEVEL > 0 .OR. this%DROPTOL > DZERO) THEN + this%IPC = 3 + ELSE + this%IPC = 1 + END IF + IF (this%RELAX > DZERO) THEN + this%IPC = this%IPC + 1 + END IF + ! + ! -- ERROR CHECKING FOR OPTIONS + IF (this%ISCL < 0) this%ISCL = 0 + IF (this%ISCL > 2) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR ISCL MUST BE <= 2' + call store_error(errmsg) + END IF + IF (this%IORD < 0) this%IORD = 0 + IF (this%IORD > 2) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR IORD MUST BE <= 2' + call store_error(errmsg) + END IF + IF (this%NORTH < 0) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR NORTH MUST >= 0' + call store_error(errmsg) + END IF + IF (this%RCLOSE == DZERO) THEN + IF (this%ICNVGOPT /= 3) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR RCLOSE MUST > 0.0' + call store_error(errmsg) + END IF + END IF + IF (this%RELAX < DZERO) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR RELAX MUST BE >= 0.0' + call store_error(errmsg) + END IF + IF (this%RELAX > DONE) THEN + WRITE (errmsg, '(A)') 'IMSLINEAR7AR RELAX MUST BE <= 1.0' + call store_error(errmsg) + END IF + ! + ! -- CHECK FOR ERRORS IN IMSLINEAR + if (count_errors() > 0) then + call parser%StoreErrorUnit() + end if + ! + ! -- INITIALIZE IMSLINEAR VARIABLES + this%NITERC = 0 + ! + ! -- ALLOCATE AND INITIALIZE MEMORY FOR IMSLINEAR + iscllen = 1 + IF (this%ISCL .NE. 0) iscllen = NEQ + CALL mem_allocate(this%DSCALE, iscllen, 'DSCALE', TRIM(this%memoryPath)) + CALL mem_allocate(this%DSCALE2, iscllen, 'DSCALE2', TRIM(this%memoryPath)) + ! + ! -- ALLOCATE MEMORY FOR PRECONDITIONING MATRIX + ijlu = 1 + ijw = 1 + iwlu = 1 + ! + ! -- ILU0 AND MILU0 + this%NIAPC = this%NEQ + this%NJAPC = this%NJA + ! + ! -- ILUT AND MILUT + IF (this%IPC == 3 .OR. this%IPC == 4) THEN + this%NIAPC = this%NEQ + IF (this%LEVEL > 0) THEN + iwk = this%NEQ * (this%LEVEL * 2 + 1) + ELSE + iwk = 0 + DO n = 1, NEQ + i = IA(n + 1) - IA(n) + IF (i > iwk) THEN + iwk = i + END IF + END DO + iwk = this%NEQ * iwk + END IF + this%NJAPC = iwk + ijlu = iwk + ijw = 2 * this%NEQ + iwlu = this%NEQ + 1 + END IF + this%NJLU = ijlu + this%NJW = ijw + this%NWLU = iwlu + ! + ! -- ALLOCATE BASE PRECONDITIONER VECTORS + CALL mem_allocate(this%IAPC, this%NIAPC + 1, 'IAPC', TRIM(this%memoryPath)) + CALL mem_allocate(this%JAPC, this%NJAPC, 'JAPC', TRIM(this%memoryPath)) + CALL mem_allocate(this%APC, this%NJAPC, 'APC', TRIM(this%memoryPath)) + ! + ! -- ALLOCATE MEMORY FOR ILU0 AND MILU0 NON-ZERO ROW ENTRY VECTOR + CALL mem_allocate(this%IW, this%NIAPC, 'IW', TRIM(this%memoryPath)) + CALL mem_allocate(this%W, this%NIAPC, 'W', TRIM(this%memoryPath)) + ! + ! -- ALLOCATE MEMORY FOR ILUT VECTORS + CALL mem_allocate(this%JLU, ijlu, 'JLU', TRIM(this%memoryPath)) + CALL mem_allocate(this%JW, ijw, 'JW', TRIM(this%memoryPath)) + CALL mem_allocate(this%WLU, iwlu, 'WLU', TRIM(this%memoryPath)) + ! + ! -- GENERATE IAPC AND JAPC FOR ILU0 AND MILU0 + IF (this%IPC == 1 .OR. this%IPC == 2) THEN + CALL ims_base_pccrs(this%NEQ, this%NJA, this%IA, this%JA, & + this%IAPC, this%JAPC) + END IF + ! + ! -- ALLOCATE SPACE FOR PERMUTATION VECTOR + i0 = 1 + iolen = 1 + IF (this%IORD .NE. 0) THEN + i0 = this%NEQ + iolen = this%NJA + END IF + CALL mem_allocate(this%LORDER, i0, 'LORDER', TRIM(this%memoryPath)) + CALL mem_allocate(this%IORDER, i0, 'IORDER', TRIM(this%memoryPath)) + CALL mem_allocate(this%IARO, i0 + 1, 'IARO', TRIM(this%memoryPath)) + CALL mem_allocate(this%JARO, iolen, 'JARO', TRIM(this%memoryPath)) + CALL mem_allocate(this%ARO, iolen, 'ARO', TRIM(this%memoryPath)) + ! + ! -- ALLOCATE WORKING VECTORS FOR IMSLINEAR SOLVER + CALL mem_allocate(this%ID, this%NEQ, 'ID', TRIM(this%memoryPath)) + CALL mem_allocate(this%D, this%NEQ, 'D', TRIM(this%memoryPath)) + CALL mem_allocate(this%P, this%NEQ, 'P', TRIM(this%memoryPath)) + CALL mem_allocate(this%Q, this%NEQ, 'Q', TRIM(this%memoryPath)) + CALL mem_allocate(this%Z, this%NEQ, 'Z', TRIM(this%memoryPath)) + ! + ! -- ALLOCATE MEMORY FOR BCGS WORKING ARRAYS + this%NIABCGS = 1 + IF (this%ILINMETH == 2) THEN + this%NIABCGS = this%NEQ + END IF + CALL mem_allocate(this%T, this%NIABCGS, 'T', TRIM(this%memoryPath)) + CALL mem_allocate(this%V, this%NIABCGS, 'V', TRIM(this%memoryPath)) + CALL mem_allocate(this%DHAT, this%NIABCGS, 'DHAT', TRIM(this%memoryPath)) + CALL mem_allocate(this%PHAT, this%NIABCGS, 'PHAT', TRIM(this%memoryPath)) + CALL mem_allocate(this%QHAT, this%NIABCGS, 'QHAT', TRIM(this%memoryPath)) + ! + ! -- INITIALIZE IMSLINEAR VECTORS + DO n = 1, iscllen + this%DSCALE(n) = DONE + this%DSCALE2(n) = DONE + END DO + DO n = 1, this%NJAPC + this%APC(n) = DZERO + END DO + ! + ! -- WORKING VECTORS + DO n = 1, this%NEQ + this%ID(n) = IZERO + this%D(n) = DZERO + this%P(n) = DZERO + this%Q(n) = DZERO + this%Z(n) = DZERO + END DO + DO n = 1, this%NIAPC + this%IW(n) = IZERO + this%W(n) = DZERO + END DO + ! + ! -- BCGS WORKING VECTORS + DO n = 1, this%NIABCGS + this%T(n) = DZERO + this%V(n) = DZERO + this%DHAT(n) = DZERO + this%PHAT(n) = DZERO + this%QHAT(n) = DZERO + END DO + ! + ! -- ILUT AND MILUT WORKING VECTORS + DO n = 1, ijlu + this%JLU(n) = DZERO + END DO + DO n = 1, ijw + this%JW(n) = DZERO + END DO + DO n = 1, iwlu + this%WLU(n) = DZERO + END DO + ! + ! -- REORDERING VECTORS + DO n = 1, i0 + 1 + this%IARO(n) = IZERO + END DO + DO n = 1, iolen + this%JARO(n) = IZERO + this%ARO(n) = DZERO + END DO + ! + ! -- REVERSE CUTHILL MCKEE AND MINIMUM DEGREE ORDERING + IF (this%IORD .NE. 0) THEN + CALL ims_base_calc_order(this%IORD, this%NEQ, this%NJA, this%IA, & + this%JA, this%LORDER, this%IORDER) + END IF + ! + ! -- ALLOCATE MEMORY FOR STORING ITERATION CONVERGENCE DATA + ! + ! -- RETURN + RETURN + END SUBROUTINE imslinear_ar + + !> @ brief Write summary of settings + !! + !! Write summary of linear accelerator settings. + !! + !< + subroutine imslinear_summary(this, mxiter) + ! -- dummy variables + class(ImsLinearDataType), intent(inout) :: this !< ImsLinearDataType instance + integer(I4B), intent(in) :: mxiter !< maximum number of outer iterations + ! -- local variables + CHARACTER(LEN=10) :: clin(0:2) + CHARACTER(LEN=31) :: clintit(0:2) + CHARACTER(LEN=20) :: cipc(0:4) + CHARACTER(LEN=20) :: cscale(0:2) + CHARACTER(LEN=25) :: corder(0:2) + CHARACTER(LEN=16), DIMENSION(0:4) :: ccnvgopt + CHARACTER(LEN=15) :: clevel + CHARACTER(LEN=15) :: cdroptol + integer(I4B) :: i + integer(I4B) :: j + ! -- data + DATA clin/'UNKNOWN ', & + &'CG ', & + &'BCGS '/ + DATA clintit/' UNKNOWN ', & + &' CONJUGATE-GRADIENT ', & + &'BICONJUGATE-GRADIENT STABILIZED'/ + DATA cipc/'UNKNOWN ', & + &'INCOMPLETE LU ', & + &'MOD. INCOMPLETE LU ', & + &'INCOMPLETE LUT ', & + &'MOD. INCOMPLETE LUT '/ + DATA cscale/'NO SCALING ', & + &'SYMMETRIC SCALING ', & + &'L2 NORM SCALING '/ + DATA corder/'ORIGINAL ORDERING ', & + &'RCM ORDERING ', & + &'MINIMUM DEGREE ORDERING '/ + DATA ccnvgopt/'INFINITY NORM ', & + &'INFINITY NORM S ', & + &'L2 NORM ', & + &'RELATIVE L2NORM ', & + &'L2 NORM W. REL. '/ + ! -- formats +02010 FORMAT(1X, /, 7X, 'SOLUTION BY THE', 1X, A31, 1X, 'METHOD', & + /, 1X, 66('-'), /, & + ' MAXIMUM OF ', I0, ' CALLS OF SOLUTION ROUTINE', /, & + ' MAXIMUM OF ', I0, & + ' INTERNAL ITERATIONS PER CALL TO SOLUTION ROUTINE', /, & + ' LINEAR ACCELERATION METHOD =', 1X, A, /, & + ' MATRIX PRECONDITIONING TYPE =', 1X, A, /, & + ' MATRIX SCALING APPROACH =', 1X, A, /, & + ' MATRIX REORDERING APPROACH =', 1X, A, /, & + ' NUMBER OF ORTHOGONALIZATIONS =', 1X, I0, /, & + ' HEAD CHANGE CRITERION FOR CLOSURE =', E15.5, /, & + ' RESIDUAL CHANGE CRITERION FOR CLOSURE =', E15.5, /, & + ' RESIDUAL CONVERGENCE OPTION =', 1X, I0, /, & + ' RESIDUAL CONVERGENCE NORM =', 1X, A, /, & + ' RELAXATION FACTOR =', E15.5) +02015 FORMAT(' NUMBER OF LEVELS =', A15, /, & + ' DROP TOLERANCE =', A15, //) +2030 FORMAT(1X, A20, 1X, 6(I6, 1X)) +2040 FORMAT(1X, 20('-'), 1X, 6(6('-'), 1X)) +2050 FORMAT(1X, 62('-'),/) ! +! -- ----------------------------------------------------------- + ! + ! -- initialize clevel and cdroptol + clevel = '' + cdroptol = '' + ! + ! -- write common variables to all linear accelerators + write (this%iout, 2010) & + clintit(this%ILINMETH), MXITER, this%ITER1, & + clin(this%ILINMETH), cipc(this%IPC), & + cscale(this%ISCL), corder(this%IORD), & + this%NORTH, this%DVCLOSE, this%RCLOSE, & + this%ICNVGOPT, ccnvgopt(this%ICNVGOPT), & + this%RELAX + if (this%level > 0) then + write (clevel, '(i15)') this%level + end if + if (this%droptol > DZERO) then + write (cdroptol, '(e15.5)') this%droptol + end if + IF (this%level > 0 .or. this%droptol > DZERO) THEN + write (this%iout, 2015) trim(adjustl(clevel)), & + trim(adjustl(cdroptol)) + ELSE + write (this%iout, '(//)') + END IF + + if (this%iord /= 0) then + ! + ! -- WRITE SUMMARY OF REORDERING INFORMATION TO LIST FILE + if (this%iprims == 2) then + DO i = 1, this%neq, 6 + write (this%iout, 2030) 'ORIGINAL NODE :', & + (j, j=i, MIN(i + 5, this%neq)) + write (this%iout, 2040) + write (this%iout, 2030) 'REORDERED INDEX :', & + (this%lorder(j), j=i, MIN(i + 5, this%neq)) + write (this%iout, 2030) 'REORDERED NODE :', & + (this%iorder(j), j=i, MIN(i + 5, this%neq)) + write (this%iout, 2050) + END DO + END IF + end if + ! + ! -- return + return + end subroutine imslinear_summary + + !> @ brief Allocate and initialize scalars + !! + !! Allocate and inititialize linear accelerator scalars + !! + !< + subroutine allocate_scalars(this) + ! -- modules + use MemoryManagerModule, only: mem_allocate + ! -- dummy variables + class(ImsLinearDataType), intent(inout) :: this !< ImsLinearDataType instance + ! + ! -- allocate scalars + call mem_allocate(this%iout, 'IOUT', this%memoryPath) + call mem_allocate(this%ilinmeth, 'ILINMETH', this%memoryPath) + call mem_allocate(this%iter1, 'ITER1', this%memoryPath) + call mem_allocate(this%ipc, 'IPC', this%memoryPath) + call mem_allocate(this%iscl, 'ISCL', this%memoryPath) + call mem_allocate(this%iord, 'IORD', this%memoryPath) + call mem_allocate(this%north, 'NORTH', this%memoryPath) + call mem_allocate(this%icnvgopt, 'ICNVGOPT', this%memoryPath) + call mem_allocate(this%iacpc, 'IACPC', this%memoryPath) + call mem_allocate(this%niterc, 'NITERC', this%memoryPath) + call mem_allocate(this%niabcgs, 'NIABCGS', this%memoryPath) + call mem_allocate(this%niapc, 'NIAPC', this%memoryPath) + call mem_allocate(this%njapc, 'NJAPC', this%memoryPath) + call mem_allocate(this%dvclose, 'DVCLOSE', this%memoryPath) + call mem_allocate(this%rclose, 'RCLOSE', this%memoryPath) + call mem_allocate(this%relax, 'RELAX', this%memoryPath) + call mem_allocate(this%epfact, 'EPFACT', this%memoryPath) + call mem_allocate(this%l2norm0, 'L2NORM0', this%memoryPath) + call mem_allocate(this%droptol, 'DROPTOL', this%memoryPath) + call mem_allocate(this%level, 'LEVEL', this%memoryPath) + call mem_allocate(this%njlu, 'NJLU', this%memoryPath) + call mem_allocate(this%njw, 'NJW', this%memoryPath) + call mem_allocate(this%nwlu, 'NWLU', this%memoryPath) + ! + ! -- initialize scalars + this%iout = 0 + this%ilinmeth = 0 + this%iter1 = 0 + this%ipc = 0 + this%iscl = 0 + this%iord = 0 + this%north = 0 + this%icnvgopt = 0 + this%iacpc = 0 + this%niterc = 0 + this%niabcgs = 0 + this%niapc = 0 + this%njapc = 0 + this%dvclose = DZERO + this%rclose = DZERO + this%relax = DZERO + this%epfact = DZERO + this%l2norm0 = 0 + this%droptol = DZERO + this%level = 0 + this%njlu = 0 + this%njw = 0 + this%nwlu = 0 + ! + ! -- return + return + end subroutine allocate_scalars + + !> @ brief Deallocate memory + !! + !! Deallocate linear accelerator memory. + !! + !< + subroutine imslinear_da(this) + ! -- modules + use MemoryManagerModule, only: mem_deallocate + ! -- dummy variables + class(ImsLinearDataType), intent(inout) :: this !< linear datatype instance + ! + ! -- arrays + call mem_deallocate(this%dscale) + call mem_deallocate(this%dscale2) + call mem_deallocate(this%iapc) + call mem_deallocate(this%japc) + call mem_deallocate(this%apc) + call mem_deallocate(this%iw) + call mem_deallocate(this%w) + call mem_deallocate(this%jlu) + call mem_deallocate(this%jw) + call mem_deallocate(this%wlu) + call mem_deallocate(this%lorder) + call mem_deallocate(this%iorder) + call mem_deallocate(this%iaro) + call mem_deallocate(this%jaro) + call mem_deallocate(this%aro) + call mem_deallocate(this%id) + call mem_deallocate(this%d) + call mem_deallocate(this%p) + call mem_deallocate(this%q) + call mem_deallocate(this%z) + call mem_deallocate(this%t) + call mem_deallocate(this%v) + call mem_deallocate(this%dhat) + call mem_deallocate(this%phat) + call mem_deallocate(this%qhat) + ! + ! -- scalars + call mem_deallocate(this%iout) + call mem_deallocate(this%ilinmeth) + call mem_deallocate(this%iter1) + call mem_deallocate(this%ipc) + call mem_deallocate(this%iscl) + call mem_deallocate(this%iord) + call mem_deallocate(this%north) + call mem_deallocate(this%icnvgopt) + call mem_deallocate(this%iacpc) + call mem_deallocate(this%niterc) + call mem_deallocate(this%niabcgs) + call mem_deallocate(this%niapc) + call mem_deallocate(this%njapc) + call mem_deallocate(this%dvclose) + call mem_deallocate(this%rclose) + call mem_deallocate(this%relax) + call mem_deallocate(this%epfact) + call mem_deallocate(this%l2norm0) + call mem_deallocate(this%droptol) + call mem_deallocate(this%level) + call mem_deallocate(this%njlu) + call mem_deallocate(this%njw) + call mem_deallocate(this%nwlu) + ! + ! -- nullify pointers + nullify (this%iprims) + nullify (this%neq) + nullify (this%nja) + nullify (this%ia) + nullify (this%ja) + nullify (this%amat) + nullify (this%rhs) + nullify (this%x) + ! + ! -- return + return + end subroutine imslinear_da + + !> @ brief Set default settings + !! + !! Set default linear accelerator settings. + !! + !< + SUBROUTINE imslinear_set_input(this, IFDPARAM) + ! -- dummy variables + CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance + integer(I4B), INTENT(IN) :: IFDPARAM !< complexity option + ! -- code + SELECT CASE (IFDPARAM) + ! + ! -- Simple option + CASE (1) + this%ITER1 = 50 + this%ILINMETH = 1 + this%IPC = 1 + this%ISCL = 0 + this%IORD = 0 + this%DVCLOSE = DEM3 + this%RCLOSE = DEM1 + this%RELAX = DZERO + this%LEVEL = 0 + this%DROPTOL = DZERO + this%NORTH = 0 + ! + ! -- Moderate + CASE (2) + this%ITER1 = 100 + this%ILINMETH = 2 + this%IPC = 2 + this%ISCL = 0 + this%IORD = 0 + this%DVCLOSE = DEM2 + this%RCLOSE = DEM1 + this%RELAX = 0.97D0 + this%LEVEL = 0 + this%DROPTOL = DZERO + this%NORTH = 0 + ! + ! -- Complex + CASE (3) + this%ITER1 = 500 + this%ILINMETH = 2 + this%IPC = 3 + this%ISCL = 0 + this%IORD = 0 + this%DVCLOSE = DEM1 + this%RCLOSE = DEM1 + this%RELAX = DZERO + this%LEVEL = 5 + this%DROPTOL = DEM4 + this%NORTH = 2 + END SELECT + ! + ! -- return + RETURN + END SUBROUTINE imslinear_set_input + + !> @ brief Base linear accelerator subroutine + !! + !! Base linear accelerator subroutine that scales and reorders + !! the system of equations, if necessary, updates the preconditioner, + !! and calls the appropriate linear accelerator. + !! + !< + SUBROUTINE imslinear_ap(this, ICNVG, KSTP, KITER, IN_ITER, & + NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & + CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & + DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) + ! -- modules + USE SimModule + ! -- dummy variables + CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance + integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) + integer(I4B), INTENT(IN) :: KSTP !< time step number + integer(I4B), INTENT(IN) :: KITER !< outer iteration number + integer(I4B), INTENT(INOUT) :: IN_ITER !< inner iteration number + ! -- convergence information dummy variables + integer(I4B), INTENT(IN) :: NCONV !< + integer(I4B), INTENT(IN) :: CONVNMOD !< + integer(I4B), DIMENSION(CONVNMOD + 1), INTENT(INOUT) :: CONVMODSTART !< + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< + integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< + character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< + integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< + integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< + real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< + real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< + ! -- local variables + integer(I4B) :: n + integer(I4B) :: innerit + integer(I4B) :: irc + integer(I4B) :: itmax + real(DP) :: dnrm2 + ! + ! -- set epfact based on timestep + IF (this%ICNVGOPT == 2) THEN + IF (KSTP == 1) THEN + this%EPFACT = 0.01 + ELSE + this%EPFACT = 0.10 + END IF + ELSE IF (this%ICNVGOPT == 4) THEN + this%EPFACT = DEM4 + ELSE + this%EPFACT = DONE + END IF + ! + ! -- SCALE PROBLEM + IF (this%ISCL .NE. 0) THEN + CALL ims_base_scale(0, this%ISCL, & + this%NEQ, this%NJA, this%IA, this%JA, & + this%AMAT, this%X, this%RHS, & + this%DSCALE, this%DSCALE2) + END IF + ! + ! -- PERMUTE ROWS, COLUMNS, AND RHS + IF (this%IORD /= 0) THEN + CALL dperm(this%NEQ, this%AMAT, this%JA, this%IA, & + this%ARO, this%JARO, this%IARO, & + this%LORDER, this%ID, 1) + CALL dvperm(this%NEQ, this%X, this%LORDER) + CALL dvperm(this%NEQ, this%RHS, this%LORDER) + this%IA0 => this%IARO + this%JA0 => this%JARO + this%A0 => this%ARO + ELSE + this%IA0 => this%IA + this%JA0 => this%JA + this%A0 => this%AMAT + END IF + ! + ! -- UPDATE PRECONDITIONER + CALL ims_base_pcu(this%iout, this%NJA, this%NEQ, this%NIAPC, this%NJAPC, & + this%IPC, this%RELAX, this%A0, this%IA0, this%JA0, & + this%APC, this%IAPC, this%JAPC, this%IW, this%W, & + this%LEVEL, this%DROPTOL, this%NJLU, this%NJW, & + this%NWLU, this%JLU, this%JW, this%WLU) + ! + ! -- INITIALIZE SOLUTION VARIABLE AND ARRAYS + IF (KITER == 1) this%NITERC = 0 + irc = 1 + ICNVG = 0 + DO n = 1, this%NEQ + this%D(n) = DZERO + this%P(n) = DZERO + this%Q(n) = DZERO + this%Z(n) = DZERO + END DO + ! + ! -- CALCULATE INITIAL RESIDUAL + call ims_base_residual(this%NEQ, this%NJA, this%X, this%RHS, this%D, & + this%A0, this%IA0, this%JA0) + this%L2NORM0 = dnrm2(this%NEQ, this%D, 1) + ! + ! -- CHECK FOR EXACT SOLUTION + itmax = this%ITER1 + IF (this%L2NORM0 == DZERO) THEN + itmax = 0 + ICNVG = 1 + END IF + ! + ! -- SOLUTION BY THE CONJUGATE GRADIENT METHOD + IF (this%ILINMETH == 1) THEN + CALL ims_base_cg(ICNVG, itmax, innerit, & + this%NEQ, this%NJA, this%NIAPC, this%NJAPC, & + this%IPC, this%NITERC, this%ICNVGOPT, this%NORTH, & + this%DVCLOSE, this%RCLOSE, this%L2NORM0, & + this%EPFACT, this%IA0, this%JA0, this%A0, & + this%IAPC, this%JAPC, this%APC, & + this%X, this%RHS, this%D, this%P, this%Q, this%Z, & + this%NJLU, this%IW, this%JLU, & + NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & + CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & + DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) + ! + ! -- SOLUTION BY THE BICONJUGATE GRADIENT STABILIZED METHOD + ELSE IF (this%ILINMETH == 2) THEN + CALL ims_base_bcgs(ICNVG, itmax, innerit, & + this%NEQ, this%NJA, this%NIAPC, this%NJAPC, & + this%IPC, this%NITERC, this%ICNVGOPT, this%NORTH, & + this%ISCL, this%DSCALE, & + this%DVCLOSE, this%RCLOSE, this%L2NORM0, & + this%EPFACT, this%IA0, this%JA0, this%A0, & + this%IAPC, this%JAPC, this%APC, & + this%X, this%RHS, this%D, this%P, this%Q, & + this%T, this%V, this%DHAT, this%PHAT, this%QHAT, & + this%NJLU, this%IW, this%JLU, & + NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & + CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & + DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) + END IF + ! + ! -- BACK PERMUTE AMAT, SOLUTION, AND RHS + IF (this%IORD /= 0) THEN + CALL dperm(this%NEQ, this%A0, this%JA0, this%IA0, & + this%AMAT, this%JA, this%IA, & + this%IORDER, this%ID, 1) + CALL dvperm(this%NEQ, this%X, this%IORDER) + CALL dvperm(this%NEQ, this%RHS, this%IORDER) + END IF + ! + ! -- UNSCALE PROBLEM + IF (this%ISCL .NE. 0) THEN + CALL ims_base_scale(1, this%ISCL, & + this%NEQ, this%NJA, this%IA, this%JA, & + this%AMAT, this%X, this%RHS, & + this%DSCALE, this%DSCALE2) + END IF + ! + ! -- SET IMS INNER ITERATION NUMBER (IN_ITER) TO NUMBER OF + ! IMSLINEAR INNER ITERATIONS (innerit) + IN_ITER = innerit + ! + ! -- RETURN + RETURN + END SUBROUTINE imslinear_ap + +END MODULE IMSLinearModule diff --git a/src/Solution/LinearMethods/ims8misc.f90 b/src/Solution/LinearMethods/ims8misc.f90 new file mode 100644 index 00000000000..0000f7d2ccb --- /dev/null +++ b/src/Solution/LinearMethods/ims8misc.f90 @@ -0,0 +1,54 @@ +MODULE IMSLinearMisc + + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, DONE + + private + public :: ims_misc_thomas + +CONTAINS + + !> @brief Tridiagonal solve using the Thomas algorithm + !! + !! Subroutine to solve tridiagonal linear equations using the + !! Thomas algorithm. + !! + !< + subroutine ims_misc_thomas(n, tl, td, tu, b, x, w) + implicit none + ! -- dummy variables + integer(I4B), intent(in) :: n !< number of matrix rows + real(DP), dimension(n), intent(in) :: tl !< lower matrix terms + real(DP), dimension(n), intent(in) :: td !< diagonal matrix terms + real(DP), dimension(n), intent(in) :: tu !< upper matrix terms + real(DP), dimension(n), intent(in) :: b !< right-hand side vector + real(DP), dimension(n), intent(inout) :: x !< solution vector + real(DP), dimension(n), intent(inout) :: w !< work vector + ! -- local variables + integer(I4B) :: j + real(DP) :: bet + real(DP) :: beti + ! + ! -- initialize variables + w(1) = DZERO + bet = td(1) + beti = DONE / bet + x(1) = b(1) * beti + ! + ! -- decomposition and forward substitution + do j = 2, n + w(j) = tu(j - 1) * beti + bet = td(j) - tl(j) * w(j) + beti = DONE / bet + x(j) = (b(j) - tl(j) * x(j - 1)) * beti + end do + ! + ! -- backsubstitution + do j = n - 1, 1, -1 + x(j) = x(j) - w(j + 1) * x(j + 1) + end do + ! -- return + return + end subroutine ims_misc_thomas + +END MODULE IMSLinearMisc diff --git a/src/Solution/LinearMethods/ims8reordering.f90 b/src/Solution/LinearMethods/ims8reordering.f90 new file mode 100644 index 00000000000..7b4138ff0d7 --- /dev/null +++ b/src/Solution/LinearMethods/ims8reordering.f90 @@ -0,0 +1,774 @@ +MODULE IMSReorderingModule + use KindModule, only: DP, I4B + private + public :: ims_odrv +contains + + subroutine ims_odrv(n, nja, nsp, ia, ja, p, ip, isp, flag) + ! + ! 3/12/82 + !*********************************************************************** + ! odrv -- driver for sparse matrix reordering routines + !*********************************************************************** + ! + ! description + ! + ! odrv finds a minimum degree ordering of the rows and columns + ! of a matrix m stored in (ia,ja,a) format (see below). for the + ! reordered matrix, the work and storage required to perform + ! gaussian elimination is (usually) significantly less. + ! + ! note.. odrv and its subordinate routines have been modified to + ! compute orderings for general matrices, not necessarily having any + ! symmetry. the minimum degree ordering is computed for the + ! structure of the symmetric matrix m + m-transpose. + ! modifications to the original odrv module have been made in + ! the coding in subroutine mdi, and in the initial comments in + ! subroutines odrv and md. + ! + ! if only the nonzero entries in the upper triangle of m are being + ! stored, then odrv symmetrically reorders (ia,ja,a), (optionally) + ! with the diagonal entries placed first in each row. this is to + ! ensure that if m(i,j) will be in the upper triangle of m with + ! respect to the new ordering, then m(i,j) is stored in row i (and + ! thus m(j,i) is not stored), whereas if m(i,j) will be in the + ! strict lower triangle of m, then m(j,i) is stored in row j (and + ! thus m(i,j) is not stored). + ! + ! + ! storage of sparse matrices + ! + ! the nonzero entries of the matrix m are stored row-by-row in the + ! array a. to identify the individual nonzero entries in each row, + ! we need to know in which column each entry lies. these column + ! indices are stored in the array ja. i.e., if a(k) = m(i,j), then + ! ja(k) = j. to identify the individual rows, we need to know where + ! each row starts. these row pointers are stored in the array ia. + ! i.e., if m(i,j) is the first nonzero entry (stored) in the i-th row + ! and a(k) = m(i,j), then ia(i) = k. moreover, ia(n+1) points to + ! the first location following the last element in the last row. + ! thus, the number of entries in the i-th row is ia(i+1) - ia(i), + ! the nonzero entries in the i-th row are stored consecutively in + ! + ! a(ia(i)), a(ia(i)+1), ..., a(ia(i+1)-1), + ! + ! and the corresponding column indices are stored consecutively in + ! + ! ja(ia(i)), ja(ia(i)+1), ..., ja(ia(i+1)-1). + ! + ! since the coefficient matrix is symmetric, only the nonzero entries + ! in the upper triangle need be stored. for example, the matrix + ! + ! ( 1 0 2 3 0 ) + ! ( 0 4 0 0 0 ) + ! m = ( 2 0 5 6 0 ) + ! ( 3 0 6 7 8 ) + ! ( 0 0 0 8 9 ) + ! + ! could be stored as + ! + ! - 1 2 3 4 5 6 7 8 9 10 11 12 13 + ! ---+-------------------------------------- + ! ia - 1 4 5 8 12 14 + ! ja - 1 3 4 2 1 3 4 1 3 4 5 4 5 + ! a - 1 2 3 4 2 5 6 3 6 7 8 8 9 + ! + ! or (symmetrically) as + ! + ! - 1 2 3 4 5 6 7 8 9 + ! ---+-------------------------- + ! ia - 1 4 5 7 9 10 + ! ja - 1 3 4 2 3 4 4 5 5 + ! a - 1 2 3 4 5 6 7 8 9 . + ! + ! + ! parameters + ! + ! n - order of the matrix + ! + ! nja - number of nonzeroes in the matrix + ! + ! nsp - declared dimension of the one-dimensional array isp. nsp + ! must be at least 3n+4k, where k is the number of nonzeroes + ! in the strict upper triangle of m + ! + ! ia - integer one-dimensional array containing pointers to delimit + ! rows in ja and a. dimension = n+1 + ! + ! ja - integer one-dimensional array containing the column indices + ! corresponding to the elements of a. dimension = number of + ! nonzero entries in (the upper triangle of) m + ! + ! a - real one-dimensional array containing the nonzero entries in + ! (the upper triangle of) m, stored by rows. dimension = + ! number of nonzero entries in (the upper triangle of) m + ! + ! p - integer one-dimensional array used to return the permutation + ! of the rows and columns of m corresponding to the minimum + ! degree ordering. dimension = n + ! + ! ip - integer one-dimensional array used to return the inverse of + ! the permutation returned in p. dimension = n + ! + ! isp - integer one-dimensional array used for working storage. + ! dimension = nsp + ! + ! path - integer path specification. values and their meanings are - + ! 1 find minimum degree ordering only + ! 2 find minimum degree ordering and reorder symmetrically + ! stored matrix (used when only the nonzero entries in + ! the upper triangle of m are being stored) + ! 3 reorder symmetrically stored matrix as specified by + ! input permutation (used when an ordering has already + ! been determined and only the nonzero entries in the + ! upper triangle of m are being stored) + ! 4 same as 2 but put diagonal entries at start of each row + ! 5 same as 3 but put diagonal entries at start of each row + ! + ! flag - integer error flag. values and their meanings are - + ! 0 no errors detected + ! 9n+k insufficient storage in md + ! 10n+1 insufficient storage in odrv + ! 11n+1 illegal path specification + ! + ! + ! conversion from real to double precision + ! + ! change the real declarations in odrv and sro to double precision + ! declarations. + ! + !----------------------------------------------------------------------- + ! + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: nja + integer(I4B), intent(in) :: nsp + integer(I4B), dimension(n + 1), intent(in) :: ia + integer(I4B), dimension(nja), intent(in) :: ja + integer(I4B), dimension(n), intent(inout) :: p + integer(I4B), dimension(n), intent(inout) :: ip + integer(I4B), dimension(nsp), intent(inout) :: isp + integer(I4B), intent(inout) :: flag + + ! -- local + integer(I4B) :: v + integer(I4B) :: l + integer(I4B) :: head + integer(I4B) :: mmax + integer(I4B) :: next + integer(I4B) :: path + ! + ! set path for finding ordering only + ! + path = 1 + ! + ! + ! initialize error flag and validate path specification + flag = 0 + if (path < 1 .or. 5 < path) go to 111 + ! + ! find minimum degree ordering + mmax = (nsp - n) / 2 + v = 1 + l = v + mmax + head = l + mmax + next = head + n + if (mmax < n) go to 110 + ! + call ims_md(n, nja, ia, ja, mmax, isp(v), isp(l), isp(head), p, & + ip, isp(v), flag) + if (flag .ne. 0) go to 100 + ! + return + ! + ! ** error -- error detected in md + ! flag = 9 * n + vi from routine mdi. + ! +100 return + ! ** error -- insufficient storage +110 flag = 10 * n + 1 + return + ! ** error -- illegal path specified +111 flag = 11 * n + 1 + return + end subroutine ims_odrv + + subroutine ims_md(n, nja, ia, ja, mmax, v, l, head, last, next, & + mark, flag) + ! + !***************************************************************** + ! ims_md -- minimum degree algorithm (based on element model) + !***************************************************************** + ! + ! description + ! + ! ims_md finds a minimum degree ordering of the rows and + ! columns of a general sparse matrix m stored in (ia,ja,a) + ! format. when the structure of m is nonsymmetric, the ordering + ! is that obtained for the symmetric matrix m + m-transpose. + ! + ! + ! additional parameters + ! + ! mmax - declared dimension of the one-dimensional arrays v and l. + ! mmax must be at least n+2k, where k is the number of + ! nonzeroes in the strict upper triangle of m + ! + ! v - integer one-dimensional work array. dimension = mmax + ! + ! l - integer one-dimensional work array. dimension = mmax + ! + ! head - integer one-dimensional work array. dimension = n + ! + ! last - integer one-dimensional array used to return the permutation + ! of the rows and columns of m corresponding to the minimum + ! degree ordering. dimension = n + ! + ! next - integer one-dimensional array used to return the inverse of + ! the permutation returned in last. dimension = n + ! + ! mark - integer one-dimensional work array (may be the same as v). + ! dimension = n + ! + ! flag - integer error flag. values and their meanings are - + ! 0 no errors detected + ! 11n+1 insufficient storage in md + ! + ! + ! definitions of internal parameters + ! + ! ---------+--------------------------------------------------------- + ! v(s) - value field of list entry + ! ---------+--------------------------------------------------------- + ! l(s) - link field of list entry (0 =) end of list) + ! ---------+--------------------------------------------------------- + ! l(vi) - pointer to element list of uneliminated vertex vi + ! ---------+--------------------------------------------------------- + ! l(ej) - pointer to boundary list of active element ej + ! ---------+--------------------------------------------------------- + ! head(d) - vj =) vj head of d-list d + ! - 0 =) no vertex in d-list d + ! + ! + ! - vi uneliminated vertex + ! - vi in ek - vi not in ek + ! ---------+-----------------------------+--------------------------- + ! next(vi) - undefined but nonnegative - vj =) vj next in d-list + ! - - 0 =) vi tail of d-list + ! ---------+-----------------------------+--------------------------- + ! last(vi) - (not set until mdp) - -d =) vi head of d-list d + ! --vk =) compute degree - vj =) vj last in d-list + ! - ej =) vi prototype of ej - 0 =) vi not in any d-list + ! - 0 =) do not compute degree - + ! ---------+-----------------------------+--------------------------- + ! mark(vi) - mark(vk) - nonneg. tag .lt. mark(vk) + ! + ! + ! - vi eliminated vertex + ! - ei active element - otherwise + ! ---------+-----------------------------+--------------------------- + ! next(vi) - -j =) vi was j-th vertex - -j =) vi was j-th vertex + ! - to be eliminated - to be eliminated + ! ---------+-----------------------------+--------------------------- + ! last(vi) - m =) size of ei = m - undefined + ! ---------+-----------------------------+--------------------------- + ! mark(vi) - -m =) overlap count of ei - undefined + ! - with ek = m - + ! - otherwise nonnegative tag - + ! - .lt. mark(vk) - + ! + !----------------------------------------------------------------------- + ! + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: nja + integer(I4B), dimension(n + 1), intent(in) :: ia + integer(I4B), dimension(nja), intent(in) :: ja + integer(I4B), intent(in) :: mmax + integer(I4B), dimension(mmax), intent(inout) :: v + integer(I4B), dimension(mmax), intent(inout) :: l + integer(I4B), dimension(n), intent(inout) :: head + integer(I4B), dimension(n), intent(inout) :: last + integer(I4B), dimension(n), intent(inout) :: next + integer(I4B), dimension(n), intent(inout) :: mark + integer(I4B), intent(inout) :: flag + + ! -- local + integer(I4B) :: tag + integer(I4B) :: dmin + integer(I4B) :: vk + integer(I4B) :: ek + integer(I4B) :: tail + integer(I4B) :: k + + equivalence(vk, ek) + ! + ! initialization + tag = 0 + call ims_mdi(n, nja, ia, ja, mmax, v, l, head, last, next, & + mark, tag, flag) + if (flag .ne. 0) return + ! + k = 0 + dmin = 1 + ! + ! while k .lt. n do +1 if (k >= n) go to 4 + ! + ! search for vertex of minimum degree +2 if (head(dmin) > 0) go to 3 + dmin = dmin + 1 + go to 2 + ! + ! remove vertex vk of minimum degree from degree list +3 vk = head(dmin) + head(dmin) = next(vk) + if (head(dmin) > 0) last(head(dmin)) = -dmin + ! + ! number vertex vk, adjust tag, and tag vk + k = k + 1 + next(vk) = -k + last(ek) = dmin - 1 + tag = tag + last(ek) + mark(vk) = tag + ! + ! form element ek from uneliminated neighbors of vk + call ims_mdm(n, mmax, vk, tail, v, l, last, next, mark) + ! + ! purge inactive elements and do mass elimination + call ims_mdp(n, mmax, k, ek, tail, v, l, head, last, next, mark) + ! + ! update degrees of uneliminated vertices in ek + call ims_mdu(n, mmax, ek, dmin, v, l, head, last, next, mark) + ! + go to 1 + ! + ! generate inverse permutation from permutation +4 do k = 1, n + next(k) = -next(k) + last(next(k)) = k + end do + ! + return + end subroutine ims_md + + subroutine ims_mdi(n, nja, ia, ja, mmax, v, l, head, last, next, & + mark, tag, flag) + ! + !*********************************************************************** + ! ims_mdi -- initialization + !*********************************************************************** + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: nja + integer(I4B), dimension(n + 1), intent(in) :: ia + integer(I4B), dimension(nja), intent(in) :: ja + integer(I4B), intent(in) :: mmax + integer(I4B), dimension(mmax), intent(inout) :: v + integer(I4B), dimension(mmax), intent(inout) :: l + integer(I4B), dimension(n), intent(inout) :: head + integer(I4B), dimension(n), intent(inout) :: last + integer(I4B), dimension(n), intent(inout) :: next + integer(I4B), dimension(n), intent(inout) :: mark + integer(I4B), intent(in) :: tag + integer(I4B), intent(inout) :: flag + + ! -- local + integer(I4B) :: sfs + integer(I4B) :: vi + integer(I4B) :: dvi + integer(I4B) :: vj + integer(I4B) :: jmin + integer(I4B) :: jmax + integer(I4B) :: j + integer(I4B) :: lvk + integer(I4B) :: kmax + integer(I4B) :: k + integer(I4B) :: nextvi + integer(I4B) :: ieval + ! + ! initialize degrees, element lists, and degree lists + do vi = 1, n + mark(vi) = 1 + l(vi) = 0 + head(vi) = 0 + end do + sfs = n + 1 + ! + ! create nonzero structure + ! for each nonzero entry a(vi,vj) + louter: do vi = 1, n + jmin = ia(vi) + jmax = ia(vi + 1) - 1 + if (jmin > jmax) cycle louter + linner1: do j = jmin, jmax !5 + vj = ja(j) + !if (vj-vi) 2, 5, 4 + ieval = vj - vi + if (ieval == 0) cycle linner1 !5 + if (ieval > 0) go to 4 + ! + ! if a(vi,vj) is in strict lower triangle + ! check for previous occurrence of a(vj,vi) + lvk = vi + kmax = mark(vi) - 1 + if (kmax == 0) go to 4 + linner2: do k = 1, kmax + lvk = l(lvk) + if (v(lvk) == vj) cycle linner1 !5 + end do linner2 + ! for unentered entries a(vi,vj) +4 if (sfs >= mmax) go to 101 + ! + ! enter vj in element list for vi + mark(vi) = mark(vi) + 1 + v(sfs) = vj + l(sfs) = l(vi) + l(vi) = sfs + sfs = sfs + 1 + ! + ! enter vi in element list for vj + mark(vj) = mark(vj) + 1 + v(sfs) = vi + l(sfs) = l(vj) + l(vj) = sfs + sfs = sfs + 1 + end do linner1 + end do louter + ! + ! create degree lists and initialize mark vector + do vi = 1, n + dvi = mark(vi) + next(vi) = head(dvi) + head(dvi) = vi + last(vi) = -dvi + nextvi = next(vi) + if (nextvi > 0) last(nextvi) = vi + mark(vi) = tag + end do + ! + return + ! + ! ** error- insufficient storage +101 flag = 9 * n + vi + return + end subroutine ims_mdi + + subroutine ims_mdm(n, mmax, vk, tail, v, l, last, next, mark) + ! + !*********************************************************************** + ! ims_mdm -- form element from uneliminated neighbors of vk + !*********************************************************************** + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: mmax + integer(I4B), intent(in) :: vk + integer(I4B), intent(inout) :: tail + integer(I4B), dimension(mmax), intent(inout) :: v + integer(I4B), dimension(mmax), intent(inout) :: l + integer(I4B), dimension(n), intent(inout) :: last + integer(I4B), dimension(n), intent(inout) :: next + integer(I4B), dimension(n), intent(inout) :: mark + + ! -- local + integer(I4B) :: tag + integer(I4B) :: s + integer(I4B) :: ls + integer(I4B) :: vs + integer(I4B) :: es + integer(I4B) :: b + integer(I4B) :: lb + integer(I4B) :: vb + integer(I4B) :: blp + integer(I4B) :: blpmax + + equivalence(vs, es) + ! + ! initialize tag and list of uneliminated neighbors + tag = mark(vk) + tail = vk + ! + ! for each vertex/element vs/es in element list of vk + ls = l(vk) +1 s = ls + if (s == 0) go to 5 + ls = l(s) + vs = v(s) + if (next(vs) < 0) go to 2 + ! + ! if vs is uneliminated vertex, then tag and append to list of + ! uneliminated neighbors + mark(vs) = tag + l(tail) = s + tail = s + go to 4 + ! + ! if es is active element, then ... + ! for each vertex vb in boundary list of element es +2 lb = l(es) + blpmax = last(es) + louter: do blp = 1, blpmax !3 + b = lb + lb = l(b) + vb = v(b) + ! + ! if vb is untagged vertex, then tag and append to list of + ! uneliminated neighbors + if (mark(vb) >= tag) cycle louter !3 + mark(vb) = tag + l(tail) = b + tail = b + end do louter + ! + ! mark es inactive + mark(es) = tag + ! +4 go to 1 + ! + ! terminate list of uneliminated neighbors +5 l(tail) = 0 + ! + return + end subroutine ims_mdm + + subroutine ims_mdp(n, mmax, k, ek, tail, v, l, head, last, next, mark) + ! + !*********************************************************************** + ! ims_mdp -- purge inactive elements and do mass elimination + !*********************************************************************** + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: mmax + integer(I4B), intent(inout) :: k + integer(I4B), intent(in) :: ek + integer(I4B), intent(inout) :: tail + integer(I4B), dimension(mmax), intent(inout) :: v + integer(I4B), dimension(mmax), intent(inout) :: l + integer(I4B), dimension(n), intent(inout) :: head + integer(I4B), dimension(n), intent(inout) :: last + integer(I4B), dimension(n), intent(inout) :: next + integer(I4B), dimension(n), intent(inout) :: mark + + ! -- local + integer(I4B) :: tag + integer(I4B) :: free + integer(I4B) :: li + integer(I4B) :: vi + integer(I4B) :: lvi + integer(I4B) :: evi + integer(I4B) :: s + integer(I4B) :: ls + integer(I4B) :: es + integer(I4B) :: ilp + integer(I4B) :: ilpmax + integer(I4B) :: i + ! + ! initialize tag + tag = mark(ek) + ! + ! for each vertex vi in ek + li = ek + ilpmax = last(ek) + if (ilpmax <= 0) go to 12 + louter: do ilp = 1, ilpmax !11 + i = li + li = l(i) + vi = v(li) + ! + ! remove vi from degree list + if (last(vi) == 0) go to 3 + if (last(vi) > 0) go to 1 + head(-last(vi)) = next(vi) + go to 2 +1 next(last(vi)) = next(vi) +2 if (next(vi) > 0) last(next(vi)) = last(vi) + ! + ! remove inactive items from element list of vi +3 ls = vi +4 s = ls + ls = l(s) + if (ls == 0) go to 6 + es = v(ls) + if (mark(es) < tag) go to 5 + free = ls + l(s) = l(ls) + ls = s +5 go to 4 + ! + ! if vi is interior vertex, then remove from list and eliminate + +6 lvi = l(vi) + if (lvi .ne. 0) go to 7 + l(i) = l(li) + li = i + ! + k = k + 1 + next(vi) = -k + last(ek) = last(ek) - 1 + cycle louter !11 + ! + ! else ... + ! classify vertex vi +7 if (l(lvi) .ne. 0) go to 9 + evi = v(lvi) + if (next(evi) >= 0) go to 9 + if (mark(evi) < 0) go to 8 + ! + ! if vi is prototype vertex, then mark as such, initialize + ! overlap count for corresponding element, and move vi to end + ! of boundary list + last(vi) = evi + mark(evi) = -1 + l(tail) = li + tail = li + l(i) = l(li) + li = i + go to 10 + ! + ! else if vi is duplicate vertex, then mark as such and adjust + ! overlap count for corresponding element +8 last(vi) = 0 + mark(evi) = mark(evi) - 1 + go to 10 + ! + ! else mark vi to compute degree +9 last(vi) = -ek + ! + ! insert ek in element list of vi +10 v(free) = ek + l(free) = l(vi) + l(vi) = free + end do louter !11 + ! + ! terminate boundary list +12 l(tail) = 0 + ! + return + end subroutine ims_mdp + + subroutine ims_mdu(n, mmax, ek, dmin, v, l, head, last, next, mark) + ! + !*********************************************************************** + ! ims_mdu -- update degrees of uneliminated vertices in ek + !*********************************************************************** + implicit none + + ! -- dummy variables + integer(I4B), intent(in) :: n + integer(I4B), intent(in) :: mmax + integer(I4B), intent(in) :: ek + integer(I4B), intent(inout) :: dmin + integer(I4B), dimension(mmax), intent(inout) :: v + integer(I4B), dimension(mmax), intent(inout) :: l + integer(I4B), dimension(n), intent(inout) :: head + integer(I4B), dimension(n), intent(inout) :: last + integer(I4B), dimension(n), intent(inout) :: next + integer(I4B), dimension(n), intent(inout) :: mark + + ! -- local + integer(I4B) :: tag + integer(I4B) :: vi + integer(I4B) :: evi + integer(I4B) :: dvi + integer(I4B) :: s + integer(I4B) :: vs + integer(I4B) :: es + integer(I4B) :: b + integer(I4B) :: vb + integer(I4B) :: ilp + integer(I4B) :: ilpmax + integer(I4B) :: blp + integer(I4B) :: blpmax + integer(I4B) :: i + + equivalence(vs, es) + ! + ! initialize tag + tag = mark(ek) - last(ek) + ! + ! for each vertex vi in ek + i = ek + ilpmax = last(ek) + if (ilpmax <= 0) go to 11 + louter: do ilp = 1, ilpmax !10 + i = l(i) + vi = v(i) + !if (last(vi)) 1, 10, 8 + if (last(vi) == 0) cycle louter !10 + if (last(vi) > 0) goto 8 + ! + ! if vi neither prototype nor duplicate vertex, then merge elements + ! to compute degree + tag = tag + 1 + dvi = last(ek) + ! + ! for each vertex/element vs/es in element list of vi + s = l(vi) +2 s = l(s) + if (s == 0) go to 9 + vs = v(s) + if (next(vs) < 0) go to 3 + ! + ! if vs is uneliminated vertex, then tag and adjust degree + mark(vs) = tag + dvi = dvi + 1 + go to 5 + ! + ! if es is active element, then expand + ! check for outmatched vertex +3 if (mark(es) < 0) go to 6 + ! + ! for each vertex vb in es + b = es + blpmax = last(es) + linner: do blp = 1, blpmax !4 + b = l(b) + vb = v(b) + ! + ! if vb is untagged, then tag and adjust degree + if (mark(vb) >= tag) cycle linner !4 + mark(vb) = tag + dvi = dvi + 1 + end do linner !4 + ! +5 go to 2 + ! + ! else if vi is outmatched vertex, then adjust overlaps but do not + ! compute degree +6 last(vi) = 0 + mark(es) = mark(es) - 1 +7 s = l(s) + if (s == 0) cycle louter !10 + es = v(s) + if (mark(es) < 0) mark(es) = mark(es) - 1 + go to 7 + ! + ! else if vi is prototype vertex, then calculate degree by + ! inclusion/exclusion and reset overlap count +8 evi = last(vi) + dvi = last(ek) + last(evi) + mark(evi) + mark(evi) = 0 + ! + ! insert vi in appropriate degree list +9 next(vi) = head(dvi) + head(dvi) = vi + last(vi) = -dvi + if (next(vi) > 0) last(next(vi)) = vi + if (dvi < dmin) dmin = dvi + ! + end do louter !10 + ! +11 return + end subroutine ims_mdu + +end module IMSReorderingModule diff --git a/src/Solution/NumericalSolution.f90 b/src/Solution/NumericalSolution.f90 index 6cc6c9468f2..e820e01afad 100644 --- a/src/Solution/NumericalSolution.f90 +++ b/src/Solution/NumericalSolution.f90 @@ -1,134 +1,135 @@ ! This is the numerical solution module. module NumericalSolutionModule - use KindModule, only: DP, I4B, LGP - use TimerModule, only: code_timer - use ConstantsModule, only: LINELENGTH, LENSOLUTIONNAME, LENPAKLOC, & - DPREC, DZERO, DEM20, DEM15, DEM6, & - DEM4, DEM3, DEM2, DEM1, DHALF, DONETHIRD, & - DONE, DTHREE, DEP3, DEP6, DEP20, DNODATA, & - TABLEFT, TABRIGHT, & - MNORMAL, MVALIDATE, & - LENMEMPATH - use MemoryHelperModule, only: create_mem_path - use TableModule, only: TableType, table_cr - use GenericUtilitiesModule, only: is_same, sim_message, stop_with_error - use VersionModule, only: IDEVELOPMODE - use BaseModelModule, only: BaseModelType - use BaseExchangeModule, only: BaseExchangeType - use BaseSolutionModule, only: BaseSolutionType, AddBaseSolutionToList - use ListModule, only: ListType - use ListsModule, only: basesolutionlist - use NumericalModelModule, only: NumericalModelType, & - AddNumericalModelToList, & - GetNumericalModelFromList - use NumericalExchangeModule, only: NumericalExchangeType, & - AddNumericalExchangeToList, & + use KindModule, only: DP, I4B, LGP + use TimerModule, only: code_timer + use ConstantsModule, only: LINELENGTH, LENSOLUTIONNAME, LENPAKLOC, & + DPREC, DZERO, DEM20, DEM15, DEM6, & + DEM4, DEM3, DEM2, DEM1, DHALF, DONETHIRD, & + DONE, DTHREE, DEP3, DEP6, DEP20, DNODATA, & + TABLEFT, TABRIGHT, & + MNORMAL, MVALIDATE, & + LENMEMPATH + use MemoryHelperModule, only: create_mem_path + use TableModule, only: TableType, table_cr + use GenericUtilitiesModule, only: is_same, sim_message, stop_with_error + use VersionModule, only: IDEVELOPMODE + use BaseModelModule, only: BaseModelType + use BaseExchangeModule, only: BaseExchangeType + use BaseSolutionModule, only: BaseSolutionType, AddBaseSolutionToList + use ListModule, only: ListType + use ListsModule, only: basesolutionlist + use NumericalModelModule, only: NumericalModelType, & + AddNumericalModelToList, & + GetNumericalModelFromList + use NumericalExchangeModule, only: NumericalExchangeType, & + AddNumericalExchangeToList, & GetNumericalExchangeFromList - use SparseModule, only: sparsematrix - use SimVariablesModule, only: iout, isim_mode - use BlockParserModule, only: BlockParserType + use SparseModule, only: sparsematrix + use SimVariablesModule, only: iout, isim_mode + use BlockParserModule, only: BlockParserType use IMSLinearModule + use DistributedDataModule implicit none private - + public :: solution_create public :: NumericalSolutionType public :: GetNumericalSolutionFromList - + type, extends(BaseSolutionType) :: NumericalSolutionType - character(len=LENMEMPATH) :: memoryPath !< the path for storing solution variables in the memory manager - character(len=LINELENGTH) :: fname !< input file name - type(ListType), pointer :: modellist !< list of models in solution - type(ListType), pointer :: exchangelist !< list of exchanges in solution - integer(I4B), pointer :: id !< solution number - integer(I4B), pointer :: iu !< input file unit - real(DP), pointer :: ttform !< timer - total formulation time - real(DP), pointer :: ttsoln !< timer - total solution time - integer(I4B), pointer :: isymmetric => null() !< flag indicating if matrix symmetry is required - integer(I4B), pointer :: neq => null() !< number of equations - integer(I4B), pointer :: nja => null() !< number of non-zero entries - integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< CRS row pointers - integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< CRS column pointers - real(DP), dimension(:), pointer, contiguous :: amat => null() !< coefficient matrix - real(DP), dimension(:), pointer, contiguous :: rhs => null() !< right-hand side vector - real(DP), dimension(:), pointer, contiguous :: x => null() !< dependent-variable vector - integer(I4B), dimension(:), pointer, contiguous :: active => null() !< active cell array - real(DP), dimension(:), pointer, contiguous :: xtemp => null() !< temporary vector for previous dependent-variable iterate - type(BlockParserType) :: parser !< block parser object + character(len=LENMEMPATH) :: memoryPath !< the path for storing solution variables in the memory manager + character(len=LINELENGTH) :: fname !< input file name + type(ListType), pointer :: modellist !< list of models in solution + type(ListType), pointer :: exchangelist !< list of exchanges in solution + integer(I4B), pointer :: id !< solution number + integer(I4B), pointer :: iu !< input file unit + real(DP), pointer :: ttform !< timer - total formulation time + real(DP), pointer :: ttsoln !< timer - total solution time + integer(I4B), pointer :: isymmetric => null() !< flag indicating if matrix symmetry is required + integer(I4B), pointer :: neq => null() !< number of equations + integer(I4B), pointer :: nja => null() !< number of non-zero entries + integer(I4B), dimension(:), pointer, contiguous :: ia => null() !< CRS row pointers + integer(I4B), dimension(:), pointer, contiguous :: ja => null() !< CRS column pointers + real(DP), dimension(:), pointer, contiguous :: amat => null() !< coefficient matrix + real(DP), dimension(:), pointer, contiguous :: rhs => null() !< right-hand side vector + real(DP), dimension(:), pointer, contiguous :: x => null() !< dependent-variable vector + integer(I4B), dimension(:), pointer, contiguous :: active => null() !< active cell array + real(DP), dimension(:), pointer, contiguous :: xtemp => null() !< temporary vector for previous dependent-variable iterate + type(BlockParserType) :: parser !< block parser object ! ! -- sparse matrix data - real(DP), pointer :: theta => null() !< under-relaxation theta - real(DP), pointer :: akappa => null() !< under-relaxation kappa - real(DP), pointer :: gamma => null() !< under-relaxation gamma - real(DP), pointer :: amomentum => null() !< under-relaxation momentum term - real(DP), pointer :: breduc => null() !< backtracking reduction factor - real(DP), pointer :: btol => null() !< backtracking tolerance - real(DP), pointer :: res_lim => null() !< backtracking residual threshold - real(DP), pointer :: dvclose => null() !< dependent-variable closure criteria - real(DP), pointer :: bigchold => null() !< cooley under-relaxation weight - real(DP), pointer :: bigch => null() !< under-relaxation maximum dependent-variable change - real(DP), pointer :: relaxold => null() !< under-relaxation previous relaxation factor - real(DP), pointer :: res_prev => null() !< previous L-2 norm - real(DP), pointer :: res_new => null() !< current L-2 norm - integer(I4B), pointer :: icnvg => null() !< convergence flag (1) non-convergence (0) - integer(I4B), pointer :: itertot_timestep => null() !< total nr. of linear solves per call to sln_ca - integer(I4B), pointer :: iouttot_timestep => null() !< total nr. of outer iterations per call to sln_ca - integer(I4B), pointer :: itertot_sim => null() !< total nr. of inner iterations for simulation - integer(I4B), pointer :: mxiter => null() !< maximum number of Picard iterations - integer(I4B), pointer :: linmeth => null() !< linear acceleration method used - integer(I4B), pointer :: nonmeth => null() !< under-relaxation method used - integer(I4B), pointer :: numtrack => null() !< maximum number of backtracks - integer(I4B), pointer :: iprims => null() !< solver print option - integer(I4B), pointer :: ibflag => null() !< backtracking flag (1) on (0) off - integer(I4B), dimension(:,:), pointer, contiguous:: lrch => null() !< location of the largest dependent-variable change at the end of a Picard iteration - real(DP), dimension(:), pointer, contiguous :: hncg => null() !< largest dependent-variable change at the end of a Picard iteration - real(DP), dimension(:), pointer, contiguous :: dxold => null() !< DBD under-relaxation previous dependent-variable change - real(DP), dimension(:), pointer, contiguous :: deold => null() !< DBD under-relaxation dependent-variable change variable - real(DP), dimension(:), pointer, contiguous :: wsave => null() !< DBD under-relaxation sign-change factor - real(DP), dimension(:), pointer, contiguous :: hchold => null() !< DBD under-relaxation weighted dependent-variable change + real(DP), pointer :: theta => null() !< under-relaxation theta + real(DP), pointer :: akappa => null() !< under-relaxation kappa + real(DP), pointer :: gamma => null() !< under-relaxation gamma + real(DP), pointer :: amomentum => null() !< under-relaxation momentum term + real(DP), pointer :: breduc => null() !< backtracking reduction factor + real(DP), pointer :: btol => null() !< backtracking tolerance + real(DP), pointer :: res_lim => null() !< backtracking residual threshold + real(DP), pointer :: dvclose => null() !< dependent-variable closure criteria + real(DP), pointer :: bigchold => null() !< cooley under-relaxation weight + real(DP), pointer :: bigch => null() !< under-relaxation maximum dependent-variable change + real(DP), pointer :: relaxold => null() !< under-relaxation previous relaxation factor + real(DP), pointer :: res_prev => null() !< previous L-2 norm + real(DP), pointer :: res_new => null() !< current L-2 norm + integer(I4B), pointer :: icnvg => null() !< convergence flag (1) non-convergence (0) + integer(I4B), pointer :: itertot_timestep => null() !< total nr. of linear solves per call to sln_ca + integer(I4B), pointer :: iouttot_timestep => null() !< total nr. of outer iterations per call to sln_ca + integer(I4B), pointer :: itertot_sim => null() !< total nr. of inner iterations for simulation + integer(I4B), pointer :: mxiter => null() !< maximum number of Picard iterations + integer(I4B), pointer :: linmeth => null() !< linear acceleration method used + integer(I4B), pointer :: nonmeth => null() !< under-relaxation method used + integer(I4B), pointer :: numtrack => null() !< maximum number of backtracks + integer(I4B), pointer :: iprims => null() !< solver print option + integer(I4B), pointer :: ibflag => null() !< backtracking flag (1) on (0) off + integer(I4B), dimension(:, :), pointer, contiguous :: lrch => null() !< location of the largest dependent-variable change at the end of a Picard iteration + real(DP), dimension(:), pointer, contiguous :: hncg => null() !< largest dependent-variable change at the end of a Picard iteration + real(DP), dimension(:), pointer, contiguous :: dxold => null() !< DBD under-relaxation previous dependent-variable change + real(DP), dimension(:), pointer, contiguous :: deold => null() !< DBD under-relaxation dependent-variable change variable + real(DP), dimension(:), pointer, contiguous :: wsave => null() !< DBD under-relaxation sign-change factor + real(DP), dimension(:), pointer, contiguous :: hchold => null() !< DBD under-relaxation weighted dependent-variable change ! ! -- convergence summary information - character(len=31), dimension(:), pointer, contiguous :: caccel => null() !< convergence string - integer(I4B), pointer :: icsvouterout => null() !< Picard iteration CSV output flag and file unit - integer(I4B), pointer :: icsvinnerout => null() !< Inner iteration CSV output flag and file unit - integer(I4B), pointer :: nitermax => null() !< maximum number of iterations in a time step (maxiter * maxinner) - integer(I4B), pointer :: convnmod => null() !< number of models in the solution - integer(I4B), dimension(:), pointer, contiguous :: convmodstart => null() !< pointer to the start of each model in the convmod* arrays - integer(I4B), dimension(:), pointer, contiguous :: locdv => null() !< location of the maximum dependent-variable change in the solution - integer(I4B), dimension(:), pointer, contiguous :: locdr => null() !< location of the maximum flow change in the solution - integer(I4B), dimension(:), pointer, contiguous :: itinner => null() !< actual number of inner iterations in each Picard iteration - integer(I4B), pointer, dimension(:,:), contiguous :: convlocdv => null() !< location of the maximum dependent-variable change in each model in the solution - integer(I4B), pointer, dimension(:,:), contiguous :: convlocdr => null() !< location of the maximum flow change in each model in the solution - real(DP), dimension(:), pointer, contiguous :: dvmax => null() !< maximum dependent-variable change in the solution - real(DP), dimension(:), pointer, contiguous :: drmax => null() !< maximum flow change in the solution - real(DP), pointer, dimension(:,:), contiguous :: convdvmax => null() !< maximum dependent-variable change in each model in the solution - real(DP), pointer, dimension(:,:), contiguous :: convdrmax => null() !< maximum flow change in each model in the solution + character(len=31), dimension(:), pointer, contiguous :: caccel => null() !< convergence string + integer(I4B), pointer :: icsvouterout => null() !< Picard iteration CSV output flag and file unit + integer(I4B), pointer :: icsvinnerout => null() !< Inner iteration CSV output flag and file unit + integer(I4B), pointer :: nitermax => null() !< maximum number of iterations in a time step (maxiter * maxinner) + integer(I4B), pointer :: convnmod => null() !< number of models in the solution + integer(I4B), dimension(:), pointer, contiguous :: convmodstart => null() !< pointer to the start of each model in the convmod* arrays + integer(I4B), dimension(:), pointer, contiguous :: locdv => null() !< location of the maximum dependent-variable change in the solution + integer(I4B), dimension(:), pointer, contiguous :: locdr => null() !< location of the maximum flow change in the solution + integer(I4B), dimension(:), pointer, contiguous :: itinner => null() !< actual number of inner iterations in each Picard iteration + integer(I4B), pointer, dimension(:, :), contiguous :: convlocdv => null() !< location of the maximum dependent-variable change in each model in the solution + integer(I4B), pointer, dimension(:, :), contiguous :: convlocdr => null() !< location of the maximum flow change in each model in the solution + real(DP), dimension(:), pointer, contiguous :: dvmax => null() !< maximum dependent-variable change in the solution + real(DP), dimension(:), pointer, contiguous :: drmax => null() !< maximum flow change in the solution + real(DP), pointer, dimension(:, :), contiguous :: convdvmax => null() !< maximum dependent-variable change in each model in the solution + real(DP), pointer, dimension(:, :), contiguous :: convdrmax => null() !< maximum flow change in each model in the solution ! ! -- pseudo-transient continuation - integer(I4B), pointer :: iallowptc => null() !< flag indicating if ptc applied this time step - integer(I4B), pointer :: iptcopt => null() !< option for how to calculate the initial PTC value (ptcdel0) - integer(I4B), pointer :: iptcout => null() !< PTC output flag and file unit - real(DP), pointer :: l2norm0 => null() !< L-2 norm at the start of the first Picard iteration - real(DP), pointer :: ptcdel => null() !< PTC delta value - real(DP), pointer :: ptcdel0 => null() !< initial PTC delta value - real(DP), pointer :: ptcexp => null() !< PTC exponent - real(DP), pointer :: ptcthresh => null() !< PTC threshold value (0.001) - real(DP), pointer :: ptcrat => null() !< ratio of the PTC value and the minimum of the diagonal of AMAT used to determine if the PTC effect has decayed + integer(I4B), pointer :: iallowptc => null() !< flag indicating if ptc applied this time step + integer(I4B), pointer :: iptcopt => null() !< option for how to calculate the initial PTC value (ptcdel0) + integer(I4B), pointer :: iptcout => null() !< PTC output flag and file unit + real(DP), pointer :: l2norm0 => null() !< L-2 norm at the start of the first Picard iteration + real(DP), pointer :: ptcdel => null() !< PTC delta value + real(DP), pointer :: ptcdel0 => null() !< initial PTC delta value + real(DP), pointer :: ptcexp => null() !< PTC exponent + real(DP), pointer :: ptcthresh => null() !< PTC threshold value (0.001) + real(DP), pointer :: ptcrat => null() !< ratio of the PTC value and the minimum of the diagonal of AMAT used to determine if the PTC effect has decayed ! ! -- adaptive time step - real(DP), pointer :: atsfrac => null() !< adaptive time step faction + real(DP), pointer :: atsfrac => null() !< adaptive time step faction ! ! -- linear accelerator storage - type(ImsLinearDataType), pointer :: imslinear => null() !< IMS linear acceleration object + type(ImsLinearDataType), pointer :: imslinear => null() !< IMS linear acceleration object ! ! -- sparse object - type(sparsematrix) :: sparse !< sparse object + type(sparsematrix) :: sparse !< sparse object ! ! -- table objects - type(TableType), pointer :: innertab => null() !< inner iteration table object - type(TableType), pointer :: outertab => null() !< Picard iteration table object + type(TableType), pointer :: innertab => null() !< inner iteration table object + type(TableType), pointer :: outertab => null() !< Picard iteration table object contains procedure :: sln_df @@ -165,30 +166,30 @@ module NumericalSolutionModule procedure, private :: sln_buildsystem procedure, private :: writeCSVHeader procedure, private :: writePTCInfoToFile - + ! Expose these for use through the BMI/XMI: procedure, public :: prepareSolve procedure, public :: solve procedure, public :: finalizeSolve - + end type NumericalSolutionType contains !> @ brief Create a new solution !! -!! Create a new solution using the data in filename, assign this new +!! Create a new solution using the data in filename, assign this new !! solution an id number and store the solution in the basesolutionlist. !! Also open the filename for later reading. !! !< -subroutine solution_create(filename, id) + subroutine solution_create(filename, id) ! -- modules use SimVariablesModule, only: iout - use InputOutputModule, only: getunit, openfile + use InputOutputModule, only: getunit, openfile ! -- dummy variables - character(len=*),intent(in) :: filename !< solution input file name - integer(I4B),intent(in) :: id !< solution id + character(len=*), intent(in) :: filename !< solution input file name + integer(I4B), intent(in) :: id !< solution id ! -- local variables integer(I4B) :: inunit type(NumericalSolutionType), pointer :: solution => null() @@ -196,14 +197,14 @@ subroutine solution_create(filename, id) character(len=LENSOLUTIONNAME) :: solutionname ! ! -- Create a new solution and add it to the basesolutionlist container - allocate(solution) + allocate (solution) solbase => solution - write(solutionname,'(a, i0)') 'SLN_', id + write (solutionname, '(a, i0)') 'SLN_', id ! solution%name = solutionname solution%memoryPath = create_mem_path(solutionname) - allocate(solution%modellist) - allocate(solution%exchangelist) + allocate (solution%modellist) + allocate (solution%exchangelist) ! call solution%allocate_scalars() ! @@ -214,11 +215,11 @@ subroutine solution_create(filename, id) ! -- Open solution input file for reading later after problem size is known ! Check to see if the file is already opened, which can happen when ! running in single model mode - inquire(file=filename, number=inunit) + inquire (file=filename, number=inunit) - if(inunit < 0) inunit = getunit() + if (inunit < 0) inunit = getunit() solution%iu = inunit - write(iout,'(/a,a)') ' Creating solution: ', solution%name + write (iout, '(/a,a)') ' Creating solution: ', solution%name call openfile(solution%iu, iout, filename, 'IMS') ! ! -- Initialize block parser @@ -274,7 +275,7 @@ subroutine allocate_scalars(this) call mem_allocate(this%icsvinnerout, 'ICSVINNEROUT', this%memoryPath) call mem_allocate(this%nitermax, 'NITERMAX', this%memoryPath) call mem_allocate(this%convnmod, 'CONVNMOD', this%memoryPath) - call mem_allocate(this%iallowptc, 'IALLOWPTC', this%memoryPath) + call mem_allocate(this%iallowptc, 'IALLOWPTC', this%memoryPath) call mem_allocate(this%iptcopt, 'IPTCOPT', this%memoryPath) call mem_allocate(this%iptcout, 'IPTCOUT', this%memoryPath) call mem_allocate(this%l2norm0, 'L2NORM0', this%memoryPath) @@ -343,7 +344,7 @@ subroutine allocate_arrays(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables class(NumericalModelType), pointer :: mp => null() integer(I4B) :: i @@ -364,16 +365,21 @@ subroutine allocate_arrays(this) call mem_allocate(this%wsave, 0, 'WSAVE', this%memoryPath) call mem_allocate(this%hchold, 0, 'HCHOLD', this%memoryPath) call mem_allocate(this%deold, 0, 'DEOLD', this%memoryPath) - call mem_allocate(this%convmodstart, this%convnmod+1, 'CONVMODSTART', this%memoryPath) + call mem_allocate(this%convmodstart, this%convnmod + 1, 'CONVMODSTART', & + this%memoryPath) call mem_allocate(this%locdv, this%convnmod, 'LOCDV', this%memoryPath) call mem_allocate(this%locdr, this%convnmod, 'LOCDR', this%memoryPath) call mem_allocate(this%itinner, 0, 'ITINNER', this%memoryPath) - call mem_allocate(this%convlocdv, this%convnmod, 0, 'CONVLOCDV', this%memoryPath) - call mem_allocate(this%convlocdr, this%convnmod, 0, 'CONVLOCDR', this%memoryPath) + call mem_allocate(this%convlocdv, this%convnmod, 0, 'CONVLOCDV', & + this%memoryPath) + call mem_allocate(this%convlocdr, this%convnmod, 0, 'CONVLOCDR', & + this%memoryPath) call mem_allocate(this%dvmax, this%convnmod, 'DVMAX', this%memoryPath) call mem_allocate(this%drmax, this%convnmod, 'DRMAX', this%memoryPath) - call mem_allocate(this%convdvmax, this%convnmod, 0, 'CONVDVMAX', this%memoryPath) - call mem_allocate(this%convdrmax, this%convnmod, 0, 'CONVDRMAX', this%memoryPath) + call mem_allocate(this%convdvmax, this%convnmod, 0, 'CONVDVMAX', & + this%memoryPath) + call mem_allocate(this%convdrmax, this%convnmod, 0, 'CONVDRMAX', & + this%memoryPath) ! ! -- initialize allocated arrays do i = 1, this%neq @@ -381,7 +387,7 @@ subroutine allocate_arrays(this) this%xtemp(i) = DZERO this%dxold(i) = DZERO this%active(i) = 1 !default is active - enddo + end do do i = 1, this%convnmod this%locdv(i) = 0 this%locdr(i) = 0 @@ -395,7 +401,7 @@ subroutine allocate_arrays(this) do i = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, i) ieq = ieq + mp%neq - this%convmodstart(i+1) = ieq + this%convmodstart(i + 1) = ieq end do ! ! -- return @@ -404,10 +410,10 @@ end subroutine allocate_arrays !> @ brief Define the solution !! - !! Define a new solution. Must be called after the models and exchanges have + !! Define a new solution. Must be called after the models and exchanges have !! been added to solution. The order of the steps is (1) Allocate neq and nja, - !! (2) Assign model offsets and solution ids, (3) Allocate and initialize - !! the solution arrays, (4) Point each model's x and rhs arrays, and + !! (2) Assign model offsets and solution ids, (3) Allocate and initialize + !! the solution arrays, (4) Point each model's x and rhs arrays, and !! (5) Initialize the sparsematrix instance !! !< @@ -415,7 +421,7 @@ subroutine sln_df(this) ! modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables class(NumericalModelType), pointer :: mp => null() integer(I4B) :: i @@ -427,7 +433,7 @@ subroutine sln_df(this) call mp%set_idsoln(this%id) call mp%set_moffset(this%neq) this%neq = this%neq + mp%neq - enddo + end do ! ! -- Allocate and initialize solution arrays call this%allocate_arrays() @@ -438,15 +444,15 @@ subroutine sln_df(this) call mp%set_xptr(this%x, 'X', this%name) call mp%set_rhsptr(this%rhs, 'RHS', this%name) call mp%set_iboundptr(this%active, 'IBOUND', this%name) - enddo + end do ! ! -- Create the sparsematrix instance - allocate(rowmaxnnz(this%neq)) - do i=1,this%neq - rowmaxnnz(i)=4 - enddo + allocate (rowmaxnnz(this%neq)) + do i = 1, this%neq + rowmaxnnz(i) = 4 + end do call this%sparse%init(this%neq, this%neq, rowmaxnnz) - deallocate(rowmaxnnz) + deallocate (rowmaxnnz) ! ! -- Assign connections, fill ia/ja, map connections call this%sln_connect() @@ -467,7 +473,7 @@ subroutine sln_ar(this) use SimModule, only: store_error, count_errors, deprecation_warning use InputOutputModule, only: getunit, openfile ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables class(NumericalModelType), pointer :: mp => null() class(NumericalExchangeType), pointer :: cp => null() @@ -484,18 +490,20 @@ subroutine sln_ar(this) logical :: isfound, endOfBlock integer(I4B) :: ival real(DP) :: rval - character(len=*),parameter :: fmtcsvout = & - "(4x, 'CSV OUTPUT WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" - character(len=*),parameter :: fmtptcout = & - "(4x, 'PTC OUTPUT WILL BE SAVED TO FILE: ', a, /4x, 'OPENED ON UNIT: ', I7)" + character(len=*), parameter :: fmtcsvout = & + "(4x, 'CSV OUTPUT WILL BE SAVED TO FILE: ', a, & + &/4x, 'OPENED ON UNIT: ', I7)" + character(len=*), parameter :: fmtptcout = & + "(4x, 'PTC OUTPUT WILL BE SAVED TO FILE: ', a, & + &/4x, 'OPENED ON UNIT: ', I7)" character(len=*), parameter :: fmterrasym = & "(a,' **',a,'** PRODUCES AN ASYMMETRIC COEFFICIENT MATRIX, BUT THE & - &CONJUGATE GRADIENT METHOD WAS SELECTED. USE BICGSTAB INSTEAD. ')" + &CONJUGATE GRADIENT METHOD WAS SELECTED. USE BICGSTAB INSTEAD. ')" ! ! identify package and initialize. - WRITE(IOUT,1) this%iu -00001 FORMAT(1X,/1X,'IMS -- ITERATIVE MODEL SOLUTION PACKAGE, VERSION 6', & - & ', 4/28/2017',/,9X,'INPUT READ FROM UNIT',I5) + WRITE (IOUT, 1) this%iu +00001 FORMAT(1X, /1X, 'IMS -- ITERATIVE MODEL SOLUTION PACKAGE, VERSION 6', & + ', 4/28/2017', /, 9X, 'INPUT READ FROM UNIT', I5) ! ! -- initialize i = 1 @@ -505,11 +513,11 @@ subroutine sln_ar(this) ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(iout,'(/1x,a)')'PROCESSING IMS OPTIONS' + write (iout, '(/1x,a)') 'PROCESSING IMS OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -517,30 +525,30 @@ subroutine sln_ar(this) select case (keyword) case ('PRINT_OPTION') call this%parser%GetStringCaps(keyword) - if (keyword.eq.'NONE') then + if (keyword .eq. 'NONE') then this%iprims = 0 - else if (keyword.eq.'SUMMARY') then + else if (keyword .eq. 'SUMMARY') then this%iprims = 1 - else if (keyword.eq.'ALL') then + else if (keyword .eq. 'ALL') then this%iprims = 2 else - write(errmsg,'(3a)') & + write (errmsg, '(3a)') & 'UNKNOWN IMS PRINT OPTION (', trim(keyword), ').' call store_error(errmsg) end if case ('COMPLEXITY') call this%parser%GetStringCaps(keyword) - if (keyword.eq.'SIMPLE') then + if (keyword .eq. 'SIMPLE') then ifdparam = 1 - WRITE(IOUT,21) - else if (keyword.eq.'MODERATE') then + WRITE (IOUT, 21) + else if (keyword .eq. 'MODERATE') then ifdparam = 2 - WRITE(IOUT,23) - else if (keyword.eq.'COMPLEX') then + WRITE (IOUT, 23) + else if (keyword .eq. 'COMPLEX') then ifdparam = 3 - WRITE(IOUT,25) + WRITE (IOUT, 25) else - write(errmsg,'(3a)') & + write (errmsg, '(3a)') & 'UNKNOWN IMS COMPLEXITY OPTION (', trim(keyword), ').' call store_error(errmsg) end if @@ -549,11 +557,11 @@ subroutine sln_ar(this) if (keyword == 'FILEOUT') then call this%parser%GetString(fname) this%icsvouterout = getunit() - call openfile(this%icsvouterout, iout, fname, 'CSV_OUTER_OUTPUT', & + call openfile(this%icsvouterout, iout, fname, 'CSV_OUTER_OUTPUT', & filstat_opt='REPLACE') - write(iout,fmtcsvout) trim(fname), this%icsvouterout + write (iout, fmtcsvout) trim(fname), this%icsvouterout else - write(errmsg,'(a)') 'OPTIONAL CSV_OUTER_OUTPUT ' // & + write (errmsg, '(a)') 'OPTIONAL CSV_OUTER_OUTPUT '// & 'KEYWORD MUST BE FOLLOWED BY FILEOUT' call store_error(errmsg) end if @@ -562,85 +570,85 @@ subroutine sln_ar(this) if (keyword == 'FILEOUT') then call this%parser%GetString(fname) this%icsvinnerout = getunit() - call openfile(this%icsvinnerout, iout, fname, 'CSV_INNER_OUTPUT', & + call openfile(this%icsvinnerout, iout, fname, 'CSV_INNER_OUTPUT', & filstat_opt='REPLACE') - write(iout,fmtcsvout) trim(fname), this%icsvinnerout + write (iout, fmtcsvout) trim(fname), this%icsvinnerout else - write(errmsg,'(a)') 'OPTIONAL CSV_INNER_OUTPUT ' // & + write (errmsg, '(a)') 'OPTIONAL CSV_INNER_OUTPUT '// & 'KEYWORD MUST BE FOLLOWED BY FILEOUT' call store_error(errmsg) end if case ('NO_PTC') call this%parser%GetStringCaps(keyword) - select case(keyword) - case ('ALL') - ival = 0 - msg = 'ALL' - case ('FIRST') - ival = -1 - msg = 'THE FIRST' - case default - ival = 0 - msg = 'ALL' + select case (keyword) + case ('ALL') + ival = 0 + msg = 'ALL' + case ('FIRST') + ival = -1 + msg = 'THE FIRST' + case default + ival = 0 + msg = 'ALL' end select this%iallowptc = ival - write(IOUT,'(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION DISABLED FOR' // & - ' ' // trim(adjustl(msg)) // ' STRESS-PERIOD(S)' - case('ATS_OUTER_MAXIMUM_FRACTION') + write (IOUT, '(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION DISABLED FOR'// & + ' '//trim(adjustl(msg))//' STRESS-PERIOD(S)' + case ('ATS_OUTER_MAXIMUM_FRACTION') rval = this%parser%GetDouble() if (rval < DZERO .or. rval > DHALF) then - write(errmsg,'(a,G0)') 'VALUE FOR ATS_OUTER_MAXIMUM_FRAC MUST BE & + write (errmsg, '(a,G0)') 'VALUE FOR ATS_OUTER_MAXIMUM_FRAC MUST BE & &BETWEEN 0 AND 0.5. FOUND ', rval call store_error(errmsg) end if this%atsfrac = rval - write(IOUT,'(1x,A,G0)') 'ADAPTIVE TIME STEP SETTING FOUND. FRACTION & + write (IOUT, '(1x,A,G0)') 'ADAPTIVE TIME STEP SETTING FOUND. FRACTION & &OF OUTER MAXIMUM USED TO INCREASE OR DECREASE TIME STEP SIZE IS ',& &this%atsfrac - ! - ! -- DEPRECATED OPTIONS + ! + ! -- DEPRECATED OPTIONS case ('CSV_OUTPUT') call this%parser%GetStringCaps(keyword) if (keyword == 'FILEOUT') then call this%parser%GetString(fname) this%icsvouterout = getunit() - call openfile(this%icsvouterout, iout, fname, 'CSV_OUTPUT', & + call openfile(this%icsvouterout, iout, fname, 'CSV_OUTPUT', & filstat_opt='REPLACE') - write(iout,fmtcsvout) trim(fname), this%icsvouterout + write (iout, fmtcsvout) trim(fname), this%icsvouterout ! ! -- create warning message - write(warnmsg,'(a)') & - 'OUTER ITERATION INFORMATION WILL BE SAVED TO ' // trim(fname) + write (warnmsg, '(a)') & + 'OUTER ITERATION INFORMATION WILL BE SAVED TO '//trim(fname) ! ! -- create deprecation warning - call deprecation_warning('OPTIONS', 'CSV_OUTPUT', '6.1.1', & + call deprecation_warning('OPTIONS', 'CSV_OUTPUT', '6.1.1', & warnmsg, this%parser%GetUnit()) else - write(errmsg,'(a)') 'OPTIONAL CSV_OUTPUT ' // & + write (errmsg, '(a)') 'OPTIONAL CSV_OUTPUT '// & 'KEYWORD MUST BE FOLLOWED BY FILEOUT' call store_error(errmsg) end if - ! - ! -- right now these are options that are only available in the - ! development version and are not included in the documentation. - ! These options are only available when IDEVELOPMODE in - ! constants module is set to 1 + ! + ! -- right now these are options that are only available in the + ! development version and are not included in the documentation. + ! These options are only available when IDEVELOPMODE in + ! constants module is set to 1 case ('DEV_PTC') call this%parser%DevOpt() this%iallowptc = 1 - write(IOUT,'(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION ENABLED' - case('DEV_PTC_OUTPUT') + write (IOUT, '(1x,A)') 'PSEUDO-TRANSIENT CONTINUATION ENABLED' + case ('DEV_PTC_OUTPUT') call this%parser%DevOpt() this%iallowptc = 1 call this%parser%GetStringCaps(keyword) if (keyword == 'FILEOUT') then call this%parser%GetString(fname) this%iptcout = getunit() - call openfile(this%iptcout, iout, fname, 'PTC-OUT', & + call openfile(this%iptcout, iout, fname, 'PTC-OUT', & filstat_opt='REPLACE') - write(iout,fmtptcout) trim(fname), this%iptcout + write (iout, fmtptcout) trim(fname), this%iptcout else - write(errmsg,'(a)') & + write (errmsg, '(a)') & 'OPTIONAL PTC_OUTPUT KEYWORD MUST BE FOLLOWED BY FILEOUT' call store_error(errmsg) end if @@ -648,62 +656,62 @@ subroutine sln_ar(this) call this%parser%DevOpt() this%iallowptc = 1 this%iptcopt = 1 - write(IOUT,'(1x,A)') & - 'PSEUDO-TRANSIENT CONTINUATION USES BNORM AND L2NORM TO ' // & + write (IOUT, '(1x,A)') & + 'PSEUDO-TRANSIENT CONTINUATION USES BNORM AND L2NORM TO '// & 'SET INITIAL VALUE' case ('DEV_PTC_EXPONENT') call this%parser%DevOpt() rval = this%parser%GetDouble() if (rval < DZERO) then - write(errmsg,'(a)') 'PTC_EXPONENT MUST BE > 0.' + write (errmsg, '(a)') 'PTC_EXPONENT MUST BE > 0.' call store_error(errmsg) else this%iallowptc = 1 this%ptcexp = rval - write(IOUT,'(1x,A,1x,g15.7)') & + write (IOUT, '(1x,A,1x,g15.7)') & 'PSEUDO-TRANSIENT CONTINUATION EXPONENT', this%ptcexp end if case ('DEV_PTC_THRESHOLD') call this%parser%DevOpt() rval = this%parser%GetDouble() if (rval < DZERO) then - write(errmsg,'(a)') 'PTC_THRESHOLD MUST BE > 0.' + write (errmsg, '(a)') 'PTC_THRESHOLD MUST BE > 0.' call store_error(errmsg) else this%iallowptc = 1 this%ptcthresh = rval - write(IOUT,'(1x,A,1x,g15.7)') & + write (IOUT, '(1x,A,1x,g15.7)') & 'PSEUDO-TRANSIENT CONTINUATION THRESHOLD', this%ptcthresh end if case ('DEV_PTC_DEL0') call this%parser%DevOpt() rval = this%parser%GetDouble() if (rval < DZERO) then - write(errmsg,'(a)')'IMS sln_ar: PTC_DEL0 MUST BE > 0.' + write (errmsg, '(a)') 'IMS sln_ar: PTC_DEL0 MUST BE > 0.' call store_error(errmsg) else this%iallowptc = 1 this%ptcdel0 = rval - write(IOUT,'(1x,A,1x,g15.7)') & + write (IOUT, '(1x,A,1x,g15.7)') & 'PSEUDO-TRANSIENT CONTINUATION INITIAL TIMESTEP', this%ptcdel0 end if case default - write(errmsg,'(a,2(1x,a))') & + write (errmsg, '(a,2(1x,a))') & 'UNKNOWN IMS OPTION (', trim(keyword), ').' call store_error(errmsg) end select end do - write(iout,'(1x,a)')'END OF IMS OPTIONS' + write (iout, '(1x,a)') 'END OF IMS OPTIONS' else - write(iout,'(1x,a)')'NO IMS OPTION BLOCK DETECTED.' + write (iout, '(1x,a)') 'NO IMS OPTION BLOCK DETECTED.' end if -00021 FORMAT(1X,'SIMPLE OPTION:',/, & - & 1X,'DEFAULT SOLVER INPUT VALUES FOR FAST SOLUTIONS') -00023 FORMAT(1X,'MODERATE OPTION:',/,1X,'DEFAULT SOLVER', & - & ' INPUT VALUES REFLECT MODERETELY NONLINEAR MODEL') -00025 FORMAT(1X,'COMPLEX OPTION:',/,1X,'DEFAULT SOLVER', & - & ' INPUT VALUES REFLECT STRONGLY NONLINEAR MODEL') +00021 FORMAT(1X, 'SIMPLE OPTION:', /, & + 1X, 'DEFAULT SOLVER INPUT VALUES FOR FAST SOLUTIONS') +00023 FORMAT(1X, 'MODERATE OPTION:', /, 1X, 'DEFAULT SOLVER', & + ' INPUT VALUES REFLECT MODERETELY NONLINEAR MODEL') +00025 FORMAT(1X, 'COMPLEX OPTION:', /, 1X, 'DEFAULT SOLVER', & + ' INPUT VALUES REFLECT STRONGLY NONLINEAR MODEL') !-------READ NONLINEAR ITERATION PARAMETERS AND LINEAR SOLVER SELECTION INDEX ! -- set default nonlinear parameters @@ -711,11 +719,11 @@ subroutine sln_ar(this) ! ! -- get NONLINEAR block call this%parser%GetBlock('NONLINEAR', isfound, ierr, & - supportOpenClose=.true., blockRequired=.FALSE.) + supportOpenClose=.true., blockRequired=.FALSE.) ! ! -- parse NONLINEAR block if detected if (isfound) then - write(iout,'(/1x,a)')'PROCESSING IMS NONLINEAR' + write (iout, '(/1x,a)') 'PROCESSING IMS NONLINEAR' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -723,9 +731,9 @@ subroutine sln_ar(this) ! -- parse keyword select case (keyword) case ('OUTER_DVCLOSE') - this%dvclose = this%parser%GetDouble() + this%dvclose = this%parser%GetDouble() case ('OUTER_MAXIMUM') - this%mxiter = this%parser%GetInteger() + this%mxiter = this%parser%GetInteger() case ('UNDER_RELAXATION') call this%parser%GetStringCaps(keyword) ival = 0 @@ -738,7 +746,7 @@ subroutine sln_ar(this) else if (keyword == 'DBD') then ival = 3 else - write(errmsg,'(3a)') & + write (errmsg, '(3a)') & 'UNKNOWN UNDER_RELAXATION SPECIFIED (', trim(keyword), ').' call store_error(errmsg) end if @@ -746,11 +754,11 @@ subroutine sln_ar(this) case ('LINEAR_SOLVER') call this%parser%GetStringCaps(keyword) ival = 1 - if (keyword.eq.'DEFAULT' .or. & - keyword.eq.'LINEAR') then + if (keyword .eq. 'DEFAULT' .or. & + keyword .eq. 'LINEAR') then ival = 1 else - write(errmsg,'(3a)') & + write (errmsg, '(3a)') & 'UNKNOWN LINEAR_SOLVER SPECIFIED (', trim(keyword), ').' call store_error(errmsg) end if @@ -762,7 +770,7 @@ subroutine sln_ar(this) case ('UNDER_RELAXATION_GAMMA') this%gamma = this%parser%GetDouble() case ('UNDER_RELAXATION_MOMENTUM') - this%amomentum = this%parser%GetDouble() + this%amomentum = this%parser%GetDouble() case ('BACKTRACKING_NUMBER') this%numtrack = this%parser%GetInteger() IF (this%numtrack > 0) this%ibflag = 1 @@ -772,37 +780,37 @@ subroutine sln_ar(this) this%breduc = this%parser%GetDouble() case ('BACKTRACKING_RESIDUAL_LIMIT') this%res_lim = this%parser%GetDouble() - ! - ! -- deprecated variables + ! + ! -- deprecated variables case ('OUTER_HCLOSE') - this%dvclose = this%parser%GetDouble() + this%dvclose = this%parser%GetDouble() ! ! -- create warning message - write(warnmsg,'(a)') & + write (warnmsg, '(a)') & 'SETTING OUTER_DVCLOSE TO OUTER_HCLOSE VALUE' ! ! -- create deprecation warning - call deprecation_warning('NONLINEAR', 'OUTER_HCLOSE', '6.1.1', & + call deprecation_warning('NONLINEAR', 'OUTER_HCLOSE', '6.1.1', & warnmsg, this%parser%GetUnit()) case ('OUTER_RCLOSEBND') ! ! -- create warning message - write(warnmsg,'(a)') & + write (warnmsg, '(a)') & 'OUTER_DVCLOSE IS USED TO EVALUATE PACKAGE CONVERGENCE' ! ! -- create deprecation warning - call deprecation_warning('NONLINEAR', 'OUTER_RCLOSEBND', '6.1.1', & + call deprecation_warning('NONLINEAR', 'OUTER_RCLOSEBND', '6.1.1', & warnmsg, this%parser%GetUnit()) case default - write(errmsg,'(3a)') & + write (errmsg, '(3a)') & 'UNKNOWN IMS NONLINEAR KEYWORD (', trim(keyword), ').' call store_error(errmsg) end select end do - write(iout,'(1x,a)') 'END OF IMS NONLINEAR DATA' + write (iout, '(1x,a)') 'END OF IMS NONLINEAR DATA' else - if (IFDPARAM.EQ.0) then - write(errmsg,'(a)') 'NO IMS NONLINEAR BLOCK DETECTED.' + if (IFDPARAM .EQ. 0) then + write (errmsg, '(a)') 'NO IMS NONLINEAR BLOCK DETECTED.' call store_error(errmsg) end if end if @@ -818,19 +826,19 @@ subroutine sln_ar(this) ! ! -- check that MXITER is greater than zero if (this%mxiter <= 0) then - write(errmsg,'(a)') 'OUTER ITERATION NUMBER MUST BE > 0.' + write (errmsg, '(a)') 'OUTER ITERATION NUMBER MUST BE > 0.' call store_error(errmsg) END IF ! ! -- write under-relaxation option - if ( this%nonmeth > 0 )then - WRITE(IOUT,*) '**UNDER-RELAXATION WILL BE USED***' - WRITE(IOUT,*) - elseif ( this%nonmeth == 0 )then - WRITE(IOUT,*) '***UNDER-RELAXATION WILL NOT BE USED***' - WRITE(IOUT,*) + if (this%nonmeth > 0) then + WRITE (IOUT, *) '**UNDER-RELAXATION WILL BE USED***' + WRITE (IOUT, *) + elseif (this%nonmeth == 0) then + WRITE (IOUT, *) '***UNDER-RELAXATION WILL NOT BE USED***' + WRITE (IOUT, *) else - WRITE(errmsg,'(a)') & + WRITE (errmsg, '(a)') & 'INCORRECT VALUE FOR VARIABLE NONMETH WAS SPECIFIED.' call store_error(errmsg) end if @@ -838,40 +846,40 @@ subroutine sln_ar(this) ! -- ensure gamma is > 0 for simple if (this%nonmeth == 1) then if (this%gamma == 0) then - WRITE(errmsg, '(a)') & + WRITE (errmsg, '(a)') & 'GAMMA must be greater than zero if SIMPLE under-relaxation is used.' call store_error(errmsg) end if end if ! - ! -- call secondary subroutine to initialize and read linear + ! -- call secondary subroutine to initialize and read linear ! solver parameters IMSLINEAR solver - if ( this%linmeth == 1 )then - allocate(this%imslinear) - WRITE(IOUT,*) '***IMS LINEAR SOLVER WILL BE USED***' - call this%imslinear%imslinear_allocate(this%name, this%parser, IOUT, & - this%iprims, this%mxiter, & - ifdparam, imslinear, & - this%neq, this%nja, this%ia, & - this%ja, this%amat, this%rhs, & + if (this%linmeth == 1) then + allocate (this%imslinear) + WRITE (IOUT, *) '***IMS LINEAR SOLVER WILL BE USED***' + call this%imslinear%imslinear_allocate(this%name, this%parser, IOUT, & + this%iprims, this%mxiter, & + ifdparam, imslinear, & + this%neq, this%nja, this%ia, & + this%ja, this%amat, this%rhs, & this%x, this%nitermax) - WRITE(IOUT,*) - if ( imslinear.eq.1 ) then + WRITE (IOUT, *) + if (imslinear .eq. 1) then this%isymmetric = 1 end if - ! - ! -- incorrect linear solver flag + ! + ! -- incorrect linear solver flag ELSE - WRITE(errmsg, '(a)') & + WRITE (errmsg, '(a)') & 'INCORRECT VALUE FOR LINEAR SOLUTION METHOD SPECIFIED.' call store_error(errmsg) END IF ! ! -- write message about matrix symmetry if (this%isymmetric == 1) then - write(iout, '(1x,a,/)') 'A symmetric matrix will be solved' + write (iout, '(1x,a,/)') 'A symmetric matrix will be solved' else - write(iout, '(1x,a,/)') 'An asymmetric matrix will be solved' + write (iout, '(1x,a,/)') 'An asymmetric matrix will be solved' end if ! ! -- If CG, then go through each model and each exchange and check @@ -882,67 +890,67 @@ subroutine sln_ar(this) do i = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, i) if (mp%get_iasym() /= 0) then - write(errmsg, fmterrasym) 'MODEL', trim(adjustl(mp%name)) + write (errmsg, fmterrasym) 'MODEL', trim(adjustl(mp%name)) call store_error(errmsg) - endif - enddo + end if + end do ! ! -- Exchanges do i = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, i) if (cp%get_iasym() /= 0) then - write(errmsg, fmterrasym) 'EXCHANGE', trim(adjustl(cp%name)) + write (errmsg, fmterrasym) 'EXCHANGE', trim(adjustl(cp%name)) call store_error(errmsg) - endif - enddo + end if + end do ! - endif + end if ! ! -- write solver data to output file ! ! -- non-linear solver data - WRITE(IOUT,9002) this%dvclose, this%mxiter, & - this%iprims, this%nonmeth, this%linmeth + WRITE (IOUT, 9002) this%dvclose, this%mxiter, & + this%iprims, this%nonmeth, this%linmeth ! ! -- standard outer iteration formats -9002 FORMAT(1X,'OUTER ITERATION CONVERGENCE CRITERION (DVCLOSE) = ', E15.6, & - & /1X,'MAXIMUM NUMBER OF OUTER ITERATIONS (MXITER) = ', I0, & - & /1X,'SOLVER PRINTOUT INDEX (IPRIMS) = ', I0, & - & /1X,'NONLINEAR ITERATION METHOD (NONLINMETH) = ', I0, & - & /1X,'LINEAR SOLUTION METHOD (LINMETH) = ', I0) +9002 FORMAT(1X, 'OUTER ITERATION CONVERGENCE CRITERION (DVCLOSE) = ', E15.6, & + /1X, 'MAXIMUM NUMBER OF OUTER ITERATIONS (MXITER) = ', I0, & + /1X, 'SOLVER PRINTOUT INDEX (IPRIMS) = ', I0, & + /1X, 'NONLINEAR ITERATION METHOD (NONLINMETH) = ', I0, & + /1X, 'LINEAR SOLUTION METHOD (LINMETH) = ', I0) ! if (this%nonmeth == 1) then ! simple - write(iout, 9003) this%gamma + write (iout, 9003) this%gamma else if (this%nonmeth == 2) then ! cooley - write(iout, 9004) this%gamma + write (iout, 9004) this%gamma else if (this%nonmeth == 3) then ! delta bar delta - write(iout, 9005) this%theta, this%akappa, this%gamma, this%amomentum + write (iout, 9005) this%theta, this%akappa, this%gamma, this%amomentum end if ! ! -- write backtracking information - if(this%numtrack /= 0) write(iout, 9006) this%numtrack, this%btol, & - this%breduc,this%res_lim + if (this%numtrack /= 0) write (iout, 9006) this%numtrack, this%btol, & + this%breduc, this%res_lim ! ! -- under-relaxation formats (simple, cooley, dbd) -9003 FORMAT(1X,'UNDER-RELAXATION FACTOR (GAMMA) = ', E15.6) -9004 FORMAT(1X,'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', E15.6) -9005 FORMAT(1X,'UNDER-RELAXATION WEIGHT REDUCTION FACTOR (THETA) = ', E15.6, & - & /1X,'UNDER-RELAXATION WEIGHT INCREASE INCREMENT (KAPPA) = ', E15.6, & - & /1X,'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', E15.6, & - & /1X,'UNDER-RELAXATION MOMENTUM TERM (AMOMENTUM) = ', E15.6) +9003 FORMAT(1X, 'UNDER-RELAXATION FACTOR (GAMMA) = ', E15.6) +9004 FORMAT(1X, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', E15.6) +9005 FORMAT(1X, 'UNDER-RELAXATION WEIGHT REDUCTION FACTOR (THETA) = ', E15.6, & + /1X, 'UNDER-RELAXATION WEIGHT INCREASE INCREMENT (KAPPA) = ', E15.6, & + /1X, 'UNDER-RELAXATION PREVIOUS HISTORY FACTOR (GAMMA) = ', E15.6, & + /1X, 'UNDER-RELAXATION MOMENTUM TERM (AMOMENTUM) = ', E15.6) ! ! -- backtracking formats -9006 FORMAT(1X,'MAXIMUM NUMBER OF BACKTRACKS (NUMTRACK) = ', I0, & - & /1X,'BACKTRACKING TOLERANCE FACTOR (BTOL) = ', E15.6, & - & /1X,'BACKTRACKING REDUCTION FACTOR (BREDUC) = ', E15.6, & - & /1X,'BACKTRACKING RESIDUAL LIMIT (RES_LIM) = ', E15.6) +9006 FORMAT(1X, 'MAXIMUM NUMBER OF BACKTRACKS (NUMTRACK) = ', I0, & + /1X, 'BACKTRACKING TOLERANCE FACTOR (BTOL) = ', E15.6, & + /1X, 'BACKTRACKING REDUCTION FACTOR (BREDUC) = ', E15.6, & + /1X, 'BACKTRACKING RESIDUAL LIMIT (RES_LIM) = ', E15.6) ! ! -- linear solver data call this%imslinear%imslinear_summary(this%mxiter) ! -- write summary of solver error messages ierr = count_errors() - if (ierr>0) then + if (ierr > 0) then call this%parser%StoreErrorUnit() end if ! @@ -951,7 +959,7 @@ subroutine sln_ar(this) call mem_reallocate(this%lrch, 3, this%mxiter, 'LRCH', this%name) ! delta-bar-delta under-relaxation - if(this%nonmeth == 3)then + if (this%nonmeth == 3) then call mem_reallocate(this%wsave, this%neq, 'WSAVE', this%name) call mem_reallocate(this%hchold, this%neq, 'HCHOLD', this%name) call mem_reallocate(this%deold, this%neq, 'DEOLD', this%name) @@ -960,7 +968,7 @@ subroutine sln_ar(this) this%hchold(i) = DZERO this%deold(i) = DZERO end do - endif + end if this%hncg = DZERO this%lrch = 0 @@ -971,18 +979,18 @@ subroutine sln_ar(this) this%nitermax = 1 end if - allocate(this%caccel(this%nitermax)) + allocate (this%caccel(this%nitermax)) im = this%convnmod - call mem_reallocate(this%itinner, this%nitermax, 'ITINNER', & + call mem_reallocate(this%itinner, this%nitermax, 'ITINNER', & trim(this%name)) - call mem_reallocate(this%convlocdv, im, this%nitermax, 'CONVLOCDV', & + call mem_reallocate(this%convlocdv, im, this%nitermax, 'CONVLOCDV', & trim(this%name)) - call mem_reallocate(this%convlocdr, im, this%nitermax, 'CONVLOCDR', & + call mem_reallocate(this%convlocdr, im, this%nitermax, 'CONVLOCDR', & trim(this%name)) - call mem_reallocate(this%convdvmax, im, this%nitermax, 'CONVDVMAX', & + call mem_reallocate(this%convdvmax, im, this%nitermax, 'CONVDVMAX', & trim(this%name)) - call mem_reallocate(this%convdrmax, im, this%nitermax, 'CONVDRMAX', & + call mem_reallocate(this%convdrmax, im, this%nitermax, 'CONVDRMAX', & trim(this%name)) do i = 1, this%nitermax this%itinner(i) = 0 @@ -1018,7 +1026,7 @@ subroutine sln_calculate_delt(this) use AdaptiveTimeStepModule, only: ats_submit_delt use ConstantsModule, only: DTWO, DTHREE ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables integer(I4B) :: idir real(DP) :: delt_temp @@ -1035,13 +1043,13 @@ subroutine sln_calculate_delt(this) fact_upper = this%mxiter - fact_lower if (this%iouttot_timestep < int(fact_lower)) then ! -- increase delt according to tsfactats - idir = 1 + idir = 1 else if (this%iouttot_timestep > int(fact_upper)) then ! -- decrease delt according to tsfactats - idir = -1 + idir = -1 else ! -- do not change delt - idir = 0 + idir = 0 end if ! ! -- submit stable dt for upcoming step @@ -1050,7 +1058,7 @@ subroutine sln_calculate_delt(this) ! return end subroutine sln_calculate_delt - + !> @ brief Advance solution !! !! Advance solution. @@ -1060,24 +1068,24 @@ subroutine sln_ad(this) ! -- modules use TdisModule, only: kstp, kper ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! ! -- write headers to CSV file if (kper == 1 .and. kstp == 1) then call this%writeCSVHeader() end if - + ! write PTC info on models to iout call this%writePTCInfoToFile(kper) - + ! reset convergence flag and inner solve counter this%icnvg = 0 - this%itertot_timestep = 0 - this%iouttot_timestep = 0 - + this%itertot_timestep = 0 + this%iouttot_timestep = 0 + return end subroutine sln_ad - + !> @ brief Output solution !! !! Output solution data. Currently does nothing. @@ -1085,7 +1093,7 @@ end subroutine sln_ad !< subroutine sln_ot(this) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! ! -- Nothing to do here ! @@ -1100,16 +1108,16 @@ end subroutine sln_ot !< subroutine sln_fp(this) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! - ! -- write timer output + ! -- write timer output if (IDEVELOPMODE == 1) then - write(this%imslinear%iout, '(//1x,a,1x,a,1x,a)') & + write (this%imslinear%iout, '(//1x,a,1x,a,1x,a)') & 'Solution', trim(adjustl(this%name)), 'summary' - write(this%imslinear%iout, "(1x,70('-'))") - write(this%imslinear%iout, '(1x,a,1x,g0,1x,a)') & + write (this%imslinear%iout, "(1x,70('-'))") + write (this%imslinear%iout, '(1x,a,1x,g0,1x,a)') & 'Total formulate time: ', this%ttform, 'seconds' - write(this%imslinear%iout, '(1x,a,1x,g0,1x,a,/)') & + write (this%imslinear%iout, '(1x,a,1x,g0,1x,a,/)') & 'Total solution time: ', this%ttsoln, 'seconds' end if ! @@ -1126,33 +1134,33 @@ subroutine sln_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! ! -- IMSLinearModule call this%imslinear%imslinear_da() - deallocate(this%imslinear) + deallocate (this%imslinear) ! ! -- lists call this%modellist%Clear() call this%exchangelist%Clear() - deallocate(this%modellist) - deallocate(this%exchangelist) + deallocate (this%modellist) + deallocate (this%exchangelist) ! ! -- character arrays - deallocate(this%caccel) + deallocate (this%caccel) ! ! -- inner iteration table object if (associated(this%innertab)) then call this%innertab%table_da() - deallocate(this%innertab) - nullify(this%innertab) + deallocate (this%innertab) + nullify (this%innertab) end if ! ! -- outer iteration table object if (associated(this%outertab)) then call this%outertab%table_da() - deallocate(this%outertab) - nullify(this%outertab) + deallocate (this%outertab) + nullify (this%outertab) end if ! ! -- arrays @@ -1237,102 +1245,102 @@ end subroutine sln_da !< subroutine sln_ca(this, isgcnvg, isuppress_output) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag - integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag + integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output ! -- local variables class(NumericalModelType), pointer :: mp => null() character(len=LINELENGTH) :: line character(len=LINELENGTH) :: fmt integer(I4B) :: im - integer(I4B) :: kiter ! non-linear iteration counter + integer(I4B) :: kiter ! non-linear iteration counter ! ------------------------------------------------------------------------------ - + ! advance the models, exchanges, and solution call this%prepareSolve() - + select case (isim_mode) - case (MVALIDATE) - line = 'mode="validation" -- Skipping matrix assembly and solution.' - fmt = "(/,1x,a,/)" - do im = 1, this%modellist%Count() - mp => GetNumericalModelFromList(this%modellist, im) - call mp%model_message(line, fmt=fmt) - end do - case(MNORMAL) - ! nonlinear iteration loop for this solution - outerloop: do kiter = 1, this%mxiter - - ! perform a single iteration - call this%solve(kiter) - - ! exit if converged - if (this%icnvg == 1) then - exit outerloop - end if - - end do outerloop - - ! finish up, write convergence info, CSV file, budgets and flows, ... - call this%finalizeSolve(kiter, isgcnvg, isuppress_output) + case (MVALIDATE) + line = 'mode="validation" -- Skipping matrix assembly and solution.' + fmt = "(/,1x,a,/)" + do im = 1, this%modellist%Count() + mp => GetNumericalModelFromList(this%modellist, im) + call mp%model_message(line, fmt=fmt) + end do + case (MNORMAL) + ! nonlinear iteration loop for this solution + outerloop: do kiter = 1, this%mxiter + + ! perform a single iteration + call this%solve(kiter) + + ! exit if converged + if (this%icnvg == 1) then + exit outerloop + end if + + end do outerloop + + ! finish up, write convergence info, CSV file, budgets and flows, ... + call this%finalizeSolve(kiter, isgcnvg, isuppress_output) end select ! ! -- return return - + end subroutine sln_ca - + !> @ brief CSV header !! !! Write header for solver output to comma-separated value files. !! !< - subroutine writeCSVHeader(this) - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + subroutine writeCSVHeader(this) + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! local variables integer(I4B) :: im class(NumericalModelType), pointer :: mp => null() ! ! -- outer iteration csv header if (this%icsvouterout > 0) then - write(this%icsvouterout, '(*(G0,:,","))') & - 'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', & - 'inner_iterations', 'solution_outer_dvmax', & - 'solution_outer_dvmax_model', 'solution_outer_dvmax_package', & + write (this%icsvouterout, '(*(G0,:,","))') & + 'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', & + 'inner_iterations', 'solution_outer_dvmax', & + 'solution_outer_dvmax_model', 'solution_outer_dvmax_package', & 'solution_outer_dvmax_node' end if ! ! -- inner iteration csv header if (this%icsvinnerout > 0) then - write(this%icsvinnerout, '(*(G0,:,","))', advance='NO') & - 'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', & - 'ninner', 'solution_inner_dvmax', 'solution_inner_dvmax_model', & + write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') & + 'total_inner_iterations', 'totim', 'kper', 'kstp', 'nouter', & + 'ninner', 'solution_inner_dvmax', 'solution_inner_dvmax_model', & 'solution_inner_dvmax_node' - write(this%icsvinnerout, '(*(G0,:,","))', advance='NO') & - '', 'solution_inner_drmax', 'solution_inner_drmax_model', & + write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') & + '', 'solution_inner_drmax', 'solution_inner_drmax_model', & 'solution_inner_drmax_node', 'solution_inner_alpha' if (this%imslinear%ilinmeth == 2) then - write(this%icsvinnerout, '(*(G0,:,","))', advance='NO') & + write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') & '', 'solution_inner_omega' end if ! -- check for more than one model if (this%convnmod > 1) then - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) - write(this%icsvinnerout, '(*(G0,:,","))', advance='NO') & - '', trim(adjustl(mp%name)) // '_inner_dvmax', & - trim(adjustl(mp%name)) // '_inner_dvmax_node', & - trim(adjustl(mp%name)) // '_inner_drmax', & - trim(adjustl(mp%name)) // '_inner_drmax_node' + write (this%icsvinnerout, '(*(G0,:,","))', advance='NO') & + '', trim(adjustl(mp%name))//'_inner_dvmax', & + trim(adjustl(mp%name))//'_inner_dvmax_node', & + trim(adjustl(mp%name))//'_inner_drmax', & + trim(adjustl(mp%name))//'_inner_drmax_node' end do end if - write(this%icsvinnerout,'(a)') '' + write (this%icsvinnerout, '(a)') '' end if ! ! -- return return end subroutine writeCSVHeader - + !> @ brief PTC header !! !! Write header for pseudo-transient continuation information to a file. @@ -1341,11 +1349,11 @@ end subroutine writeCSVHeader subroutine writePTCInfoToFile(this, kper) ! -- dummy variables class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: kper !< current stress period number + integer(I4B), intent(in) :: kper !< current stress period number ! -- local variable integer(I4B) :: n, im, iallowptc, iptc class(NumericalModelType), pointer :: mp => null() - + ! -- determine if PTC will be used in any model n = 1 do im = 1, this%modellist%Count() @@ -1360,24 +1368,24 @@ subroutine writePTCInfoToFile(this, kper) else iallowptc = 0 end if - ! -- no_ptc_option is ALL (0) or using PTC (1) + ! -- no_ptc_option is ALL (0) or using PTC (1) else iallowptc = this%iallowptc end if iptc = iptc * iallowptc if (iptc /= 0) then if (n == 1) then - write(iout, '(//)') + write (iout, '(//)') n = 0 end if - write(iout, '(1x,a,1x,i0,1x,3a)') & - 'PSEUDO-TRANSIENT CONTINUATION WILL BE APPLIED TO MODEL', im, '("', & + write (iout, '(1x,a,1x,i0,1x,3a)') & + 'PSEUDO-TRANSIENT CONTINUATION WILL BE APPLIED TO MODEL', im, '("', & trim(adjustl(mp%name)), '") DURING THIS TIME STEP' end if - enddo - + end do + end subroutine writePTCInfoToFile - + !> @ brief prepare to solve !! !! Prepare for the system solve by advancing the simulation. @@ -1391,29 +1399,32 @@ subroutine prepareSolve(this) integer(I4B) :: im class(NumericalExchangeType), pointer :: cp => null() class(NumericalModelType), pointer :: mp => null() - - ! -- Exchange advance - do ic=1,this%exchangelist%Count() + + ! synchronize for AD + call distributed_data%synchronize(this%id, BEFORE_AD) + + ! -- Exchange advance + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_ad() - enddo - + end do + ! -- Model advance do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_ad() - enddo - + end do + ! advance solution call this%sln_ad() - + end subroutine prepareSolve - + !> @ brief Build and solve the simulation !! - !! Builds and solve the system for this numerical solution. + !! Builds and solve the system for this numerical solution. !! It roughly consists of the following steps - !! (1) backtracking, (2) reset amat and rhs (3) calculate matrix + !! (1) backtracking, (2) reset amat and rhs (3) calculate matrix !! terms (*_cf), (4) add coefficients to matrix (*_fc), (6) newton-raphson, !! (6) PTC, (7) linear solve, (8) convergence checks, (9) write output, !! and (10) underrelaxation @@ -1423,11 +1434,11 @@ subroutine solve(this, kiter) ! -- modules use TdisModule, only: kstp, kper, totim ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: kiter !< Picard iteration number + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: kiter !< Picard iteration number ! -- local variables class(NumericalModelType), pointer :: mp => null() - class(NumericalExchangeType), pointer :: cp => null() + class(NumericalExchangeType), pointer :: cp => null() character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag character(len=LINELENGTH) :: line @@ -1438,16 +1449,16 @@ subroutine solve(this, kiter) character(len=25) :: cval character(len=7) :: cmsg integer(I4B) :: ic - integer(I4B) :: im + integer(I4B) :: im integer(I4B) :: icsv0 integer(I4B) :: kcsv0 integer(I4B) :: ntabrows integer(I4B) :: ntabcols - integer(I4B) :: i0, i1 + integer(I4B) :: i0, i1 integer(I4B) :: itestmat, n - integer(I4B) :: iter - integer(I4B) :: inewtonur - integer(I4B) :: locmax_nur + integer(I4B) :: iter + integer(I4B) :: inewtonur + integer(I4B) :: locmax_nur integer(I4B) :: iend integer(I4B) :: icnvgmod integer(I4B) :: iptc @@ -1480,9 +1491,9 @@ subroutine solve(this, kiter) end if ! ! -- initialize table and define columns - title = trim(this%memoryPath) // ' OUTER ITERATION SUMMARY' + title = trim(this%memoryPath)//' OUTER ITERATION SUMMARY' call table_cr(this%outertab, this%name, title) - call this%outertab%table_df(ntabrows, ntabcols, iout, & + call this%outertab%table_df(ntabrows, ntabcols, iout, & finalize=.FALSE.) tag = 'OUTER ITERATION STEP' call this%outertab%initialize_column(tag, 25, alignment=TABLEFT) @@ -1513,35 +1524,35 @@ subroutine solve(this, kiter) if (this%numtrack > 0) then call this%sln_backtracking(mp, cp, kiter) end if - + call code_timer(0, ttform, this%ttform) - + ! (re)build the solution matrix call this%sln_buildsystem(kiter, inewton=1) - + ! ! -- Add exchange Newton-Raphson terms to solution - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_nr(kiter, this%ia, this%amat) - enddo + end do ! ! -- Calculate pseudo-transient continuation factor for each model iptc = 0 ptcf = DZERO - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) - call mp%model_ptc(kiter, this%neq, this%nja, & - this%ia, this%ja, this%x, & - this%rhs, this%amat, & + call mp%model_ptc(kiter, this%neq, this%nja, & + this%ia, this%ja, this%x, & + this%rhs, this%amat, & iptc, ptcf) end do ! ! -- Add model Newton-Raphson terms to solution - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_nr(kiter, this%amat, this%nja, 1) - enddo + end do call code_timer(1, ttform, this%ttform) ! ! -- linear solve @@ -1549,8 +1560,8 @@ subroutine solve(this, kiter) CALL this%sln_ls(kiter, kstp, kper, iter, iptc, ptcf) call code_timer(1, ttsoln, this%ttsoln) ! - ! -- increment counters storing the total number of linear and - ! non-linear iterations for this timestep and the total + ! -- increment counters storing the total number of linear and + ! non-linear iterations for this timestep and the total ! number of linear iterations for all timesteps this%itertot_timestep = this%itertot_timestep + iter this%iouttot_timestep = this%iouttot_timestep + 1 @@ -1561,16 +1572,16 @@ subroutine solve(this, kiter) !------------------------------------------------------- itestmat = 0 if (itestmat /= 0) then - open(99,file='sol_MF6.TXT') - WRITE(99,*) 'MATRIX SOLUTION FOLLOWS' - WRITE(99,'(10(I8,G15.4))') (n, this%x(N), N = 1, this%NEQ) - close(99) + open (99, file='sol_MF6.TXT') + WRITE (99, *) 'MATRIX SOLUTION FOLLOWS' + WRITE (99, '(10(I8,G15.4))') (n, this%x(N), N=1, this%NEQ) + close (99) call stop_with_error() end if !------------------------------------------------------- - ! + ! ! -- check convergence of solution - call this%sln_outer_check(this%hncg(kiter), this%lrch(1,kiter)) + call this%sln_outer_check(this%hncg(kiter), this%lrch(1, kiter)) if (this%icnvg /= 0) then this%icnvg = 0 if (abs(this%hncg(kiter)) <= this%dvclose) then @@ -1598,9 +1609,9 @@ subroutine solve(this, kiter) if (this%icnvg /= 0) then if (this%ptcrat > this%ptcthresh) then this%icnvg = 0 - cmsg = trim(cmsg) // 'PTC' + cmsg = trim(cmsg)//'PTC' if (iend /= 0) then - write(line, '(a)') & + write (line, '(a)') & 'PSEUDO-TRANSIENT CONTINUATION CAUSED CONVERGENCE FAILURE' call sim_message(line) end if @@ -1611,7 +1622,7 @@ subroutine solve(this, kiter) ! -- write maximum dependent-variable change from linear solver to list file if (this%iprims > 0) then cval = 'Model' - call this%sln_get_loc(this%lrch(1,kiter), strh) + call this%sln_get_loc(this%lrch(1, kiter), strh) ! ! -- add data to outertab call this%outertab%add_term(cval) @@ -1629,7 +1640,7 @@ subroutine solve(this, kiter) end if ! ! -- Additional convergence check for exchanges - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_cc(this%icnvg) end do @@ -1642,13 +1653,13 @@ subroutine solve(this, kiter) do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%get_mcellid(0, cmod) - call mp%model_cc(this%itertot_sim, kiter, iend, icnvgmod, & + call mp%model_cc(this%itertot_sim, kiter, iend, icnvgmod, & cpak, ipak, dpak) if (ipak /= 0) then ipos0 = index(cpak, '-', back=.true.) ipos1 = len_trim(cpak) - write(cpakout, '(a,a,"-(",i0,")",a)') & - trim(cmod), cpak(1:ipos0-1), ipak, cpak(ipos0:ipos1) + write (cpakout, '(a,a,"-(",i0,")",a)') & + trim(cmod), cpak(1:ipos0 - 1), ipak, cpak(ipos0:ipos1) else cpakout = ' ' end if @@ -1659,7 +1670,7 @@ subroutine solve(this, kiter) this%icnvg = 0 ! -- write message to stdout if (iend /= 0) then - write(line, '(3a)') & + write (line, '(3a)') & 'PACKAGE (', trim(cpakout), ') CAUSED CONVERGENCE FAILURE' call sim_message(line) end if @@ -1694,22 +1705,22 @@ subroutine solve(this, kiter) ! -- under-relaxation - only done if convergence not achieved if (this%icnvg /= 1) then if (this%nonmeth > 0) then - call this%sln_underrelax(kiter, this%hncg(kiter), this%neq, & + call this%sln_underrelax(kiter, this%hncg(kiter), this%neq, & this%active, this%x, this%xtemp) else - call this%sln_calcdx(this%neq, this%active, & - this%x, this%xtemp, this%dxold) - endif + call this%sln_calcdx(this%neq, this%active, & + this%x, this%xtemp, this%dxold) + end if ! ! -- adjust heads by newton under-relaxation, if necessary inewtonur = 0 dxmax_nur = DZERO locmax_nur = 0 - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) i0 = mp%moffset + 1 i1 = i0 + mp%neq - 1 - call mp%model_nur(mp%neq, this%x(i0:i1), this%xtemp(i0:i1), & + call mp%model_nur(mp%neq, this%x(i0:i1), this%xtemp(i0:i1), & this%dxold(i0:i1), inewtonur, dxmax_nur, locmax_nur) end do ! @@ -1721,20 +1732,20 @@ subroutine solve(this, kiter) call this%sln_maxval(this%neq, this%dxold, dxmax) ! ! -- evaluate convergence - if (abs(dxmax) <= this%dvclose .and. & - abs(this%hncg(kiter)) <= this%dvclose .and. & + if (abs(dxmax) <= this%dvclose .and. & + abs(this%hncg(kiter)) <= this%dvclose .and. & abs(dpak) <= this%dvclose) then this%icnvg = 1 ! ! -- reset outer dependent-variable change and location for output - call this%sln_outer_check(this%hncg(kiter), this%lrch(1,kiter)) + call this%sln_outer_check(this%hncg(kiter), this%lrch(1, kiter)) ! - ! -- write revised dependent-variable change data after + ! -- write revised dependent-variable change data after ! newton under-relaxation if (this%iprims > 0) then cval = 'Newton under-relaxation' cmsg = '*' - call this%sln_get_loc(this%lrch(1,kiter), strh) + call this%sln_get_loc(this%lrch(1, kiter), strh) ! ! -- add data to outertab call this%outertab%add_term(cval) @@ -1760,40 +1771,40 @@ subroutine solve(this, kiter) ! -- set outer dependent-variable change variable outer_hncg = this%hncg(kiter) ! - ! -- model convergence error + ! -- model convergence error if (abs(outer_hncg) > abs(dpak)) then ! ! -- get model number and user node number - call this%sln_get_nodeu(this%lrch(1,kiter), im, nodeu) + call this%sln_get_nodeu(this%lrch(1, kiter), im, nodeu) cpakout = '' - ! - ! -- package convergence error + ! + ! -- package convergence error else ! ! -- set convergence error, model number, user node number, ! and package name outer_hncg = dpak ipos0 = index(cmod, '_') - read(cmod(1:ipos0-1), *) im + read (cmod(1:ipos0 - 1), *) im nodeu = ipak ipos0 = index(cpak, '-', back=.true.) - cpakout = cpak(1:ipos0-1) + cpakout = cpak(1:ipos0 - 1) end if ! ! -- write line to outer iteration csv file - write(this%icsvouterout, '(*(G0,:,","))') & - this%itertot_sim, totim, kper, kstp, kiter, iter, & - outer_hncg, im, trim(cpakout), nodeu + write (this%icsvouterout, '(*(G0,:,","))') & + this%itertot_sim, totim, kper, kstp, kiter, iter, & + outer_hncg, im, trim(cpakout), nodeu end if ! ! -- write to inner iteration csv file if (this%icsvinnerout > 0) then - call this%csv_convergence_summary(this%icsvinnerout, totim, kper, kstp, & + call this%csv_convergence_summary(this%icsvinnerout, totim, kper, kstp, & kiter, iter, icsv0, kcsv0) end if - + end subroutine solve - + !> @ brief finalize a solution !! !! Finalize the solution. Called after the outer iteration loop. @@ -1803,21 +1814,21 @@ subroutine finalizeSolve(this, kiter, isgcnvg, isuppress_output) ! -- modules use TdisModule, only: kper, kstp ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: kiter !< Picard iteration number after convergence or failure - integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: kiter !< Picard iteration number after convergence or failure + integer(I4B), intent(inout) :: isgcnvg !< solution group convergence flag integer(I4B), intent(in) :: isuppress_output !< flag for suppressing output ! -- local variables integer(I4B) :: ic, im class(NumericalModelType), pointer :: mp => null() class(NumericalExchangeType), pointer :: cp => null() - ! -- formats for convergence info - character(len=*), parameter :: fmtnocnvg = & - &"(1X,'Solution ', i0, ' did not converge for stress period ', i0, & + ! -- formats for convergence info + character(len=*), parameter :: fmtnocnvg = & + "(1X,'Solution ', i0, ' did not converge for stress period ', i0, & &' and time step ', i0)" - character(len=*), parameter :: fmtcnvg = & - &"(1X, I0, ' CALLS TO NUMERICAL SOLUTION ', 'IN TIME STEP ', I0, & - &' STRESS PERIOD ',I0,/1X,I0,' TOTAL ITERATIONS')" + character(len=*), parameter :: fmtcnvg = & + "(1X, I0, ' CALLS TO NUMERICAL SOLUTION ', 'IN TIME STEP ', I0, & + &' STRESS PERIOD ',I0,/1X,I0,' TOTAL ITERATIONS')" ! ! -- finalize the outer iteration table if (this%iprims > 0) then @@ -1829,62 +1840,63 @@ subroutine finalizeSolve(this, kiter, isgcnvg, isuppress_output) ! -- convergence was achieved if (this%icnvg /= 0) then if (this%iprims > 0) then - write(iout, fmtcnvg) kiter, kstp, kper, this%itertot_timestep + write (iout, fmtcnvg) kiter, kstp, kper, this%itertot_timestep end if - ! - ! -- convergence was not achieved + ! + ! -- convergence was not achieved else - write(iout, fmtnocnvg) this%id, kper, kstp + write (iout, fmtnocnvg) this%id, kper, kstp end if ! ! -- write inner iteration convergence summary if (this%iprims == 2) then ! ! -- write summary for each model - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call this%convergence_summary(mp%iout, im, this%itertot_timestep) end do ! ! -- write summary for entire solution - call this%convergence_summary(iout, this%convnmod+1, this%itertot_timestep) + call this%convergence_summary(iout, this%convnmod + 1, & + this%itertot_timestep) end if ! ! -- set solution goup convergence flag if (this%icnvg == 0) isgcnvg = 0 ! ! -- Calculate flow for each model - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_cq(this%icnvg, isuppress_output) - enddo + end do ! ! -- Calculate flow for each exchange do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_cq(isgcnvg, isuppress_output, this%id) - enddo + end do ! ! -- Budget terms for each model - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_bd(this%icnvg, isuppress_output) - enddo + end do ! ! -- Budget terms for each exchange do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_bd(isgcnvg, isuppress_output, this%id) - enddo - + end do + end subroutine finalizeSolve - + ! helper routine to calculate coefficients and setup the solution matrix subroutine sln_buildsystem(this, kiter, inewton) class(NumericalSolutionType) :: this integer(I4B), intent(in) :: kiter integer(I4B), intent(in) :: inewton - + ! local integer(I4B) :: im, ic class(NumericalModelType), pointer :: mp @@ -1892,34 +1904,41 @@ subroutine sln_buildsystem(this, kiter, inewton) ! ! -- Set amat and rhs to zero call this%sln_reset() - + + ! synchronize for CF + call distributed_data%synchronize(this%id, BEFORE_CF) + ! ! -- Calculate the matrix terms for each exchange - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_cf(kiter) - enddo + end do ! ! -- Calculate the matrix terms for each model - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_cf(kiter) - enddo + end do + + ! synchronize for FC + call distributed_data%synchronize(this%id, BEFORE_FC) + ! ! -- Add exchange coefficients to the solution - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_fc(kiter, this%ia, this%amat, this%rhs, inewton) - enddo + end do ! ! -- Add model coefficients to the solution - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_fc(kiter, this%amat, this%nja, inewton) - enddo - + end do + end subroutine sln_buildsystem - + !> @ brief Solution convergence summary !! !! Save convergence summary to a File. @@ -1927,12 +1946,12 @@ end subroutine sln_buildsystem !< subroutine convergence_summary(this, iu, im, itertot_timestep) ! -- modules - use InputOutputModule, only:getunit + use InputOutputModule, only: getunit ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: iu !< file unit number for summary file - integer(I4B), intent(in) :: im !< model number - integer(I4B), intent(in) :: itertot_timestep !< total iteration for the time step + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: iu !< file unit number for summary file + integer(I4B), intent(in) :: im !< model number + integer(I4B), intent(in) :: itertot_timestep !< total iteration for the time step ! -- local variables character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag @@ -1966,7 +1985,7 @@ subroutine convergence_summary(this, iu, im, itertot_timestep) ntabcols = 7 ! ! -- initialize table and define columns - title = trim(this%memoryPath) // ' INNER ITERATION SUMMARY' + title = trim(this%memoryPath)//' INNER ITERATION SUMMARY' call table_cr(this%innertab, this%name, title) call this%innertab%table_df(ntabrows, ntabcols, iu) tag = 'TOTAL ITERATION' @@ -1983,8 +2002,8 @@ subroutine convergence_summary(this, iu, im, itertot_timestep) call this%innertab%initialize_column(tag, 15, alignment=TABRIGHT) tag = 'MAXIMUM RESIDUAL MODEL-(CELLID)' call this%innertab%initialize_column(tag, LENPAKLOC, alignment=TABRIGHT) - ! - ! -- reset the output unit and the number of rows (maxbound) + ! + ! -- reset the output unit and the number of rows (maxbound) else call this%innertab%set_maxbound(itertot_timestep) call this%innertab%set_iout(iu) @@ -2036,26 +2055,25 @@ subroutine convergence_summary(this, iu, im, itertot_timestep) return end subroutine convergence_summary - !> @ brief Solution convergence CSV summary !! !! Save convergence summary to a comma-separated value file. !! !< - subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, & + subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, & niter, istart, kstart) ! -- modules - use InputOutputModule, only:getunit + use InputOutputModule, only: getunit ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: iu !< file unit number - real(DP), intent(in) :: totim !< total simulation time - integer(I4B), intent(in) :: kper !< stress period number - integer(I4B), intent(in) :: kstp !< time step number - integer(I4B), intent(in) :: kouter !< number of outer (Picard) iterations - integer(I4B), intent(in) :: niter !< number of inner iteration in this time step - integer(I4B), intent(in) :: istart !< starting iteration number for this time step - integer(I4B), intent(in) :: kstart !< starting position in the conv* arrays + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: iu !< file unit number + real(DP), intent(in) :: totim !< total simulation time + integer(I4B), intent(in) :: kper !< stress period number + integer(I4B), intent(in) :: kstp !< time step number + integer(I4B), intent(in) :: kouter !< number of outer (Picard) iterations + integer(I4B), intent(in) :: niter !< number of inner iteration in this time step + integer(I4B), intent(in) :: istart !< starting iteration number for this time step + integer(I4B), intent(in) :: kstart !< starting position in the conv* arrays ! -- local integer(I4B) :: itot integer(I4B) :: im @@ -2075,7 +2093,7 @@ subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, & ! -- write inner iteration results to the inner csv output file do k = 1, niter kpos = kstart + k - 1 - write(iu, '(*(G0,:,","))', advance='NO') & + write (iu, '(*(G0,:,","))', advance='NO') & itot, totim, kper, kstp, kouter, k ! ! -- solution summary @@ -2094,14 +2112,14 @@ subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, & ! ! -- get model number and user node number for dv call this%sln_get_nodeu(locdv, im, nodeu) - write(iu, '(*(G0,:,","))', advance='NO') '', dv, im, nodeu + write (iu, '(*(G0,:,","))', advance='NO') '', dv, im, nodeu ! ! -- get model number and user node number for dr call this%sln_get_nodeu(locdr, im, nodeu) - write(iu, '(*(G0,:,","))', advance='NO') '', dr, im, nodeu + write (iu, '(*(G0,:,","))', advance='NO') '', dr, im, nodeu ! ! -- write acceleration parameters - write(iu, '(*(G0,:,","))', advance='NO') & + write (iu, '(*(G0,:,","))', advance='NO') & '', trim(adjustl(this%caccel(kpos))) ! ! -- write information for each model @@ -2114,23 +2132,23 @@ subroutine csv_convergence_summary(this, iu, totim, kper, kstp, kouter, & ! ! -- get model number and user node number for dv call this%sln_get_nodeu(locdv, im, nodeu) - write(iu, '(*(G0,:,","))', advance='NO') '', dv, nodeu + write (iu, '(*(G0,:,","))', advance='NO') '', dv, nodeu ! ! -- get model number and user node number for dr call this%sln_get_nodeu(locdr, im, nodeu) - write(iu, '(*(G0,:,","))', advance='NO') '', dr, nodeu + write (iu, '(*(G0,:,","))', advance='NO') '', dr, nodeu end do end if ! ! -- write line - write(iu,'(a)') '' + write (iu, '(a)') '' ! ! -- update itot itot = itot + 1 end do ! ! -- flush file - flush(iu) + flush (iu) ! ! -- return return @@ -2138,33 +2156,33 @@ end subroutine csv_convergence_summary !> @ brief Save solution data to a file !! - !! Save solution ia vector, ja vector , coefficient matrix, right-hand side + !! Save solution ia vector, ja vector , coefficient matrix, right-hand side !! vector, and the dependent-variable vector to a file. !! !< subroutine save(this, filename) ! -- modules - use InputOutputModule, only:getunit + use InputOutputModule, only: getunit ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - character(len=*), intent(in) :: filename !< filename to save solution data + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + character(len=*), intent(in) :: filename !< filename to save solution data ! -- local variables integer(I4B) :: inunit ! ------------------------------------------------------------------------------ ! inunit = getunit() - open(unit=inunit,file=filename,status='unknown') - write(inunit,*) 'ia' - write(inunit,*) this%ia - write(inunit,*) 'ja' - write(inunit,*) this%ja - write(inunit,*) 'amat' - write(inunit,*) this%amat - write(inunit,*) 'rhs' - write(inunit,*) this%rhs - write(inunit,*) 'x' - write(inunit,*) this%x - close(inunit) + open (unit=inunit, file=filename, status='unknown') + write (inunit, *) 'ia' + write (inunit, *) this%ia + write (inunit, *) 'ja' + write (inunit, *) this%ja + write (inunit, *) 'amat' + write (inunit, *) this%amat + write (inunit, *) 'rhs' + write (inunit, *) this%rhs + write (inunit, *) 'x' + write (inunit, *) this%x + close (inunit) ! ! -- return return @@ -2177,13 +2195,13 @@ end subroutine save !< subroutine add_model(this, mp) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - class(BaseModelType), pointer, intent(in) :: mp !< model instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(BaseModelType), pointer, intent(in) :: mp !< model instance ! -- local variables class(NumericalModelType), pointer :: m => null() ! ! -- add a model - select type(mp) + select type (mp) class is (NumericalModelType) m => mp call AddNumericalModelToList(this%modellist, m) @@ -2200,7 +2218,7 @@ end subroutine add_model !< function get_models(this) result(models) ! -- return variable - type(ListType), pointer :: models !< pointer to the model list + type(ListType), pointer :: models !< pointer to the model list ! -- dummy variables class(NumericalSolutionType) :: this !< NumericalSolutionType instance @@ -2215,13 +2233,13 @@ end function get_models !< subroutine add_exchange(this, exchange) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance - class(BaseExchangeType), pointer, intent(in) :: exchange !< model exchange instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(BaseExchangeType), pointer, intent(in) :: exchange !< model exchange instance ! -- local variables class(NumericalExchangeType), pointer :: num_ex => null() ! ! -- add exchange - select type(exchange) + select type (exchange) class is (NumericalExchangeType) num_ex => exchange call AddNumericalExchangeToList(this%exchangelist, num_ex) @@ -2235,17 +2253,17 @@ end subroutine add_exchange !< function get_exchanges(this) result(exchanges) class(NumericalSolutionType) :: this !< instance of the numerical solution - type(ListType), pointer :: exchanges !< pointer to the exchange list + type(ListType), pointer :: exchanges !< pointer to the exchange list exchanges => this%exchangelist end function get_exchanges - + !> @ brief Assign solution connections !! - !! Assign solution connections. This is the main workhorse method for a - !! solution. The method goes through all the models and all the connections - !! and builds up the sparse matrix. Steps are (1) add internal model + !! Assign solution connections. This is the main workhorse method for a + !! solution. The method goes through all the models and all the connections + !! and builds up the sparse matrix. Steps are (1) add internal model !! connections, (2) add cross terms, (3) allocate solution arrays, (4) create !! mapping arrays, and (5) fill cross term values if necessary. !! @@ -2254,7 +2272,7 @@ subroutine sln_connect(this) ! -- modules use MemoryManagerModule, only: mem_allocate ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables class(NumericalModelType), pointer :: mp => null() class(NumericalExchangeType), pointer :: cp => null() @@ -2263,39 +2281,39 @@ subroutine sln_connect(this) integer(I4B) :: ierror ! ! -- Add internal model connections to sparse - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_ac(this%sparse) - enddo + end do ! ! -- Add the cross terms to sparse - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_ac(this%sparse) - enddo - ! + end do + ! ! -- The number of non-zero array values are now known so ! -- ia and ja can be created from sparse. then destroy sparse - this%nja=this%sparse%nnz + this%nja = this%sparse%nnz call mem_allocate(this%ja, this%nja, 'JA', this%name) call mem_allocate(this%amat, this%nja, 'AMAT', this%name) call this%sparse%sort() - call this%sparse%filliaja(this%ia,this%ja,ierror) + call this%sparse%filliaja(this%ia, this%ja, ierror) call this%sparse%destroy() ! ! -- Create mapping arrays for each model. Mapping assumes ! -- that each row has the diagonal in the first position, ! -- however, rows do not need to be sorted. - do im=1,this%modellist%Count() + do im = 1, this%modellist%Count() mp => GetNumericalModelFromList(this%modellist, im) call mp%model_mc(this%ia, this%ja) - enddo + end do ! ! -- Create arrays for mapping exchange connections to global solution - do ic=1,this%exchangelist%Count() + do ic = 1, this%exchangelist%Count() cp => GetNumericalExchangeFromList(this%exchangelist, ic) call cp%exg_mc(this%ia, this%ja) - enddo + end do ! ! -- return return @@ -2303,13 +2321,13 @@ end subroutine sln_connect !> @ brief Reset the solution !! - !! Reset the solution by setting the coefficient matrix and right-hand side + !! Reset the solution by setting the coefficient matrix and right-hand side !! vectors to zero. !! !< subroutine sln_reset(this) ! -- dummy variables - class(NumericalSolutionType) :: this !< NumericalSolutionType instance + class(NumericalSolutionType) :: this !< NumericalSolutionType instance ! -- local variables integer(I4B) :: i ! @@ -2333,7 +2351,7 @@ end subroutine sln_reset !< subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance integer(I4B), intent(in) :: kiter integer(I4B), intent(in) :: kstp integer(I4B), intent(in) :: kper @@ -2373,9 +2391,9 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) adiag = abs(this%amat(this%ia(n))) if (adiag < DEM15) then this%amat(this%ia(n)) = diagval - this%rhs(n) = this%rhs(n) + diagval * this%x(n) - endif - ! -- Dirichlet boundary or no-flow cell + this%rhs(n) = this%rhs(n) + diagval * this%x(n) + end if + ! -- Dirichlet boundary or no-flow cell else this%amat(this%ia(n)) = DONE this%rhs(n) = this%x(n) @@ -2414,8 +2432,8 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) else iallowptc = 0 end if - ! - ! -- no_ptc_option is ALL (0) or using PTC (1) + ! + ! -- no_ptc_option is ALL (0) or using PTC (1) else iallowptc = this%iallowptc end if @@ -2426,8 +2444,8 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) ! -- calculate or modify pseudo transient continuation terms and add ! to amat diagonals if (iptct /= 0) then - call this%sln_l2norm(this%neq, this%nja, & - this%ia, this%ja, this%active, & + call this%sln_l2norm(this%neq, this%nja, & + this%ia, this%ja, this%active, & this%amat, this%rhs, this%x, l2norm) ! -- confirm that the l2norm exceeds previous l2norm ! if not, there is no need to add ptc terms @@ -2448,9 +2466,9 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) if (iptct /= 0) then if (kiter == 1) then if (this%iptcout > 0) then - write(this%iptcout, '(A10,6(1x,A15),2(1x,A15))') 'OUTER ITER', & - ' PTCDEL', ' L2NORM0', ' L2NORM', & - ' RHSNORM', ' 1/PTCDEL', ' DIAGONAL MIN.', & + write (this%iptcout, '(A10,6(1x,A15),2(1x,A15))') 'OUTER ITER', & + ' PTCDEL', ' L2NORM0', ' L2NORM', & + ' RHSNORM', ' 1/PTCDEL', ' DIAGONAL MIN.', & ' RHSNORM/L2NORM', ' STOPPING CRIT.' end if if (this%ptcdel0 > DZERO) then @@ -2463,7 +2481,7 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) else bnorm = DZERO do n = 1, this%neq - if (this%active(n).gt.0) then + if (this%active(n) .gt. 0) then bnorm = bnorm + this%rhs(n) * this%rhs(n) end if end do @@ -2496,9 +2514,9 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) end do bnorm = sqrt(bnorm) if (this%iptcout > 0) then - write(this%iptcout, '(i10,6(1x,e15.7),2(1x,f15.6))') & - kiter, this%ptcdel, this%l2norm0, l2norm, bnorm, & - ptcval, diagmin, bnorm/l2norm, ptcval / diagmin + write (this%iptcout, '(i10,6(1x,e15.7),2(1x,f15.6))') & + kiter, this%ptcdel, this%l2norm0, l2norm, bnorm, & + ptcval, diagmin, bnorm / l2norm, ptcval / diagmin end if this%l2norm0 = l2norm end if @@ -2508,17 +2526,17 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) !------------------------------------------------------- itestmat = 0 if (itestmat == 1) then - write(fname, fmtfname) this%id, kper, kstp, kiter + write (fname, fmtfname) this%id, kper, kstp, kiter print *, 'Saving amat to: ', trim(adjustl(fname)) - open(99,file=trim(adjustl(fname))) - WRITE(99,*)'NODE, RHS, AMAT FOLLOW' + open (99, file=trim(adjustl(fname))) + WRITE (99, *) 'NODE, RHS, AMAT FOLLOW' DO N = 1, this%NEQ I1 = this%IA(N) - I2 = this%IA(N+1)-1 - WRITE(99,'(*(G0,:,","))') N, this%RHS(N), (this%ja(i),i=i1,i2), & - (this%AMAT(I),I=I1,I2) + I2 = this%IA(N + 1) - 1 + WRITE (99, '(*(G0,:,","))') N, this%RHS(N), (this%ja(i), i=i1, i2), & + (this%AMAT(I), I=I1, I2) END DO - close(99) + close (99) !stop end if !------------------------------------------------------- @@ -2527,13 +2545,13 @@ subroutine sln_ls(this, kiter, kstp, kper, in_iter, iptc, ptcf) ! ! -- ims linear solver - linmeth option 1 if (this%linmeth == 1) then - call this%imslinear%imslinear_apply(this%icnvg, kstp, kiter, in_iter, & - this%nitermax, & - this%convnmod, this%convmodstart, & - this%locdv, this%locdr, & - this%caccel, this%itinner, & - this%convlocdv, this%convlocdr, & - this%dvmax, this%drmax, & + call this%imslinear%imslinear_apply(this%icnvg, kstp, kiter, in_iter, & + this%nitermax, & + this%convnmod, this%convmodstart, & + this%locdv, this%locdr, & + this%caccel, this%itinner, & + this%convlocdv, this%convlocdr, & + this%dvmax, this%drmax, & this%convdvmax, this%convdrmax) end if ! @@ -2557,12 +2575,12 @@ end subroutine sln_ls !< subroutine sln_setouter(this, ifdparam) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: ifdparam !< complexity option (1) simple (2) moderate (3) complex + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: ifdparam !< complexity option (1) simple (2) moderate (3) complex ! ! -- simple option - select case ( ifdparam ) - case ( 1 ) + select case (ifdparam) + case (1) this%dvclose = dem3 this%mxiter = 25 this%nonmeth = 0 @@ -2574,9 +2592,9 @@ subroutine sln_setouter(this, ifdparam) this%btol = DZERO this%breduc = DZERO this%res_lim = DZERO - ! - ! -- moderate - case ( 2 ) + ! + ! -- moderate + case (2) this%dvclose = dem2 this%mxiter = 50 this%nonmeth = 3 @@ -2588,9 +2606,9 @@ subroutine sln_setouter(this, ifdparam) this%btol = DZERO this%breduc = DZERO this%res_lim = DZERO - ! - ! -- complex - case ( 3 ) + ! + ! -- complex + case (3) this%dvclose = dem1 this%mxiter = 100 this%nonmeth = 3 @@ -2611,16 +2629,16 @@ end subroutine sln_setouter !> @ brief Perform backtracking !! !! Perform backtracking on the solution in the maximum number of backtrack - !! iterations (nbtrack) is greater than 0 and the backtracking criteria + !! iterations (nbtrack) is greater than 0 and the backtracking criteria !! are exceeded. !! !< subroutine sln_backtracking(this, mp, cp, kiter) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - class(NumericalModelType), pointer :: mp !< model pointer (currently null()) - class(NumericalExchangeType), pointer :: cp !< exchange pointer (currently null()) - integer(I4B), intent(in) :: kiter !< Picard iteration number + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + class(NumericalModelType), pointer :: mp !< model pointer (currently null()) + class(NumericalExchangeType), pointer :: cp !< exchange pointer (currently null()) + integer(I4B), intent(in) :: kiter !< Picard iteration number ! -- local variables character(len=7) :: cmsg integer(I4B) :: nb @@ -2631,23 +2649,23 @@ subroutine sln_backtracking(this, mp, cp, kiter) ! ! -- initialize local variables ibflag = 0 - + ! ! -- refill amat and rhs with standard conductance call this%sln_buildsystem(kiter, inewton=0) - + ! ! -- calculate initial l2 norm if (kiter == 1) then - call this%sln_l2norm(this%neq, this%nja, & - this%ia, this%ja, this%active, & - this%amat, this%rhs, this%x, this%res_prev) + call this%sln_l2norm(this%neq, this%nja, & + this%ia, this%ja, this%active, & + this%amat, this%rhs, this%x, this%res_prev) resin = this%res_prev ibflag = 0 else - call this%sln_l2norm(this%neq, this%nja, & - this%ia, this%ja, this%active, & - this%amat, this%rhs, this%x, this%res_new) + call this%sln_l2norm(this%neq, this%nja, & + this%ia, this%ja, this%active, & + this%amat, this%rhs, this%x, this%res_new) resin = this%res_new end if ibtcnt = 0 @@ -2667,15 +2685,15 @@ subroutine sln_backtracking(this, mp, cp, kiter) end if ! ibtcnt = nb - + ! recalculate linear system (amat and rhs) call this%sln_buildsystem(kiter, inewton=0) - + ! ! -- calculate updated l2norm - call this%sln_l2norm(this%neq, this%nja, & - this%ia, this%ja, this%active, & - this%amat, this%rhs, this%x, this%res_new) + call this%sln_l2norm(this%neq, this%nja, & + this%ia, this%ja, this%active, & + this%amat, this%rhs, this%x, this%res_new) ! ! -- evaluate if back tracking can be terminated if (nb == this%numtrack) then @@ -2683,7 +2701,7 @@ subroutine sln_backtracking(this, mp, cp, kiter) exit btloop end if if (this%res_new < this%res_prev * this%btol) then - ibflag = 1 + ibflag = 1 exit btloop end if if (this%res_new < this%res_lim) then @@ -2704,7 +2722,7 @@ subroutine sln_backtracking(this, mp, cp, kiter) end if ! ! -- add data to outertab - call this%outertab%add_term( 'Backtracking') + call this%outertab%add_term('Backtracking') call this%outertab%add_term(kiter) call this%outertab%add_term(' ') if (this%numtrack > 0) then @@ -2731,7 +2749,7 @@ end subroutine sln_backtracking subroutine sln_backtracking_xupdate(this, btflag) ! -- dummy variables class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(inout) :: btflag !< backtracking flag (1) backtracking performed (0) backtracking not performed + integer(I4B), intent(inout) :: btflag !< backtracking flag (1) backtracking performed (0) backtracking not performed ! -- local variables integer(I4B) :: n real(DP) :: delx @@ -2745,7 +2763,7 @@ subroutine sln_backtracking_xupdate(this, btflag) chmax = 0.0 do n = 1, this%neq if (this%active(n) < 1) cycle - delx = this%breduc*(this%x(n) - this%xtemp(n)) + delx = this%breduc * (this%x(n) - this%xtemp(n)) absdelx = abs(delx) if (absdelx > chmax) chmax = absdelx end do @@ -2755,7 +2773,7 @@ subroutine sln_backtracking_xupdate(this, btflag) btflag = 1 do n = 1, this%neq if (this%active(n) < 1) cycle - delx = this%breduc*(this%x(n) - this%xtemp(n)) + delx = this%breduc * (this%x(n) - this%xtemp(n)) this%x(n) = this%xtemp(n) + delx end do end if @@ -2772,16 +2790,16 @@ end subroutine sln_backtracking_xupdate !< subroutine sln_l2norm(this, neq, nja, ia, ja, active, amat, rhs, x, l2norm) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: neq !< number of equations - integer(I4B), intent(in) :: nja !< number of non-zero entries - integer(I4B), dimension(neq+1), intent(in) :: ia !< CRS row pointers - integer(I4B), dimension(nja), intent(in) :: ja !< CRS column pointers - integer(I4B), dimension(neq), intent(in) :: active !< active cell flag vector (1) inactive (0) - real(DP), dimension(nja), intent(in) :: amat !< coefficient matrix - real(DP), dimension(neq), intent(in) :: rhs !< right-hand side vector - real(DP), dimension(neq), intent(in) :: x !< dependent-variable vector - real(DP), intent(inout) :: l2norm !< calculated L-2 norm + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: neq !< number of equations + integer(I4B), intent(in) :: nja !< number of non-zero entries + integer(I4B), dimension(neq + 1), intent(in) :: ia !< CRS row pointers + integer(I4B), dimension(nja), intent(in) :: ja !< CRS column pointers + integer(I4B), dimension(neq), intent(in) :: active !< active cell flag vector (1) inactive (0) + real(DP), dimension(nja), intent(in) :: amat !< coefficient matrix + real(DP), dimension(neq), intent(in) :: rhs !< right-hand side vector + real(DP), dimension(neq), intent(in) :: x !< dependent-variable vector + real(DP), intent(inout) :: l2norm !< calculated L-2 norm ! -- local variables integer(I4B) :: n integer(I4B) :: j @@ -2796,7 +2814,7 @@ subroutine sln_l2norm(this, neq, nja, ia, ja, active, amat, rhs, x, l2norm) do n = 1, neq if (active(n) > 0) then rowsum = DZERO - do j = ia(n), ia(n+1)-1 + do j = ia(n), ia(n + 1) - 1 jcol = ja(j) rowsum = rowsum + amat(j) * x(jcol) end do @@ -2818,10 +2836,10 @@ end subroutine sln_l2norm !< subroutine sln_maxval(this, nsize, v, vmax) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: nsize !< length of vector - real(DP), dimension(nsize), intent(in) :: v !< input vector - real(DP), intent(inout) :: vmax !< maximum value + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: nsize !< length of vector + real(DP), dimension(nsize), intent(in) :: v !< input vector + real(DP), intent(inout) :: vmax !< maximum value ! -- local variables integer(I4B) :: n real(DP) :: d @@ -2855,12 +2873,12 @@ end subroutine sln_maxval !< subroutine sln_calcdx(this, neq, active, x, xtemp, dx) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: neq !< number of equations - integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1) - real(DP), dimension(neq), intent(in) :: x !< current dependent-variable - real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable - real(DP), dimension(neq), intent(inout) :: dx !< dependent-variable change + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: neq !< number of equations + integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1) + real(DP), dimension(neq), intent(in) :: x !< current dependent-variable + real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable + real(DP), dimension(neq), intent(inout) :: dx !< dependent-variable change ! -- local integer(I4B) :: n ! @@ -2878,7 +2896,6 @@ subroutine sln_calcdx(this, neq, active, x, xtemp, dx) return end subroutine sln_calcdx - !> @ brief Under-relaxation !! !! Under relax using the simple, cooley, or delta-bar-delta methods. @@ -2886,13 +2903,13 @@ end subroutine sln_calcdx !< subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: kiter !< Picard iteration number - real(DP), intent(in) :: bigch !< maximum dependent-variable change - integer(I4B), intent(in) :: neq !< number of equations - integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1) - real(DP), dimension(neq), intent(inout) :: x !< current dependent-variable - real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: kiter !< Picard iteration number + real(DP), intent(in) :: bigch !< maximum dependent-variable change + integer(I4B), intent(in) :: neq !< number of equations + integer(I4B), dimension(neq), intent(in) :: active !< active cell flag (1) + real(DP), dimension(neq), intent(inout) :: x !< current dependent-variable + real(DP), dimension(neq), intent(in) :: xtemp !< previous dependent-variable ! -- local variables integer(I4B) :: n real(DP) :: ww @@ -2917,8 +2934,8 @@ subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) ! -- dampen dependent variable solution x(n) = xtemp(n) + this%gamma * delx end do - ! - ! -- option for using cooley underrelaxation + ! + ! -- option for using cooley underrelaxation else if (this%nonmeth == 2) then ! ! -- set bigch @@ -2943,7 +2960,7 @@ subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) this%relaxold = relax ! ! -- modify cooley to use weighted average of past changes - this%bigchold = (DONE - this%gamma) * this%bigch + this%gamma * & + this%bigchold = (DONE - this%gamma) * this%bigch + this%gamma * & this%bigchold ! ! -- compute new dependent variable after under-relaxation @@ -2959,8 +2976,8 @@ subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) x(n) = xtemp(n) + relax * delx end do end if - ! - ! -- option for using delta-bar-delta scheme to under-relax for all equations + ! + ! -- option for using delta-bar-delta scheme to under-relax for all equations else if (this%nonmeth == 3) then do n = 1, neq ! @@ -2971,7 +2988,7 @@ subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) delx = x(n) - xtemp(n) ! ! -- initialize values for first iteration - if ( kiter == 1 ) then + if (kiter == 1) then this%wsave(n) = DONE this%hchold(n) = DEM20 this%deold(n) = DZERO @@ -2981,20 +2998,20 @@ subroutine sln_underrelax(this, kiter, bigch, neq, active, x, xtemp) ww = this%wsave(n) ! ! for flip-flop condition, decrease factor - if ( this%deold(n)*delx < DZERO ) then + if (this%deold(n) * delx < DZERO) then ww = this%theta * this%wsave(n) ! -- when change is of same sign, increase factor else ww = this%wsave(n) + this%akappa end if - if ( ww > DONE ) ww = DONE + if (ww > DONE) ww = DONE this%wsave(n) = ww ! ! -- compute weighted average of past changes in hchold if (kiter == 1) then this%hchold(n) = delx else - this%hchold(n) = (DONE - this%gamma) * delx + & + this%hchold(n) = (DONE - this%gamma) * delx + & this%gamma * this%hchold(n) end if ! @@ -3017,15 +3034,15 @@ end subroutine sln_underrelax !> @ brief Determine maximum dependent-variable change !! - !! Determine the maximum dependent-variable change at the end of a + !! Determine the maximum dependent-variable change at the end of a !! Picard iteration. !! !< subroutine sln_outer_check(this, hncg, lrch) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - real(DP), intent(inout) :: hncg !< maximum dependent-variable change - integer(I4B), intent(inout) :: lrch !< location of the maximum dependent-variable change + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + real(DP), intent(inout) :: hncg !< maximum dependent-variable change + integer(I4B), intent(inout) :: lrch !< location of the maximum dependent-variable change ! -- local variables integer(I4B) :: nb real(DP) :: bigch @@ -3039,7 +3056,7 @@ subroutine sln_outer_check(this, hncg, lrch) bigch = DZERO abigch = DZERO do n = 1, this%neq - if(this%active(n) < 1) cycle + if (this%active(n) < 1) cycle hdif = this%x(n) - this%xtemp(n) ahdif = abs(hdif) if (ahdif >= abigch) then @@ -3064,11 +3081,11 @@ end subroutine sln_outer_check !< subroutine sln_get_loc(this, nodesln, str) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: nodesln !< solution node number - character(len=*), intent(inout) :: str !< string with user node number + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: nodesln !< solution node number + character(len=*), intent(inout) :: str !< string with user node number ! -- local variables - class(NumericalModelType), pointer :: mp=> null() + class(NumericalModelType), pointer :: mp => null() integer(I4B) :: i integer(I4B) :: istart integer(I4B) :: iend @@ -3104,12 +3121,12 @@ end subroutine sln_get_loc !< subroutine sln_get_nodeu(this, nodesln, im, nodeu) ! -- dummy variables - class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance - integer(I4B), intent(in) :: nodesln !< solution node number - integer(I4B), intent(inout) :: im !< solution model number - integer(I4B), intent(inout) :: nodeu !< user node number + class(NumericalSolutionType), intent(inout) :: this !< NumericalSolutionType instance + integer(I4B), intent(in) :: nodesln !< solution node number + integer(I4B), intent(inout) :: im !< solution model number + integer(I4B), intent(inout) :: nodeu !< user node number ! -- local variables - class(NumericalModelType),pointer :: mp => null() + class(NumericalModelType), pointer :: mp => null() integer(I4B) :: i integer(I4B) :: istart integer(I4B) :: iend @@ -3141,11 +3158,11 @@ end subroutine sln_get_nodeu !! Get a numerical solution from a list. !! !< - function CastAsNumericalSolutionClass(obj) result (res) + function CastAsNumericalSolutionClass(obj) result(res) ! -- dummy variables - class(*), pointer, intent(inout) :: obj !< generic object + class(*), pointer, intent(inout) :: obj !< generic object ! -- return variable - class(NumericalSolutionType), pointer :: res !< output NumericalSolutionType + class(NumericalSolutionType), pointer :: res !< output NumericalSolutionType ! ! -- initialize return variable res => null() @@ -3162,18 +3179,18 @@ function CastAsNumericalSolutionClass(obj) result (res) ! -- return return end function CastAsNumericalSolutionClass - + !> @ brief Get a numerical solution !! !! Get a numerical solution from a list. !! !< - function GetNumericalSolutionFromList(list, idx) result (res) + function GetNumericalSolutionFromList(list, idx) result(res) ! -- dummy variables - type(ListType), intent(inout) :: list !< list of numerical solutions - integer(I4B), intent(in) :: idx !< value to retrieve from the list + type(ListType), intent(inout) :: list !< list of numerical solutions + integer(I4B), intent(in) :: idx !< value to retrieve from the list ! -- return variables - class(NumericalSolutionType), pointer :: res !< numerical solution + class(NumericalSolutionType), pointer :: res !< numerical solution ! -- local variables class(*), pointer :: obj ! diff --git a/src/Solution/SolutionGroup.f90 b/src/Solution/SolutionGroup.f90 index 92cde54146b..c51076e802c 100644 --- a/src/Solution/SolutionGroup.f90 +++ b/src/Solution/SolutionGroup.f90 @@ -1,10 +1,10 @@ module SolutionGroupModule - use KindModule, only: DP, I4B - use ListsModule, only: basesolutionlist + use KindModule, only: DP, I4B + use ListsModule, only: basesolutionlist use BaseSolutionModule, only: BaseSolutionType, AddBaseSolutionToList, & GetBaseSolutionFromList - use ListModule, only: ListType - + use ListModule, only: ListType + implicit none private public :: SolutionGroupType, AddSolutionGroupToList, & @@ -12,19 +12,19 @@ module SolutionGroupModule private :: CastAsSolutionGroupClass type :: SolutionGroupType - integer(I4B), pointer :: id - integer(I4B), pointer :: mxiter - integer(I4B), pointer :: nsolutions - integer(I4B), dimension(:), allocatable :: idsolutions !array of solution ids in basesolutionlist + integer(I4B), pointer :: id + integer(I4B), pointer :: mxiter + integer(I4B), pointer :: nsolutions + integer(I4B), dimension(:), allocatable :: idsolutions !array of solution ids in basesolutionlist contains - procedure :: sgp_ca - procedure :: sgp_da + procedure :: sgp_ca + procedure :: sgp_da procedure, private :: allocate_scalars - procedure :: add_solution + procedure :: add_solution end type SolutionGroupType - - contains - + +contains + subroutine solutiongroup_create(sgp, id) ! ****************************************************************************** ! solutiongroup_create -- Create a new solution group @@ -33,17 +33,17 @@ subroutine solutiongroup_create(sgp, id) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ type(SolutionGroupType), pointer :: sgp - integer(I4B), intent(in) :: id + integer(I4B), intent(in) :: id ! ------------------------------------------------------------------------------ ! - allocate(sgp) + allocate (sgp) call sgp%allocate_scalars() sgp%id = id ! ! -- return return end subroutine solutiongroup_create - + subroutine sgp_ca(this) ! ****************************************************************************** ! sgp_ca -- Calculate the solution group @@ -55,27 +55,27 @@ subroutine sgp_ca(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH - use SimVariablesModule, only: iout, isimcnvg, lastStepFailed - use TdisModule, only: kstp, kper + use ConstantsModule, only: LINELENGTH + use SimVariablesModule, only: iout, isimcnvg, lastStepFailed + use TdisModule, only: kstp, kper ! -- dummy class(SolutionGroupType) :: this ! -- local - class(BaseSolutionType), pointer :: sp + class(BaseSolutionType), pointer :: sp integer(I4B) :: kpicard, isgcnvg, isuppress_output integer(I4B) :: is, isoln ! -- formats - character(len=*), parameter :: fmtnocnvg = & - "(1X,'Solution Group ', i0, ' did not converge for stress period ', i0, & + character(len=*), parameter :: fmtnocnvg = & + "(1X,'Solution Group ', i0, ' did not converge for stress period ', i0, & &' and time step ', i0)" ! ------------------------------------------------------------------------------ ! ! -- Suppress output during picard iterations - if(this%mxiter > 1) then + if (this%mxiter > 1) then isuppress_output = 1 else isuppress_output = 0 - endif + end if ! ! -- set failed flag lastStepFailed = 0 @@ -83,35 +83,35 @@ subroutine sgp_ca(this) ! -- Picard loop picardloop: do kpicard = 1, this%mxiter if (this%mxiter > 1) then - write(iout,'(/a,i6/)') 'SOLUTION GROUP PICARD ITERATION: ', kpicard + write (iout, '(/a,i6/)') 'SOLUTION GROUP PICARD ITERATION: ', kpicard end if isgcnvg = 1 do is = 1, this%nsolutions isoln = this%idsolutions(is) sp => GetBaseSolutionFromList(basesolutionlist, isoln) call sp%sln_ca(isgcnvg, isuppress_output) - enddo - if(isgcnvg == 1) exit picardloop - enddo picardloop + end do + if (isgcnvg == 1) exit picardloop + end do picardloop ! ! -- if a picard loop was used and the solution group converged ! then rerun the timestep and save the output. Or if there ! is only one picard iteration, then do nothing as models ! are assumed to be explicitly coupled. - if(isgcnvg == 1) then - if(this%mxiter > 1) then + if (isgcnvg == 1) then + if (this%mxiter > 1) then isuppress_output = 0 do is = 1, this%nsolutions isoln = this%idsolutions(is) sp => GetBaseSolutionFromList(basesolutionlist, isoln) call sp%sln_ca(isgcnvg, isuppress_output) - enddo - endif + end do + end if else isimcnvg = 0 lastStepFailed = 1 - write(iout, fmtnocnvg) this%id, kper, kstp - endif + write (iout, fmtnocnvg) this%id, kper, kstp + end if ! ! -- return return @@ -127,10 +127,10 @@ subroutine sgp_da(this) class(SolutionGroupType) :: this ! ------------------------------------------------------------------------------ ! - deallocate(this%id) - deallocate(this%mxiter) - deallocate(this%nsolutions) - deallocate(this%idsolutions) + deallocate (this%id) + deallocate (this%mxiter) + deallocate (this%nsolutions) + deallocate (this%idsolutions) ! ! -- return return @@ -146,9 +146,9 @@ subroutine allocate_scalars(this) class(SolutionGroupType) :: this ! ------------------------------------------------------------------------------ ! - allocate(this%id) - allocate(this%mxiter) - allocate(this%nsolutions) + allocate (this%id) + allocate (this%mxiter) + allocate (this%nsolutions) this%id = 0 this%mxiter = 1 this%nsolutions = 0 @@ -183,7 +183,7 @@ subroutine add_solution(this, isoln, sp) return end subroutine add_solution - function CastAsSolutionGroupClass(obj) result (res) + function CastAsSolutionGroupClass(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj class(SolutionGroupType), pointer :: res @@ -201,7 +201,7 @@ end function CastAsSolutionGroupClass subroutine AddSolutionGroupToList(list, solutiongroup) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(SolutionGroupType), pointer, intent(inout) :: solutiongroup ! -- local class(*), pointer :: obj @@ -211,13 +211,13 @@ subroutine AddSolutionGroupToList(list, solutiongroup) ! return end subroutine AddSolutionGroupToList - - function GetSolutionGroupFromList(list, idx) result (res) + + function GetSolutionGroupFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - class(SolutionGroupType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + class(SolutionGroupType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Solution/SparseMatrixSolver/ims8base.f90 b/src/Solution/SparseMatrixSolver/ims8base.f90 deleted file mode 100644 index 3b10e2761b3..00000000000 --- a/src/Solution/SparseMatrixSolver/ims8base.f90 +++ /dev/null @@ -1,1319 +0,0 @@ - -!> @brief This module contains the IMS linear accelerator subroutines -!! -!! This module contains the IMS linear accelerator subroutines used by a -!! MODFLOW 6 solution. -!< -MODULE IMSLinearBaseModule - ! -- modules - use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, IZERO, & - DZERO, DPREC, DEM6, DEM3, DHALF, DONE - use GenericUtilitiesModule, only: sim_message, is_same - use BlockParserModule, only: BlockParserType - use IMSReorderingModule, only: ims_odrv - - IMPLICIT NONE - - type(BlockParserType), private :: parser - - contains - - !> @ brief Preconditioned Conjugate Gradient linear accelerator - !! - !! Apply the Preconditioned Conjugate Gradient linear accelerator to - !! the current coefficient matrix, right-hand side, using the current - !! dependent-variable. - !! - !< - SUBROUTINE ims_base_cg(ICNVG, ITMAX, INNERIT, & - NEQ, NJA, NIAPC, NJAPC, & - IPC, NITERC, ICNVGOPT, NORTH, & - DVCLOSE, RCLOSE, L2NORM0, EPFACT, & - IA0, JA0, A0, IAPC, JAPC, APC, & - X, B, D, P, Q, Z, & - NJLU, IW, JLU, & - NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & - CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & - DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) - ! -- dummy variables - integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) - integer(I4B), INTENT(IN) :: ITMAX !< maximum number of inner iterations - integer(I4B), INTENT(INOUT) :: INNERIT !< inner iteration count - integer(I4B), INTENT(IN) :: NEQ !< number of equations - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows - integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries - integer(I4B), INTENT(IN) :: IPC !< preconditioner option - integer(I4B), INTENT(INOUT) :: NITERC !< total number of inner iterations - integer(I4B), INTENT(IN) :: ICNVGOPT !< flow convergence criteria option - integer(I4B), INTENT(IN) :: NORTH !< orthogonalization frequency - real(DP), INTENT(IN) :: DVCLOSE !< dependent-variable closure criteria - real(DP), INTENT(IN) :: RCLOSE !< flow closure criteria - real(DP), INTENT(IN) :: L2NORM0 !< initial L-2 norm for system of equations - real(DP), INTENT(IN) :: EPFACT !< factor for decreasing flow convergence criteria for subsequent Picard iterations - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA0 !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA0 !< CRS column pointers - real(DP), DIMENSION(NJA), INTENT(IN) :: A0 !< coefficient matrix - integer(I4B), DIMENSION(NIAPC + 1), INTENT(IN) :: IAPC !< preconditioner CRS row pointers - integer(I4B), DIMENSION(NJAPC), INTENT(IN) :: JAPC !< preconditioner CRS column pointers - real(DP), DIMENSION(NJAPC), INTENT(IN) :: APC !< preconditioner matrix - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent-variable vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: B !< right-hand side vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: P !< working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Q !< working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Z !< working vector - ! -- ILUT dummy variables - integer(I4B), INTENT(IN) :: NJLU !< preconditioner length of JLU vector - integer(I4B), DIMENSION(NIAPC), INTENT(IN) :: IW !< preconditioner integer working vector - integer(I4B), DIMENSION(NJLU), INTENT(IN) :: JLU !< preconditioner JLU working vector - ! -- convergence information dummy variables dummy variables - integer(I4B), INTENT(IN) :: NCONV !< maximum number of inner iterations in a time step (maxiter * maxinner) - integer(I4B), INTENT(IN) :: CONVNMOD !< number of models in the solution - integer(I4B), DIMENSION(CONVNMOD + 1), INTENT(INOUT) :: CONVMODSTART !< pointer to the start of each model in the convmod* arrays - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< location of the maximum dependent-variable change in the solution - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< location of the maximum flow change in the solution - character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< convergence string - integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< actual number of inner iterations in each Picard iteration - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< location of the maximum dependent-variable change in each model in the solution - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< location of the maximum flow change in each model in the solution - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< maximum dependent-variable change in the solution - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< maximum flow change in the solution - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< maximum dependent-variable change in each model in the solution - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< maximum flow change in each model in the solution - ! -- local variables - LOGICAL :: lorth - logical :: lsame - character(len=31) :: cval - integer(I4B) :: n - integer(I4B) :: iiter - integer(I4B) :: xloc, rloc - integer(I4B) :: im, im0, im1 - real(DP) :: ddot - real(DP) :: tv - real(DP) :: deltax - real(DP) :: rmax - real(DP) :: l2norm - real(DP) :: rcnvg - real(DP) :: denom - real(DP) :: alpha, beta - real(DP) :: rho, rho0 - ! - ! -- initialize local variables - rho0 = DZERO - rho = DZERO - INNERIT = 0 - ! - ! -- INNER ITERATION - INNER: DO iiter = 1, itmax - INNERIT = INNERIT + 1 - NITERC = NITERC + 1 - ! - ! -- APPLY PRECONDITIONER - SELECT CASE (IPC) - ! - ! -- ILU0 AND MILU0 - CASE (1, 2) - CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, D, Z) - ! - ! -- ILUT AND MILUT - CASE (3, 4) - CALL lusol(NEQ, D, Z, APC, JLU, IW) - END SELECT - rho = ddot(NEQ, D, 1, Z, 1) - ! - ! -- COMPUTE DIRECTIONAL VECTORS - IF (IITER == 1) THEN - DO n = 1, NEQ - P(n) = Z(n) - END DO - ELSE - beta = rho/rho0 - DO n = 1, NEQ - P(n) = Z(n) + beta*P(n) - END DO - END IF - ! - ! -- COMPUTE ITERATES - ! - ! -- UPDATE Q - call amux( NEQ, P, Q, A0, JA0, IA0 ) - denom = ddot(NEQ, P, 1, Q, 1) - denom = denom + SIGN(DPREC, denom) - alpha = rho/denom - ! - ! -- UPDATE X AND RESIDUAL - deltax = DZERO - rmax = DZERO - l2norm = DZERO - DO im = 1, CONVNMOD - DVMAX(im) = DZERO - DRMAX(im) = DZERO - END DO - im = 1 - im0 = CONVMODSTART(1) - im1 = CONVMODSTART(2) - DO n = 1, NEQ - ! - ! -- determine current model index - if (n == im1) then - im = im + 1 - im0 = CONVMODSTART(im) - im1 = CONVMODSTART(im + 1) - end if - ! - ! -- identify deltax and rmax - tv = alpha*P(n) - X(n) = X(n) + tv - IF (ABS(tv) > ABS(deltax)) THEN - deltax = tv - xloc = n - END IF - IF (ABS(tv) > ABS(DVMAX(im))) THEN - DVMAX(im) = tv - LOCDV(im) = n - END IF - tv = D(n) - tv = tv - alpha*Q(n) - D(n) = tv - IF (ABS(tv) > ABS(rmax)) THEN - rmax = tv - rloc = n - END IF - IF (ABS(tv) > ABS(DRMAX(im))) THEN - DRMAX(im) = tv - LOCDR(im) = n - END IF - l2norm = l2norm + tv*tv - END DO - l2norm = SQRT(l2norm) - ! - ! -- SAVE SOLVER convergence information dummy variables - IF (NCONV > 1) THEN !< - n = NITERC - WRITE (cval, '(g15.7)') alpha - CACCEL(n) = cval - ITINNER(n) = iiter - DO im = 1, CONVNMOD - CONVLOCDV(im, n) = LOCDV(im) - CONVLOCDR(im, n) = LOCDR(im) - CONVDVMAX(im, n) = DVMAX(im) - CONVDRMAX(im, n) = DRMAX(im) - END DO - END IF - ! - ! -- TEST FOR SOLVER CONVERGENCE - IF (ICNVGOPT == 2 .OR. ICNVGOPT == 3 .OR. ICNVGOPT == 4) THEN - rcnvg = l2norm - ELSE - rcnvg = rmax - END IF - CALL ims_base_testcnvg(ICNVGOPT, ICNVG, INNERIT, & - deltax, rcnvg, & - L2NORM0, EPFACT, DVCLOSE, RCLOSE) - ! - ! -- CHECK FOR EXACT SOLUTION - IF (rcnvg == DZERO) ICNVG = 1 - ! - ! -- CHECK FOR STANDARD CONVERGENCE - IF (ICNVG .NE. 0) EXIT INNER - ! - ! -- CHECK THAT CURRENT AND PREVIOUS rho ARE DIFFERENT - lsame = is_same(rho, rho0) - IF (lsame) THEN - EXIT INNER - END IF - ! - ! -- RECALCULATE THE RESIDUAL - IF (NORTH > 0) THEN - lorth = mod(iiter + 1, NORTH) == 0 - IF (lorth) THEN - call ims_base_residual(NEQ, NJA, X, B, D, A0, IA0, JA0) - END IF - END IF - ! - ! -- exit inner if rho is zero - if (rho == DZERO) then - exit inner - end if - ! - ! -- SAVE CURRENT INNER ITERATES - rho0 = rho - END DO INNER - ! - ! -- RESET ICNVG - IF (ICNVG < 0) ICNVG = 0 - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_cg - - !> @ brief Preconditioned BiConjugate Gradient Stabilized linear accelerator - !! - !! Apply the Preconditioned BiConjugate Gradient Stabilized linear - !! accelerator to the current coefficient matrix, right-hand side, using - !! the currentdependent-variable. - !! - !< - SUBROUTINE ims_base_bcgs(ICNVG, ITMAX, INNERIT, & - NEQ, NJA, NIAPC, NJAPC, & - IPC, NITERC, ICNVGOPT, NORTH, ISCL, DSCALE, & - DVCLOSE, RCLOSE, L2NORM0, EPFACT, & - IA0, JA0, A0, IAPC, JAPC, APC, & - X, B, D, P, Q, & - T, V, DHAT, PHAT, QHAT, & - NJLU, IW, JLU, & - NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & - CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & - DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) - ! -- dummy variables - integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) - integer(I4B), INTENT(IN) :: ITMAX !< maximum number of inner iterations - integer(I4B), INTENT(INOUT) :: INNERIT !< inner iteration count - integer(I4B), INTENT(IN) :: NEQ !< number of equations - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows - integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries - integer(I4B), INTENT(IN) :: IPC !< preconditioner option - integer(I4B), INTENT(INOUT) :: NITERC !< total number of inner iterations - integer(I4B), INTENT(IN) :: ICNVGOPT !< flow convergence criteria option - integer(I4B), INTENT(IN) :: NORTH !< orthogonalization frequency - integer(I4B), INTENT(IN) :: ISCL !< scaling option - real(DP), DIMENSION(NEQ), INTENT(IN) :: DSCALE !< scaling vector - real(DP), INTENT(IN) :: DVCLOSE !< dependent-variable closure criteria - real(DP), INTENT(IN) :: RCLOSE !< flow closure criteria - real(DP), INTENT(IN) :: L2NORM0 !< initial L-2 norm for system of equations - real(DP), INTENT(IN) :: EPFACT !< factor for decreasing flow convergence criteria for subsequent Picard iterations - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA0 !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA0 !< CRS column pointers - real(DP), DIMENSION(NJA), INTENT(IN) :: A0 !< coefficient matrix - integer(I4B), DIMENSION(NIAPC + 1), INTENT(IN) :: IAPC !< preconditioner CRS row pointers - integer(I4B), DIMENSION(NJAPC), INTENT(IN) :: JAPC !< preconditioner CRS column pointers - real(DP), DIMENSION(NJAPC), INTENT(IN) :: APC !< preconditioner matrix - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent-variable vector - real(DP), DIMENSION(NEQ), INTENT(IN) :: B !< right-hand side vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: P !< preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: Q !< preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: T !< preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: V !< preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DHAT !< BCGS preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: PHAT !< BCGS preconditioner working vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: QHAT !< BCGS preconditioner working vector - ! -- ILUT dummy variables - integer(I4B), INTENT(IN) :: NJLU !< preconditioner length of JLU vector - integer(I4B), DIMENSION(NIAPC), INTENT(IN) :: IW !< preconditioner integer working vector - integer(I4B), DIMENSION(NJLU), INTENT(IN) :: JLU !< preconditioner JLU working vector - ! -- convergence information dummy variables - integer(I4B), INTENT(IN) :: NCONV !< maximum number of inner iterations in a time step (maxiter * maxinner) - integer(I4B), INTENT(IN) :: CONVNMOD !< number of models in the solution - integer(I4B), DIMENSION(CONVNMOD + 1), INTENT(INOUT) :: CONVMODSTART !< pointer to the start of each model in the convmod* arrays - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< location of the maximum dependent-variable change in the solution - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< location of the maximum flow change in the solution - character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< convergence string - integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< actual number of inner iterations in each Picard iteration - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< location of the maximum dependent-variable change in each model in the solution - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< location of the maximum flow change in each model in the solution - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< maximum dependent-variable change in the solution - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< maximum flow change in the solution - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< maximum dependent-variable change in each model in the solution - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< maximum flow change in each model in the solution - ! -- local variables - LOGICAL :: LORTH - logical :: lsame - character(len=15) :: cval1, cval2 - integer(I4B) :: n - integer(I4B) :: iiter - integer(I4B) :: xloc, rloc - integer(I4B) :: im, im0, im1 - real(DP) :: ddot - real(DP) :: tv - real(DP) :: deltax - real(DP) :: rmax - real(DP) :: l2norm - real(DP) :: rcnvg - real(DP) :: alpha, alpha0 - real(DP) :: beta - real(DP) :: rho, rho0 - real(DP) :: omega, omega0 - real(DP) :: numer, denom - ! - ! -- initialize local variables - INNERIT = 0 - alpha = DZERO - alpha0 = DZERO - beta = DZERO - rho = DZERO - rho0 = DZERO - omega = DZERO - omega0 = DZERO - ! - ! -- SAVE INITIAL RESIDUAL - DO n = 1, NEQ - DHAT(n) = D(n) - END DO - ! - ! -- INNER ITERATION - INNER: DO iiter = 1, itmax - INNERIT = INNERIT + 1 - NITERC = NITERC + 1 - ! - ! -- CALCULATE rho - rho = ddot(NEQ, DHAT, 1, D, 1) - ! - ! -- COMPUTE DIRECTIONAL VECTORS - IF (IITER == 1) THEN - DO n = 1, NEQ - P(n) = D(n) - END DO - ELSE - beta = (rho/rho0)*(alpha0/omega0) - DO n = 1, NEQ - P(n) = D(n) + beta*(P(n) - omega0*V(n)) - END DO - END IF - ! - ! -- APPLY PRECONDITIONER TO UPDATE PHAT - SELECT CASE (IPC) - ! - ! -- ILU0 AND MILU0 - CASE (1, 2) - CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, P, PHAT) - ! - ! -- ILUT AND MILUT - CASE (3, 4) - CALL lusol(NEQ, P, PHAT, APC, JLU, IW) - END SELECT - ! - ! -- COMPUTE ITERATES - ! - ! -- UPDATE V WITH A AND PHAT - call amux( NEQ, PHAT, V, A0, JA0, IA0 ) - ! - ! -- UPDATE alpha WITH DHAT AND V - denom = ddot(NEQ, DHAT, 1, V, 1) - denom = denom + SIGN(DPREC, denom) - alpha = rho/denom - ! - ! -- UPDATE Q - DO n = 1, NEQ - Q(n) = D(n) - alpha*V(n) - END DO - ! - ! ! -- CALCULATE INFINITY NORM OF Q - TEST FOR TERMINATION - ! ! TERMINATE IF rmax IS LESS THAN MACHINE PRECISION (DPREC) - ! rmax = DZERO - ! DO n = 1, NEQ - ! tv = Q(n) - ! IF (ISCL.NE.0 ) tv = tv / DSCALE(n) - ! IF (ABS(tv) > ABS(rmax) ) rmax = tv - ! END DO - ! IF (ABS(rmax).LE.DPREC) THEN - ! deltax = DZERO - ! DO n = 1, NEQ - ! tv = alpha * PHAT(n) - ! IF (ISCL.NE.0) THEN - ! tv = tv * DSCALE(n) - ! END IF - ! X(n) = X(n) + tv - ! IF (ABS(tv) > ABS(deltax) ) deltax = tv - ! END DO - ! CALL IMSLINEARSUB_TESTCNVG(ICNVGOPT, ICNVG, INNERIT, & - ! deltax, rmax, & - ! rmax, EPFACT, DVCLOSE, RCLOSE ) - ! IF (ICNVG.NE.0 ) EXIT INNER - ! END IF - ! - ! -- APPLY PRECONDITIONER TO UPDATE QHAT - SELECT CASE (IPC) - ! - ! -- ILU0 AND MILU0 - CASE (1, 2) - CALL ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, Q, QHAT) - ! - ! -- ILUT AND MILUT - CASE (3, 4) - CALL lusol(NEQ, Q, QHAT, APC, JLU, IW) - END SELECT - ! - ! -- UPDATE T WITH A AND QHAT - call amux( NEQ, QHAT, T, A0, JA0, IA0 ) - ! - ! -- UPDATE omega - numer = ddot(NEQ, T, 1, Q, 1) - denom = ddot(NEQ, T, 1, T, 1) - denom = denom + SIGN(DPREC, denom) - omega = numer/denom - ! - ! -- UPDATE X AND RESIDUAL - deltax = DZERO - rmax = DZERO - l2norm = DZERO - DO im = 1, CONVNMOD - DVMAX(im) = DZERO - DRMAX(im) = DZERO - END DO - im = 1 - im0 = CONVMODSTART(1) - im1 = CONVMODSTART(2) - DO n = 1, NEQ - ! - ! -- determine current model index - if (n == im1) then - im = im + 1 - im0 = CONVMODSTART(im) - im1 = CONVMODSTART(im + 1) - end if - ! - ! -- X AND DX - tv = alpha*PHAT(n) + omega*QHAT(n) - X(n) = X(n) + tv - IF (ISCL .NE. 0) THEN - tv = tv*DSCALE(n) - END IF - IF (ABS(tv) > ABS(deltax)) THEN - deltax = tv - xloc = n - END IF - IF (ABS(tv) > ABS(DVMAX(im))) THEN - DVMAX(im) = tv - LOCDV(im) = n - END IF - ! - ! -- RESIDUAL - tv = Q(n) - omega*T(n) - D(n) = tv - IF (ISCL .NE. 0) THEN - tv = tv/DSCALE(n) - END IF - IF (ABS(tv) > ABS(rmax)) THEN - rmax = tv - rloc = n - END IF - IF (ABS(tv) > ABS(DRMAX(im))) THEN - DRMAX(im) = tv - LOCDR(im) = n - END IF - l2norm = l2norm + tv*tv - END DO - l2norm = sqrt(l2norm) - ! - ! -- SAVE SOLVER convergence information dummy variables - IF (NCONV > 1) THEN !< - n = NITERC - WRITE (cval1, '(g15.7)') alpha - WRITE (cval2, '(g15.7)') omega - CACCEL(n) = trim(adjustl(cval1))//','//trim(adjustl(cval2)) - ITINNER(n) = iiter - DO im = 1, CONVNMOD - CONVLOCDV(im, n) = LOCDV(im) - CONVLOCDR(im, n) = LOCDR(im) - CONVDVMAX(im, n) = DVMAX(im) - CONVDRMAX(im, n) = DRMAX(im) - END DO - END IF - ! - ! -- TEST FOR SOLVER CONVERGENCE - IF (ICNVGOPT == 2 .OR. ICNVGOPT == 3 .OR. ICNVGOPT == 4) THEN - rcnvg = l2norm - ELSE - rcnvg = rmax - END IF - CALL ims_base_testcnvg(ICNVGOPT, ICNVG, INNERIT, & - deltax, rcnvg, & - L2NORM0, EPFACT, DVCLOSE, RCLOSE) - ! - ! -- CHECK FOR EXACT SOLUTION - IF (rcnvg == DZERO) ICNVG = 1 - ! - ! -- CHECK FOR STANDARD CONVERGENCE - IF (ICNVG .NE. 0) EXIT INNER - ! - ! -- CHECK THAT CURRENT AND PREVIOUS rho, alpha, AND omega ARE - ! DIFFERENT - lsame = is_same(rho, rho0) - IF (lsame) THEN - EXIT INNER - END IF - lsame = is_same(alpha, alpha0) - IF (lsame) THEN - EXIT INNER - END IF - lsame = is_same(omega, omega0) - IF (lsame) THEN - EXIT INNER - END IF - ! - ! -- RECALCULATE THE RESIDUAL - IF (NORTH > 0) THEN - LORTH = mod(iiter + 1, NORTH) == 0 - IF (LORTH) THEN - call ims_base_residual(NEQ, NJA, X, B, D, A0, IA0, JA0) - END IF - END IF - ! - ! -- exit inner if rho or omega are zero - if (rho*omega == DZERO) then - exit inner - end if - ! - ! -- SAVE CURRENT INNER ITERATES - rho0 = rho - alpha0 = alpha - omega0 = omega - END DO INNER - ! - ! -- RESET ICNVG - IF (ICNVG < 0) ICNVG = 0 - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_bcgs - - !> @ brief Calculate LORDER AND IORDER - !! - !! Calculate LORDER and IORDER for reordering. - !! - !< - SUBROUTINE ims_base_calc_order(IORD, NEQ, NJA, IA, JA, LORDER, IORDER) - ! -- modules - use SimModule, only: store_error, count_errors - ! -- dummy variables - integer(I4B), INTENT(IN) :: IORD !< reordering optionn - integer(I4B), INTENT(IN) :: NEQ !< number of rows - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< row pointer - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< column pointer - integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: LORDER !< reorder vector - integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: IORDER !< inverse of reorder vector - ! -- local variables - character(len=LINELENGTH) :: errmsg - integer(I4B) :: n - integer(I4B) :: nsp - integer(I4B), DIMENSION(:), ALLOCATABLE :: iwork0 - integer(I4B), DIMENSION(:), ALLOCATABLE :: iwork1 - integer(I4B) :: iflag - ! - ! -- initialize lorder and iorder - DO n = 1, NEQ - LORDER(n) = IZERO - IORDER(n) = IZERO - END DO - ! ALLOCATE (iwork0(NEQ)) - SELECT CASE (IORD) - CASE (1) - CALL genrcm(NEQ, NJA, IA, JA, LORDER) - CASE (2) - nsp = 3*NEQ + 4*NJA - allocate(iwork0(NEQ)) - allocate(iwork1(nsp)) - CALL ims_odrv(NEQ, NJA, nsp, IA, JA, LORDER, iwork0, & - iwork1, iflag) - IF (iflag .NE. 0) THEN - write (errmsg, '(A,1X,A)') & - 'IMSLINEARSUB_CALC_ORDER ERROR CREATING MINIMUM DEGREE ', & - 'ORDER PERMUTATION ' - call store_error(errmsg) - END IF - ! - ! -- DEALLOCATE TEMPORARY STORAGE - deallocate(iwork0, iwork1) - END SELECT - ! - ! -- GENERATE INVERSE OF LORDER - DO n = 1, NEQ - IORDER(LORDER(n)) = n - END DO - ! - ! -- terminate if errors occured - if (count_errors() > 0) then - call parser%StoreErrorUnit() - end if - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_calc_order - - ! - !> @ brief Scale the coefficient matrix - !! - !! Scale the coefficient matrix (AMAT), the right-hand side (B), - !! and the estimate of the dependent variable (X). - !! - !< - SUBROUTINE ims_base_scale(IOPT, ISCL, NEQ, NJA, IA, JA, AMAT, X, B, & - DSCALE, DSCALE2) - ! -- dummy variables - integer(I4B), INTENT(IN) :: IOPT !< flag to scale (0) or unscale the system of equations - integer(I4B), INTENT(IN) :: ISCL !< scaling option (1) symmetric (2) L-2 norm - integer(I4B), INTENT(IN) :: NEQ !< number of equations - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointer - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointer - real(DP), DIMENSION(NJA), INTENT(INOUT) :: AMAT !< coefficient matrix - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: X !< dependent variable - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: B !< right-hand side - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DSCALE !< first scaling vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: DSCALE2 !< second scaling vector - ! -- local variables - integer(I4B) :: i, n - integer(I4B) :: id, jc - integer(I4B) :: i0, i1 - real(DP) :: v, c1, c2 - ! - ! -- SCALE SCALE AMAT, X, AND B - IF (IOPT == 0) THEN - ! - ! -- SYMMETRIC SCALING - SELECT CASE (ISCL) - CASE (1) - DO n = 1, NEQ - id = IA(n) - v = AMAT(id) - c1 = DONE/SQRT(ABS(v)) - DSCALE(n) = c1 - DSCALE2(n) = c1 - END DO - ! - ! -- SCALE AMAT -- AMAT = DSCALE(row) * AMAT(i) * DSCALE2(col) - DO n = 1, NEQ - c1 = DSCALE(n) - i0 = IA(n) - i1 = IA(n + 1) - 1 - DO i = i0, i1 - jc = JA(i) - c2 = DSCALE2(jc) - AMAT(i) = c1*AMAT(i)*c2 - END DO - END DO - ! - ! -- L-2 NORM SCALING - CASE (2) - ! - ! -- SCALE EACH ROW SO THAT THE L-2 NORM IS 1 - DO n = 1, NEQ - c1 = DZERO - i0 = IA(n) - i1 = IA(n + 1) - 1 - DO i = i0, i1 - c1 = c1 + AMAT(i)*AMAT(i) - END DO - c1 = SQRT(c1) - IF (c1 == DZERO) THEN - c1 = DONE - ELSE - c1 = DONE/c1 - END IF - DSCALE(n) = c1 - ! - ! -- INITIAL SCALING OF AMAT -- AMAT = DSCALE(row) * AMAT(i) - DO i = i0, i1 - AMAT(i) = c1*AMAT(i) - END DO - END DO - ! - ! -- SCALE EACH COLUMN SO THAT THE L-2 NORM IS 1 - DO n = 1, NEQ - DSCALE2(n) = DZERO - END DO - c2 = DZERO - DO n = 1, NEQ - i0 = IA(n) - i1 = IA(n + 1) - 1 - DO i = i0, i1 - jc = JA(i) - c2 = AMAT(i) - DSCALE2(jc) = DSCALE2(jc) + c2*c2 - END DO - END DO - DO n = 1, NEQ - c2 = DSCALE2(n) - IF (c2 == DZERO) THEN - c2 = DONE - ELSE - c2 = DONE/SQRT(c2) - END IF - DSCALE2(n) = c2 - END DO - ! - ! -- FINAL SCALING OF AMAT -- AMAT = DSCALE2(col) * AMAT(i) - DO n = 1, NEQ - i0 = IA(n) - i1 = IA(n + 1) - 1 - DO i = i0, i1 - jc = JA(i) - c2 = DSCALE2(jc) - AMAT(i) = c2*AMAT(i) - END DO - END DO - END SELECT - ! - ! -- SCALE X AND B - DO n = 1, NEQ - c1 = DSCALE(n) - c2 = DSCALE2(n) - X(n) = X(n)/c2 - B(n) = B(n)*c1 - END DO - ! - ! -- UNSCALE SCALE AMAT, X, AND B - ELSE - DO n = 1, NEQ - c1 = DSCALE(n) - i0 = IA(n) - i1 = IA(n + 1) - 1 - ! - ! -- UNSCALE AMAT - DO i = i0, i1 - jc = JA(i) - c2 = DSCALE2(jc) - AMAT(i) = (DONE/c1)*AMAT(i)*(DONE/c2) - END DO - ! - ! -- UNSCALE X AND B - c2 = DSCALE2(n) - X(n) = X(n)*c2 - B(n) = B(n)/c1 - END DO - END IF - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_scale - - !> @ brief Update the preconditioner - !! - !! Update the preconditioner using the current coefficient matrix. - !! - !< - SUBROUTINE ims_base_pcu(IOUT, NJA, NEQ, NIAPC, NJAPC, IPC, RELAX, & - AMAT, IA, JA, APC, IAPC, JAPC, IW, W, & - LEVEL, DROPTOL, NJLU, NJW, NWLU, JLU, JW, WLU) - ! -- modules - use SimModule, only: store_error, count_errors - ! -- dummy variables - integer(I4B), INTENT(IN) :: IOUT !< simulation listing file unit - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NEQ !< number of equations - integer(I4B), INTENT(IN) :: NIAPC !< preconditioner number of rows - integer(I4B), INTENT(IN) :: NJAPC !< preconditioner number of non-zero entries - integer(I4B), INTENT(IN) :: IPC !< precoditioner (1) ILU0 (2) MILU0 (3) ILUT (4) MILUT - real(DP), INTENT(IN) :: RELAX !< preconditioner relaxation factor for MILU0 and MILUT - real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers - real(DP), DIMENSION(NJAPC), INTENT(INOUT) :: APC !< preconditioner matrix - integer(I4B), DIMENSION(NIAPC + 1), INTENT(INOUT) :: IAPC !< preconditioner CRS row pointers - integer(I4B), DIMENSION(NJAPC), INTENT(INOUT) :: JAPC !< preconditioner CRS column pointers - integer(I4B), DIMENSION(NIAPC), INTENT(INOUT) :: IW !< preconditioner integed work vector - real(DP), DIMENSION(NIAPC), INTENT(INOUT) :: W !< preconditioner work verctor - ! -- ILUT dummy variables - integer(I4B), INTENT(IN) :: LEVEL !< number of levels of fill for ILUT and MILUT - real(DP), INTENT(IN) :: DROPTOL !< drop tolerance - integer(I4B), INTENT(IN) :: NJLU !< length of JLU working vector - integer(I4B), INTENT(IN) :: NJW !< length of JW working vector - integer(I4B), INTENT(IN) :: NWLU !< length of WLU working vector - integer(I4B), DIMENSION(NJLU), INTENT(INOUT) :: JLU !< ILUT/MILUT JLU working vector - integer(I4B), DIMENSION(NJW), INTENT(INOUT) :: JW !< ILUT/MILUT JW working vector - real(DP), DIMENSION(NWLU), INTENT(INOUT) :: WLU !< ILUT/MILUT WLU working vector - ! -- local variables - character(len=LINELENGTH) :: errmsg - character(len=100), dimension(5), parameter :: cerr = & - ["Elimination process has generated a row in L or U whose length is > n.", & - "The matrix L overflows the array al. ", & - "The matrix U overflows the array alu. ", & - "Illegal value for lfil. ", & - "Zero row encountered. "] - integer(I4B) :: ipcflag - integer(I4B) :: icount - integer(I4B) :: ierr - real(DP) :: delta - ! -- formats -2000 FORMAT(/, ' MATRIX IS SEVERELY NON-DIAGONALLY DOMINANT.', & - /, ' ADDED SMALL VALUE TO PIVOT ', i0, ' TIMES IN', & - ' IMSLINEARSUB_PCU.') - ! - ! -- initialize local variables - ipcflag = 0 - icount = 0 - delta = DZERO - PCSCALE: DO - SELECT CASE (IPC) - ! - ! -- ILU0 AND MILU0 - CASE (1, 2) - CALL ims_base_pcilu0(NJA, NEQ, AMAT, IA, JA, & - APC, IAPC, JAPC, IW, W, & - RELAX, ipcflag, delta) - ! - ! -- ILUT AND MILUT - CASE (3, 4) - ierr = 0 - CALL ilut(NEQ, AMAT, JA, IA, LEVEL, DROPTOL, & - APC, JLU, IW, NJAPC, WLU, JW, ierr, & - relax, ipcflag, delta) - if (ierr /= 0) then - if (ierr > 0) then - write (errmsg, '(a,1x,i0,1x,a)') & - 'ILUT: zero pivot encountered at step number', ierr, '.' - else - write (errmsg, '(a,1x,a)') 'ILUT:', cerr(-ierr) - end if - call store_error(errmsg) - call parser%StoreErrorUnit() - end if - ! - ! -- ADDITIONAL PRECONDITIONERS - CASE DEFAULT - ipcflag = 0 - END SELECT - IF (ipcflag < 1) THEN - EXIT PCSCALE - END IF - delta = 1.5d0*delta + DEM3 - ipcflag = 0 - IF (delta > DHALF) THEN - delta = DHALF - ipcflag = 2 - END IF - icount = icount + 1 - ! - ! -- terminate pcscale loop if not making progress - if (icount > 10) then - exit PCSCALE - end if - - END DO PCSCALE - ! - ! -- write error message if small value added to pivot - if (icount > 0) then - write (IOUT, 2000) icount - end if - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_pcu - - !> @ brief Jacobi preconditioner - !! - !! Calculate the Jacobi preconditioner (inverse of the diagonal) using - !! the current coefficient matrix. - !! - !< - SUBROUTINE ims_base_pcjac(NJA, NEQ, AMAT, APC, IA, JA) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NEQ !< number of equations - real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: APC !< preconditioner matrix - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers - ! -- local variables - integer(I4B) :: i, n - integer(I4B) :: ic0, ic1 - integer(I4B) :: id - real(DP) :: tv - ! -- code - DO n = 1, NEQ - ic0 = IA(n) - ic1 = IA(n + 1) - 1 - id = IA(n) - DO i = ic0, ic1 - IF (JA(i) == n) THEN - id = i - EXIT - END IF - END DO - tv = AMAT(id) - IF (ABS(tv) > DZERO) tv = DONE/tv - APC(n) = tv - END DO - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_pcjac - - !> @ brief Apply the Jacobi preconditioner - !! - !! Apply the Jacobi preconditioner and return the resultant vector. - !! - !< - SUBROUTINE ims_base_jaca(NEQ, A, D1, D2) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NEQ !< number of equations - real(DP), DIMENSION(NEQ), INTENT(IN) :: A !< Jacobi preconditioner - real(DP), DIMENSION(NEQ), INTENT(IN) :: D1 !< input vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D2 !< resultant vector - ! -- local variables - integer(I4B) :: n - real(DP) :: tv - ! -- code - DO n = 1, NEQ - tv = A(n)*D1(n) - D2(n) = tv - END DO - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_jaca - - !> @ brief Update the ILU0 preconditioner - !! - !! Update the ILU0 preconditioner using the current coefficient matrix. - !! - !< - SUBROUTINE ims_base_pcilu0(NJA, NEQ, AMAT, IA, JA, & - APC, IAPC, JAPC, IW, W, & - RELAX, IPCFLAG, DELTA) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NEQ !< number of equations - real(DP), DIMENSION(NJA), INTENT(IN) :: AMAT !< coefficient matrix - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers - real(DP), DIMENSION(NJA), INTENT(INOUT) :: APC !< preconditioned matrix - integer(I4B), DIMENSION(NEQ + 1), INTENT(INOUT) :: IAPC !< preconditioner CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(INOUT) :: JAPC !< preconditioner CRS column pointers - integer(I4B), DIMENSION(NEQ), INTENT(INOUT) :: IW !< preconditioner integer work vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: W !< preconditioner work vector - real(DP), INTENT(IN) :: RELAX !< MILU0 preconditioner relaxation factor - integer(I4B), INTENT(INOUT) :: IPCFLAG !< preconditioner error flag - real(DP), INTENT(IN) :: DELTA !< factor used to correct non-diagonally dominant matrices - ! -- local variables - integer(I4B) :: ic0, ic1 - integer(I4B) :: iic0, iic1 - integer(I4B) :: iu, iiu - integer(I4B) :: j, n - integer(I4B) :: jj - integer(I4B) :: jcol, jw - integer(I4B) :: jjcol - real(DP) :: drelax - real(DP) :: sd1 - real(DP) :: tl - real(DP) :: rs - real(DP) :: d - ! - ! -- initialize local variables - drelax = RELAX - DO n = 1, NEQ - IW(n) = 0 - W(n) = DZERO - END DO - MAIN: DO n = 1, NEQ - ic0 = IA(n) - ic1 = IA(n + 1) - 1 - DO j = ic0, ic1 - jcol = JA(j) - IW(jcol) = 1 - W(jcol) = W(jcol) + AMAT(j) - END DO - ic0 = IAPC(n) - ic1 = IAPC(n + 1) - 1 - iu = JAPC(n) - rs = DZERO - LOWER: DO j = ic0, iu - 1 - jcol = JAPC(j) - iic0 = IAPC(jcol) - iic1 = IAPC(jcol + 1) - 1 - iiu = JAPC(jcol) - tl = W(jcol)*APC(jcol) - W(jcol) = tl - DO jj = iiu, iic1 - jjcol = JAPC(jj) - jw = IW(jjcol) - IF (jw .NE. 0) THEN - W(jjcol) = W(jjcol) - tl*APC(jj) - ELSE - rs = rs + tl*APC(jj) - END IF - END DO - END DO LOWER - ! - ! -- DIAGONAL - CALCULATE INVERSE OF DIAGONAL FOR SOLUTION - d = W(n) - tl = (DONE + DELTA)*d - (drelax*rs) - ! - ! -- ENSURE THAT THE SIGN OF THE DIAGONAL HAS NOT CHANGED AND IS - sd1 = SIGN(d, tl) - IF (sd1 .NE. d) THEN - ! - ! -- USE SMALL VALUE IF DIAGONAL SCALING IS NOT EFFECTIVE FOR - ! PIVOTS THAT CHANGE THE SIGN OF THE DIAGONAL - IF (IPCFLAG > 1) THEN - tl = SIGN(DEM6, d) - ! - ! -- DIAGONAL SCALING CONTINUES TO BE EFFECTIVE - ELSE - IPCFLAG = 1 - EXIT MAIN - END IF - END IF - IF (ABS(tl) == DZERO) THEN - ! - ! -- USE SMALL VALUE IF DIAGONAL SCALING IS NOT EFFECTIVE FOR - ! ZERO PIVOTS - IF (IPCFLAG > 1) THEN - tl = SIGN(DEM6, d) - ! - ! -- DIAGONAL SCALING CONTINUES TO BE EFFECTIVE FOR ELIMINATING - ELSE - IPCFLAG = 1 - EXIT MAIN - END IF - END IF - APC(n) = DONE/tl - ! - ! -- RESET POINTER FOR IW TO ZERO - IW(n) = 0 - W(n) = DZERO - DO j = ic0, ic1 - jcol = JAPC(j) - APC(j) = W(jcol) - IW(jcol) = 0 - W(jcol) = DZERO - END DO - END DO MAIN - ! - ! -- RESET IPCFLAG IF SUCCESSFUL COMPLETION OF MAIN - IPCFLAG = 0 - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_pcilu0 - - !> @ brief Apply the ILU0 and MILU0 preconditioners - !! - !! Apply the ILU0 and MILU0 preconditioners to the passed vector (R). - !! - !< - SUBROUTINE ims_base_ilu0a(NJA, NEQ, APC, IAPC, JAPC, R, D) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NJA !< number of non-zero entries - integer(I4B), INTENT(IN) :: NEQ !< number of equations - real(DP), DIMENSION(NJA), INTENT(IN) :: APC !< ILU0/MILU0 preconditioner matrix - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IAPC !< ILU0/MILU0 preconditioner CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JAPC !< ILU0/MILU0 preconditioner CRS column pointers - real(DP), DIMENSION(NEQ), INTENT(IN) :: R !< input vector - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< output vector after applying APC to R - ! -- local variables - integer(I4B) :: ic0, ic1 - integer(I4B) :: iu - integer(I4B) :: jcol - integer(I4B) :: j, n - real(DP) :: tv - ! - ! -- FORWARD SOLVE - APC * D = R - FORWARD: DO n = 1, NEQ - tv = R(n) - ic0 = IAPC(n) - ic1 = IAPC(n + 1) - 1 - iu = JAPC(n) - 1 - LOWER: DO j = ic0, iu - jcol = JAPC(j) - tv = tv - APC(j)*D(jcol) - END DO LOWER - D(n) = tv - END DO FORWARD - ! - ! -- BACKWARD SOLVE - D = D / U - BACKWARD: DO n = NEQ, 1, -1 - ic0 = IAPC(n) - ic1 = IAPC(n + 1) - 1 - iu = JAPC(n) - tv = D(n) - UPPER: DO j = iu, ic1 - jcol = JAPC(j) - tv = tv - APC(j)*D(jcol) - END DO UPPER - ! - ! -- COMPUTE D FOR DIAGONAL - D = D / U - D(n) = tv*APC(n) - END DO BACKWARD - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_ilu0a - - !> @ brief Test for solver convergence - !! - !! General routine for testing for solver convergence based on the - !! user-specified convergence option (Icnvgopt). - !< - ! - ! -- TEST FOR SOLVER CONVERGENCE - SUBROUTINE ims_base_testcnvg(Icnvgopt, Icnvg, Iiter, & - Dvmax, Rmax, & - Rmax0, Epfact, Dvclose, Rclose) - ! -- dummy variables - integer(I4B), INTENT(IN) :: Icnvgopt !< convergence option - see documentation for option - integer(I4B), INTENT(INOUT) :: Icnvg !< flag indicating if convergence achieved (1) or not (0) - integer(I4B), INTENT(IN) :: Iiter !< inner iteration number (used for strict convergence option) - real(DP), INTENT(IN) :: Dvmax !< maximum dependent-variable change - real(DP), INTENT(IN) :: Rmax !< maximum flow change - real(DP), INTENT(IN) :: Rmax0 !< initial flow change (initial L2-norm) - real(DP), INTENT(IN) :: Epfact !< factor for reducing convergence criteria in subsequent Picard iterations - real(DP), INTENT(IN) :: Dvclose !< Maximum depenendent-variable change allowed - real(DP), INTENT(IN) :: Rclose !< Maximum flow change alowed - ! -- code - IF (Icnvgopt == 0) THEN - IF (ABS(Dvmax) <= Dvclose .AND. ABS(Rmax) <= Rclose) THEN - Icnvg = 1 - END IF - ELSE IF (Icnvgopt == 1) THEN - IF (ABS(Dvmax) <= Dvclose .AND. ABS(Rmax) <= Rclose) THEN - IF (iiter == 1) THEN - Icnvg = 1 - ELSE - Icnvg = -1 - END IF - END IF - ELSE IF (Icnvgopt == 2) THEN - IF (ABS(Dvmax) <= Dvclose .OR. Rmax <= Rclose) THEN - Icnvg = 1 - ELSE IF (Rmax <= Rmax0*Epfact) THEN - Icnvg = -1 - END IF - ELSE IF (Icnvgopt == 3) THEN - IF (ABS(Dvmax) <= Dvclose) THEN - Icnvg = 1 - ELSE IF (Rmax <= Rmax0*Rclose) THEN - Icnvg = -1 - END IF - ELSE IF (Icnvgopt == 4) THEN - IF (ABS(Dvmax) <= Dvclose .AND. Rmax <= Rclose) THEN - Icnvg = 1 - ELSE IF (Rmax <= Rmax0*Epfact) THEN - Icnvg = -1 - END IF - END IF - ! - ! -- return - RETURN - END SUBROUTINE ims_base_testcnvg - - !> @ brief Generate CRS pointers for the preconditioner - !! - !! Generate the CRS row and column pointers for the preconditioner. - !! JAPC(1:NEQ) hHas the position of the upper entry for a row, - !! JAPC(NEQ+1:NJA) is the column position for entry, - !! APC(1:NEQ) is the preconditioned inverse of the diagonal, and - !! APC(NEQ+1:NJA) are the preconditioned entries for off diagonals. - !< - SUBROUTINE ims_base_pccrs(NEQ, NJA, IA, JA, & - IAPC, JAPC) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NEQ !< - integer(I4B), INTENT(IN) :: NJA !< - integer(I4B), DIMENSION(NEQ + 1), INTENT(IN) :: IA !< - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< - integer(I4B), DIMENSION(NEQ + 1), INTENT(INOUT) :: IAPC !< - integer(I4B), DIMENSION(NJA), INTENT(INOUT) :: JAPC !< - ! -- local variables - integer(I4B) :: n, j - integer(I4B) :: i0, i1 - integer(I4B) :: nlen - integer(I4B) :: ic, ip - integer(I4B) :: jcol - integer(I4B), DIMENSION(:), ALLOCATABLE :: iarr - ! -- code - ip = NEQ + 1 - DO n = 1, NEQ - i0 = IA(n) - i1 = IA(n + 1) - 1 - nlen = i1 - i0 - ALLOCATE (iarr(nlen)) - ic = 0 - DO j = i0, i1 - jcol = JA(j) - IF (jcol == n) CYCLE - ic = ic + 1 - iarr(ic) = jcol - END DO - CALL ims_base_isort(nlen, iarr) - IAPC(n) = ip - DO j = 1, nlen - jcol = iarr(j) - JAPC(ip) = jcol - ip = ip + 1 - END DO - DEALLOCATE (iarr) - END DO - IAPC(NEQ + 1) = NJA + 1 - ! - ! -- POSITION OF THE FIRST UPPER ENTRY FOR ROW - DO n = 1, NEQ - i0 = IAPC(n) - i1 = IAPC(n + 1) - 1 - JAPC(n) = IAPC(n + 1) - DO j = i0, i1 - jcol = JAPC(j) - IF (jcol > n) THEN - JAPC(n) = j - EXIT - END IF - END DO - END DO - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_pccrs - - !> @brief In-place sorting for an integer array - !! - !! Subroutine sort an integer array in-place. - !! - !< - SUBROUTINE ims_base_isort(NVAL, IARRAY) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NVAL !< length of the interger array - integer(I4B), DIMENSION(NVAL), INTENT(INOUT) :: IARRAY !< integer array to be sorted - ! -- local variables - integer(I4B) :: i, j, itemp - ! -- code - DO i = 1, NVAL - 1 - DO j = i + 1, NVAL - if (IARRAY(i) > IARRAY(j)) then - itemp = IARRAY(j) - IARRAY(j) = IARRAY(i) - IARRAY(i) = itemp - END IF - END DO - END DO - ! - ! -- RETURN - RETURN - END SUBROUTINE ims_base_isort - - !> @brief Calculate residual - !! - !! Subroutine to calculate the residual. - !! - !< - SUBROUTINE ims_base_residual(NEQ, NJA, X, B, D, A, IA, JA) - ! -- dummy variables - integer(I4B), INTENT(IN) :: NEQ !< length of vectors - integer(I4B), INTENT(IN) :: NJA !< length of coefficient matrix - real(DP), DIMENSION(NEQ), INTENT(IN) :: X !< dependent variable - real(DP), DIMENSION(NEQ), INTENT(IN) :: B !< right-hand side - real(DP), DIMENSION(NEQ), INTENT(INOUT) :: D !< residual - real(DP), DIMENSION(NJA), INTENT(IN) :: A !< coefficient matrix - integer(I4B), DIMENSION(NEQ+1), INTENT(IN) :: IA !< CRS row pointers - integer(I4B), DIMENSION(NJA), INTENT(IN) :: JA !< CRS column pointers - ! -- local variables - integer(I4B) :: n - ! -- code - ! - ! -- calculate matrix-vector product - call amux(NEQ, X, D, A, JA, IA) - ! - ! -- subtract matrix-vector product from right-hand side - DO n = 1, NEQ - D(n) = B(n) - D(n) - END DO - ! - ! -- return - RETURN - END SUBROUTINE ims_base_residual - - END MODULE IMSLinearBaseModule diff --git a/src/Solution/SparseMatrixSolver/ims8linear.f90 b/src/Solution/SparseMatrixSolver/ims8linear.f90 deleted file mode 100644 index b30bebdcdaa..00000000000 --- a/src/Solution/SparseMatrixSolver/ims8linear.f90 +++ /dev/null @@ -1,1017 +0,0 @@ -MODULE IMSLinearModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH, LENSOLUTIONNAME, LENMEMPATH, & - IZERO, DZERO, DPREC, DSAME, & - DEM8, DEM6, DEM5, DEM4, DEM3, DEM2, DEM1, & - DHALF, DONE, DTWO, & - VDEBUG - use GenericUtilitiesModule, only: sim_message - use IMSLinearBaseModule, only: ims_base_cg, ims_base_bcgs, & - ims_base_pccrs, ims_base_calc_order, & - ims_base_scale, ims_base_pcu, & - ims_base_residual - use BlockParserModule, only: BlockParserType - - IMPLICIT NONE - private - - TYPE, PUBLIC :: ImsLinearDataType - character(len=LENMEMPATH) :: memoryPath !< the path for storing variables in the memory manager - integer(I4B), POINTER :: iout => NULL() !< simulation listing file unit - integer(I4B), POINTER :: IPRIMS => NULL() !< print flag - integer(I4B), POINTER :: ILINMETH => NULL() !< linear accelerator (1) cg, (2) bicgstab - integer(I4B), POINTER :: ITER1 => NULL() !< maximum inner iterations - integer(I4B), POINTER :: IPC => NULL() !< preconditioner flag - integer(I4B), POINTER :: ISCL => NULL() !< scaling flag - integer(I4B), POINTER :: IORD => NULL() !< reordering flag - integer(I4B), POINTER :: NORTH => NULL() !< orthogonalization interval - integer(I4B), POINTER :: ICNVGOPT => NULL() !< rclose convergence option flag - integer(I4B), POINTER :: IACPC => NULL() !< preconditioner CRS row pointers - integer(I4B), POINTER :: NITERC => NULL() !< - integer(I4B), POINTER :: NIABCGS => NULL() !< size of working vectors for BCGS linear accelerator - integer(I4B), POINTER :: NIAPC => NULL() !< preconditioner number of rows - integer(I4B), POINTER :: NJAPC => NULL() !< preconditioner number of non-zero entries - real(DP), POINTER :: DVCLOSE => NULL() !< dependent variable convergence criteria - real(DP), POINTER :: RCLOSE => NULL() !< flow convergence criteria - real(DP), POINTER :: RELAX => NULL() !< preconditioner MILU0/MILUT relaxation factor - real(DP), POINTER :: EPFACT => NULL() !< factor for decreasing convergence criteria in seubsequent Picard iterations - real(DP), POINTER :: L2NORM0 => NULL() !< initial L2 norm - ! -- ilut variables - integer(I4B), POINTER :: LEVEL => NULL() !< preconditioner number of levels - real(DP), POINTER :: DROPTOL => NULL() !< preconditioner drop tolerance - integer(I4B), POINTER :: NJLU => NULL() !< length of jlu work vector - integer(I4B), POINTER :: NJW => NULL() !< length of jw work vector - integer(I4B), POINTER :: NWLU => NULL() !< length of wlu work vector - ! -- pointers to solution variables - integer(I4B), POINTER :: NEQ => NULL() !< number of equations (rows in matrix) - integer(I4B), POINTER :: NJA => NULL() !< number of non-zero values in amat - integer(I4B), dimension(:), pointer, contiguous :: IA => NULL() !< position of start of each row - integer(I4B), dimension(:), pointer, contiguous :: JA => NULL() !< column pointer - real(DP), dimension(:), pointer, contiguous :: AMAT => NULL() !< coefficient matrix - real(DP), dimension(:), pointer, contiguous :: RHS => NULL() !< right-hand side of equation - real(DP), dimension(:), pointer, contiguous :: X => NULL() !< dependent variable - ! VECTORS - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DSCALE => NULL() !< scaling factor - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DSCALE2 => NULL() !< unscaling factor - integer(I4B), POINTER,DIMENSION(:),CONTIGUOUS :: IAPC => NULL() !< position of start of each row in preconditioner matrix - integer(I4B), POINTER,DIMENSION(:),CONTIGUOUS :: JAPC => NULL() !< preconditioner matrix column pointer - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: APC => NULL() !< preconditioner coefficient matrix - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: LORDER => NULL() !< reordering mapping - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IORDER => NULL() !< mapping to restore reordered matrix - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IARO => NULL() !< position of start of each row in reordered matrix - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JARO => NULL() !< reordered matrix column pointer - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: ARO => NULL() !< reordered coefficient matrix - ! WORKING ARRAYS - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IW => NULL() !< integer working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: W => NULL() !< real working array - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: ID => NULL() !< integer working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: D => NULL() !< real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: P => NULL() !< real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: Q => NULL() !< real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: Z => NULL() !< real working array - ! BICGSTAB WORKING ARRAYS - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: T => NULL() !< BICGSTAB real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: V => NULL() !< BICGSTAB real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: DHAT => NULL() !< BICGSTAB real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: PHAT => NULL() !< BICGSTAB real working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: QHAT => NULL() !< rBICGSTAB eal working array - ! POINTERS FOR USE WITH BOTH ORIGINAL AND RCM ORDERINGS - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: IA0 => NULL() !< pointer to current CRS row pointers - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JA0 => NULL() !< pointer to current CRS column pointers - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: A0 => NULL() !< pointer to current coefficient matrix - ! ILUT WORKING ARRAYS - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JLU => NULL() !< ilut integer working array - integer(I4B), POINTER, DIMENSION(:), CONTIGUOUS :: JW => NULL() !< ilut integer working array - real(DP), POINTER, DIMENSION(:), CONTIGUOUS :: WLU => NULL() !< ilut real working array - - ! PROCEDURES (METHODS) - CONTAINS - PROCEDURE :: IMSLINEAR_ALLOCATE => imslinear_ar - procedure :: imslinear_summary - PROCEDURE :: IMSLINEAR_APPLY => imslinear_ap - procedure :: IMSLINEAR_DA => imslinear_da - procedure, private :: allocate_scalars - ! -- PRIVATE PROCEDURES - PROCEDURE, PRIVATE :: SET_IMSLINEAR_INPUT => imslinear_set_input - END TYPE ImsLinearDataType - - - CONTAINS - - !> @ brief Allocate storage and read data - !! - !! Allocate storage for linear accelerators and read data - !! - !< - SUBROUTINE imslinear_ar(this, NAME, parser, IOUT, IPRIMS, MXITER, IFDPARAM, & - IMSLINEARM, NEQ, NJA, IA, JA, AMAT, RHS, X, & - NINNER, LFINDBLOCK) - ! -- modules - use MemoryManagerModule, only: mem_allocate - use MemoryHelperModule, only: create_mem_path - use SimModule, only: store_error, count_errors, & - deprecation_warning - ! -- dummy variables - CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance - CHARACTER (LEN=LENSOLUTIONNAME), INTENT(IN) :: NAME !< solution name - type(BlockParserType) :: parser !< block parser - integer(I4B), INTENT(IN) :: IOUT !< simulation listing file unit - integer(I4B), TARGET, INTENT(IN) :: IPRIMS !< print option - integer(I4B), INTENT(IN) :: MXITER !< maximum outer iterations - integer(I4B), INTENT(IN) :: IFDPARAM !< complexity option - integer(I4B), INTENT(INOUT) :: IMSLINEARM !< linear method option (1) CG (2) BICGSTAB - integer(I4B), TARGET, INTENT(IN) :: NEQ !< number of equations - integer(I4B), TARGET, INTENT(IN) :: NJA !< number of non-zero entries in the coefficient matrix - integer(I4B), DIMENSION(NEQ+1), TARGET, INTENT(IN) :: IA !< pointer to the start of a row in the coefficient matrix - integer(I4B), DIMENSION(NJA), TARGET, INTENT(IN) :: JA !< column pointer - real(DP), DIMENSION(NJA), TARGET, INTENT(IN) :: AMAT !< coefficient matrix - real(DP), DIMENSION(NEQ), TARGET, INTENT(INOUT) :: RHS !< right-hand side - real(DP), DIMENSION(NEQ), TARGET, INTENT(INOUT) :: X !< dependent variables - integer(I4B), TARGET, INTENT(INOUT) :: NINNER !< maximum number of inner iterations - integer(I4B), INTENT(IN), OPTIONAL :: LFINDBLOCK !< flag indicating if the linear block is present (1) or missing (0) - - ! -- local variables - LOGICAL :: lreaddata - character(len=LINELENGTH) :: errmsg - character(len=LINELENGTH) :: warnmsg - character(len=LINELENGTH) :: keyword - integer(I4B) :: i, n - integer(I4B) :: i0 - integer(I4B) :: iscllen, iolen - integer(I4B) :: ierr - real(DP) :: r - logical :: isfound, endOfBlock - integer(I4B) :: ijlu - integer(I4B) :: ijw - integer(I4B) :: iwlu - integer(I4B) :: iwk - ! - ! -- SET LREADDATA - IF (PRESENT(LFINDBLOCK)) THEN - IF (LFINDBLOCK < 1) THEN - lreaddata = .FALSE. - ELSE - lreaddata = .TRUE. - END IF - ELSE - lreaddata = .TRUE. - END IF - ! - ! -- DEFINE NAME - this%memoryPath = create_mem_path(name, 'IMSLinear') - ! - ! -- SET POINTERS TO SOLUTION STORAGE - this%IPRIMS => IPRIMS - this%NEQ => NEQ - this%NJA => NJA - this%IA => IA - this%JA => JA - this%AMAT => AMAT - this%RHS => RHS - this%X => X - ! - ! -- ALLOCATE SCALAR VARIABLES - call this%allocate_scalars() - ! - ! -- initialize iout - this%iout = iout - ! - ! -- DEFAULT VALUES - this%IORD = 0 - this%ISCL = 0 - this%IPC = 0 - this%LEVEL = 0 - ! - ! -- TRANSFER COMMON VARIABLES FROM IMS TO IMSLINEAR - this%ILINMETH = 0 - - this%IACPC = 0 - this%RELAX = DZERO !0.97 - - this%DROPTOL = DZERO - - this%NORTH = 0 - - this%ICNVGOPT = 0 - ! - ! -- PRINT A MESSAGE IDENTIFYING IMSLINEAR SOLVER PACKAGE - write(iout,2000) -02000 FORMAT (1X,/1X,'IMSLINEAR -- UNSTRUCTURED LINEAR SOLUTION', & - & ' PACKAGE, VERSION 8, 04/28/2017') - ! - ! -- SET DEFAULT IMSLINEAR PARAMETERS - CALL this%SET_IMSLINEAR_INPUT(IFDPARAM) - NINNER = this%iter1 - ! - ! -- get IMSLINEAR block - if (lreaddata) then - call parser%GetBlock('LINEAR', isfound, ierr, & - supportOpenClose=.true., blockRequired=.FALSE.) - else - isfound = .FALSE. - end if - ! - ! -- parse IMSLINEAR block if detected - if (isfound) then - write(iout,'(/1x,a)')'PROCESSING LINEAR DATA' - do - call parser%GetNextLine(endOfBlock) - if (endOfBlock) exit - call parser%GetStringCaps(keyword) - ! -- parse keyword - select case (keyword) - case ('INNER_DVCLOSE') - this%DVCLOSE = parser%GetDouble() - case ('INNER_RCLOSE') - this%rclose = parser%GetDouble() - ! -- look for additional key words - call parser%GetStringCaps(keyword) - if (keyword == 'STRICT') then - this%ICNVGOPT = 1 - else if (keyword == 'L2NORM_RCLOSE') then - this%ICNVGOPT = 2 - else if (keyword == 'RELATIVE_RCLOSE') then - this%ICNVGOPT = 3 - else if (keyword == 'L2NORM_RELATIVE_RCLOSE') then - this%ICNVGOPT = 4 - end if - case ('INNER_MAXIMUM') - i = parser%GetInteger() - this%iter1 = i - NINNER = i - case ('LINEAR_ACCELERATION') - call parser%GetStringCaps(keyword) - if (keyword.eq.'CG') then - this%ILINMETH = 1 - else if (keyword.eq.'BICGSTAB') then - this%ILINMETH = 2 - else - this%ILINMETH = 0 - write(errmsg,'(3a)') & - 'UNKNOWN IMSLINEAR LINEAR_ACCELERATION METHOD (', & - trim(keyword), ').' - call store_error(errmsg) - end if - case ('SCALING_METHOD') - call parser%GetStringCaps(keyword) - i = 0 - if (keyword.eq.'NONE') then - i = 0 - else if (keyword.eq.'DIAGONAL') then - i = 1 - else if (keyword.eq.'L2NORM') then - i = 2 - else - write(errmsg,'(3a)') & - 'UNKNOWN IMSLINEAR SCALING_METHOD (', trim(keyword), ').' - call store_error(errmsg) - end if - this%ISCL = i - case ('RED_BLACK_ORDERING') - i = 0 - case ('REORDERING_METHOD') - call parser%GetStringCaps(keyword) - i = 0 - if (keyword == 'NONE') then - i = 0 - else if (keyword == 'RCM') then - i = 1 - else if (keyword == 'MD') then - i = 2 - else - write(errmsg,'(3a)') & - 'UNKNOWN IMSLINEAR REORDERING_METHOD (', trim(keyword), ').' - call store_error(errmsg) - end if - this%IORD = i - case ('NUMBER_ORTHOGONALIZATIONS') - this%north = parser%GetInteger() - case ('RELAXATION_FACTOR') - this%relax = parser%GetDouble() - case ('PRECONDITIONER_LEVELS') - i = parser%GetInteger() - this%level = i - if (i < 0) then - write(errmsg,'(a,1x,a)') & - 'IMSLINEAR PRECONDITIONER_LEVELS MUST BE GREATER THAN', & - 'OR EQUAL TO ZERO' - call store_error(errmsg) - end if - case ('PRECONDITIONER_DROP_TOLERANCE') - r = parser%GetDouble() - this%DROPTOL = r - if (r < DZERO) then - write(errmsg,'(a,1x,a)') & - 'IMSLINEAR PRECONDITIONER_DROP_TOLERANCE', & - 'MUST BE GREATER THAN OR EQUAL TO ZERO' - call store_error(errmsg) - end if - ! - ! -- deprecated variables - case ('INNER_HCLOSE') - this%DVCLOSE = parser%GetDouble() - ! - ! -- create warning message - write(warnmsg,'(a)') & - 'SETTING INNER_DVCLOSE TO INNER_HCLOSE VALUE' - ! - ! -- create deprecation warning - call deprecation_warning('LINEAR', 'INNER_HCLOSE', '6.1.1', & - warnmsg, parser%GetUnit()) - ! - ! -- default - case default - write(errmsg,'(3a)') & - 'UNKNOWN IMSLINEAR KEYWORD (', trim(keyword), ').' - call store_error(errmsg) - end select - end do - write(iout,'(1x,a)') 'END OF LINEAR DATA' - else - if (IFDPARAM == 0) THEN - write(errmsg,'(a)') 'NO LINEAR BLOCK DETECTED.' - call store_error(errmsg) - end if - end if - - IMSLINEARM = this%ILINMETH - ! - ! -- DETERMINE PRECONDITIONER - IF (this%LEVEL > 0 .OR. this%DROPTOL > DZERO) THEN - this%IPC = 3 - ELSE - this%IPC = 1 - END IF - IF (this%RELAX > DZERO) THEN - this%IPC = this%IPC + 1 - END IF - ! - ! -- ERROR CHECKING FOR OPTIONS - IF (this%ISCL < 0 ) this%ISCL = 0 - IF (this%ISCL > 2 ) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR ISCL MUST BE <= 2' - call store_error(errmsg) - END IF - IF (this%IORD < 0 ) this%IORD = 0 - IF (this%IORD > 2) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR IORD MUST BE <= 2' - call store_error(errmsg) - END IF - IF (this%NORTH < 0) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR NORTH MUST >= 0' - call store_error(errmsg) - END IF - IF (this%RCLOSE == DZERO) THEN - IF (this%ICNVGOPT /= 3) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR RCLOSE MUST > 0.0' - call store_error(errmsg) - END IF - END IF - IF (this%RELAX < DZERO) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR RELAX MUST BE >= 0.0' - call store_error(errmsg) - END IF - IF (this%RELAX > DONE) THEN - WRITE(errmsg,'(A)') 'IMSLINEAR7AR RELAX MUST BE <= 1.0' - call store_error(errmsg) - END IF - ! - ! -- CHECK FOR ERRORS IN IMSLINEAR - if (count_errors() > 0) then - call parser%StoreErrorUnit() - endif - ! - ! -- INITIALIZE IMSLINEAR VARIABLES - this%NITERC = 0 - ! - ! -- ALLOCATE AND INITIALIZE MEMORY FOR IMSLINEAR - iscllen = 1 - IF (this%ISCL.NE.0 ) iscllen = NEQ - CALL mem_allocate(this%DSCALE, iscllen, 'DSCALE', TRIM(this%memoryPath)) - CALL mem_allocate(this%DSCALE2, iscllen, 'DSCALE2', TRIM(this%memoryPath)) - ! - ! -- ALLOCATE MEMORY FOR PRECONDITIONING MATRIX - ijlu = 1 - ijw = 1 - iwlu = 1 - ! - ! -- ILU0 AND MILU0 - this%NIAPC = this%NEQ - this%NJAPC = this%NJA - ! - ! -- ILUT AND MILUT - IF (this%IPC == 3 .OR. this%IPC == 4) THEN - this%NIAPC = this%NEQ - IF (this%LEVEL > 0) THEN - iwk = this%NEQ * (this%LEVEL * 2 + 1) - ELSE - iwk = 0 - DO n = 1, NEQ - i = IA(n+1) - IA(n) - IF (i > iwk) THEN - iwk = i - END IF - END DO - iwk = this%NEQ * iwk - END IF - this%NJAPC = iwk - ijlu = iwk - ijw = 2 * this%NEQ - iwlu = this%NEQ + 1 - END IF - this%NJLU = ijlu - this%NJW = ijw - this%NWLU = iwlu - ! - ! -- ALLOCATE BASE PRECONDITIONER VECTORS - CALL mem_allocate(this%IAPC, this%NIAPC+1, 'IAPC', TRIM(this%memoryPath)) - CALL mem_allocate(this%JAPC, this%NJAPC, 'JAPC', TRIM(this%memoryPath)) - CALL mem_allocate(this%APC, this%NJAPC, 'APC', TRIM(this%memoryPath)) - ! - ! -- ALLOCATE MEMORY FOR ILU0 AND MILU0 NON-ZERO ROW ENTRY VECTOR - CALL mem_allocate(this%IW, this%NIAPC, 'IW', TRIM(this%memoryPath)) - CALL mem_allocate(this%W, this%NIAPC, 'W', TRIM(this%memoryPath)) - ! - ! -- ALLOCATE MEMORY FOR ILUT VECTORS - CALL mem_allocate(this%JLU, ijlu, 'JLU', TRIM(this%memoryPath)) - CALL mem_allocate(this%JW, ijw, 'JW', TRIM(this%memoryPath)) - CALL mem_allocate(this%WLU, iwlu, 'WLU', TRIM(this%memoryPath)) - ! - ! -- GENERATE IAPC AND JAPC FOR ILU0 AND MILU0 - IF (this%IPC == 1 .OR. this%IPC == 2) THEN - CALL ims_base_pccrs(this%NEQ,this%NJA,this%IA,this%JA, & - this%IAPC,this%JAPC) - END IF - ! - ! -- ALLOCATE SPACE FOR PERMUTATION VECTOR - i0 = 1 - iolen = 1 - IF (this%IORD.NE.0) THEN - i0 = this%NEQ - iolen = this%NJA - END IF - CALL mem_allocate(this%LORDER, i0, 'LORDER', TRIM(this%memoryPath)) - CALL mem_allocate(this%IORDER, i0, 'IORDER', TRIM(this%memoryPath)) - CALL mem_allocate(this%IARO, i0+1, 'IARO', TRIM(this%memoryPath)) - CALL mem_allocate(this%JARO, iolen, 'JARO', TRIM(this%memoryPath)) - CALL mem_allocate(this%ARO, iolen, 'ARO', TRIM(this%memoryPath)) - ! - ! -- ALLOCATE WORKING VECTORS FOR IMSLINEAR SOLVER - CALL mem_allocate(this%ID, this%NEQ, 'ID', TRIM(this%memoryPath)) - CALL mem_allocate(this%D, this%NEQ, 'D', TRIM(this%memoryPath)) - CALL mem_allocate(this%P, this%NEQ, 'P', TRIM(this%memoryPath)) - CALL mem_allocate(this%Q, this%NEQ, 'Q', TRIM(this%memoryPath)) - CALL mem_allocate(this%Z, this%NEQ, 'Z', TRIM(this%memoryPath)) - ! - ! -- ALLOCATE MEMORY FOR BCGS WORKING ARRAYS - this%NIABCGS = 1 - IF (this%ILINMETH == 2) THEN - this%NIABCGS = this%NEQ - END IF - CALL mem_allocate(this%T, this%NIABCGS, 'T', TRIM(this%memoryPath)) - CALL mem_allocate(this%V, this%NIABCGS, 'V', TRIM(this%memoryPath)) - CALL mem_allocate(this%DHAT, this%NIABCGS, 'DHAT', TRIM(this%memoryPath)) - CALL mem_allocate(this%PHAT, this%NIABCGS, 'PHAT', TRIM(this%memoryPath)) - CALL mem_allocate(this%QHAT, this%NIABCGS, 'QHAT', TRIM(this%memoryPath)) - ! - ! -- INITIALIZE IMSLINEAR VECTORS - DO n = 1, iscllen - this%DSCALE(n) = DONE - this%DSCALE2(n) = DONE - END DO - DO n = 1, this%NJAPC - this%APC(n) = DZERO - END DO - ! - ! -- WORKING VECTORS - DO n = 1, this%NEQ - this%ID(n) = IZERO - this%D(n) = DZERO - this%P(n) = DZERO - this%Q(n) = DZERO - this%Z(n) = DZERO - END DO - DO n = 1, this%NIAPC - this%IW(n) = IZERO - this%W(n) = DZERO - END DO - ! - ! -- BCGS WORKING VECTORS - DO n = 1, this%NIABCGS - this%T(n) = DZERO - this%V(n) = DZERO - this%DHAT(n) = DZERO - this%PHAT(n) = DZERO - this%QHAT(n) = DZERO - END DO - ! - ! -- ILUT AND MILUT WORKING VECTORS - DO n = 1, ijlu - this%JLU(n) = DZERO - END DO - DO n = 1, ijw - this%JW(n) = DZERO - END DO - DO n = 1, iwlu - this%WLU(n) = DZERO - END DO - ! - ! -- REORDERING VECTORS - DO n = 1, i0 + 1 - this%IARO(n) = IZERO - END DO - DO n = 1, iolen - this%JARO(n) = IZERO - this%ARO(n) = DZERO - END DO - ! - ! -- REVERSE CUTHILL MCKEE AND MINIMUM DEGREE ORDERING - IF (this%IORD.NE.0) THEN - CALL ims_base_calc_order(this%IORD,this%NEQ, this%NJA,this%IA,this%JA, & - this%LORDER,this%IORDER) - END IF - ! - ! -- ALLOCATE MEMORY FOR STORING ITERATION CONVERGENCE DATA - ! - ! -- RETURN - RETURN - END SUBROUTINE imslinear_ar - - !> @ brief Write summary of settings - !! - !! Write summary of linear accelerator settings. - !! - !< - subroutine imslinear_summary(this, mxiter) - ! -- dummy variables - class(ImsLinearDataType), intent(inout) :: this !< ImsLinearDataType instance - integer(I4B), intent(in) :: mxiter !< maximum number of outer iterations - ! -- local variables - CHARACTER (LEN= 10) :: clin(0:2) - CHARACTER (LEN= 31) :: clintit(0:2) - CHARACTER (LEN= 20) :: cipc(0:4) - CHARACTER (LEN= 20) :: cscale(0:2) - CHARACTER (LEN= 25) :: corder(0:2) - CHARACTER (LEN= 16), DIMENSION(0:4) :: ccnvgopt - CHARACTER (LEN= 15) :: clevel - CHARACTER (LEN= 15) :: cdroptol - integer(I4B) :: i - integer(I4B) :: j - ! -- data - DATA clin /'UNKNOWN ', & - 'CG ', & - & 'BCGS '/ - DATA clintit /' UNKNOWN ', & - ' CONJUGATE-GRADIENT ', & - & 'BICONJUGATE-GRADIENT STABILIZED'/ - DATA cipc /'UNKNOWN ', & - & 'INCOMPLETE LU ', & - & 'MOD. INCOMPLETE LU ', & - & 'INCOMPLETE LUT ', & - & 'MOD. INCOMPLETE LUT '/ - DATA cscale/'NO SCALING ', & - & 'SYMMETRIC SCALING ', & - & 'L2 NORM SCALING '/ - DATA corder/'ORIGINAL ORDERING ', & - & 'RCM ORDERING ', & - & 'MINIMUM DEGREE ORDERING '/ - DATA ccnvgopt /'INFINITY NORM ', & - & 'INFINITY NORM S ', & - & 'L2 NORM ', & - & 'RELATIVE L2NORM ', & - 'L2 NORM W. REL. '/ - ! -- formats -02010 FORMAT (1X,/,7X,'SOLUTION BY THE',1X,A31,1X,'METHOD', & - & /,1X,66('-'),/, & - & ' MAXIMUM OF ',I0,' CALLS OF SOLUTION ROUTINE',/, & - & ' MAXIMUM OF ',I0, & - & ' INTERNAL ITERATIONS PER CALL TO SOLUTION ROUTINE',/, & - & ' LINEAR ACCELERATION METHOD =',1X,A,/, & - & ' MATRIX PRECONDITIONING TYPE =',1X,A,/, & - & ' MATRIX SCALING APPROACH =',1X,A,/, & - & ' MATRIX REORDERING APPROACH =',1X,A,/, & - & ' NUMBER OF ORTHOGONALIZATIONS =',1X,I0,/, & - & ' HEAD CHANGE CRITERION FOR CLOSURE =',E15.5,/, & - & ' RESIDUAL CHANGE CRITERION FOR CLOSURE =',E15.5,/, & - & ' RESIDUAL CONVERGENCE OPTION =',1X,I0,/, & - & ' RESIDUAL CONVERGENCE NORM =',1X,A,/, & - & ' RELAXATION FACTOR =',E15.5) -02015 FORMAT (' NUMBER OF LEVELS =',A15,/, & - & ' DROP TOLERANCE =',A15,//) -2030 FORMAT(1X,A20,1X,6(I6,1X)) -2040 FORMAT(1X,20('-'),1X,6(6('-'),1X)) -2050 FORMAT(1X,62('-'),/) ! -! -- ----------------------------------------------------------- - ! - ! -- initialize clevel and cdroptol - clevel = '' - cdroptol = '' - ! - ! -- write common variables to all linear accelerators - write(this%iout,2010) & - clintit(this%ILINMETH), MXITER, this%ITER1, & - clin(this%ILINMETH), cipc(this%IPC), & - cscale(this%ISCL), corder(this%IORD), & - this%NORTH, this%DVCLOSE, this%RCLOSE, & - this%ICNVGOPT, ccnvgopt(this%ICNVGOPT), & - this%RELAX - if (this%level > 0) then - write(clevel, '(i15)') this%level - end if - if (this%droptol > DZERO) then - write(cdroptol, '(e15.5)') this%droptol - end if - IF (this%level > 0 .or. this%droptol > DZERO) THEN - write(this%iout,2015) trim(adjustl(clevel)), & - trim(adjustl(cdroptol)) - ELSE - write(this%iout,'(//)') - END IF - - if (this%iord /= 0) then - ! - ! -- WRITE SUMMARY OF REORDERING INFORMATION TO LIST FILE - if (this%iprims == 2) then - DO i = 1, this%neq, 6 - write(this%iout,2030) 'ORIGINAL NODE :', & - (j,j=i,MIN(i+5,this%neq)) - write(this%iout,2040) - write(this%iout,2030) 'REORDERED INDEX :', & - (this%lorder(j),j=i,MIN(i+5,this%neq)) - write(this%iout,2030) 'REORDERED NODE :', & - (this%iorder(j),j=i,MIN(i+5,this%neq)) - write(this%iout,2050) - END DO - END IF - end if - ! - ! -- return - return - end subroutine imslinear_summary - - !> @ brief Allocate and initialize scalars - !! - !! Allocate and inititialize linear accelerator scalars - !! - !< - subroutine allocate_scalars(this) - ! -- modules - use MemoryManagerModule, only: mem_allocate - ! -- dummy variables - class(ImsLinearDataType), intent(inout) :: this !< ImsLinearDataType instance - ! - ! -- allocate scalars - call mem_allocate(this%iout, 'IOUT', this%memoryPath) - call mem_allocate(this%ilinmeth, 'ILINMETH', this%memoryPath) - call mem_allocate(this%iter1, 'ITER1', this%memoryPath) - call mem_allocate(this%ipc, 'IPC', this%memoryPath) - call mem_allocate(this%iscl, 'ISCL', this%memoryPath) - call mem_allocate(this%iord, 'IORD', this%memoryPath) - call mem_allocate(this%north, 'NORTH', this%memoryPath) - call mem_allocate(this%icnvgopt, 'ICNVGOPT', this%memoryPath) - call mem_allocate(this%iacpc, 'IACPC', this%memoryPath) - call mem_allocate(this%niterc, 'NITERC', this%memoryPath) - call mem_allocate(this%niabcgs, 'NIABCGS', this%memoryPath) - call mem_allocate(this%niapc, 'NIAPC', this%memoryPath) - call mem_allocate(this%njapc, 'NJAPC', this%memoryPath) - call mem_allocate(this%dvclose, 'DVCLOSE', this%memoryPath) - call mem_allocate(this%rclose, 'RCLOSE', this%memoryPath) - call mem_allocate(this%relax, 'RELAX', this%memoryPath) - call mem_allocate(this%epfact, 'EPFACT', this%memoryPath) - call mem_allocate(this%l2norm0, 'L2NORM0', this%memoryPath) - call mem_allocate(this%droptol, 'DROPTOL', this%memoryPath) - call mem_allocate(this%level, 'LEVEL', this%memoryPath) - call mem_allocate(this%njlu, 'NJLU', this%memoryPath) - call mem_allocate(this%njw, 'NJW', this%memoryPath) - call mem_allocate(this%nwlu, 'NWLU', this%memoryPath) - ! - ! -- initialize scalars - this%iout = 0 - this%ilinmeth = 0 - this%iter1 = 0 - this%ipc = 0 - this%iscl = 0 - this%iord = 0 - this%north = 0 - this%icnvgopt = 0 - this%iacpc = 0 - this%niterc = 0 - this%niabcgs = 0 - this%niapc = 0 - this%njapc = 0 - this%dvclose = DZERO - this%rclose = DZERO - this%relax = DZERO - this%epfact = DZERO - this%l2norm0 = 0 - this%droptol = DZERO - this%level = 0 - this%njlu = 0 - this%njw = 0 - this%nwlu = 0 - ! - ! -- return - return - end subroutine allocate_scalars - - !> @ brief Deallocate memory - !! - !! Deallocate linear accelerator memory. - !! - !< - subroutine imslinear_da(this) - ! -- modules - use MemoryManagerModule, only: mem_deallocate - ! -- dummy variables - class(ImsLinearDataType), intent(inout) :: this !< linear datatype instance - ! - ! -- arrays - call mem_deallocate(this%dscale) - call mem_deallocate(this%dscale2) - call mem_deallocate(this%iapc) - call mem_deallocate(this%japc) - call mem_deallocate(this%apc) - call mem_deallocate(this%iw) - call mem_deallocate(this%w) - call mem_deallocate(this%jlu) - call mem_deallocate(this%jw) - call mem_deallocate(this%wlu) - call mem_deallocate(this%lorder) - call mem_deallocate(this%iorder) - call mem_deallocate(this%iaro) - call mem_deallocate(this%jaro) - call mem_deallocate(this%aro) - call mem_deallocate(this%id) - call mem_deallocate(this%d) - call mem_deallocate(this%p) - call mem_deallocate(this%q) - call mem_deallocate(this%z) - call mem_deallocate(this%t) - call mem_deallocate(this%v) - call mem_deallocate(this%dhat) - call mem_deallocate(this%phat) - call mem_deallocate(this%qhat) - ! - ! -- scalars - call mem_deallocate(this%iout) - call mem_deallocate(this%ilinmeth) - call mem_deallocate(this%iter1) - call mem_deallocate(this%ipc) - call mem_deallocate(this%iscl) - call mem_deallocate(this%iord) - call mem_deallocate(this%north) - call mem_deallocate(this%icnvgopt) - call mem_deallocate(this%iacpc) - call mem_deallocate(this%niterc) - call mem_deallocate(this%niabcgs) - call mem_deallocate(this%niapc) - call mem_deallocate(this%njapc) - call mem_deallocate(this%dvclose) - call mem_deallocate(this%rclose) - call mem_deallocate(this%relax) - call mem_deallocate(this%epfact) - call mem_deallocate(this%l2norm0) - call mem_deallocate(this%droptol) - call mem_deallocate(this%level) - call mem_deallocate(this%njlu) - call mem_deallocate(this%njw) - call mem_deallocate(this%nwlu) - ! - ! -- nullify pointers - nullify(this%iprims) - nullify(this%neq) - nullify(this%nja) - nullify(this%ia) - nullify(this%ja) - nullify(this%amat) - nullify(this%rhs) - nullify(this%x) - ! - ! -- return - return - end subroutine imslinear_da - - !> @ brief Set default settings - !! - !! Set default linear accelerator settings. - !! - !< - SUBROUTINE imslinear_set_input(this, IFDPARAM) - ! -- dummy variables - CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance - integer(I4B), INTENT(IN) :: IFDPARAM !< complexity option - ! -- code - SELECT CASE ( IFDPARAM ) - ! - ! -- Simple option - CASE(1) - this%ITER1 = 50 - this%ILINMETH=1 - this%IPC = 1 - this%ISCL = 0 - this%IORD = 0 - this%DVCLOSE = DEM3 - this%RCLOSE = DEM1 - this%RELAX = DZERO - this%LEVEL = 0 - this%DROPTOL = DZERO - this%NORTH = 0 - ! - ! -- Moderate - CASE(2) - this%ITER1 = 100 - this%ILINMETH=2 - this%IPC = 2 - this%ISCL = 0 - this%IORD = 0 - this%DVCLOSE = DEM2 - this%RCLOSE = DEM1 - this%RELAX = 0.97D0 - this%LEVEL = 0 - this%DROPTOL = DZERO - this%NORTH = 0 - ! - ! -- Complex - CASE(3) - this%ITER1 = 500 - this%ILINMETH=2 - this%IPC = 3 - this%ISCL = 0 - this%IORD = 0 - this%DVCLOSE = DEM1 - this%RCLOSE = DEM1 - this%RELAX = DZERO - this%LEVEL = 5 - this%DROPTOL = DEM4 - this%NORTH = 2 - END SELECT - ! - ! -- return - RETURN - END SUBROUTINE imslinear_set_input - - !> @ brief Base linear accelerator subroutine - !! - !! Base linear accelerator subroutine that scales and reorders - !! the system of equations, if necessary, updates the preconditioner, - !! and calls the appropriate linear accelerator. - !! - !< - SUBROUTINE imslinear_ap(this,ICNVG,KSTP,KITER,IN_ITER, & - NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & - CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & - DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) - ! -- modules - USE SimModule - ! -- dummy variables - CLASS(ImsLinearDataType), INTENT(INOUT) :: this !< ImsLinearDataType instance - integer(I4B), INTENT(INOUT) :: ICNVG !< convergence flag (1) non-convergence (0) - integer(I4B), INTENT(IN) :: KSTP !< time step number - integer(I4B), INTENT(IN) :: KITER !< outer iteration number - integer(I4B), INTENT(INOUT) :: IN_ITER !< inner iteration number - ! -- convergence information dummy variables - integer(I4B), INTENT(IN) :: NCONV !< - integer(I4B), INTENT(IN) :: CONVNMOD !< - integer(I4B), DIMENSION(CONVNMOD+1), INTENT(INOUT) ::CONVMODSTART !< - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDV !< - integer(I4B), DIMENSION(CONVNMOD), INTENT(INOUT) :: LOCDR !< - character(len=31), DIMENSION(NCONV), INTENT(INOUT) :: CACCEL !< - integer(I4B), DIMENSION(NCONV), INTENT(INOUT) :: ITINNER !< - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDV !< - integer(I4B), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVLOCDR !< - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DVMAX !< - real(DP), DIMENSION(CONVNMOD), INTENT(INOUT) :: DRMAX !< - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDVMAX !< - real(DP), DIMENSION(CONVNMOD, NCONV), INTENT(INOUT) :: CONVDRMAX !< - ! -- local variables - integer(I4B) :: n - integer(I4B) :: innerit - integer(I4B) :: irc - integer(I4B) :: itmax - real(DP) :: dnrm2 - ! - ! -- set epfact based on timestep - IF (this%ICNVGOPT == 2) THEN - IF (KSTP == 1) THEN - this%EPFACT = 0.01 - ELSE - this%EPFACT = 0.10 - END IF - ELSE IF (this%ICNVGOPT == 4) THEN - this%EPFACT = DEM4 - ELSE - this%EPFACT = DONE - END IF - ! - ! -- SCALE PROBLEM - IF (this%ISCL.NE.0) THEN - CALL ims_base_scale(0,this%ISCL, & - this%NEQ,this%NJA,this%IA,this%JA, & - this%AMAT,this%X,this%RHS, & - this%DSCALE,this%DSCALE2) - END IF - ! - ! -- PERMUTE ROWS, COLUMNS, AND RHS - IF (this%IORD /= 0) THEN - CALL dperm(this%NEQ, this%AMAT, this%JA, this%IA, & - this%ARO, this%JARO, this%IARO, & - this%LORDER, this%ID, 1) - CALL dvperm(this%NEQ, this%X, this%LORDER) - CALL dvperm(this%NEQ, this%RHS, this%LORDER) - this%IA0 => this%IARO - this%JA0 => this%JARO - this%A0 => this%ARO - ELSE - this%IA0 => this%IA - this%JA0 => this%JA - this%A0 => this%AMAT - END IF - ! - ! -- UPDATE PRECONDITIONER - CALL ims_base_pcu(this%iout,this%NJA,this%NEQ,this%NIAPC,this%NJAPC, & - this%IPC, this%RELAX, this%A0, this%IA0, this%JA0, & - this%APC,this%IAPC,this%JAPC,this%IW,this%W, & - this%LEVEL, this%DROPTOL, this%NJLU, this%NJW, & - this%NWLU, this%JLU, this%JW, this%WLU) - ! - ! -- INITIALIZE SOLUTION VARIABLE AND ARRAYS - IF (KITER == 1 ) this%NITERC = 0 - irc = 1 - ICNVG = 0 - DO n = 1, this%NEQ - this%D(n) = DZERO - this%P(n) = DZERO - this%Q(n) = DZERO - this%Z(n) = DZERO - END DO - ! - ! -- CALCULATE INITIAL RESIDUAL - call ims_base_residual(this%NEQ, this%NJA, this%X, this%RHS, this%D, & - this%A0, this%IA0, this%JA0) - this%L2NORM0 = dnrm2(this%NEQ, this%D, 1) - ! - ! -- CHECK FOR EXACT SOLUTION - itmax = this%ITER1 - IF (this%L2NORM0 == DZERO) THEN - itmax = 0 - ICNVG = 1 - END IF - ! - ! -- SOLUTION BY THE CONJUGATE GRADIENT METHOD - IF (this%ILINMETH == 1) THEN - CALL ims_base_cg(ICNVG, itmax, innerit, & - this%NEQ, this%NJA, this%NIAPC, this%NJAPC, & - this%IPC, this%NITERC, this%ICNVGOPT, this%NORTH, & - this%DVCLOSE, this%RCLOSE, this%L2NORM0, & - this%EPFACT, this%IA0, this%JA0, this%A0, & - this%IAPC, this%JAPC, this%APC, & - this%X, this%RHS, this%D, this%P, this%Q, this%Z, & - this%NJLU, this%IW, this%JLU, & - NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & - CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & - DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) - ! - ! -- SOLUTION BY THE BICONJUGATE GRADIENT STABILIZED METHOD - ELSE IF (this%ILINMETH == 2) THEN - CALL ims_base_bcgs(ICNVG, itmax, innerit, & - this%NEQ, this%NJA, this%NIAPC, this%NJAPC, & - this%IPC, this%NITERC, this%ICNVGOPT, this%NORTH,& - this%ISCL, this%DSCALE, & - this%DVCLOSE, this%RCLOSE, this%L2NORM0, & - this%EPFACT, this%IA0, this%JA0, this%A0, & - this%IAPC, this%JAPC, this%APC, & - this%X, this%RHS, this%D, this%P, this%Q, & - this%T, this%V, this%DHAT, this%PHAT, this%QHAT, & - this%NJLU, this%IW, this%JLU, & - NCONV, CONVNMOD, CONVMODSTART, LOCDV, LOCDR, & - CACCEL, ITINNER, CONVLOCDV, CONVLOCDR, & - DVMAX, DRMAX, CONVDVMAX, CONVDRMAX) - END IF - ! - ! -- BACK PERMUTE AMAT, SOLUTION, AND RHS - IF (this%IORD /= 0) THEN - CALL dperm(this%NEQ, this%A0, this%JA0, this%IA0, & - this%AMAT, this%JA, this%IA, & - this%IORDER, this%ID, 1) - CALL dvperm(this%NEQ, this%X, this%IORDER) - CALL dvperm(this%NEQ, this%RHS, this%IORDER) - END IF - ! - ! -- UNSCALE PROBLEM - IF (this%ISCL.NE.0) THEN - CALL ims_base_scale(1, this%ISCL, & - this%NEQ, this%NJA, this%IA, this%JA, & - this%AMAT, this%X, this%RHS, & - this%DSCALE, this%DSCALE2) - END IF - ! - ! -- SET IMS INNER ITERATION NUMBER (IN_ITER) TO NUMBER OF - ! IMSLINEAR INNER ITERATIONS (innerit) - IN_ITER = innerit - ! - ! -- RETURN - RETURN - END SUBROUTINE imslinear_ap - -END MODULE IMSLinearModule diff --git a/src/Solution/SparseMatrixSolver/ims8reordering.f90 b/src/Solution/SparseMatrixSolver/ims8reordering.f90 deleted file mode 100644 index 684f4232594..00000000000 --- a/src/Solution/SparseMatrixSolver/ims8reordering.f90 +++ /dev/null @@ -1,781 +0,0 @@ - MODULE IMSReorderingModule - use KindModule, only: DP, I4B - private - public :: ims_odrv - contains - - subroutine ims_odrv(n, nja, nsp, ia, ja, p, ip, isp, flag) - ! - ! 3/12/82 - !*********************************************************************** - ! odrv -- driver for sparse matrix reordering routines - !*********************************************************************** - ! - ! description - ! - ! odrv finds a minimum degree ordering of the rows and columns - ! of a matrix m stored in (ia,ja,a) format (see below). for the - ! reordered matrix, the work and storage required to perform - ! gaussian elimination is (usually) significantly less. - ! - ! note.. odrv and its subordinate routines have been modified to - ! compute orderings for general matrices, not necessarily having any - ! symmetry. the minimum degree ordering is computed for the - ! structure of the symmetric matrix m + m-transpose. - ! modifications to the original odrv module have been made in - ! the coding in subroutine mdi, and in the initial comments in - ! subroutines odrv and md. - ! - ! if only the nonzero entries in the upper triangle of m are being - ! stored, then odrv symmetrically reorders (ia,ja,a), (optionally) - ! with the diagonal entries placed first in each row. this is to - ! ensure that if m(i,j) will be in the upper triangle of m with - ! respect to the new ordering, then m(i,j) is stored in row i (and - ! thus m(j,i) is not stored), whereas if m(i,j) will be in the - ! strict lower triangle of m, then m(j,i) is stored in row j (and - ! thus m(i,j) is not stored). - ! - ! - ! storage of sparse matrices - ! - ! the nonzero entries of the matrix m are stored row-by-row in the - ! array a. to identify the individual nonzero entries in each row, - ! we need to know in which column each entry lies. these column - ! indices are stored in the array ja. i.e., if a(k) = m(i,j), then - ! ja(k) = j. to identify the individual rows, we need to know where - ! each row starts. these row pointers are stored in the array ia. - ! i.e., if m(i,j) is the first nonzero entry (stored) in the i-th row - ! and a(k) = m(i,j), then ia(i) = k. moreover, ia(n+1) points to - ! the first location following the last element in the last row. - ! thus, the number of entries in the i-th row is ia(i+1) - ia(i), - ! the nonzero entries in the i-th row are stored consecutively in - ! - ! a(ia(i)), a(ia(i)+1), ..., a(ia(i+1)-1), - ! - ! and the corresponding column indices are stored consecutively in - ! - ! ja(ia(i)), ja(ia(i)+1), ..., ja(ia(i+1)-1). - ! - ! since the coefficient matrix is symmetric, only the nonzero entries - ! in the upper triangle need be stored. for example, the matrix - ! - ! ( 1 0 2 3 0 ) - ! ( 0 4 0 0 0 ) - ! m = ( 2 0 5 6 0 ) - ! ( 3 0 6 7 8 ) - ! ( 0 0 0 8 9 ) - ! - ! could be stored as - ! - ! - 1 2 3 4 5 6 7 8 9 10 11 12 13 - ! ---+-------------------------------------- - ! ia - 1 4 5 8 12 14 - ! ja - 1 3 4 2 1 3 4 1 3 4 5 4 5 - ! a - 1 2 3 4 2 5 6 3 6 7 8 8 9 - ! - ! or (symmetrically) as - ! - ! - 1 2 3 4 5 6 7 8 9 - ! ---+-------------------------- - ! ia - 1 4 5 7 9 10 - ! ja - 1 3 4 2 3 4 4 5 5 - ! a - 1 2 3 4 5 6 7 8 9 . - ! - ! - ! parameters - ! - ! n - order of the matrix - ! - ! nja - number of nonzeroes in the matrix - ! - ! nsp - declared dimension of the one-dimensional array isp. nsp - ! must be at least 3n+4k, where k is the number of nonzeroes - ! in the strict upper triangle of m - ! - ! ia - integer one-dimensional array containing pointers to delimit - ! rows in ja and a. dimension = n+1 - ! - ! ja - integer one-dimensional array containing the column indices - ! corresponding to the elements of a. dimension = number of - ! nonzero entries in (the upper triangle of) m - ! - ! a - real one-dimensional array containing the nonzero entries in - ! (the upper triangle of) m, stored by rows. dimension = - ! number of nonzero entries in (the upper triangle of) m - ! - ! p - integer one-dimensional array used to return the permutation - ! of the rows and columns of m corresponding to the minimum - ! degree ordering. dimension = n - ! - ! ip - integer one-dimensional array used to return the inverse of - ! the permutation returned in p. dimension = n - ! - ! isp - integer one-dimensional array used for working storage. - ! dimension = nsp - ! - ! path - integer path specification. values and their meanings are - - ! 1 find minimum degree ordering only - ! 2 find minimum degree ordering and reorder symmetrically - ! stored matrix (used when only the nonzero entries in - ! the upper triangle of m are being stored) - ! 3 reorder symmetrically stored matrix as specified by - ! input permutation (used when an ordering has already - ! been determined and only the nonzero entries in the - ! upper triangle of m are being stored) - ! 4 same as 2 but put diagonal entries at start of each row - ! 5 same as 3 but put diagonal entries at start of each row - ! - ! flag - integer error flag. values and their meanings are - - ! 0 no errors detected - ! 9n+k insufficient storage in md - ! 10n+1 insufficient storage in odrv - ! 11n+1 illegal path specification - ! - ! - ! conversion from real to double precision - ! - ! change the real declarations in odrv and sro to double precision - ! declarations. - ! - !----------------------------------------------------------------------- - ! - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: nja - integer(I4B), intent(in) :: nsp - integer(I4B), dimension(n+1), intent(in) :: ia - integer(I4B), dimension(nja), intent(in) :: ja - integer(I4B), dimension(n), intent(inout) :: p - integer(I4B), dimension(n), intent(inout) :: ip - integer(I4B), dimension(nsp), intent(inout) :: isp - integer(I4B), intent(inout) :: flag - - ! -- local - integer(I4B) :: v - integer(I4B) :: l - integer(I4B) :: head - integer(I4B) :: mmax - integer(I4B) :: next - integer(I4B) :: path - ! - ! set path for finding ordering only - ! - path = 1 - ! - ! - ! initialize error flag and validate path specification - flag = 0 - if (path < 1 .or. 5 < path) go to 111 - ! - ! find minimum degree ordering - mmax = (nsp-n)/2 - v = 1 - l = v + mmax - head = l + mmax - next = head + n - if (mmax < n) go to 110 - ! - call ims_md(n, nja, ia, ja, mmax, isp(v), isp(l), isp(head), p, & - ip, isp(v), flag) - if (flag.ne.0) go to 100 - ! - return - ! - ! ** error -- error detected in md - ! flag = 9 * n + vi from routine mdi. - ! -100 return - ! ** error -- insufficient storage -110 flag = 10*n + 1 - return - ! ** error -- illegal path specified -111 flag = 11*n + 1 - return - end subroutine ims_odrv - - - - subroutine ims_md(n, nja, ia, ja, mmax, v, l, head, last, next, & - mark, flag) - ! - !***************************************************************** - ! ims_md -- minimum degree algorithm (based on element model) - !***************************************************************** - ! - ! description - ! - ! ims_md finds a minimum degree ordering of the rows and - ! columns of a general sparse matrix m stored in (ia,ja,a) - ! format. when the structure of m is nonsymmetric, the ordering - ! is that obtained for the symmetric matrix m + m-transpose. - ! - ! - ! additional parameters - ! - ! mmax - declared dimension of the one-dimensional arrays v and l. - ! mmax must be at least n+2k, where k is the number of - ! nonzeroes in the strict upper triangle of m - ! - ! v - integer one-dimensional work array. dimension = mmax - ! - ! l - integer one-dimensional work array. dimension = mmax - ! - ! head - integer one-dimensional work array. dimension = n - ! - ! last - integer one-dimensional array used to return the permutation - ! of the rows and columns of m corresponding to the minimum - ! degree ordering. dimension = n - ! - ! next - integer one-dimensional array used to return the inverse of - ! the permutation returned in last. dimension = n - ! - ! mark - integer one-dimensional work array (may be the same as v). - ! dimension = n - ! - ! flag - integer error flag. values and their meanings are - - ! 0 no errors detected - ! 11n+1 insufficient storage in md - ! - ! - ! definitions of internal parameters - ! - ! ---------+--------------------------------------------------------- - ! v(s) - value field of list entry - ! ---------+--------------------------------------------------------- - ! l(s) - link field of list entry (0 =) end of list) - ! ---------+--------------------------------------------------------- - ! l(vi) - pointer to element list of uneliminated vertex vi - ! ---------+--------------------------------------------------------- - ! l(ej) - pointer to boundary list of active element ej - ! ---------+--------------------------------------------------------- - ! head(d) - vj =) vj head of d-list d - ! - 0 =) no vertex in d-list d - ! - ! - ! - vi uneliminated vertex - ! - vi in ek - vi not in ek - ! ---------+-----------------------------+--------------------------- - ! next(vi) - undefined but nonnegative - vj =) vj next in d-list - ! - - 0 =) vi tail of d-list - ! ---------+-----------------------------+--------------------------- - ! last(vi) - (not set until mdp) - -d =) vi head of d-list d - ! --vk =) compute degree - vj =) vj last in d-list - ! - ej =) vi prototype of ej - 0 =) vi not in any d-list - ! - 0 =) do not compute degree - - ! ---------+-----------------------------+--------------------------- - ! mark(vi) - mark(vk) - nonneg. tag .lt. mark(vk) - ! - ! - ! - vi eliminated vertex - ! - ei active element - otherwise - ! ---------+-----------------------------+--------------------------- - ! next(vi) - -j =) vi was j-th vertex - -j =) vi was j-th vertex - ! - to be eliminated - to be eliminated - ! ---------+-----------------------------+--------------------------- - ! last(vi) - m =) size of ei = m - undefined - ! ---------+-----------------------------+--------------------------- - ! mark(vi) - -m =) overlap count of ei - undefined - ! - with ek = m - - ! - otherwise nonnegative tag - - ! - .lt. mark(vk) - - ! - !----------------------------------------------------------------------- - ! - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: nja - integer(I4B), dimension(n+1), intent(in) :: ia - integer(I4B), dimension(nja), intent(in) :: ja - integer(I4B), intent(in) :: mmax - integer(I4B), dimension(mmax), intent(inout) :: v - integer(I4B), dimension(mmax), intent(inout) :: l - integer(I4B), dimension(n), intent(inout) :: head - integer(I4B), dimension(n), intent(inout) :: last - integer(I4B), dimension(n), intent(inout) :: next - integer(I4B), dimension(n), intent(inout) :: mark - integer(I4B), intent(inout) :: flag - - ! -- local - integer(I4B) :: tag - integer(I4B) :: dmin - integer(I4B) :: vk - integer(I4B) :: ek - integer(I4B) :: tail - integer(I4B) :: k - - equivalence(vk, ek) - ! - ! initialization - tag = 0 - call ims_mdi(n, nja, ia, ja, mmax ,v, l, head, last, next, & - mark, tag, flag) - if (flag.ne.0) return - ! - k = 0 - dmin = 1 - ! - ! while k .lt. n do -1 if (k >= n) go to 4 - ! - ! search for vertex of minimum degree -2 if (head(dmin) > 0) go to 3 - dmin = dmin + 1 - go to 2 - ! - ! remove vertex vk of minimum degree from degree list -3 vk = head(dmin) - head(dmin) = next(vk) - if (head(dmin) > 0) last(head(dmin)) = -dmin - ! - ! number vertex vk, adjust tag, and tag vk - k = k+1 - next(vk) = -k - last(ek) = dmin - 1 - tag = tag + last(ek) - mark(vk) = tag - ! - ! form element ek from uneliminated neighbors of vk - call ims_mdm(n, mmax, vk, tail, v, l, last, next, mark) - ! - ! purge inactive elements and do mass elimination - call ims_mdp(n, mmax, k, ek, tail, v, l, head, last, next, mark) - ! - ! update degrees of uneliminated vertices in ek - call ims_mdu(n, mmax, ek, dmin, v, l, head, last, next, mark) - ! - go to 1 - ! - ! generate inverse permutation from permutation -4 do k = 1, n - next(k) = -next(k) - last(next(k)) = k - end do - ! - return - end subroutine ims_md - - - subroutine ims_mdi(n, nja, ia, ja, mmax, v, l, head, last, next, & - mark, tag, flag) - ! - !*********************************************************************** - ! ims_mdi -- initialization - !*********************************************************************** - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: nja - integer(I4B), dimension(n+1), intent(in) :: ia - integer(I4B), dimension(nja), intent(in) :: ja - integer(I4B), intent(in) :: mmax - integer(I4B), dimension(mmax), intent(inout) :: v - integer(I4B), dimension(mmax), intent(inout) :: l - integer(I4B), dimension(n), intent(inout) :: head - integer(I4B), dimension(n), intent(inout) :: last - integer(I4B), dimension(n), intent(inout) :: next - integer(I4B), dimension(n), intent(inout) :: mark - integer(I4B), intent(in) :: tag - integer(I4B), intent(inout) :: flag - - ! -- local - integer(I4B) :: sfs - integer(I4B) :: vi - integer(I4B) :: dvi - integer(I4B) :: vj - integer(I4B) :: jmin - integer(I4B) :: jmax - integer(I4B) :: j - integer(I4B) :: lvk - integer(I4B) :: kmax - integer(I4B) :: k - integer(I4B) :: nextvi - integer(I4B) :: ieval - ! - ! initialize degrees, element lists, and degree lists - do vi = 1, n - mark(vi) = 1 - l(vi) = 0 - head(vi) = 0 - end do - sfs = n + 1 - ! - ! create nonzero structure - ! for each nonzero entry a(vi,vj) - louter: do vi = 1, n - jmin = ia(vi) - jmax = ia(vi+1) - 1 - if (jmin > jmax) cycle louter - linner1: do j = jmin, jmax !5 - vj = ja(j) - !if (vj-vi) 2, 5, 4 - ieval = vj - vi - if (ieval == 0) cycle linner1 !5 - if (ieval > 0) go to 4 - ! - ! if a(vi,vj) is in strict lower triangle - ! check for previous occurrence of a(vj,vi) - lvk = vi - kmax = mark(vi) - 1 - if (kmax == 0) go to 4 - linner2: do k = 1, kmax - lvk = l(lvk) - if (v(lvk) == vj) cycle linner1 !5 - end do linner2 - ! for unentered entries a(vi,vj) -4 if (sfs >= mmax) go to 101 - ! - ! enter vj in element list for vi - mark(vi) = mark(vi) + 1 - v(sfs) = vj - l(sfs) = l(vi) - l(vi) = sfs - sfs = sfs+1 - ! - ! enter vi in element list for vj - mark(vj) = mark(vj) + 1 - v(sfs) = vi - l(sfs) = l(vj) - l(vj) = sfs - sfs = sfs + 1 - end do linner1 - end do louter - ! - ! create degree lists and initialize mark vector - do vi = 1, n - dvi = mark(vi) - next(vi) = head(dvi) - head(dvi) = vi - last(vi) = -dvi - nextvi = next(vi) - if (nextvi > 0) last(nextvi) = vi - mark(vi) = tag - end do - ! - return - ! - ! ** error- insufficient storage -101 flag = 9*n + vi - return - end subroutine ims_mdi - - - - subroutine ims_mdm(n, mmax, vk, tail, v, l, last, next, mark) - ! - !*********************************************************************** - ! ims_mdm -- form element from uneliminated neighbors of vk - !*********************************************************************** - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: mmax - integer(I4B), intent(in) :: vk - integer(I4B), intent(inout) :: tail - integer(I4B), dimension(mmax), intent(inout) :: v - integer(I4B), dimension(mmax), intent(inout) :: l - integer(I4B), dimension(n), intent(inout) :: last - integer(I4B), dimension(n), intent(inout) :: next - integer(I4B), dimension(n), intent(inout) :: mark - - ! -- local - integer(I4B) :: tag - integer(I4B) :: s - integer(I4B) :: ls - integer(I4B) :: vs - integer(I4B) :: es - integer(I4B) :: b - integer(I4B) :: lb - integer(I4B) :: vb - integer(I4B) :: blp - integer(I4B) :: blpmax - - equivalence (vs, es) - ! - ! initialize tag and list of uneliminated neighbors - tag = mark(vk) - tail = vk - ! - ! for each vertex/element vs/es in element list of vk - ls = l(vk) -1 s = ls - if (s == 0) go to 5 - ls = l(s) - vs = v(s) - if (next(vs) < 0) go to 2 - ! - ! if vs is uneliminated vertex, then tag and append to list of - ! uneliminated neighbors - mark(vs) = tag - l(tail) = s - tail = s - go to 4 - ! - ! if es is active element, then ... - ! for each vertex vb in boundary list of element es -2 lb = l(es) - blpmax = last(es) - louter: do blp = 1, blpmax !3 - b = lb - lb = l(b) - vb = v(b) - ! - ! if vb is untagged vertex, then tag and append to list of - ! uneliminated neighbors - if (mark(vb) >= tag) cycle louter !3 - mark(vb) = tag - l(tail) = b - tail = b - end do louter - ! - ! mark es inactive - mark(es) = tag - ! -4 go to 1 - ! - ! terminate list of uneliminated neighbors -5 l(tail) = 0 - ! - return - end subroutine ims_mdm - - - subroutine ims_mdp(n, mmax, k, ek, tail, v, l, head, last, next, mark) - ! - !*********************************************************************** - ! ims_mdp -- purge inactive elements and do mass elimination - !*********************************************************************** - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: mmax - integer(I4B), intent(inout) :: k - integer(I4B), intent(in) :: ek - integer(I4B), intent(inout) :: tail - integer(I4B), dimension(mmax), intent(inout) :: v - integer(I4B), dimension(mmax), intent(inout) :: l - integer(I4B), dimension(n), intent(inout) :: head - integer(I4B), dimension(n), intent(inout) :: last - integer(I4B), dimension(n), intent(inout) :: next - integer(I4B), dimension(n), intent(inout) :: mark - - ! -- local - integer(I4B) :: tag - integer(I4B) :: free - integer(I4B) :: li - integer(I4B) :: vi - integer(I4B) :: lvi - integer(I4B) :: evi - integer(I4B) :: s - integer(I4B) :: ls - integer(I4B) :: es - integer(I4B) :: ilp - integer(I4B) :: ilpmax - integer(I4B) :: i - ! - ! initialize tag - tag = mark(ek) - ! - ! for each vertex vi in ek - li = ek - ilpmax = last(ek) - if (ilpmax <= 0) go to 12 - louter: do ilp = 1, ilpmax !11 - i = li - li = l(i) - vi = v(li) - ! - ! remove vi from degree list - if (last(vi) == 0) go to 3 - if (last(vi) > 0) go to 1 - head(-last(vi)) = next(vi) - go to 2 -1 next(last(vi)) = next(vi) -2 if (next(vi) > 0) last(next(vi)) = last(vi) - ! - ! remove inactive items from element list of vi -3 ls = vi -4 s = ls - ls = l(s) - if (ls == 0) go to 6 - es = v(ls) - if (mark(es) < tag) go to 5 - free = ls - l(s) = l(ls) - ls = s -5 go to 4 - ! - ! if vi is interior vertex, then remove from list and eliminate - -6 lvi = l(vi) - if (lvi.ne.0) go to 7 - l(i) = l(li) - li = i - ! - k = k + 1 - next(vi) = -k - last(ek) = last(ek) - 1 - cycle louter !11 - ! - ! else ... - ! classify vertex vi -7 if (l(lvi).ne.0) go to 9 - evi = v(lvi) - if (next(evi) >= 0) go to 9 - if (mark(evi) < 0) go to 8 - ! - ! if vi is prototype vertex, then mark as such, initialize - ! overlap count for corresponding element, and move vi to end - ! of boundary list - last(vi) = evi - mark(evi) = -1 - l(tail) = li - tail = li - l(i) = l(li) - li = i - go to 10 - ! - ! else if vi is duplicate vertex, then mark as such and adjust - ! overlap count for corresponding element -8 last(vi) = 0 - mark(evi) = mark(evi) - 1 - go to 10 - ! - ! else mark vi to compute degree -9 last(vi) = -ek - ! - ! insert ek in element list of vi -10 v(free) = ek - l(free) = l(vi) - l(vi) = free - end do louter !11 - ! - ! terminate boundary list -12 l(tail) = 0 - ! - return - end subroutine ims_mdp - - - subroutine ims_mdu(n, mmax, ek, dmin, v, l, head, last, next, mark) - ! - !*********************************************************************** - ! ims_mdu -- update degrees of uneliminated vertices in ek - !*********************************************************************** - implicit none - - ! -- dummy variables - integer(I4B), intent(in) :: n - integer(I4B), intent(in) :: mmax - integer(I4B), intent(in) :: ek - integer(I4B), intent(inout) :: dmin - integer(I4B), dimension(mmax), intent(inout) :: v - integer(I4B), dimension(mmax), intent(inout) :: l - integer(I4B), dimension(n), intent(inout) :: head - integer(I4B), dimension(n), intent(inout) :: last - integer(I4B), dimension(n), intent(inout) :: next - integer(I4B), dimension(n), intent(inout) :: mark - - ! -- local - integer(I4B) :: tag - integer(I4B) :: vi - integer(I4B) :: evi - integer(I4B) :: dvi - integer(I4B) :: s - integer(I4B) :: vs - integer(I4B) :: es - integer(I4B) :: b - integer(I4B) :: vb - integer(I4B) :: ilp - integer(I4B) :: ilpmax - integer(I4B) :: blp - integer(I4B) :: blpmax - integer(I4B) :: i - - equivalence (vs, es) - ! - ! initialize tag - tag = mark(ek) - last(ek) - ! - ! for each vertex vi in ek - i = ek - ilpmax = last(ek) - if (ilpmax <= 0) go to 11 - louter: do ilp = 1, ilpmax !10 - i = l(i) - vi = v(i) - !if (last(vi)) 1, 10, 8 - if (last(vi) == 0) cycle louter !10 - if (last(vi) > 0) goto 8 - ! - ! if vi neither prototype nor duplicate vertex, then merge elements - ! to compute degree - tag = tag + 1 - dvi = last(ek) - ! - ! for each vertex/element vs/es in element list of vi - s = l(vi) -2 s = l(s) - if (s == 0) go to 9 - vs = v(s) - if (next(vs) < 0) go to 3 - ! - ! if vs is uneliminated vertex, then tag and adjust degree - mark(vs) = tag - dvi = dvi + 1 - go to 5 - ! - ! if es is active element, then expand - ! check for outmatched vertex -3 if (mark(es) < 0) go to 6 - ! - ! for each vertex vb in es - b = es - blpmax = last(es) - linner: do blp = 1, blpmax !4 - b = l(b) - vb = v(b) - ! - ! if vb is untagged, then tag and adjust degree - if (mark(vb) >= tag) cycle linner !4 - mark(vb) = tag - dvi = dvi + 1 - end do linner !4 - ! -5 go to 2 - ! - ! else if vi is outmatched vertex, then adjust overlaps but do not - ! compute degree -6 last(vi) = 0 - mark(es) = mark(es) - 1 -7 s = l(s) - if (s == 0) cycle louter !10 - es = v(s) - if (mark(es) < 0) mark(es) = mark(es) - 1 - go to 7 - ! - ! else if vi is prototype vertex, then calculate degree by - ! inclusion/exclusion and reset overlap count -8 evi = last(vi) - dvi = last(ek) + last(evi) + mark(evi) - mark(evi) = 0 - ! - ! insert vi in appropriate degree list -9 next(vi) = head(dvi) - head(dvi) = vi - last(vi) = -dvi - if (next(vi) > 0) last(next(vi)) = vi - if (dvi < dmin) dmin = dvi - ! - end do louter !10 - ! -11 return - end subroutine ims_mdu - - end module IMSReorderingModule \ No newline at end of file diff --git a/src/Timing/ats.f90 b/src/Timing/ats.f90 index db895122e4d..1fca4d34010 100644 --- a/src/Timing/ats.f90 +++ b/src/Timing/ats.f90 @@ -3,7 +3,7 @@ ! Ensure ATS not specified for steady state period ! Add courant time step constraint and other stability controls for GWT model module AdaptiveTimeStepModule - + use KindModule, only: DP, I4B, LGP use SimVariablesModule, only: iout, errmsg, warnmsg use SimModule, only: store_error, count_errors, store_warning @@ -22,20 +22,20 @@ module AdaptiveTimeStepModule public :: ats_cr public :: ats_da - integer(I4B), pointer :: nper => null() !< set equal to nper - integer(I4B), pointer :: maxats => null() !< number of ats entries - real(DP), public, pointer :: dtstable => null() !< delt value required for stability - integer(I4B), dimension(:), pointer, contiguous :: kperats => null() !< array of stress period numbers to apply ats (size NPER) - integer(I4B), dimension(:), pointer, contiguous :: iperats => null() !< array of stress period numbers to apply ats (size MAXATS) - real(DP), dimension(:), pointer, contiguous :: dt0 => null() !< input array of initial time step sizes - real(DP), dimension(:), pointer, contiguous :: dtmin => null() !< input array of minimum time step sizes - real(DP), dimension(:), pointer, contiguous :: dtmax => null() !< input array of maximum time step sizes - real(DP), dimension(:), pointer, contiguous :: dtadj => null() !< input array of time step factors for shortening or increasing - real(DP), dimension(:), pointer, contiguous :: dtfailadj => null() !< input array of time step factors for shortening due to nonconvergence - type(BlockParserType) :: parser !< block parser for reading input file - - contains - + integer(I4B), pointer :: nper => null() !< set equal to nper + integer(I4B), pointer :: maxats => null() !< number of ats entries + real(DP), public, pointer :: dtstable => null() !< delt value required for stability + integer(I4B), dimension(:), pointer, contiguous :: kperats => null() !< array of stress period numbers to apply ats (size NPER) + integer(I4B), dimension(:), pointer, contiguous :: iperats => null() !< array of stress period numbers to apply ats (size MAXATS) + real(DP), dimension(:), pointer, contiguous :: dt0 => null() !< input array of initial time step sizes + real(DP), dimension(:), pointer, contiguous :: dtmin => null() !< input array of minimum time step sizes + real(DP), dimension(:), pointer, contiguous :: dtmax => null() !< input array of maximum time step sizes + real(DP), dimension(:), pointer, contiguous :: dtadj => null() !< input array of time step factors for shortening or increasing + real(DP), dimension(:), pointer, contiguous :: dtfailadj => null() !< input array of time step factors for shortening due to nonconvergence + type(BlockParserType) :: parser !< block parser for reading input file + +contains + !> @ brief Determine if period is adaptive !! !! Check settings and determine if kper is an adaptive @@ -53,7 +53,7 @@ function isAdaptivePeriod(kper) result(lv) end if return end function isAdaptivePeriod - + !> @ brief Create ATS object !! !! Create a new ATS object, and read and check input. @@ -66,7 +66,7 @@ subroutine ats_cr(inunit, nper_tdis) integer(I4B), intent(in) :: nper_tdis ! -- local ! -- formats - character(len=*),parameter :: fmtheader = & + character(len=*), parameter :: fmtheader = & "(1X,/1X,'ATS -- ADAPTIVE TIME STEP PACKAGE,', / & &' VERSION 1 : 03/18/2021 - INPUT READ FROM UNIT ',I0)" ! @@ -74,7 +74,7 @@ subroutine ats_cr(inunit, nper_tdis) call ats_allocate_scalars() ! ! -- Identify package - write(iout, fmtheader) inunit + write (iout, fmtheader) inunit ! ! -- Initialize block parser call parser%initialize(inunit, iout) @@ -110,7 +110,7 @@ end subroutine ats_cr !> @ brief Allocate scalars !! - !! Allocate and initialize scalars for the ATS package. + !! Allocate and initialize scalars for the ATS package. !! !< subroutine ats_allocate_scalars() @@ -130,10 +130,10 @@ subroutine ats_allocate_scalars() ! -- return return end subroutine ats_allocate_scalars - + !> @ brief Allocate arrays !! - !! Allocate and initialize arrays for the ATS package. + !! Allocate and initialize arrays for the ATS package. !! !< subroutine ats_allocate_arrays() @@ -171,7 +171,7 @@ end subroutine ats_allocate_arrays !> @ brief Deallocate variables !! - !! Deallocate all ATS variables. + !! Deallocate all ATS variables. !! !< subroutine ats_da() @@ -197,7 +197,7 @@ end subroutine ats_da !> @ brief Read options !! - !! Read options from ATS input file. + !! Read options from ATS input file. !! !< subroutine ats_read_options() @@ -210,33 +210,33 @@ subroutine ats_read_options() ! ! -- get options block call parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING ATS OPTIONS' + write (iout, '(1x,a)') 'PROCESSING ATS OPTIONS' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN ATS OPTION: ', & - trim(keyword) + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN ATS OPTION: ', & + trim(keyword) call store_error(errmsg) call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)') 'END OF ATS OPTIONS' + write (iout, '(1x,a)') 'END OF ATS OPTIONS' end if ! ! -- Return return end subroutine ats_read_options - + !> @ brief Read dimensions !! - !! Read dimensions from ATS input file. + !! Read dimensions from ATS input file. !! !< subroutine ats_read_dimensions() @@ -247,33 +247,33 @@ subroutine ats_read_dimensions() logical :: isfound, endOfBlock ! -- formats character(len=*), parameter :: fmtmaxats = & - "(1X,I0,' ADAPTIVE TIME STEP RECORDS(S) WILL FOLLOW IN PERIODDATA')" + &"(1X,I0,' ADAPTIVE TIME STEP RECORDS(S) WILL FOLLOW IN PERIODDATA')" ! ! -- get DIMENSIONS block call parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING ATS DIMENSIONS' + write (iout, '(1x,a)') 'PROCESSING ATS DIMENSIONS' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('MAXATS') - maxats = parser%GetInteger() - write(iout, fmtmaxats) maxats - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN ATS DIMENSION: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case ('MAXATS') + maxats = parser%GetInteger() + write (iout, fmtmaxats) maxats + case default + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN ATS DIMENSION: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)') 'END OF ATS DIMENSIONS' + write (iout, '(1x,a)') 'END OF ATS DIMENSIONS' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if @@ -281,10 +281,10 @@ subroutine ats_read_dimensions() ! -- Return return end subroutine ats_read_dimensions - + !> @ brief Read timing !! - !! Read timing information from ATS input file. + !! Read timing information from ATS input file. !! !< subroutine ats_read_timing() @@ -298,11 +298,11 @@ subroutine ats_read_timing() ! ! -- get PERIODDATA block call parser%GetBlock('PERIODDATA', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse block if detected if (isfound) then - write(iout,'(1x,a)')'READING ATS PERIODDATA' + write (iout, '(1x,a)') 'READING ATS PERIODDATA' do n = 1, maxats call parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -314,18 +314,18 @@ subroutine ats_read_timing() dtmax(n) = parser%GetDouble() dtadj(n) = parser%GetDouble() dtfailadj(n) = parser%GetDouble() - enddo + end do ! ! -- Close the block call parser%terminateblock() ! ! -- Check for errors - if(count_errors() > 0) then + if (count_errors() > 0) then call parser%StoreErrorUnit() - endif - write(iout,'(1x,a)') 'END READING ATS PERIODDATA' + end if + write (iout, '(1x,a)') 'END READING ATS PERIODDATA' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED PERIODDATA BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED PERIODDATA BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if @@ -333,10 +333,10 @@ subroutine ats_read_timing() ! -- Return return end subroutine ats_read_timing - + !> @ brief Process input !! - !! Process ATS input by filling the kperats array. + !! Process ATS input by filling the kperats array. !! !< subroutine ats_process_input() @@ -351,10 +351,10 @@ subroutine ats_process_input() end if end do end subroutine ats_process_input - + !> @ brief Write input table !! - !! Write a table showing the ATS input read from the perioddata block. + !! Write a table showing the ATS input read from the perioddata block. !! !< subroutine ats_input_table() @@ -392,35 +392,35 @@ subroutine ats_input_table() call inputtab%add_term(dtmax(n)) call inputtab%add_term(dtadj(n)) call inputtab%add_term(dtfailadj(n)) - end do + end do ! ! -- deallocate the table call inputtab%table_da() - deallocate(inputtab) - nullify(inputtab) + deallocate (inputtab) + nullify (inputtab) return end subroutine ats_input_table - + !> @ brief Check timing !! !! Perform a check on the input data to make sure values are within - !! required ranges. + !! required ranges. !! !< subroutine ats_check_timing() integer(I4B) :: n - write(iout,'(1x,a)') 'PROCESSING ATS INPUT' + write (iout, '(1x,a)') 'PROCESSING ATS INPUT' do n = 1, maxats ! ! -- check iperats if (iperats(n) < 1) then - write(errmsg, '(a, i0, a, i0)') & + write (errmsg, '(a, i0, a, i0)') & 'IPERATS MUST BE GREATER THAN ZERO. FOUND ', iperats(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) end if if (iperats(n) > nper) then - write(warnmsg, '(a, i0, a, i0)') & + write (warnmsg, '(a, i0, a, i0)') & 'IPERATS GREATER THAN NPER. FOUND ', iperats(n), & ' FOR ATS PERIODDATA RECORD ', n call store_warning(warnmsg) @@ -428,7 +428,7 @@ subroutine ats_check_timing() ! ! -- check dt0 if (dt0(n) < DZERO) then - write(errmsg, '(a, g15.7, a, i0)') & + write (errmsg, '(a, g15.7, a, i0)') & 'DT0 MUST BE >= ZERO. FOUND ', dt0(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) @@ -436,7 +436,7 @@ subroutine ats_check_timing() ! ! -- check dtmin if (dtmin(n) <= DZERO) then - write(errmsg, '(a, g15.7, a, i0)') & + write (errmsg, '(a, g15.7, a, i0)') & 'DTMIN MUST BE > ZERO. FOUND ', dtmin(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) @@ -444,7 +444,7 @@ subroutine ats_check_timing() ! ! -- check dtmax if (dtmax(n) <= DZERO) then - write(errmsg, '(a, g15.7, a, i0)') & + write (errmsg, '(a, g15.7, a, i0)') & 'DTMAX MUST BE > ZERO. FOUND ', dtmax(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) @@ -452,7 +452,7 @@ subroutine ats_check_timing() ! ! -- check dtmin <= dtmax if (dtmin(n) > dtmax(n)) then - write(errmsg, '(a, 2g15.7, a, i0)') & + write (errmsg, '(a, 2g15.7, a, i0)') & 'DTMIN MUST BE < DTMAX. FOUND ', dtmin(n), dtmax(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) @@ -460,7 +460,7 @@ subroutine ats_check_timing() ! ! -- check dtadj if (dtadj(n) .ne. DZERO .and. dtadj(n) < DONE) then - write(errmsg, '(a, g15.7, a, i0)') & + write (errmsg, '(a, g15.7, a, i0)') & 'DTADJ MUST BE 0 or >= 1.0. FOUND ', dtadj(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) @@ -468,25 +468,25 @@ subroutine ats_check_timing() ! ! -- check dtfailadj if (dtfailadj(n) .ne. DZERO .and. dtfailadj(n) < DONE) then - write(errmsg, '(a, g15.7, a, i0)') & + write (errmsg, '(a, g15.7, a, i0)') & 'DTFAILADJ MUST BE 0 or >= 1.0. FOUND ', dtfailadj(n), & ' FOR ATS PERIODDATA RECORD ', n call store_error(errmsg) end if - + end do ! ! -- Check for errors - if(count_errors() > 0) then + if (count_errors() > 0) then call parser%StoreErrorUnit() - endif - write(iout,'(1x,a)') 'DONE PROCESSING ATS INPUT' + end if + write (iout, '(1x,a)') 'DONE PROCESSING ATS INPUT' end subroutine ats_check_timing - + !> @ brief Write period message !! !! Write message to mfsim.lst file with information on ATS settings - !! for this period. + !! for this period. !! !< subroutine ats_period_message(kper) @@ -494,7 +494,7 @@ subroutine ats_period_message(kper) integer(I4B), intent(in) :: kper ! -- local integer(I4B) :: n - character(len=*),parameter :: fmtspts = & + character(len=*), parameter :: fmtspts = & "(28X,'ATS IS OVERRIDING TIME STEPPING FOR THIS PERIOD',/ & &28X,'INITIAL TIME STEP SIZE (DT0) = ',G15.7,/ & &28X,'MINIMUM TIME STEP SIZE (DTMIN) = ',G15.7,/ & @@ -503,10 +503,10 @@ subroutine ats_period_message(kper) &28X,'DIVIDER FOR FAILED TIME STEP (DTFAILADJ) = ',G15.7,/ & &)" n = kperats(kper) - write(iout, fmtspts) dt0(n), dtmin(n), dtmax(n), dtadj(n), dtfailadj(n) + write (iout, fmtspts) dt0(n), dtmin(n), dtmax(n), dtadj(n), dtfailadj(n) return end subroutine ats_period_message - + !> @ brief Allow and external caller to submit preferred time step !! !! Submit a preferred time step length. Alternatively, if idir is @@ -524,9 +524,9 @@ subroutine ats_submit_delt(kstp, kper, dt, sloc, idir) integer(I4B) :: n real(DP) :: tsfact real(DP) :: dt_temp - character(len=*), parameter :: fmtdtsubmit = & + character(len=*), parameter :: fmtdtsubmit = & &"(1x, 'ATS: ', A,' submitted a preferred time step size of ', G15.7)" - + if (isAdaptivePeriod(kper)) then n = kperats(kper) tsfact = dtadj(n) @@ -546,7 +546,7 @@ subroutine ats_submit_delt(kstp, kper, dt, sloc, idir) dt_temp = dt end if if (kstp > 1 .and. dt_temp > DZERO) then - write(iout, fmtdtsubmit) trim(adjustl(sloc)), dt_temp + write (iout, fmtdtsubmit) trim(adjustl(sloc)), dt_temp end if if (dt_temp > DZERO .and. dt_temp < dtstable) then ! -- Reset dtstable to a smaller value @@ -556,7 +556,7 @@ subroutine ats_submit_delt(kstp, kper, dt, sloc, idir) end if return end subroutine ats_submit_delt - + !> @ brief Set time step !! !! Set the time step length (delt) for this time step using the ATS @@ -575,8 +575,8 @@ subroutine ats_set_delt(kstp, kper, pertim, perlencurrent, delt) integer(I4B) :: n real(DP) :: tstart ! -- formats - character(len=*), parameter :: fmtdt = & - &"(1x, 'ATS: time step set to ', G15.7, ' for step ', i0, & + character(len=*), parameter :: fmtdt = & + "(1x, 'ATS: time step set to ', G15.7, ' for step ', i0, & &' and period ', i0)" ! ! -- initialize the record position (n) for this stress period @@ -588,7 +588,7 @@ subroutine ats_set_delt(kstp, kper, pertim, perlencurrent, delt) ! -- Calculate delt ! ! -- Setup new stress period if kstp is 1 - if(kstp == 1) then + if (kstp == 1) then ! ! -- Assign first value of delt for this stress period if (dt0(n) /= DZERO) then @@ -619,11 +619,11 @@ subroutine ats_set_delt(kstp, kper, pertim, perlencurrent, delt) end if ! ! -- Write time step size information - write(iout, fmtdt) delt, kstp, kper + write (iout, fmtdt) delt, kstp, kper ! return end subroutine ats_set_delt - + !> @ brief Reset time step because failure has occurred !! !! Reset the time step using dtfailadj because the time step @@ -643,7 +643,7 @@ subroutine ats_reset_delt(kstp, kper, lastStepFailed, delt, finishedTrying) real(DP) :: delt_temp real(DP) :: tsfact ! -- formats - character(len=*),parameter :: fmttsi = & + character(len=*), parameter :: fmttsi = & "(1X, 'Failed solution for step ', i0, ' and period ', i0, & &' will be retried using time step of ', G15.7)" if (isAdaptivePeriod(kper)) then @@ -656,15 +656,15 @@ subroutine ats_reset_delt(kstp, kper, lastStepFailed, delt, finishedTrying) if (delt_temp >= dtmin(n)) then finishedTrying = .false. delt = delt_temp - write(iout, fmttsi) kstp, kper, delt + write (iout, fmttsi) kstp, kper, delt end if end if - + end if end if return end subroutine ats_reset_delt - + !> @ brief Set end of period indicator !! !! Determine if it is the end of the stress period and set the endofperiod @@ -679,12 +679,12 @@ subroutine ats_set_endofperiod(kper, pertim, perlencurrent, endofperiod) ! -- local integer(I4B) :: n ! - ! -- End of stress period and/or simulation? + ! -- End of stress period and/or simulation? n = kperats(kper) if (abs(pertim - perlencurrent) < dtmin(n)) then endofperiod = .true. end if return end subroutine ats_set_endofperiod - -end module AdaptiveTimeStepModule \ No newline at end of file + +end module AdaptiveTimeStepModule diff --git a/src/Timing/tdis.f90 b/src/Timing/tdis.f90 index ad09a2b99cb..01c631ac8fd 100644 --- a/src/Timing/tdis.f90 +++ b/src/Timing/tdis.f90 @@ -2,7 +2,7 @@ !convert this to a derived type? May not be necessary since only !one of them is needed. - module TdisModule +module TdisModule use KindModule, only: DP, I4B, LGP use SimVariablesModule, only: iout @@ -19,30 +19,30 @@ module TdisModule public :: tdis_ot public :: tdis_da ! - integer(I4B), public, pointer :: nper => null() !< number of stress period - integer(I4B), public, pointer :: itmuni => null() !< flag indicating time units - integer(I4B), public, pointer :: kper => null() !< current stress period number - integer(I4B), public, pointer :: kstp => null() !< current time step number - integer(I4B), public, pointer :: inats => null() !< flag indicating ats active for simulation - logical(LGP), public, pointer :: readnewdata => null() !< flag indicating time to read new data - logical(LGP), public, pointer :: endofperiod => null() !< flag indicating end of stress period - logical(LGP), public, pointer :: endofsimulation => null() !< flag indicating end of simulation - real(DP), public, pointer :: delt => null() !< length of the current time step - real(DP), public, pointer :: pertim => null() !< time relative to start of stress period - real(DP), public, pointer :: totim => null() !< time relative to start of simulation - real(DP), public, pointer :: totimc => null() !< simulation time at start of time step - real(DP), public, pointer :: deltsav => null() !< saved value for delt, used for subtiming - real(DP), public, pointer :: totimsav => null() !< saved value for totim, used for subtiming - real(DP), public, pointer :: pertimsav => null() !< saved value for pertim, used for subtiming - real(DP), public, pointer :: totalsimtime => null() !< time at end of simulation - real(DP), public, dimension(:), pointer, contiguous :: perlen => null() !< length of each stress period - integer(I4B), public, dimension(:), pointer, contiguous :: nstp => null() !< number of time steps in each stress period - real(DP), public, dimension(:), pointer, contiguous :: tsmult => null() !< time step multiplier for each stress period - character(len=LENDATETIME), pointer :: datetime0 => null() !< starting date and time for the simulation + integer(I4B), public, pointer :: nper => null() !< number of stress period + integer(I4B), public, pointer :: itmuni => null() !< flag indicating time units + integer(I4B), public, pointer :: kper => null() !< current stress period number + integer(I4B), public, pointer :: kstp => null() !< current time step number + integer(I4B), public, pointer :: inats => null() !< flag indicating ats active for simulation + logical(LGP), public, pointer :: readnewdata => null() !< flag indicating time to read new data + logical(LGP), public, pointer :: endofperiod => null() !< flag indicating end of stress period + logical(LGP), public, pointer :: endofsimulation => null() !< flag indicating end of simulation + real(DP), public, pointer :: delt => null() !< length of the current time step + real(DP), public, pointer :: pertim => null() !< time relative to start of stress period + real(DP), public, pointer :: totim => null() !< time relative to start of simulation + real(DP), public, pointer :: totimc => null() !< simulation time at start of time step + real(DP), public, pointer :: deltsav => null() !< saved value for delt, used for subtiming + real(DP), public, pointer :: totimsav => null() !< saved value for totim, used for subtiming + real(DP), public, pointer :: pertimsav => null() !< saved value for pertim, used for subtiming + real(DP), public, pointer :: totalsimtime => null() !< time at end of simulation + real(DP), public, dimension(:), pointer, contiguous :: perlen => null() !< length of each stress period + integer(I4B), public, dimension(:), pointer, contiguous :: nstp => null() !< number of time steps in each stress period + real(DP), public, dimension(:), pointer, contiguous :: tsmult => null() !< time step multiplier for each stress period + character(len=LENDATETIME), pointer :: datetime0 => null() !< starting date and time for the simulation ! type(BlockParserType), private :: parser - contains +contains subroutine tdis_cr(fname) ! ****************************************************************************** @@ -60,7 +60,7 @@ subroutine tdis_cr(fname) ! -- local integer(I4B) :: inunit ! -- formats - character(len=*),parameter :: fmtheader = & + character(len=*), parameter :: fmtheader = & "(1X,/1X,'TDIS -- TEMPORAL DISCRETIZATION PACKAGE,', / & &' VERSION 1 : 11/13/2014 - INPUT READ FROM UNIT ',I4)" ! ------------------------------------------------------------------------------ @@ -69,14 +69,14 @@ subroutine tdis_cr(fname) call tdis_allocate_scalars() ! ! -- Get a unit number for tdis and open the file if it is not opened - inquire(file=fname, number=inunit) - if(inunit < 0) then + inquire (file=fname, number=inunit) + if (inunit < 0) then inunit = getunit() call openfile(inunit, iout, fname, 'TDIS') - endif + end if ! ! -- Identify package - write(iout, fmtheader) inunit + write (iout, fmtheader) inunit ! ! -- Initialize block parser call parser%Initialize(inunit, iout) @@ -113,23 +113,23 @@ subroutine tdis_set_counters() use ConstantsModule, only: DONE, DZERO, MNORMAL, MVALIDATE, DNODATA use SimVariablesModule, only: isim_mode use GenericUtilitiesModule, only: sim_message - use AdaptiveTimeStepModule, only: isAdaptivePeriod, dtstable, & + use AdaptiveTimeStepModule, only: isAdaptivePeriod, dtstable, & ats_period_message ! -- local character(len=LINELENGTH) :: line character(len=4) :: cpref character(len=10) :: cend ! -- formats - character(len=*),parameter :: fmtspts = & - "(a, 'Solving: Stress period: ',i5,4x, 'Time step: ',i5,4x, a)" - character(len=*),parameter :: fmtvspts = & - "(' Validating: Stress period: ',i5,4x,'Time step: ',i5,4x)" - character(len=*),parameter :: fmtspi = & - "('1',/28X,'STRESS PERIOD NO. ',I0,', LENGTH =',G15.7,/ & - &28X,47('-'))" - character(len=*),parameter :: fmtspits = & - "(28X,'NUMBER OF TIME STEPS = ',I0,/ & - &28X,'MULTIPLIER FOR DELT =',F10.3)" + character(len=*), parameter :: fmtspts = & + &"(a, 'Solving: Stress period: ',i5,4x, 'Time step: ',i5,4x, a)" + character(len=*), parameter :: fmtvspts = & + &"(' Validating: Stress period: ',i5,4x,'Time step: ',i5,4x)" + character(len=*), parameter :: fmtspi = & + "('1',/28X,'STRESS PERIOD NO. ',I0,', LENGTH =',G15.7,/ & + &28X,47('-'))" + character(len=*), parameter :: fmtspits = & + "(28X,'NUMBER OF TIME STEPS = ',I0,/ & + &28X,'MULTIPLIER FOR DELT =',F10.3)" ! ------------------------------------------------------------------------------ ! ! -- Initialize variables for this step @@ -148,29 +148,29 @@ subroutine tdis_set_counters() end if ! ! -- Print stress period and time step to console - select case(isim_mode) - case(MVALIDATE) - write(line, fmtvspts) kper, kstp - case(MNORMAL) - write(line, fmtspts) cpref, kper, kstp, trim(cend) + select case (isim_mode) + case (MVALIDATE) + write (line, fmtvspts) kper, kstp + case (MNORMAL) + write (line, fmtspts) cpref, kper, kstp, trim(cend) end select call sim_message(line, level=VALL) call sim_message(line, iunit=iout, skipbefore=1, skipafter=1) ! ! -- Write message if first time step if (kstp == 1) then - write(iout, fmtspi) kper, perlen(kper) + write (iout, fmtspi) kper, perlen(kper) if (isAdaptivePeriod(kper)) then call ats_period_message(kper) else - write(iout, fmtspits) nstp(kper), tsmult(kper) + write (iout, fmtspits) nstp(kper), tsmult(kper) end if end if ! ! -- return return end subroutine tdis_set_counters - + subroutine tdis_set_timestep() ! ****************************************************************************** ! tdis_set_timestep -- Set time step length @@ -186,8 +186,8 @@ subroutine tdis_set_timestep() ! -- local logical(LGP) :: adaptivePeriod ! -- format - character(len=*), parameter :: fmttsi = & - "(28X,'INITIAL TIME STEP SIZE =',G15.7)" + character(len=*), parameter :: fmttsi = & + "(28X,'INITIAL TIME STEP SIZE =',G15.7)" ! ------------------------------------------------------------------------------ ! ! -- Initialize @@ -202,7 +202,7 @@ subroutine tdis_set_timestep() else call tdis_set_delt() if (kstp == 1) then - write(iout, fmttsi) delt + write (iout, fmttsi) delt end if end if ! @@ -227,7 +227,7 @@ subroutine tdis_set_timestep() end if ! ! -- Set end of simulation indicator - if (endofperiod .and. kper==nper) then + if (endofperiod .and. kper == nper) then endofsimulation = .true. totim = totalsimtime end if @@ -240,7 +240,7 @@ subroutine tdis_delt_reset(deltnew) ! ****************************************************************************** ! tdis_delt_reset -- reset delt and update timing variables and indicators. ! This routine is called when a timestep fails to converge, and so it is -! retried using a smaller time step (deltnew). +! retried using a smaller time step (deltnew). ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -273,7 +273,7 @@ subroutine tdis_delt_reset(deltnew) end if ! ! -- Set end of simulation indicator - if (endofperiod .and. kper==nper) then + if (endofperiod .and. kper == nper) then endofsimulation = .true. totim = totalsimtime end if @@ -294,11 +294,11 @@ subroutine tdis_set_delt() ! -- local ! ------------------------------------------------------------------------------ ! - if(kstp == 1) then + if (kstp == 1) then delt = perlen(kper) / float(nstp(kper)) - if(tsmult(kper) /= DONE) & - delt = perlen(kper) * (DONE-tsmult(kper)) / & - (DONE - tsmult(kper) ** nstp(kper)) + if (tsmult(kper) /= DONE) & + delt = perlen(kper) * (DONE - tsmult(kper)) / & + (DONE - tsmult(kper)**nstp(kper)) else delt = tsmult(kper) * delt end if @@ -317,7 +317,7 @@ end subroutine tdis_set_delt ! ! -- modules ! use ConstantsModule, only: DONE, DZERO ! ! -- formats -! character(len=*),parameter :: fmttsi = & +! character(len=*),parameter :: fmttsi = & ! "(28X,'INITIAL TIME STEP SIZE =',G15.7)" !! ------------------------------------------------------------------------------ ! ! @@ -326,8 +326,8 @@ end subroutine tdis_set_delt ! ! ! ! -- Calculate the first value of delt for this stress period ! delt = perlen(kper) / float(nstp(kper)) -! if(tsmult(kper) /= DONE) & -! delt = perlen(kper) * (DONE-tsmult(kper)) / & +! if(tsmult(kper) /= DONE) & +! delt = perlen(kper) * (DONE-tsmult(kper)) / & ! (DONE - tsmult(kper) ** nstp(kper)) ! ! ! ! -- Print length of first time step @@ -360,7 +360,7 @@ end subroutine tdis_set_delt ! end if ! if (endofperiod .and. kper==nper) then ! endofsimulation = .true. -! totim = totalsimtime +! totim = totalsimtime ! end if ! ! ! ! -- return @@ -374,73 +374,73 @@ subroutine tdis_ot(iout) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- dummy - integer(I4B), intent(in) :: iout - ! -- local - real(DP) :: zero,cnv,delsec,totsec,persec,sixty,hrday,dayyr, & - delmn,delhr,totmn,tothr,totdy,totyr,permn,perhr,perdy, & - peryr,deldy,delyr + ! -- dummy + integer(I4B), intent(in) :: iout + ! -- local + real(DP) :: zero, cnv, delsec, totsec, persec, sixty, hrday, dayyr, & + delmn, delhr, totmn, tothr, totdy, totyr, permn, perhr, & + perdy, peryr, deldy, delyr ! ------------------------------------------------------------------------------ - WRITE(IOUT,199) KSTP,KPER - 199 FORMAT(1X,///9X,'TIME SUMMARY AT END OF TIME STEP',I5, & - & ' IN STRESS PERIOD ',I4) + WRITE (IOUT, 199) KSTP, KPER +199 FORMAT(1X, ///9X, 'TIME SUMMARY AT END OF TIME STEP', I5, & + & ' IN STRESS PERIOD ', I4) !C !C1------USE TIME UNIT INDICATOR TO GET FACTOR TO CONVERT TO SECONDS. - ZERO=0.d0 - CNV=ZERO - IF(ITMUNI.EQ.1) CNV=1. - IF(ITMUNI.EQ.2) CNV=60. - IF(ITMUNI.EQ.3) CNV=3600. - IF(ITMUNI.EQ.4) CNV=86400. - IF(ITMUNI.EQ.5) CNV=31557600. + ZERO = 0.d0 + CNV = ZERO + IF (ITMUNI .EQ. 1) CNV = 1. + IF (ITMUNI .EQ. 2) CNV = 60. + IF (ITMUNI .EQ. 3) CNV = 3600. + IF (ITMUNI .EQ. 4) CNV = 86400. + IF (ITMUNI .EQ. 5) CNV = 31557600. !C !C2------IF FACTOR=0 THEN TIME UNITS ARE NON-STANDARD. - IF(CNV.NE.ZERO) GO TO 100 + IF (CNV .NE. ZERO) GO TO 100 !C !C2A-----PRINT TIMES IN NON-STANDARD TIME UNITS. - WRITE(IOUT,301) DELT,PERTIM,TOTIM - 301 FORMAT(21X,' TIME STEP LENGTH =',G15.6/ & - & 21X,' STRESS PERIOD TIME =',G15.6/ & - & 21X,'TOTAL SIMULATION TIME =',G15.6) + WRITE (IOUT, 301) DELT, PERTIM, TOTIM +301 FORMAT(21X, ' TIME STEP LENGTH =', G15.6 / & + & 21X, ' STRESS PERIOD TIME =', G15.6 / & + & 21X, 'TOTAL SIMULATION TIME =', G15.6) !C !C2B-----RETURN - RETURN + RETURN !C !C3------CALCULATE LENGTH OF TIME STEP & ELAPSED TIMES IN SECONDS. - 100 DELSEC=CNV*DELT - TOTSEC=CNV*TOTIM - PERSEC=CNV*PERTIM +100 DELSEC = CNV * DELT + TOTSEC = CNV * TOTIM + PERSEC = CNV * PERTIM !C !C4------CALCULATE TIMES IN MINUTES,HOURS,DAYS AND YEARS. - SIXTY=60. - HRDAY=24. - DAYYR=365.25 - DELMN=DELSEC/SIXTY - DELHR=DELMN/SIXTY - DELDY=DELHR/HRDAY - DELYR=DELDY/DAYYR - TOTMN=TOTSEC/SIXTY - TOTHR=TOTMN/SIXTY - TOTDY=TOTHR/HRDAY - TOTYR=TOTDY/DAYYR - PERMN=PERSEC/SIXTY - PERHR=PERMN/SIXTY - PERDY=PERHR/HRDAY - PERYR=PERDY/DAYYR + SIXTY = 60. + HRDAY = 24. + DAYYR = 365.25 + DELMN = DELSEC / SIXTY + DELHR = DELMN / SIXTY + DELDY = DELHR / HRDAY + DELYR = DELDY / DAYYR + TOTMN = TOTSEC / SIXTY + TOTHR = TOTMN / SIXTY + TOTDY = TOTHR / HRDAY + TOTYR = TOTDY / DAYYR + PERMN = PERSEC / SIXTY + PERHR = PERMN / SIXTY + PERDY = PERHR / HRDAY + PERYR = PERDY / DAYYR !C !C5------PRINT TIME STEP LENGTH AND ELAPSED TIMES IN ALL TIME UNITS. - WRITE(IOUT,200) - 200 FORMAT(19X,' SECONDS MINUTES HOURS',7X, & - & 'DAYS YEARS'/20X,59('-')) - write(IOUT,201) DELSEC,DELMN,DELHR,DELDY,DELYR - 201 FORMAT(1X,' TIME STEP LENGTH',1P,5G12.5) - WRITE(IOUT,202) PERSEC,PERMN,PERHR,PERDY,PERYR - 202 FORMAT(1X,'STRESS PERIOD TIME',1P,5G12.5) - WRITE(IOUT,203) TOTSEC,TOTMN,TOTHR,TOTDY,TOTYR - 203 FORMAT(1X,' TOTAL TIME',1P,5G12.5,/) + WRITE (IOUT, 200) +200 FORMAT(19X, ' SECONDS MINUTES HOURS', 7X, & + & 'DAYS YEARS'/20X, 59('-')) + write (IOUT, 201) DELSEC, DELMN, DELHR, DELDY, DELYR +201 FORMAT(1X, ' TIME STEP LENGTH', 1P, 5G12.5) + WRITE (IOUT, 202) PERSEC, PERMN, PERHR, PERDY, PERYR +202 FORMAT(1X, 'STRESS PERIOD TIME', 1P, 5G12.5) + WRITE (IOUT, 203) TOTSEC, TOTMN, TOTHR, TOTDY, TOTYR +203 FORMAT(1X, ' TOTAL TIME', 1P, 5G12.5,/) !C !C6------RETURN - RETURN + RETURN END subroutine tdis_ot subroutine tdis_da() @@ -475,7 +475,7 @@ subroutine tdis_da() call mem_deallocate(totalsimtime) ! ! -- strings - deallocate(datetime0) + deallocate (datetime0) ! ! -- Arrays call mem_deallocate(perlen) @@ -486,7 +486,6 @@ subroutine tdis_da() return end subroutine tdis_da - subroutine tdis_read_options() ! ****************************************************************************** ! tdis_read_options -- Read the options @@ -505,9 +504,9 @@ subroutine tdis_read_options() logical :: undspec ! -- formats character(len=*), parameter :: fmtitmuni = & - "(4x,'SIMULATION TIME UNIT IS ',A)" + &"(4x,'SIMULATION TIME UNIT IS ',A)" character(len=*), parameter :: fmtdatetime0 = & - "(4x,'SIMULATION STARTING DATE AND TIME IS ',A)" + &"(4x,'SIMULATION STARTING DATE AND TIME IS ',A)" !data ! ------------------------------------------------------------------------------ ! @@ -517,11 +516,11 @@ subroutine tdis_read_options() ! ! -- get options block call parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING TDIS OPTIONS' + write (iout, '(1x,a)') 'PROCESSING TDIS OPTIONS' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -530,60 +529,60 @@ subroutine tdis_read_options() case ('TIME_UNITS') call parser%GetStringCaps(keyword) select case (keyword) - case('UNDEFINED') + case ('UNDEFINED') itmuni = 0 - write(iout, fmtitmuni) 'UNDEFINED' + write (iout, fmtitmuni) 'UNDEFINED' undspec = .true. - case('SECONDS') + case ('SECONDS') itmuni = 1 - write(iout, fmtitmuni) 'SECONDS' - case('MINUTES') + write (iout, fmtitmuni) 'SECONDS' + case ('MINUTES') itmuni = 2 - write(iout, fmtitmuni) 'MINUTES' - case('HOURS') + write (iout, fmtitmuni) 'MINUTES' + case ('HOURS') itmuni = 3 - write(iout, fmtitmuni) 'HOURS' - case('DAYS') + write (iout, fmtitmuni) 'HOURS' + case ('DAYS') itmuni = 4 - write(iout, fmtitmuni) 'DAYS' - case('YEARS') + write (iout, fmtitmuni) 'DAYS' + case ('YEARS') itmuni = 5 - write(iout, fmtitmuni) 'YEARS' + write (iout, fmtitmuni) 'YEARS' case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN TIME_UNITS: ', & - trim(keyword) + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN TIME_UNITS: ', & + trim(keyword) call store_error(errmsg) call parser%StoreErrorUnit() end select case ('START_DATE_TIME') call parser%GetString(datetime0) - write(iout, fmtdatetime0) datetime0 + write (iout, fmtdatetime0) datetime0 case ('ATS6') call parser%GetStringCaps(keyword) - if(trim(adjustl(keyword)) /= 'FILEIN') then - errmsg = 'ATS6 keyword must be followed by "FILEIN" ' // & - 'then by filename.' + if (trim(adjustl(keyword)) /= 'FILEIN') then + errmsg = 'ATS6 keyword must be followed by "FILEIN" '// & + 'then by filename.' call store_error(errmsg) - endif + end if call parser%GetString(fname) inats = GetUnit() call openfile(inats, iout, fname, 'ATS') case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN TDIS OPTION: ', & - trim(keyword) + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN TDIS OPTION: ', & + trim(keyword) call store_error(errmsg) call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)') 'END OF TDIS OPTIONS' + write (iout, '(1x,a)') 'END OF TDIS OPTIONS' end if ! ! -- Set to itmuni to undefined if not specified - if(itmuni == 0) then - if(.not. undspec) then - write(iout, fmtitmuni) 'UNDEFINED' - endif - endif + if (itmuni == 0) then + if (.not. undspec) then + write (iout, fmtitmuni) 'UNDEFINED' + end if + end if ! ! -- Return return @@ -620,7 +619,7 @@ subroutine tdis_allocate_scalars() call mem_allocate(totalsimtime, 'TOTALSIMTIME', 'TDIS') ! ! -- strings - allocate(datetime0) + allocate (datetime0) ! ! -- Initialize variables nper = 0 @@ -645,7 +644,6 @@ subroutine tdis_allocate_scalars() return end subroutine tdis_allocate_scalars - subroutine tdis_allocate_arrays() ! ****************************************************************************** ! tdis_allocate_arrays -- Allocate tdis arrays @@ -681,35 +679,35 @@ subroutine tdis_read_dimensions() logical :: isfound, endOfBlock ! -- formats character(len=*), parameter :: fmtnper = & - "(1X,I4,' STRESS PERIOD(S) IN SIMULATION')" + "(1X,I4,' STRESS PERIOD(S) IN SIMULATION')" !data ! ------------------------------------------------------------------------------ ! ! -- get DIMENSIONS block call parser%GetBlock('DIMENSIONS', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING TDIS DIMENSIONS' + write (iout, '(1x,a)') 'PROCESSING TDIS DIMENSIONS' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('NPER') - nper = parser%GetInteger() - write(iout, fmtnper) nper - case default - write(errmsg,'(4x,a,a)')'****ERROR. UNKNOWN TDIS DIMENSION: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + case ('NPER') + nper = parser%GetInteger() + write (iout, fmtnper) nper + case default + write (errmsg, '(4x,a,a)') '****ERROR. UNKNOWN TDIS DIMENSION: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do - write(iout,'(1x,a)') 'END OF TDIS DIMENSIONS' + write (iout, '(1x,a)') 'END OF TDIS DIMENSIONS' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED DIMENSIONS BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if @@ -734,41 +732,41 @@ subroutine tdis_read_timing() integer(I4B) :: n logical :: isfound, endOfBlock ! -- formats - character(len=*), parameter :: fmtheader = & - "(1X,//1X,'STRESS PERIOD LENGTH TIME STEPS', & + character(len=*), parameter :: fmtheader = & + "(1X,//1X,'STRESS PERIOD LENGTH TIME STEPS', & &' MULTIPLIER FOR DELT',/1X,76('-'))" - character(len=*), parameter :: fmtrow = & - "(1X,I8,1PG21.7,I7,0PF25.3)" + character(len=*), parameter :: fmtrow = & + "(1X,I8,1PG21.7,I7,0PF25.3)" ! ------------------------------------------------------------------------------ ! ! -- get PERIODDATA block call parser%GetBlock('PERIODDATA', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) ! ! -- parse block if detected if (isfound) then - write(iout,'(1x,a)')'PROCESSING TDIS PERIODDATA' - write(iout, fmtheader) + write (iout, '(1x,a)') 'PROCESSING TDIS PERIODDATA' + write (iout, fmtheader) do n = 1, nper call parser%GetNextLine(endOfBlock) perlen(n) = parser%GetDouble() nstp(n) = parser%GetInteger() tsmult(n) = parser%GetDouble() - write(iout, fmtrow) n, perlen(n), nstp(n), tsmult(n) + write (iout, fmtrow) n, perlen(n), nstp(n), tsmult(n) totalsimtime = totalsimtime + perlen(n) - enddo + end do ! ! -- Check timing information call check_tdis_timing(nper, perlen, nstp, tsmult) call parser%terminateblock() ! ! -- Check for errors - if(count_errors() > 0) then + if (count_errors() > 0) then call parser%StoreErrorUnit() - endif - write(iout,'(1x,a)') 'END OF TDIS PERIODDATA' + end if + write (iout, '(1x,a)') 'END OF TDIS PERIODDATA' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED PERIODDATA BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED PERIODDATA BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if @@ -776,10 +774,10 @@ subroutine tdis_read_timing() ! -- Return return end subroutine tdis_read_timing - + subroutine check_tdis_timing(nper, perlen, nstp, tsmult) ! ****************************************************************************** -! check_tdis_timing -- Check the tdis timing information. Return back to +! check_tdis_timing -- Check the tdis timing information. Return back to ! tdis_read_timing if an error condition is found and let the ustop ! routine be called there instead so the StoreErrorUnit routine can be ! called to assign the correct file name. @@ -800,13 +798,13 @@ subroutine check_tdis_timing(nper, perlen, nstp, tsmult) real(DP) :: tstart, tend, dt character(len=LINELENGTH) :: errmsg ! -- formats - character(len=*), parameter :: fmtpwarn = & - &"(1X,/1X,'PERLEN IS ZERO FOR STRESS PERIOD ', I0, & + character(len=*), parameter :: fmtpwarn = & + "(1X,/1X,'PERLEN IS ZERO FOR STRESS PERIOD ', I0, & &'. PERLEN MUST NOT BE ZERO FOR TRANSIENT PERIODS.')" - character(len=*), parameter :: fmtsperror = & + character(len=*), parameter :: fmtsperror = & &"(A,' FOR STRESS PERIOD ', I0)" - character(len=*), parameter :: fmtdterror = & - &"('TIME STEP LENGTH OF ', G0, ' IS TOO SMALL IN PERIOD ', I0, & + character(len=*), parameter :: fmtdterror = & + "('TIME STEP LENGTH OF ', G0, ' IS TOO SMALL IN PERIOD ', I0, & &' AND TIME STEP ', I0)" ! ------------------------------------------------------------------------------ ! @@ -817,28 +815,28 @@ subroutine check_tdis_timing(nper, perlen, nstp, tsmult) do kper = 1, nper ! ! -- Error if nstp less than or equal to zero - if(nstp(kper) <= 0) then - write(errmsg, fmtsperror) 'NUMBER OF TIME STEPS LESS THAN ONE ', kper + if (nstp(kper) <= 0) then + write (errmsg, fmtsperror) 'NUMBER OF TIME STEPS LESS THAN ONE ', kper call store_error(errmsg) return end if ! ! -- Warn if perlen is zero - if(perlen(kper) == DZERO) then - write(iout, fmtpwarn) kper - return + if (perlen(kper) == DZERO) then + write (iout, fmtpwarn) kper + return end if ! ! -- Error if tsmult is less than zero - if(tsmult(kper) <= DZERO) then - write(errmsg, fmtsperror) 'TSMULT MUST BE GREATER THAN 0.0 ', kper + if (tsmult(kper) <= DZERO) then + write (errmsg, fmtsperror) 'TSMULT MUST BE GREATER THAN 0.0 ', kper call store_error(errmsg) return end if ! ! -- Error if negative period length - if(perlen(kper) < DZERO) then - write(errmsg, fmtsperror) 'PERLEN CANNOT BE LESS THAN 0.0 ', kper + if (perlen(kper) < DZERO) then + write (errmsg, fmtsperror) 'PERLEN CANNOT BE LESS THAN 0.0 ', kper call store_error(errmsg) return end if @@ -847,26 +845,26 @@ subroutine check_tdis_timing(nper, perlen, nstp, tsmult) do kstp = 1, nstp(kper) if (kstp == 1) then dt = perlen(kper) / float(nstp(kper)) - if(tsmult(kper) /= DONE) & - dt = perlen(kper) * (DONE-tsmult(kper)) / & - (DONE - tsmult(kper) ** nstp(kper)) + if (tsmult(kper) /= DONE) & + dt = perlen(kper) * (DONE - tsmult(kper)) / & + (DONE - tsmult(kper)**nstp(kper)) else dt = dt * tsmult(kper) - endif + end if tend = tstart + dt ! ! -- Error condition if tstart == tend if (tstart == tend) then - write(errmsg, fmtdterror) dt, kper, kstp + write (errmsg, fmtdterror) dt, kper, kstp call store_error(errmsg) return - endif - enddo + end if + end do ! ! -- reset tstart = tend tstart = tend ! - enddo + end do ! -- Return return end subroutine check_tdis_timing diff --git a/src/Utilities/ArrayHandlers.f90 b/src/Utilities/ArrayHandlers.f90 index f2aa62a396c..7759fb1f9ab 100644 --- a/src/Utilities/ArrayHandlers.f90 +++ b/src/Utilities/ArrayHandlers.f90 @@ -8,7 +8,7 @@ module ArrayHandlersModule public :: ExpandArray, ExpandArrayWrapper, ExtendPtrArray public :: ifind public :: remove_character - + interface ExpandArrayWrapper module procedure expand_integer_wrapper end interface @@ -18,8 +18,8 @@ module ArrayHandlersModule ! IMPORTANT: Do not use pointers to elements of arrays when using ! ExpandArray to increase the array size! The locations of array ! elements in memory are changed when ExpandArray is invoked. - module procedure expand_integer, expand_double, & - expand_character !, expand_real + module procedure expand_integer, expand_double, & + expand_character !, expand_real end interface ExpandArray interface ExtendPtrArray @@ -70,11 +70,11 @@ subroutine expand_integer_wrapper(nsize, array, minvalue, loginc) if (loginc) then increment = int(log10(real(nsize, DP)), I4B) increment = int(DTEN**increment, I4B) - ! - ! -- increase increment by a multiplier and a value no - ! smaller than a default or specified minimum size + ! + ! -- increase increment by a multiplier and a value no + ! smaller than a default or specified minimum size else - increment = int(nsize * 0.2_DP) + increment = int(nsize * 0.2_DP) increment = max(minimum_increment, increment) end if ! @@ -97,7 +97,7 @@ subroutine expand_integer(array, increment) implicit none ! -- dummy integer(I4B), allocatable, intent(inout) :: array(:) - integer(I4B), optional, intent(in) :: increment + integer(I4B), optional, intent(in) :: increment ! -- local integer(I4B) :: inclocal, isize, newsize integer(I4B), allocatable, dimension(:) :: array_temp @@ -107,20 +107,20 @@ subroutine expand_integer(array, increment) inclocal = increment else inclocal = 1 - endif + end if ! ! -- increase size of array by inclocal, retaining ! contained data if (allocated(array)) then isize = size(array) newsize = isize + inclocal - allocate(array_temp(newsize)) + allocate (array_temp(newsize)) array_temp(1:isize) = array - deallocate(array) + deallocate (array) call move_alloc(array_temp, array) else - allocate(array(inclocal)) - endif + allocate (array(inclocal)) + end if ! return end subroutine expand_integer @@ -129,7 +129,7 @@ subroutine expand_double(array, increment) implicit none ! -- dummy real(DP), allocatable, intent(inout) :: array(:) - integer(I4B), optional, intent(in) :: increment + integer(I4B), optional, intent(in) :: increment ! -- local integer(I4B) :: inclocal, isize, newsize real(DP), allocatable, dimension(:) :: array_temp @@ -139,20 +139,20 @@ subroutine expand_double(array, increment) inclocal = increment else inclocal = 1 - endif + end if ! ! -- increase size of array by inclocal, retaining ! contained data if (allocated(array)) then isize = size(array) newsize = isize + inclocal - allocate(array_temp(newsize)) + allocate (array_temp(newsize)) array_temp(1:isize) = array - deallocate(array) + deallocate (array) call move_alloc(array_temp, array) else - allocate(array(inclocal)) - endif + allocate (array(inclocal)) + end if ! return end subroutine expand_double @@ -161,7 +161,7 @@ subroutine expand_character(array, increment) implicit none ! -- dummy character(len=*), allocatable, intent(inout) :: array(:) - integer(I4B), optional, intent(in) :: increment + integer(I4B), optional, intent(in) :: increment ! -- local character(len=LINELENGTH) :: line character(len=MAXCHARLEN), allocatable, dimension(:) :: array_temp @@ -172,13 +172,13 @@ subroutine expand_character(array, increment) ! -- check character length lenc = len(array) if (lenc > MAXCHARLEN) then - write(line, '(a)') 'Error in ArrayHandlersModule: ' // & - 'Need to increase MAXCHARLEN' + write (line, '(a)') 'Error in ArrayHandlersModule: '// & + 'Need to increase MAXCHARLEN' call sim_message(line, iunit=iout, fmt=stdfmt) call sim_message(line, fmt=stdfmt) ! ! -- stop message - write(line, '(a)') 'Stopping...' + write (line, '(a)') 'Stopping...' call sim_message(line, iunit=iout) call sim_message(line) call stop_with_error(138) @@ -189,7 +189,7 @@ subroutine expand_character(array, increment) inclocal = increment else inclocal = 1 - endif + end if ! ! -- increase size of array by inclocal, retaining ! contained data @@ -198,22 +198,22 @@ subroutine expand_character(array, increment) if (allocated(array)) then isize = size(array) newsize = isize + inclocal - allocate(array_temp(isize)) - do i=1,isize + allocate (array_temp(isize)) + do i = 1, isize array_temp(i) = array(i) - enddo - deallocate(array) - allocate(array(newsize)) - do i=1,isize + end do + deallocate (array) + allocate (array(newsize)) + do i = 1, isize array(i) = array_temp(i) - enddo - do i=isize+1,newsize + end do + do i = isize + 1, newsize array(i) = '' - enddo - deallocate(array_temp) + end do + deallocate (array_temp) else - allocate(array(inclocal)) - endif + allocate (array(inclocal)) + end if ! return end subroutine expand_character @@ -238,32 +238,32 @@ subroutine extend_double(array, increment) inclocal = increment else inclocal = 1 - endif + end if ! ! -- increase size of array by inclocal, retaining ! contained data if (associated(array)) then isize = size(array) newsize = isize + inclocal - allocate(array_temp(newsize), stat=istat, errmsg=ermsg) + allocate (array_temp(newsize), stat=istat, errmsg=ermsg) if (istat /= 0) goto 99 - do i=1,isize + do i = 1, isize array_temp(i) = array(i) - enddo - deallocate(array) + end do + deallocate (array) array => array_temp else - allocate(array(inclocal)) - endif + allocate (array(inclocal)) + end if ! ! -- normal return - return + return ! ! -- Error reporting 99 continue - write(line, '(a)') 'Error in ArrayHandlersModule: ' // & - 'Could not increase array size' + write (line, '(a)') 'Error in ArrayHandlersModule: '// & + 'Could not increase array size' call sim_message(line, iunit=iout, fmt=stdfmt) call sim_message(line, fmt=stdfmt) ! @@ -272,11 +272,11 @@ subroutine extend_double(array, increment) call sim_message(ermsg) ! ! -- stop message - write(line, '(a)') 'Stopping...' + write (line, '(a)') 'Stopping...' call sim_message(line, iunit=iout) call sim_message(line) call stop_with_error(138) - + end subroutine extend_double subroutine extend_integer(array, increment) @@ -297,23 +297,23 @@ subroutine extend_integer(array, increment) inclocal = increment else inclocal = 1 - endif + end if ! ! -- increase size of array by inclocal, retaining ! contained data if (associated(array)) then isize = size(array) newsize = isize + inclocal - allocate(array_temp(newsize), stat=istat, errmsg=ermsg) + allocate (array_temp(newsize), stat=istat, errmsg=ermsg) if (istat /= 0) goto 99 - do i=1,isize + do i = 1, isize array_temp(i) = array(i) - enddo - deallocate(array) + end do + deallocate (array) array => array_temp else - allocate(array(inclocal)) - endif + allocate (array(inclocal)) + end if ! ! -- normal return return @@ -321,8 +321,8 @@ subroutine extend_integer(array, increment) ! -- Error reporting 99 continue - write(line, '(a)') 'Error in ArrayHandlersModule: ' // & - 'Could not increase array size' + write (line, '(a)') 'Error in ArrayHandlersModule: '// & + 'Could not increase array size' call sim_message(line, iunit=iout, fmt=stdfmt) call sim_message(line, fmt=stdfmt) ! @@ -331,11 +331,11 @@ subroutine extend_integer(array, increment) call sim_message(ermsg) ! ! -- stop message - write(line, '(a)') 'Stopping...' + write (line, '(a)') 'Stopping...' call sim_message(line, iunit=iout) call sim_message(line) call stop_with_error(138) - + end subroutine extend_integer function ifind_character(array, str) @@ -350,12 +350,12 @@ function ifind_character(array, str) ! -- local integer(I4B) :: i ifind_character = -1 - findloop: do i=1,size(array) - if(array(i) == str) then + findloop: do i = 1, size(array) + if (array(i) == str) then ifind_character = i exit findloop - endif - enddo findloop + end if + end do findloop return end function ifind_character @@ -372,11 +372,11 @@ function ifind_integer(iarray, ival) integer(I4B) :: i ifind_integer = -1 findloop: do i = 1, size(iarray) - if(iarray(i) == ival) then + if (iarray(i) == ival) then ifind_integer = i exit findloop - endif - enddo findloop + end if + end do findloop return end function ifind_integer @@ -385,7 +385,7 @@ subroutine remove_character(array, ipos) implicit none ! -- dummy character(len=*), allocatable, intent(inout) :: array(:) - integer(I4B), intent(in) :: ipos + integer(I4B), intent(in) :: ipos ! -- local character(len=LINELENGTH) :: line character(len=MAXCHARLEN), allocatable, dimension(:) :: array_temp @@ -397,38 +397,38 @@ subroutine remove_character(array, ipos) lenc = len(array) if (lenc > MAXCHARLEN) then - write(line, '(a)') 'Error in ArrayHandlersModule: ' // & - 'Need to increase MAXCHARLEN' + write (line, '(a)') 'Error in ArrayHandlersModule: '// & + 'Need to increase MAXCHARLEN' call sim_message(line, iunit=iout, fmt=stdfmt) call sim_message(line, fmt=stdfmt) ! ! -- stop message - write(line, '(a)') 'Stopping...' + write (line, '(a)') 'Stopping...' call sim_message(line, iunit=iout) call sim_message(line) call stop_with_error(138) - endif + end if ! ! -- calculate sizes isize = size(array) newsize = isize - 1 ! ! -- copy array to array_temp - allocate(array_temp(isize)) + allocate (array_temp(isize)) do i = 1, isize array_temp(i) = array(i) - enddo + end do ! - deallocate(array) - allocate(array(newsize)) + deallocate (array) + allocate (array(newsize)) inew = 1 do i = 1, isize - if(i /= ipos) then + if (i /= ipos) then array(inew) = array_temp(i) inew = inew + 1 - endif - enddo - deallocate(array_temp) + end if + end do + deallocate (array_temp) ! return end subroutine remove_character diff --git a/src/Utilities/ArrayRead/ArrayReaderBase.f90 b/src/Utilities/ArrayRead/ArrayReaderBase.f90 new file mode 100644 index 00000000000..e387178f087 --- /dev/null +++ b/src/Utilities/ArrayRead/ArrayReaderBase.f90 @@ -0,0 +1,186 @@ +module ArrayReaderBaseModule + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: MAXCHARLEN + use BlockParserModule, only: BlockParserType + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use InputOutputModule, only: openfile + + implicit none + private + public :: ArrayReaderBaseType + + type ArrayReaderBaseType + + type(BlockParserType), pointer :: parser => null() + integer(I4B) :: iout = 0 + integer(I4B) :: input_unit = 0 + character(len=:), allocatable :: array_name + character(len=:), allocatable :: filename + integer(I4B) :: iprn = 0 + logical(LGP) :: isConstant = .false. + logical(LGP) :: isInternal = .false. + logical(LGP) :: isOpenClose = .false. + logical(LGP) :: isBinary = .false. + + contains + + procedure :: read_array + procedure :: reset_reader + procedure :: read_control_record + procedure :: set_constant ! must be overriden + procedure :: fill_constant ! must be overriden + procedure :: fill_internal + procedure :: fill_open_close + procedure :: read_ascii ! must be overriden + procedure :: read_binary ! must be overriden + procedure :: set_factor ! must be overriden + procedure :: apply_factor ! must be overriden + procedure :: open_file + + end type ArrayReaderBaseType + +contains + + subroutine read_array(this) + class(ArrayReaderBaseType) :: this + + ! read control record + call this%read_control_record() + + ! fill array + if (this%isConstant) then + call this%fill_constant() + else if (this%isInternal) then + call this%fill_internal() + else if (this%isOpenClose) then + call this%fill_open_close() + end if + + end subroutine read_array + + subroutine reset_reader(this) + class(ArrayReaderBaseType) :: this + this%iprn = 0 + this%isConstant = .false. + this%isInternal = .false. + this%isOpenClose = .false. + this%isBinary = .false. + end subroutine reset_reader + + subroutine read_control_record(this) + class(ArrayReaderBaseType) :: this + logical(LGP) :: endOfBlock + character(len=100) :: keyword + character(len=MAXCHARLEN) :: string + + ! read the array input style + call this%parser%GetNextLine(endOfBlock) + call this%parser%GetStringCaps(keyword) + + ! load array based on the different styles + select case (keyword) + case ('CONSTANT') + this%isConstant = .true. + call this%set_constant() + case ('INTERNAL') + this%isInternal = .true. + case ('OPEN/CLOSE') + this%isOpenClose = .true. + call this%parser%GetString(string) + this%filename = trim(string) + case default + write (errmsg, *) 'Error reading control record for '// & + trim(adjustl(this%array_name))//'. & + & Use CONSTANT, INTERNAL, or OPEN/CLOSE.' + call store_error(errmsg) + call this%parser%StoreErrorUnit() + end select + + ! if INTERNAL or OPEN/CLOSE then look for FACTOR and IPRN + if (this%isInternal .or. this%isOpenClose) then + do + call this%parser%GetStringCaps(keyword) + if (keyword == '') exit + select case (keyword) + case ('FACTOR') + call this%set_factor() + case ('IPRN') + this%iprn = this%parser%GetInteger() + case ('(BINARY)') + this%isBinary = .true. + end select + end do + end if + + end subroutine read_control_record + + subroutine set_constant(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine set_constant + + subroutine fill_constant(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine fill_constant + + subroutine fill_internal(this) + class(ArrayReaderBaseType) :: this + this%input_unit = this%parser%iuactive + call this%read_ascii() + call this%apply_factor() + end subroutine fill_internal + + subroutine fill_open_close(this) + class(ArrayReaderBaseType) :: this + this%input_unit = 0 + call this%open_file() + if (this%isBinary) then + call this%read_binary() + else + call this%read_ascii() + end if + close (this%input_unit) + call this%apply_factor() + end subroutine fill_open_close + + subroutine read_ascii(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine read_ascii + + subroutine read_binary(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine read_binary + + subroutine set_factor(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine set_factor + + subroutine apply_factor(this) + class(ArrayReaderBaseType) :: this + errmsg = 'Programming error in ArrayReader' + call store_error(errmsg, terminate=.true.) + end subroutine apply_factor + + subroutine open_file(this) + use OpenSpecModule, only: FORM, ACCESS + class(ArrayReaderBaseType) :: this + if (this%isBinary) then + call openfile(this%input_unit, this%iout, this%filename, & + 'OPEN/CLOSE', fmtarg_opt=FORM, accarg_opt=ACCESS) + else + call openfile(this%input_unit, this%iout, this%filename, 'OPEN/CLOSE') + end if + end subroutine open_file + +end module ArrayReaderBaseModule diff --git a/src/Utilities/ArrayRead/Double1dReader.f90 b/src/Utilities/ArrayRead/Double1dReader.f90 new file mode 100644 index 00000000000..a34202a5d5a --- /dev/null +++ b/src/Utilities/ArrayRead/Double1dReader.f90 @@ -0,0 +1,116 @@ +module Double1dReaderModule + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: DZERO, DONE + use BlockParserModule, only: BlockParserType + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_error_unit + use ArrayReadersModule, only: read_binary_header + use ArrayReaderBaseModule, only: ArrayReaderBaseType + + implicit none + private + public :: read_dbl1d + + type, extends(ArrayReaderBaseType) :: Double1dReaderType + + real(DP) :: constant_array_value = DZERO + real(DP) :: factor = DONE + real(DP), dimension(:), contiguous, pointer :: dbl1d => null() + + contains + + procedure :: reset_reader + procedure :: set_constant ! must be overriden + procedure :: fill_constant ! must be overriden + procedure :: read_ascii ! must be overriden + procedure :: read_binary ! must be overriden + procedure :: set_factor ! must be overriden + procedure :: apply_factor ! must be overriden + + end type Double1dReaderType + +contains + + subroutine read_dbl1d(parser, dbl1d, aname) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + real(DP), dimension(:), contiguous, target :: dbl1d + character(len=*), intent(in) :: aname + ! -- local + type(Double1dReaderType) :: this + + this%parser => parser + this%dbl1d => dbl1d + this%array_name = aname + + call this%read_array() + + end subroutine read_dbl1d + + subroutine reset_reader(this) + class(Double1dReaderType) :: this + call this%ArrayReaderBaseType%reset_reader() + this%constant_array_value = DZERO + this%factor = DONE + end subroutine reset_reader + + subroutine set_constant(this) + class(Double1dReaderType) :: this + this%constant_array_value = this%parser%GetDouble() + end subroutine set_constant + + subroutine fill_constant(this) + class(Double1dReaderType) :: this + integer(I4B) :: i + do i = 1, size(this%dbl1d) + this%dbl1d(i) = this%constant_array_value + end do + end subroutine fill_constant + + subroutine read_ascii(this) + class(Double1dReaderType) :: this + integer(I4B) :: i + integer(I4B) :: istat + read (this%input_unit, *, iostat=istat, iomsg=errmsg) & + (this%dbl1d(i), i=1, size(this%dbl1d)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_ascii + + subroutine read_binary(this) + class(Double1dReaderType) :: this + integer(I4B) :: i + integer(I4B) :: nvals + integer(I4B) :: istat + call read_binary_header(this%input_unit, this%iout, this%array_name, nvals) + read (this%input_unit, iostat=istat, iomsg=errmsg) & + (this%dbl1d(i), i=1, size(this%dbl1d)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_binary + + subroutine set_factor(this) + class(Double1dReaderType) :: this + this%factor = this%parser%GetDouble() + end subroutine set_factor + + subroutine apply_factor(this) + class(Double1dReaderType) :: this + integer(I4B) :: i + if (this%factor /= DZERO) then + do i = 1, size(this%dbl1d) + this%dbl1d(i) = this%dbl1d(i) * this%factor + end do + end if + end subroutine apply_factor + +end module Double1dReaderModule diff --git a/src/Utilities/ArrayRead/Double2dReader.f90 b/src/Utilities/ArrayRead/Double2dReader.f90 new file mode 100644 index 00000000000..0df3d7bce15 --- /dev/null +++ b/src/Utilities/ArrayRead/Double2dReader.f90 @@ -0,0 +1,123 @@ +module Double2dReaderModule + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: DZERO, DONE + use BlockParserModule, only: BlockParserType + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_error_unit + use ArrayReadersModule, only: read_binary_header + use ArrayReaderBaseModule, only: ArrayReaderBaseType + + implicit none + private + public :: read_dbl2d + + type, extends(ArrayReaderBaseType) :: Double2dReaderType + + real(DP) :: constant_array_value = DZERO + real(DP) :: factor = DONE + real(DP), dimension(:, :), contiguous, pointer :: dbl2d => null() + + contains + + procedure :: reset_reader + procedure :: set_constant ! must be overriden + procedure :: fill_constant ! must be overriden + procedure :: read_ascii ! must be overriden + procedure :: read_binary ! must be overriden + procedure :: set_factor ! must be overriden + procedure :: apply_factor ! must be overriden + + end type Double2dReaderType + +contains + + subroutine read_dbl2d(parser, dbl2d, aname) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + real(DP), dimension(:, :), contiguous, target :: dbl2d + character(len=*), intent(in) :: aname + ! -- local + type(Double2dReaderType) :: this + + this%parser => parser + this%dbl2d => dbl2d + this%array_name = aname + + call this%read_array() + + end subroutine read_dbl2d + + subroutine reset_reader(this) + class(Double2dReaderType) :: this + call this%ArrayReaderBaseType%reset_reader() + this%constant_array_value = DZERO + this%factor = DONE + end subroutine reset_reader + + subroutine set_constant(this) + class(Double2dReaderType) :: this + this%constant_array_value = this%parser%GetDouble() + end subroutine set_constant + + subroutine fill_constant(this) + class(Double2dReaderType) :: this + integer(I4B) :: i, j + do i = 1, size(this%dbl2d, dim=2) + do j = 1, size(this%dbl2d, dim=1) + this%dbl2d(j, i) = this%constant_array_value + end do + end do + end subroutine fill_constant + + subroutine read_ascii(this) + class(Double2dReaderType) :: this + integer(I4B) :: i, j + integer(I4B) :: istat + do i = 1, size(this%dbl2d, dim=2) + read (this%input_unit, *, iostat=istat, iomsg=errmsg) & + (this%dbl2d(j, i), j=1, size(this%dbl2d, dim=1)) + end do + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_ascii + + subroutine read_binary(this) + class(Double2dReaderType) :: this + integer(I4B) :: i, j + integer(I4B) :: nvals + integer(I4B) :: istat + call read_binary_header(this%input_unit, this%iout, this%array_name, nvals) + read (this%input_unit, iostat=istat, iomsg=errmsg) & + ((this%dbl2d(j, i), j=1, size(this%dbl2d, dim=1)), & + i=1, size(this%dbl2d, dim=2)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_binary + + subroutine set_factor(this) + class(Double2dReaderType) :: this + this%factor = this%parser%GetDouble() + end subroutine set_factor + + subroutine apply_factor(this) + class(Double2dReaderType) :: this + integer(I4B) :: i, j + if (this%factor /= DZERO) then + do i = 1, size(this%dbl2d, dim=2) + do j = 1, size(this%dbl2d, dim=1) + this%dbl2d(j, i) = this%dbl2d(j, i) * this%factor + end do + end do + end if + end subroutine apply_factor + +end module Double2dReaderModule diff --git a/src/Utilities/ArrayRead/Integer1dReader.f90 b/src/Utilities/ArrayRead/Integer1dReader.f90 new file mode 100644 index 00000000000..60b279e9fee --- /dev/null +++ b/src/Utilities/ArrayRead/Integer1dReader.f90 @@ -0,0 +1,148 @@ +module Integer1dReaderModule + + use KindModule, only: DP, I4B, LGP + use BlockParserModule, only: BlockParserType + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_error_unit + use ArrayReadersModule, only: read_binary_header + use ArrayReaderBaseModule, only: ArrayReaderBaseType + + implicit none + private + public :: read_int1d, read_int1d_layered + + type, extends(ArrayReaderBaseType) :: Integer1dReaderType + + integer(I4B) :: constant_array_value = 0 + integer(I4B) :: factor = 1 + integer(I4B), dimension(:), contiguous, pointer :: int1d => null() + + contains + + procedure :: reset_reader + procedure :: set_constant ! must be overriden + procedure :: fill_constant ! must be overriden + procedure :: read_ascii ! must be overriden + procedure :: read_binary ! must be overriden + procedure :: set_factor ! must be overriden + procedure :: apply_factor ! must be overriden + + end type Integer1dReaderType + +contains + + subroutine read_int1d(parser, int1d, aname) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:), contiguous, target :: int1d + character(len=*), intent(in) :: aname + ! -- local + type(Integer1dReaderType) :: this + + this%parser => parser + this%int1d => int1d + this%array_name = aname + + call this%read_array() + + end subroutine read_int1d + + subroutine read_int1d_layered(parser, int1d, aname, nlay, layer_shape) + use Integer2dReaderModule, only: read_int2d + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:), contiguous, target :: int1d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncpl, nrow, ncol + integer(I4B) :: index_start, index_stop + integer(I4B), dimension(:, :), contiguous, pointer :: int2d_ptr + + ncpl = product(layer_shape) + index_start = 1 + do k = 1, nlay + index_stop = index_start + ncpl - 1 + if (size(layer_shape) == 2) then + ncol = layer_shape(1) + nrow = layer_shape(2) + int2d_ptr(1:ncol, 1:nrow) => int1d(index_start:index_stop) + call read_int2d(parser, int2d_ptr, aname) + else + call read_int1d(parser, int1d(index_start:index_stop), aname) + end if + index_start = index_stop + 1 + end do + + end subroutine read_int1d_layered + + subroutine reset_reader(this) + class(Integer1dReaderType) :: this + call this%ArrayReaderBaseType%reset_reader() + this%constant_array_value = 0 + this%factor = 1 + end subroutine reset_reader + + subroutine set_constant(this) + class(Integer1dReaderType) :: this + this%constant_array_value = this%parser%GetInteger() + end subroutine set_constant + + subroutine fill_constant(this) + class(Integer1dReaderType) :: this + integer(I4B) :: i + do i = 1, size(this%int1d) + this%int1d(i) = this%constant_array_value + end do + end subroutine fill_constant + + subroutine read_ascii(this) + class(Integer1dReaderType) :: this + integer(I4B) :: i + integer(I4B) :: nvals + integer(I4B) :: istat + nvals = size(this%int1d) + read (this%input_unit, *, iostat=istat, iomsg=errmsg) & + (this%int1d(i), i=1, size(this%int1d)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_ascii + + subroutine read_binary(this) + class(Integer1dReaderType) :: this + integer(I4B) :: i + integer(I4B) :: nvals + integer(I4B) :: istat + call read_binary_header(this%input_unit, this%iout, this%array_name, nvals) + read (this%input_unit, iostat=istat, iomsg=errmsg) & + (this%int1d(i), i=1, size(this%int1d)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_binary + + subroutine set_factor(this) + class(Integer1dReaderType) :: this + this%factor = this%parser%GetInteger() + end subroutine set_factor + + subroutine apply_factor(this) + class(Integer1dReaderType) :: this + integer(I4B) :: i + if (this%factor /= 0) then + do i = 1, size(this%int1d) + this%int1d(i) = this%int1d(i) * this%factor + end do + end if + end subroutine apply_factor + +end module Integer1dReaderModule diff --git a/src/Utilities/ArrayRead/Integer2dReader.f90 b/src/Utilities/ArrayRead/Integer2dReader.f90 new file mode 100644 index 00000000000..2fe4364d359 --- /dev/null +++ b/src/Utilities/ArrayRead/Integer2dReader.f90 @@ -0,0 +1,123 @@ +module Integer2dReaderModule + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: DZERO, DONE + use BlockParserModule, only: BlockParserType + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, store_error_unit + use ArrayReadersModule, only: read_binary_header + use ArrayReaderBaseModule, only: ArrayReaderBaseType + + implicit none + private + public :: read_int2d + + type, extends(ArrayReaderBaseType) :: Integer2dReaderType + + integer(I4B) :: constant_array_value = DZERO + integer(I4B) :: factor = DONE + integer(I4B), dimension(:, :), contiguous, pointer :: int2d => null() + + contains + + procedure :: reset_reader + procedure :: set_constant ! must be overriden + procedure :: fill_constant ! must be overriden + procedure :: read_ascii ! must be overriden + procedure :: read_binary ! must be overriden + procedure :: set_factor ! must be overriden + procedure :: apply_factor ! must be overriden + + end type Integer2dReaderType + +contains + + subroutine read_int2d(parser, int2d, aname) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:, :), contiguous, target :: int2d + character(len=*), intent(in) :: aname + ! -- local + type(Integer2dReaderType) :: this + + this%parser => parser + this%int2d => int2d + this%array_name = aname + + call this%read_array() + + end subroutine read_int2d + + subroutine reset_reader(this) + class(Integer2dReaderType) :: this + call this%ArrayReaderBaseType%reset_reader() + this%constant_array_value = 0 + this%factor = 1 + end subroutine reset_reader + + subroutine set_constant(this) + class(Integer2dReaderType) :: this + this%constant_array_value = this%parser%GetInteger() + end subroutine set_constant + + subroutine fill_constant(this) + class(Integer2dReaderType) :: this + integer(I4B) :: i, j + do i = 1, size(this%int2d, dim=2) + do j = 1, size(this%int2d, dim=1) + this%int2d(j, i) = this%constant_array_value + end do + end do + end subroutine fill_constant + + subroutine read_ascii(this) + class(Integer2dReaderType) :: this + integer(I4B) :: i, j + integer(I4B) :: istat + do i = 1, size(this%int2d, dim=2) + read (this%input_unit, *, iostat=istat, iomsg=errmsg) & + (this%int2d(j, i), j=1, size(this%int2d, dim=1)) + end do + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_ascii + + subroutine read_binary(this) + class(Integer2dReaderType) :: this + integer(I4B) :: i, j + integer(I4B) :: nvals + integer(I4B) :: istat + call read_binary_header(this%input_unit, this%iout, this%array_name, nvals) + read (this%input_unit, iostat=istat, iomsg=errmsg) & + ((this%int2d(j, i), j=1, size(this%int2d, dim=1)), & + i=1, size(this%int2d, dim=2)) + if (istat /= 0) then + errmsg = 'Error reading data for array '//trim(this%array_name)// & + '. '//trim(errmsg) + call store_error(errmsg) + call store_error_unit(this%input_unit) + end if + end subroutine read_binary + + subroutine set_factor(this) + class(Integer2dReaderType) :: this + this%factor = this%parser%GetInteger() + end subroutine set_factor + + subroutine apply_factor(this) + class(Integer2dReaderType) :: this + integer(I4B) :: i, j + if (this%factor /= DZERO) then + do i = 1, size(this%int2d, dim=2) + do j = 1, size(this%int2d, dim=1) + this%int2d(j, i) = this%int2d(j, i) * this%factor + end do + end do + end if + end subroutine apply_factor + +end module Integer2dReaderModule diff --git a/src/Utilities/ArrayRead/LayeredArrayReader.f90 b/src/Utilities/ArrayRead/LayeredArrayReader.f90 new file mode 100644 index 00000000000..3207c87c8e9 --- /dev/null +++ b/src/Utilities/ArrayRead/LayeredArrayReader.f90 @@ -0,0 +1,168 @@ +module LayeredArrayReaderModule + + use KindModule, only: DP, I4B, LGP + use BlockParserModule, only: BlockParserType + use Double1dReaderModule, only: read_dbl1d + use Double2dReaderModule, only: read_dbl2d + use Integer1dReaderModule, only: read_int1d + use Integer2dReaderModule, only: read_int2d + + implicit none + public :: read_dbl1d_layered + public :: read_dbl2d_layered + public :: read_dbl3d_layered + public :: read_int1d_layered + public :: read_int2d_layered + public :: read_int3d_layered + +contains + + subroutine read_dbl1d_layered(parser, dbl1d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + real(DP), dimension(:), contiguous, target :: dbl1d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncpl, nrow, ncol + integer(I4B) :: index_start, index_stop + real(DP), dimension(:, :), contiguous, pointer :: dbl2d_ptr => null() + + ncpl = product(layer_shape) + index_start = 1 + do k = 1, nlay + index_stop = index_start + ncpl - 1 + if (size(layer_shape) == 2) then + ncol = layer_shape(1) + nrow = layer_shape(2) + dbl2d_ptr(1:ncol, 1:nrow) => dbl1d(index_start:index_stop) + call read_dbl2d(parser, dbl2d_ptr, aname) + else + call read_dbl1d(parser, dbl1d(index_start:index_stop), aname) + end if + index_start = index_stop + 1 + end do + nullify (dbl2d_ptr) + + end subroutine read_dbl1d_layered + + subroutine read_dbl2d_layered(parser, dbl2d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + real(DP), dimension(:, :), contiguous, target :: dbl2d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncpl + real(DP), dimension(:), contiguous, pointer :: dbl1d_ptr => null() + + ncpl = layer_shape(1) + do k = 1, nlay + dbl1d_ptr(1:ncpl) => dbl2d(1:ncpl, k) + call read_dbl1d(parser, dbl1d_ptr, aname) + end do + nullify (dbl1d_ptr) + + end subroutine read_dbl2d_layered + + subroutine read_dbl3d_layered(parser, dbl3d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + real(DP), dimension(:, :, :), contiguous, target :: dbl3d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncol, nrow + real(DP), dimension(:, :), contiguous, pointer :: dbl2d_ptr => null() + + ncol = layer_shape(1) + nrow = layer_shape(2) + do k = 1, nlay + dbl2d_ptr(1:ncol, 1:nrow) => dbl3d(:, :, k:k) + call read_dbl2d(parser, dbl2d_ptr, aname) + end do + nullify (dbl2d_ptr) + + end subroutine read_dbl3d_layered + + subroutine read_int1d_layered(parser, int1d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:), contiguous, target :: int1d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncpl, nrow, ncol + integer(I4B) :: index_start, index_stop + integer(I4B), dimension(:, :), contiguous, pointer :: int2d_ptr => null() + + ncpl = product(layer_shape) + index_start = 1 + do k = 1, nlay + index_stop = index_start + ncpl - 1 + if (size(layer_shape) == 2) then + ncol = layer_shape(1) + nrow = layer_shape(2) + int2d_ptr(1:ncol, 1:nrow) => int1d(index_start:index_stop) + call read_int2d(parser, int2d_ptr, aname) + else + call read_int1d(parser, int1d(index_start:index_stop), aname) + end if + index_start = index_stop + 1 + end do + nullify (int2d_ptr) + + end subroutine read_int1d_layered + + subroutine read_int2d_layered(parser, int2d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:, :), contiguous, target :: int2d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncpl + integer(I4B), dimension(:), contiguous, pointer :: int1d_ptr => null() + + ncpl = layer_shape(1) + do k = 1, nlay + int1d_ptr(1:ncpl) => int2d(1:ncpl, k) + call read_int1d(parser, int1d_ptr, aname) + end do + nullify (int1d_ptr) + + end subroutine read_int2d_layered + + subroutine read_int3d_layered(parser, int3d, aname, nlay, layer_shape) + ! -- dummy + type(BlockParserType), intent(in), target :: parser + integer(I4B), dimension(:, :, :), contiguous, target :: int3d + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: nlay + integer(I4B), dimension(:), intent(in) :: layer_shape + ! -- local + integer(I4B) :: k + integer(I4B) :: ncol, nrow + integer(I4B), dimension(:, :), contiguous, pointer :: int2d_ptr => null() + + ncol = layer_shape(1) + nrow = layer_shape(2) + do k = 1, nlay + int2d_ptr(1:ncol, 1:nrow) => int3d(:, :, k:k) + call read_int2d(parser, int2d_ptr, aname) + end do + nullify (int2d_ptr) + + end subroutine read_int3d_layered + +end module LayeredArrayReaderModule diff --git a/src/Utilities/ArrayReaders.f90 b/src/Utilities/ArrayReaders.f90 index 17125833ea5..c3a98961285 100644 --- a/src/Utilities/ArrayReaders.f90 +++ b/src/Utilities/ArrayReaders.f90 @@ -1,27 +1,35 @@ module ArrayReadersModule - - use ConstantsModule, only: DONE, LINELENGTH, LENBIGLINE, LENBOUNDNAME, & - NAMEDBOUNDFLAG, LINELENGTH, DZERO, MAXCHARLEN, & - DZERO + + use ConstantsModule, only: DONE, LINELENGTH, LENBIGLINE, LENBOUNDNAME, & + NAMEDBOUNDFLAG, LINELENGTH, DZERO, MAXCHARLEN, & + DZERO use InputOutputModule, only: openfile, u8rdcom, urword, ucolno, ulaprw, & BuildFixedFormat, BuildFloatFormat, & BuildIntFormat - use KindModule, only: DP, I4B - use OpenSpecModule, only: ACCESS, FORM - use SimModule, only: store_error, store_error_unit + use KindModule, only: DP, I4B + use OpenSpecModule, only: ACCESS, FORM + use SimModule, only: store_error, store_error_unit implicit none private public :: ReadArray - + public :: read_binary_header + interface ReadArray - module procedure read_array_int1d, read_array_int2d, read_array_int3d, & - read_array_dbl1d, read_array_dbl2d, read_array_dbl3d, & - read_array_dbl1d_layered, read_array_int1d_layered, & - read_array_dbl3d_all, read_array_int3d_all + module procedure & + read_array_int1d, & + read_array_int2d, & + read_array_int3d, & + read_array_dbl1d, & + read_array_dbl2d, & + read_array_dbl3d, & + read_array_dbl1d_layered, & + read_array_int1d_layered, & + read_array_dbl3d_all, & + read_array_int3d_all end interface ReadArray - + ! Integer readers ! read_array_int1d(iu, iarr, aname, ndim, jj, iout, k) ! read_array_int1d_layered(iu, iarr, aname, ndim, ncol, nrow, nlay, nval, iout, k1, k2) @@ -35,19 +43,19 @@ module ArrayReadersModule ! read_array_dbl2d(iu, darr, aname, ndim, jj, ii, iout, k) ! read_array_dbl3d(iu, darr, aname, ndim, ncol, nrow, nlay, iout, k1, k2) ! read_array_dbl3d_all(iu, darr, aname, ndim, nvals, iout) - + contains ! -- Procedures that are part of ReadArray interface (integer data) subroutine read_array_int1d(iu, iarr, aname, ndim, jj, iout, k) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: jj + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: jj integer(I4B), dimension(jj), intent(inout) :: iarr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k ! layer number; 0 to not print + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k ! layer number; 0 to not print ! -- local integer(I4B) :: iclose, iconst, iprn, j, locat, ncpl, ndig integer(I4B) :: nval, nvalt @@ -57,8 +65,8 @@ subroutine read_array_int1d(iu, iarr, aname, ndim, jj, iout, k) character(len=30) :: arrname character(len=MAXCHARLEN) :: ermsg, ermsgr ! -- formats - 2 format(/,1x,a,' = ',i0, ' FOR LAYER ',i0) - 3 format(/,1x,a,' = ',i0) +2 format(/, 1x, a, ' = ', i0, ' FOR LAYER ', i0) +3 format(/, 1x, a, ' = ', i0) ! ! -- Read array control record. call read_control_int(iu, iout, aname, locat, iconst, iclose, iprn) @@ -66,60 +74,61 @@ subroutine read_array_int1d(iu, iarr, aname, ndim, jj, iout, k) ! -- Read or assign array data. if (locat == 0) then ! -- Assign constant - do j=1,jj + do j = 1, jj iarr(j) = iconst - enddo + end do if (iout > 0) then if (k > 0) then - write(iout,2) trim(aname), iconst, k + write (iout, 2) trim(aname), iconst, k else - write(iout,3) trim(aname), iconst - endif - endif + write (iout, 3) trim(aname), iconst + end if + end if elseif (locat > 0) then ! -- Read data as text - read(locat,*,iostat=istat,iomsg=ermsgr) (iarr(j),j=1,jj) + read (locat, *, iostat=istat, iomsg=ermsgr) (iarr(j), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif - do j=1,jj + end if + do j = 1, jj iarr(j) = iarr(j) * iconst - enddo + end do if (iclose == 1) then - close(locat) - endif + close (locat) + end if else ! -- Read data as binary locat = -locat nvalt = 0 do call read_binary_header(locat, iout, aname, nval) - read(locat,iostat=istat,iomsg=ermsgr) (iarr(j), j=nvalt+1, nvalt+nval) + read (locat, iostat=istat, iomsg=ermsgr) & + (iarr(j), j=nvalt + 1, nvalt + nval) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif + end if nvalt = nvalt + nval if (nvalt == size(iarr)) exit - enddo + end do ! ! -- multiply array by constant - do j=1,jj + do j = 1, jj iarr(j) = iarr(j) * iconst - enddo + end do ! ! -- close the file if (iclose == 1) then - close(locat) - endif - endif + close (locat) + end if + end if ! ! -- Print array if requested. if (iprn >= 0 .and. locat /= 0) then @@ -127,19 +136,19 @@ subroutine read_array_int1d(iu, iarr, aname, ndim, jj, iout, k) call build_format_int(iprn, prfmt, prowcolnum, ncpl, ndig) call print_array_int(iarr, aname, iout, jj, 1, k, prfmt, ncpl, ndig, & prowcolnum) - endif + end if ! return end subroutine read_array_int1d subroutine read_array_int2d(iu, iarr, aname, ndim, jj, ii, iout, k) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: jj, ii - integer(I4B), dimension(jj,ii), intent(inout) :: iarr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k ! layer number; 0 to not print + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: jj, ii + integer(I4B), dimension(jj, ii), intent(inout) :: iarr + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k ! layer number; 0 to not print ! -- local integer(I4B) :: i, iclose, iconst, iprn, j, locat, ncpl, ndig integer(I4B) :: nval @@ -149,8 +158,8 @@ subroutine read_array_int2d(iu, iarr, aname, ndim, jj, ii, iout, k) character(len=30) :: arrname character(len=MAXCHARLEN) :: ermsg, ermsgr ! -- formats - 2 format(/,1x,a,' = ',i0, ' FOR LAYER ',i0) - 3 format(/,1x,a,' = ',i0) +2 format(/, 1x, a, ' = ', i0, ' FOR LAYER ', i0) +3 format(/, 1x, a, ' = ', i0) ! ! -- Read array control record. call read_control_int(iu, iout, aname, locat, iconst, iclose, iprn) @@ -158,57 +167,57 @@ subroutine read_array_int2d(iu, iarr, aname, ndim, jj, ii, iout, k) ! -- Read or assign array data. if (locat == 0) then ! -- Assign constant - do i=1,ii - do j=1,jj - iarr(j,i) = iconst - enddo - enddo + do i = 1, ii + do j = 1, jj + iarr(j, i) = iconst + end do + end do if (iout > 0) then if (k > 0) then - write(iout,2) trim(aname), iconst, k + write (iout, 2) trim(aname), iconst, k else - write(iout,3) trim(aname), iconst - endif - endif + write (iout, 3) trim(aname), iconst + end if + end if elseif (locat > 0) then ! -- Read data as text - do i=1,ii - read(locat,*,iostat=istat,iomsg=ermsgr) (iarr(j,i),j=1,jj) + do i = 1, ii + read (locat, *, iostat=istat, iomsg=ermsgr) (iarr(j, i), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif - do j=1,jj - iarr(j,i) = iarr(j,i) * iconst - enddo - enddo + end if + do j = 1, jj + iarr(j, i) = iarr(j, i) * iconst + end do + end do if (iclose == 1) then - close(locat) - endif + close (locat) + end if else ! -- Read data as binary locat = -locat call read_binary_header(locat, iout, aname, nval) - do i=1,ii - read(locat,iostat=istat,iomsg=ermsgr) (iarr(j,i),j=1,jj) + do i = 1, ii + read (locat, iostat=istat, iomsg=ermsgr) (iarr(j, i), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif - do j=1,jj - iarr(j,i) = iarr(j,i) * iconst - enddo - enddo + end if + do j = 1, jj + iarr(j, i) = iarr(j, i) * iconst + end do + end do if (iclose == 1) then - close(locat) - endif - endif + close (locat) + end if + end if ! ! -- Print array if requested. if (iprn >= 0 .and. locat /= 0) then @@ -216,11 +225,11 @@ subroutine read_array_int2d(iu, iarr, aname, ndim, jj, ii, iout, k) call build_format_int(iprn, prfmt, prowcolnum, ncpl, ndig) call print_array_int(iarr, aname, iout, jj, ii, k, prfmt, ncpl, & ndig, prowcolnum) - endif + end if ! return end subroutine read_array_int2d - + subroutine read_array_int3d(iu, iarr, aname, ndim, ncol, nrow, nlay, iout, & k1, k2) ! ****************************************************************************** @@ -237,7 +246,7 @@ subroutine read_array_int3d(iu, iarr, aname, ndim, ncol, nrow, nlay, iout, & integer(I4B), intent(in) :: nrow integer(I4B), intent(in) :: nlay integer(I4B), intent(in) :: k1, k2 - integer(I4B), dimension(ncol,nrow,nlay), intent(inout) :: iarr + integer(I4B), dimension(ncol, nrow, nlay), intent(inout) :: iarr character(len=*), intent(in) :: aname ! -- local integer(I4B) :: k, kk @@ -247,12 +256,12 @@ subroutine read_array_int3d(iu, iarr, aname, ndim, ncol, nrow, nlay, iout, & kk = 1 else kk = k - endif - call read_array_int2d(iu, iarr(:,:,kk), aname, ndim, ncol, nrow, iout, k) - enddo + end if + call read_array_int2d(iu, iarr(:, :, kk), aname, ndim, ncol, nrow, iout, k) + end do return end subroutine read_array_int3d - + subroutine read_array_int3d_all(iu, iarr, aname, ndim, nvals, iout) ! ****************************************************************************** ! Read three-dimensional integer array, all at once. @@ -264,7 +273,7 @@ subroutine read_array_int3d_all(iu, iarr, aname, ndim, nvals, iout) integer(I4B), intent(in) :: iout integer(I4B), intent(in) :: ndim integer(I4B), intent(in) :: nvals - integer(I4B), dimension(nvals,1,1), intent(inout) :: iarr + integer(I4B), dimension(nvals, 1, 1), intent(inout) :: iarr character(len=*), intent(in) :: aname ! -- local ! ------------------------------------------------------------------------------ @@ -277,29 +286,29 @@ end subroutine read_array_int3d_all subroutine read_array_int1d_layered(iu, iarr, aname, ndim, ncol, nrow, & nlay, nval, iout, k1, k2) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: ncol, nrow, nlay, nval + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: ncol, nrow, nlay, nval integer(I4B), dimension(nval), intent(inout) :: iarr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k1, k2 + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k1, k2 ! -- local ! call read_array_int3d(iu, iarr, aname, ndim, ncol, nrow, nlay, iout, k1, k2) ! return end subroutine read_array_int1d_layered - + ! -- Procedures that are part of ReadArray interface (floating-point data) - + subroutine read_array_dbl1d(iu, darr, aname, ndim, jj, iout, k) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: jj + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: jj real(DP), dimension(jj), intent(inout) :: darr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k ! layer number; 0 to not print + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k ! layer number; 0 to not print ! -- local integer(I4B) :: j, iclose, iprn, locat, ncpl, ndig real(DP) :: cnstnt @@ -310,8 +319,8 @@ subroutine read_array_dbl1d(iu, darr, aname, ndim, jj, iout, k) character(len=30) :: arrname character(len=MAXCHARLEN) :: ermsg, ermsgr ! -- formats - 2 format(/,1x,a,' = ',g14.7,' FOR LAYER ',i0) - 3 format(/,1x,a,' = ',g14.7) +2 format(/, 1x, a, ' = ', g14.7, ' FOR LAYER ', i0) +3 format(/, 1x, a, ' = ', g14.7) ! ! -- Read array control record. call read_control_dbl(iu, iout, aname, locat, cnstnt, iclose, iprn) @@ -319,60 +328,61 @@ subroutine read_array_dbl1d(iu, darr, aname, ndim, jj, iout, k) ! -- Read or assign array data. if (locat == 0) then ! -- Assign constant - do j=1,jj + do j = 1, jj darr(j) = cnstnt - enddo + end do if (iout > 0) then if (k > 0) then - write(iout,2) trim(aname), cnstnt, k + write (iout, 2) trim(aname), cnstnt, k else - write(iout,3) trim(aname), cnstnt - endif - endif + write (iout, 3) trim(aname), cnstnt + end if + end if elseif (locat > 0) then ! -- Read data as text - read(locat,*,iostat=istat,iomsg=ermsgr) (darr(j),j=1,jj) + read (locat, *, iostat=istat, iomsg=ermsgr) (darr(j), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif - do j=1,jj + end if + do j = 1, jj darr(j) = darr(j) * cnstnt - enddo + end do if (iclose == 1) then - close(locat) - endif + close (locat) + end if else ! -- Read data as binary locat = -locat nvalt = 0 do call read_binary_header(locat, iout, aname, nval) - read(locat,iostat=istat,iomsg=ermsgr) (darr(j), j=nvalt+1, nvalt+nval) + read (locat, iostat=istat, iomsg=ermsgr) & + (darr(j), j=nvalt + 1, nvalt + nval) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif + end if nvalt = nvalt + nval if (nvalt == size(darr)) exit - enddo + end do ! ! -- multiply entire array by constant do j = 1, jj darr(j) = darr(j) * cnstnt - enddo + end do ! ! -- close the file if (iclose == 1) then - close(locat) - endif - endif + close (locat) + end if + end if ! ! -- Print array if requested. if (iprn >= 0 .and. locat /= 0) then @@ -380,19 +390,19 @@ subroutine read_array_dbl1d(iu, darr, aname, ndim, jj, iout, k) call build_format_dbl(iprn, prfmt, prowcolnum, ncpl, ndig) call print_array_dbl(darr, aname, iout, jj, 1, k, prfmt, ncpl, ndig, & prowcolnum) - endif + end if ! return end subroutine read_array_dbl1d subroutine read_array_dbl2d(iu, darr, aname, ndim, jj, ii, iout, k) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: jj, ii - real(DP), dimension(jj,ii), intent(inout) :: darr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k ! layer number; 0 to not print + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: jj, ii + real(DP), dimension(jj, ii), intent(inout) :: darr + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k ! layer number; 0 to not print ! -- local integer(I4B) :: i, iclose, iprn, j, locat, ncpl, ndig integer(I4B) :: nval @@ -403,8 +413,8 @@ subroutine read_array_dbl2d(iu, darr, aname, ndim, jj, ii, iout, k) character(len=30) :: arrname character(len=MAXCHARLEN) :: ermsg, ermsgr ! -- formats - 2 format(/,1x,a,' = ',g14.7, ' FOR LAYER ',i0) - 3 format(/,1x,a,' = ',g14.7) +2 format(/, 1x, a, ' = ', g14.7, ' FOR LAYER ', i0) +3 format(/, 1x, a, ' = ', g14.7) ! ! -- Read array control record. call read_control_dbl(iu, iout, aname, locat, cnstnt, iclose, iprn) @@ -412,57 +422,57 @@ subroutine read_array_dbl2d(iu, darr, aname, ndim, jj, ii, iout, k) ! -- Read or assign array data. if (locat == 0) then ! -- Assign constant - do i=1,ii - do j=1,jj - darr(j,i) = cnstnt - enddo - enddo + do i = 1, ii + do j = 1, jj + darr(j, i) = cnstnt + end do + end do if (iout > 0) then if (k > 0) then - write(iout,2) trim(aname), cnstnt, k + write (iout, 2) trim(aname), cnstnt, k else - write(iout,3) trim(aname), cnstnt - endif - endif + write (iout, 3) trim(aname), cnstnt + end if + end if elseif (locat > 0) then ! -- Read data as text - do i=1,ii - read(locat,*,iostat=istat,iomsg=ermsgr) (darr(j,i),j=1,jj) + do i = 1, ii + read (locat, *, iostat=istat, iomsg=ermsgr) (darr(j, i), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif - do j=1,jj - darr(j,i) = darr(j,i) * cnstnt - enddo - enddo + end if + do j = 1, jj + darr(j, i) = darr(j, i) * cnstnt + end do + end do if (iclose == 1) then - close(locat) - endif + close (locat) + end if else ! -- Read data as binary locat = -locat call read_binary_header(locat, iout, aname, nval) do i = 1, ii - read(locat,iostat=istat,iomsg=ermsgr) (darr(j,i), j = 1, jj) + read (locat, iostat=istat, iomsg=ermsgr) (darr(j, i), j=1, jj) if (istat /= 0) then arrname = adjustl(aname) - ermsg = 'Error reading data for array: ' // trim(arrname) + ermsg = 'Error reading data for array: '//trim(arrname) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif + end if do j = 1, jj - darr(j,i) = darr(j,i) * cnstnt - enddo - enddo + darr(j, i) = darr(j, i) * cnstnt + end do + end do if (iclose == 1) then - close(locat) - endif - endif + close (locat) + end if + end if ! ! -- Print array if requested. if (iprn >= 0 .and. locat /= 0) then @@ -470,11 +480,11 @@ subroutine read_array_dbl2d(iu, darr, aname, ndim, jj, ii, iout, k) call build_format_dbl(iprn, prfmt, prowcolnum, ncpl, ndig) call print_array_dbl(darr, aname, iout, jj, ii, k, prfmt, ncpl, & ndig, prowcolnum) - endif + end if ! return end subroutine read_array_dbl2d - + subroutine read_array_dbl3d(iu, darr, aname, ndim, ncol, nrow, nlay, iout, & k1, k2) ! ****************************************************************************** @@ -491,24 +501,24 @@ subroutine read_array_dbl3d(iu, darr, aname, ndim, ncol, nrow, nlay, iout, & integer(I4B), intent(in) :: nrow integer(I4B), intent(in) :: nlay integer(I4B), intent(in) :: k1, k2 - real(DP), dimension(ncol,nrow,nlay), intent(inout) :: darr + real(DP), dimension(ncol, nrow, nlay), intent(inout) :: darr character(len=*), intent(in) :: aname ! -- local integer(I4B) :: k, kk ! ------------------------------------------------------------------------------ ! - do k=k1,k2 + do k = k1, k2 if (k <= 0) then kk = 1 else kk = k - endif - call read_array_dbl2d(iu, darr(:,:,kk), aname, ndim, ncol, nrow, iout, k) - enddo + end if + call read_array_dbl2d(iu, darr(:, :, kk), aname, ndim, ncol, nrow, iout, k) + end do ! return end subroutine read_array_dbl3d - + subroutine read_array_dbl3d_all(iu, darr, aname, ndim, nvals, iout) ! ****************************************************************************** ! Read three-dimensional real array, consisting of one or more 2d arrays with @@ -521,7 +531,7 @@ subroutine read_array_dbl3d_all(iu, darr, aname, ndim, nvals, iout) integer(I4B), intent(in) :: iout integer(I4B), intent(in) :: ndim integer(I4B), intent(in) :: nvals - real(DP), dimension(nvals,1,1), intent(inout) :: darr + real(DP), dimension(nvals, 1, 1), intent(inout) :: darr character(len=*), intent(in) :: aname ! -- local ! ------------------------------------------------------------------------------ @@ -534,12 +544,12 @@ end subroutine read_array_dbl3d_all subroutine read_array_dbl1d_layered(iu, darr, aname, ndim, ncol, nrow, & nlay, nval, iout, k1, k2) ! -- dummy - integer(I4B), intent(in) :: iu, iout - integer(I4B), intent(in) :: ncol, nrow, nlay, nval + integer(I4B), intent(in) :: iu, iout + integer(I4B), intent(in) :: ncol, nrow, nlay, nval real(DP), dimension(nval), intent(inout) :: darr - character(len=*), intent(in) :: aname - integer(I4B), intent(in) :: ndim ! dis%ndim - integer(I4B), intent(in) :: k1, k2 + character(len=*), intent(in) :: aname + integer(I4B), intent(in) :: ndim ! dis%ndim + integer(I4B), intent(in) :: k1, k2 ! -- local ! call read_array_dbl3d(iu, darr, aname, ndim, ncol, nrow, nlay, iout, k1, k2) @@ -548,23 +558,23 @@ subroutine read_array_dbl1d_layered(iu, darr, aname, ndim, ncol, nrow, & end subroutine read_array_dbl1d_layered ! -- Utility procedures - + subroutine read_control_int(iu, iout, aname, locat, iconst, & iclose, iprn) ! Read an array-control record for an integer array. ! Open an input file if needed. ! If CONSTANT is specified in input, locat is returned as 0. - ! If (BINARY) is specified, locat is returned as the negative of + ! If (BINARY) is specified, locat is returned as the negative of ! the unit number opened for binary read. ! If OPEN/CLOSE is specified, iclose is returned as 1, otherwise 0. ! -- dummy - integer(I4B), intent(in) :: iu - integer(I4B), intent(in) :: iout - character(len=*), intent(in) :: aname - integer(I4B), intent(out) :: locat - integer(I4B), intent(out) :: iconst - integer(I4B), intent(out) :: iclose - integer(I4B), intent(out) :: iprn + integer(I4B), intent(in) :: iu + integer(I4B), intent(in) :: iout + character(len=*), intent(in) :: aname + integer(I4B), intent(out) :: locat + integer(I4B), intent(out) :: iconst + integer(I4B), intent(out) :: iclose + integer(I4B), intent(out) :: iprn ! -- local integer(I4B) :: icol, icol1, istart, istop, n real(DP) :: r @@ -574,23 +584,23 @@ subroutine read_control_int(iu, iout, aname, locat, iconst, & call read_control_1(iu, iout, aname, locat, iclose, line, icol, fname) if (locat == 0) then ! CONSTANT was found -- read value and return - call urword(line,icol,istart,istop,2,iconst,r,iout,iu) + call urword(line, icol, istart, istop, 2, iconst, r, iout, iu) iprn = -1 return - endif + end if icol1 = icol iconst = 1 ! ! -- Read FACTOR option from array control record. call urword(line, icol, istart, istop, 1, n, r, iout, iu) if (line(istart:istop) == 'FACTOR') then - call urword(line,icol,istart,istop,2,iconst,r,iout,iu) + call urword(line, icol, istart, istop, 2, iconst, r, iout, iu) if (iconst == 0) iconst = 1 else icol = icol1 - endif + end if ! - ! -- Read (BINARY) and IPRN options from array control record, + ! -- Read (BINARY) and IPRN options from array control record, ! and open an OPEN/CLOSE file if specified. call read_control_2(iu, iout, fname, line, icol, locat, iclose, iprn) ! @@ -602,17 +612,17 @@ subroutine read_control_dbl(iu, iout, aname, locat, cnstnt, & ! Read an array-control record for a double-precision array. ! Open an input file if needed. ! If CONSTANT is specified in input, locat is returned as 0. - ! If (BINARY) is specified, locat is returned as the negative of + ! If (BINARY) is specified, locat is returned as the negative of ! the unit number opened for binary read. ! If OPEN/CLOSE is specified, iclose is returned as 1, otherwise 0. ! -- dummy - integer(I4B), intent(in) :: iu - integer(I4B), intent(in) :: iout - character(len=*), intent(in) :: aname - integer(I4B), intent(out) :: locat - real(DP), intent(out) :: cnstnt - integer(I4B), intent(out) :: iclose - integer(I4B), intent(out) :: iprn + integer(I4B), intent(in) :: iu + integer(I4B), intent(in) :: iout + character(len=*), intent(in) :: aname + integer(I4B), intent(out) :: locat + real(DP), intent(out) :: cnstnt + integer(I4B), intent(out) :: iclose + integer(I4B), intent(out) :: iprn ! ! -- local integer(I4B) :: icol, icol1, istart, istop, n @@ -623,41 +633,41 @@ subroutine read_control_dbl(iu, iout, aname, locat, cnstnt, & call read_control_1(iu, iout, aname, locat, iclose, line, icol, fname) if (locat == 0) then ! CONSTANT was found -- read value and return - call urword(line,icol,istart,istop,3,n,cnstnt,iout,iu) + call urword(line, icol, istart, istop, 3, n, cnstnt, iout, iu) iprn = -1 return - endif + end if icol1 = icol cnstnt = DONE ! ! -- Read FACTOR option from array control record. call urword(line, icol, istart, istop, 1, n, r, iout, iu) if (line(istart:istop) == 'FACTOR') then - call urword(line,icol,istart,istop,3,n,cnstnt,iout,iu) + call urword(line, icol, istart, istop, 3, n, cnstnt, iout, iu) if (cnstnt == DZERO) cnstnt = DONE else icol = icol1 - endif + end if ! - ! -- Read (BINARY) and IPRN options from array control record, + ! -- Read (BINARY) and IPRN options from array control record, ! and open an OPEN/CLOSE file if specified. call read_control_2(iu, iout, fname, line, icol, locat, iclose, iprn) ! return end subroutine read_control_dbl - + subroutine read_control_1(iu, iout, aname, locat, iclose, line, icol, fname) ! -- Read CONSTANT, INTERNAL, or OPEN/CLOSE from array control record. ! -- dummy - integer(I4B), intent(in) :: iu - integer(I4B), intent(in) :: iout - character(len=*), intent(in) :: aname - integer(I4B), intent(out) :: locat - integer(I4B), intent(out) :: iclose + integer(I4B), intent(in) :: iu + integer(I4B), intent(in) :: iout + character(len=*), intent(in) :: aname + integer(I4B), intent(out) :: locat + integer(I4B), intent(out) :: iclose character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: icol + integer(I4B), intent(inout) :: icol character(len=*), intent(inout) :: fname - + ! -- local integer(I4B) :: istart, istop, n integer(I4B) :: ierr @@ -665,43 +675,43 @@ subroutine read_control_1(iu, iout, aname, locat, iclose, line, icol, fname) character(len=MAXCHARLEN) :: ermsg ! ! -- Read array control record. - call u8rdcom(iu,iout,line,ierr) + call u8rdcom(iu, iout, line, ierr) ! iclose = 0 icol = 1 ! -- Read first token of array control record. - call urword(line,icol,istart,istop,1,n,r,iout,iu) - if (line(istart:istop).eq.'CONSTANT') then + call urword(line, icol, istart, istop, 1, n, r, iout, iu) + if (line(istart:istop) .eq. 'CONSTANT') then locat = 0 - elseif (line(istart:istop).eq.'INTERNAL') then + elseif (line(istart:istop) .eq. 'INTERNAL') then locat = iu - elseif (line(istart:istop).eq.'OPEN/CLOSE') then - call urword(line,icol,istart,istop,0,n,r,iout,iu) + elseif (line(istart:istop) .eq. 'OPEN/CLOSE') then + call urword(line, icol, istart, istop, 0, n, r, iout, iu) fname = line(istart:istop) locat = -1 iclose = 1 else - write(ermsg, *) 'ERROR READING CONTROL RECORD FOR ' // & - trim(adjustl(aname)) + write (ermsg, *) 'ERROR READING CONTROL RECORD FOR '// & + trim(adjustl(aname)) call store_error(ermsg) call store_error(trim(adjustl(line))) - write(ermsg, *) 'Use CONSTANT, INTERNAL, or OPEN/CLOSE.' + write (ermsg, *) 'Use CONSTANT, INTERNAL, or OPEN/CLOSE.' call store_error(ermsg) call store_error_unit(iu) - endif + end if ! return end subroutine read_control_1 - + subroutine read_control_2(iu, iout, fname, line, icol, & locat, iclose, iprn) - ! -- Read (BINARY) and IPRN options from array control record, + ! -- Read (BINARY) and IPRN options from array control record, ! and open an OPEN/CLOSE file if specified. ! -- dummy - integer(I4B), intent(in) :: iu, iout, iclose - character(len=*), intent(in) :: fname + integer(I4B), intent(in) :: iu, iout, iclose + character(len=*), intent(in) :: fname character(len=*), intent(inout) :: line - integer(I4B), intent(inout) :: icol, iprn, locat + integer(I4B), intent(inout) :: icol, iprn, locat ! -- local integer(I4B) :: i, n, istart, istop, lenkey real(DP) :: r @@ -709,38 +719,38 @@ subroutine read_control_2(iu, iout, fname, line, icol, & character(len=LENBIGLINE) :: ermsg logical :: binary ! - iprn = -1 ! Printing is turned off by default + iprn = -1 ! Printing is turned off by default binary = .false. ! - if (locat.ne.0) then + if (locat .ne. 0) then ! -- CONSTANT has not been specified; array data will be read. ! -- Read at most two options. - do i=1,2 - call urword(line,icol,istart,istop,1,n,r,iout,iu) + do i = 1, 2 + call urword(line, icol, istart, istop, 1, n, r, iout, iu) keyword = line(istart:istop) lenkey = len_trim(keyword) select case (keyword) case ('(BINARY)') if (iclose == 0) then - ermsg = '"(BINARY)" option for array input is valid only if' // & + ermsg = '"(BINARY)" option for array input is valid only if'// & ' OPEN/CLOSE is also specified.' call store_error(ermsg) call store_error_unit(iu) - endif + end if binary = .true. case ('IPRN') ! -- Read IPRN value - call urword(line,icol,istart,istop,2,iprn,r,iout,iu) + call urword(line, icol, istart, istop, 2, iprn, r, iout, iu) exit case ('') exit case default ermsg = 'Invalid option found in array-control record: "' & - // trim(keyword) // '"' + //trim(keyword)//'"' call store_error(ermsg) call store_error_unit(iu) end select - enddo + end do ! if (iclose == 0) then ! -- Array data will be read from current input file. @@ -753,9 +763,9 @@ subroutine read_control_2(iu, iout, fname, line, icol, & locat = -locat else call openfile(locat, iout, fname, 'OPEN/CLOSE') - endif - endif - endif + end if + end if + end if ! return end subroutine read_control_2 @@ -763,17 +773,17 @@ end subroutine read_control_2 subroutine build_format_int(iprn, prfmt, prowcolnum, ncpl, ndig) ! -- Build a print format for integers based on IPRN. ! -- dummy - integer(I4B), intent(inout) :: iprn + integer(I4B), intent(inout) :: iprn character(len=*), intent(out) :: prfmt - logical, intent(in) :: prowcolnum - integer(I4B), intent(out) :: ncpl, ndig + logical, intent(in) :: prowcolnum + integer(I4B), intent(out) :: ncpl, ndig ! -- local integer(I4B) :: nwidp ! if (iprn < 0) then prfmt = '' return - endif + end if ! if (iprn > 9) iprn = 0 ! @@ -815,14 +825,14 @@ subroutine build_format_int(iprn, prfmt, prowcolnum, ncpl, ndig) ! return end subroutine build_format_int - + subroutine build_format_dbl(iprn, prfmt, prowcolnum, ncpl, ndig) ! -- Build a print format for reals based on IPRN. ! -- dummy - integer(I4B), intent(inout) :: iprn + integer(I4B), intent(inout) :: iprn character(len=*), intent(out) :: prfmt - logical, intent(in) :: prowcolnum - integer(I4B), intent(out) :: ncpl, ndig + logical, intent(in) :: prowcolnum + integer(I4B), intent(out) :: ncpl, ndig ! -- local integer(I4B) :: nwidp character(len=1) :: editdesc @@ -830,7 +840,7 @@ subroutine build_format_dbl(iprn, prfmt, prowcolnum, ncpl, ndig) if (iprn < 0) then prfmt = '' return - endif + end if ! if (iprn > 21) iprn = 0 ! @@ -951,7 +961,7 @@ subroutine build_format_dbl(iprn, prfmt, prowcolnum, ncpl, ndig) call BuildFixedFormat(ncpl, nwidp, ndig, prfmt, prowcolnum) else call BuildFloatFormat(ncpl, nwidp, ndig, editdesc, prfmt, prowcolnum) - endif + end if ! ndig = nwidp + 1 ! @@ -961,28 +971,28 @@ end subroutine build_format_dbl subroutine print_array_int(iarr, aname, iout, jj, ii, k, prfmt, & ncpl, ndig, prowcolnum) ! -- dummy - integer(I4B), intent(in) :: iout, jj, ii, k - integer(I4B), intent(in) :: ncpl ! # values to print per line - integer(I4B), intent(in) :: ndig ! # characters in each field - integer(I4B), dimension(jj,ii), intent(in) :: iarr ! Integer array to be printed - character(len=*), intent(in) :: aname ! Array name - character(len=*), intent(in) :: prfmt ! Print format, no row # - logical, intent(in) :: prowcolnum ! Print row & column numbers + integer(I4B), intent(in) :: iout, jj, ii, k + integer(I4B), intent(in) :: ncpl ! # values to print per line + integer(I4B), intent(in) :: ndig ! # characters in each field + integer(I4B), dimension(jj, ii), intent(in) :: iarr ! Integer array to be printed + character(len=*), intent(in) :: aname ! Array name + character(len=*), intent(in) :: prfmt ! Print format, no row # + logical, intent(in) :: prowcolnum ! Print row & column numbers ! -- local integer(I4B) :: i, j character(len=MAXCHARLEN) :: ermsg ! -- formats - 2 format(/,1x,a,1x,'FOR LAYER ',i0) - 3 format(/,1x,a) +2 format(/, 1x, a, 1x, 'FOR LAYER ', i0) +3 format(/, 1x, a) ! if (iout <= 0) return ! ! -- Write name of array if (k > 0) then - write(iout,2)trim(aname),k + write (iout, 2) trim(aname), k else - write(iout,3)trim(aname) - endif + write (iout, 3) trim(aname) + end if ! ! -- Write array if (prowcolnum) then @@ -990,19 +1000,19 @@ subroutine print_array_int(iarr, aname, iout, jj, ii, k, prfmt, & call ucolno(1, jj, 4, ncpl, ndig, iout) ! ! -- Write array values, including row numbers - do i=1,ii - write(iout, prfmt) i, (iarr(j,i),j=1,jj) - enddo + do i = 1, ii + write (iout, prfmt) i, (iarr(j, i), j=1, jj) + end do else if (ii > 1) then - ermsg = 'Program error printing array ' // trim(aname) // & + ermsg = 'Program error printing array '//trim(aname)// & ': ii > 1 when prowcolnum is false.' call store_error(ermsg, terminate=.TRUE.) - endif + end if ! ! -- Write array values, without row numbers - write(iout, prfmt) (iarr(j,1),j=1,jj) - endif + write (iout, prfmt) (iarr(j, 1), j=1, jj) + end if ! return end subroutine print_array_int @@ -1010,28 +1020,28 @@ end subroutine print_array_int subroutine print_array_dbl(darr, aname, iout, jj, ii, k, prfmt, & ncpl, ndig, prowcolnum) ! -- dummy - integer(I4B), intent(in) :: iout, jj, ii, k - integer(I4B), intent(in) :: ncpl ! # values to print per line - integer(I4B), intent(in) :: ndig ! # characters in each field - real(DP), dimension(jj,ii), intent(in) :: darr ! Real array to be printed - character(len=*), intent(in) :: aname ! Array name - character(len=*), intent(in) :: prfmt ! Print format, no row # - logical, intent(in) :: prowcolnum ! Print row & column numbers + integer(I4B), intent(in) :: iout, jj, ii, k + integer(I4B), intent(in) :: ncpl ! # values to print per line + integer(I4B), intent(in) :: ndig ! # characters in each field + real(DP), dimension(jj, ii), intent(in) :: darr ! Real array to be printed + character(len=*), intent(in) :: aname ! Array name + character(len=*), intent(in) :: prfmt ! Print format, no row # + logical, intent(in) :: prowcolnum ! Print row & column numbers ! -- local integer(I4B) :: i, j character(len=MAXCHARLEN) :: ermsg ! -- formats - 2 format(/,1x,a,1x,'FOR LAYER ',i0) - 3 format(/,1x,a) +2 format(/, 1x, a, 1x, 'FOR LAYER ', i0) +3 format(/, 1x, a) ! if (iout <= 0) return ! ! -- Write name of array if (k > 0) then - write(iout,2)trim(aname),k + write (iout, 2) trim(aname), k else - write(iout,3)trim(aname) - endif + write (iout, 3) trim(aname) + end if ! ! -- Write array if (prowcolnum) then @@ -1039,19 +1049,19 @@ subroutine print_array_dbl(darr, aname, iout, jj, ii, k, prfmt, & call ucolno(1, jj, 4, ncpl, ndig, iout) ! ! -- Write array values, including row numbers - do i=1,ii - write(iout, prfmt) i, (darr(j,i),j=1,jj) - enddo + do i = 1, ii + write (iout, prfmt) i, (darr(j, i), j=1, jj) + end do else if (ii > 1) then - ermsg = 'Program error printing array ' // trim(aname) // & + ermsg = 'Program error printing array '//trim(aname)// & ': ii > 1 when prowcolnum is false.' call store_error(ermsg, terminate=.TRUE.) - endif + end if ! ! -- Write array values, without row numbers - write(iout, prfmt) (darr(j,1),j=1,jj) - endif + write (iout, prfmt) (darr(j, 1), j=1, jj) + end if ! return end subroutine print_array_dbl @@ -1076,21 +1086,21 @@ subroutine read_binary_header(locat, iout, arrname, nval) &/,4X,'MSIZE 1: ',I0,' MSIZE 2: ',I0,' MSIZE 3: ',I0)" ! ! -- Read the header line from the binary file - read(locat, iostat=istat, iomsg=ermsgr) kstp, kper, pertim, totim, text, & + read (locat, iostat=istat, iomsg=ermsgr) kstp, kper, pertim, totim, text, & m1, m2, m3 ! ! -- Check for errors if (istat /= 0) then - ermsg = 'Error reading data for array: ' // adjustl(trim(arrname)) + ermsg = 'Error reading data for array: '//adjustl(trim(arrname)) call store_error(ermsg) call store_error(ermsgr) call store_error_unit(locat) - endif + end if ! ! -- Write message about the binary header if (iout > 0) then - write(iout, fmthdr) kstp, kper, pertim, totim, text, m1, m2, m3 - endif + write (iout, fmthdr) kstp, kper, pertim, totim, text, m1, m2, m3 + end if ! ! -- Assign the number of values that follow the header nval = m1 * m2 @@ -1098,5 +1108,5 @@ subroutine read_binary_header(locat, iout, arrname, nval) ! -- return return end subroutine read_binary_header - + end module ArrayReadersModule diff --git a/src/Utilities/BlockParser.f90 b/src/Utilities/BlockParser.f90 index eb29c678af0..2cc5159db58 100644 --- a/src/Utilities/BlockParser.f90 +++ b/src/Utilities/BlockParser.f90 @@ -5,31 +5,31 @@ !! !< module BlockParserModule - - use KindModule, only: DP, I4B - use ConstantsModule, only: LENHUGELINE, LINELENGTH, MAXCHARLEN - use VersionModule, only: IDEVELOPMODE - use InputOutputModule, only: uget_block, uget_any_block, uterminate_block, & - u9rdcom, urword, upcase - use SimModule, only: store_error, store_error_unit + + use KindModule, only: DP, I4B + use ConstantsModule, only: LENHUGELINE, LINELENGTH, MAXCHARLEN + use VersionModule, only: IDEVELOPMODE + use InputOutputModule, only: uget_block, uget_any_block, uterminate_block, & + u9rdcom, urword, upcase + use SimModule, only: store_error, store_error_unit use SimVariablesModule, only: errmsg - + implicit none - + private public :: BlockParserType - + type :: BlockParserType - integer(I4B), public :: iuactive !< flag indicating if a file unit is active, variable is not used internally - integer(I4B), private :: inunit !< file unit number - integer(I4B), private :: iuext !< external file unit number - integer(I4B), private :: iout !< listing file unit number - integer(I4B), private :: linesRead !< number of lines read - integer(I4B), private :: lloc !< line location counter - character(len=LINELENGTH), private :: blockName !< block name - character(len=LINELENGTH), private :: blockNameFound !< block name found - character(len=LENHUGELINE), private :: laststring !< last string read - character(len=:), allocatable, private :: line !< current line + integer(I4B), public :: iuactive !< flag indicating if a file unit is active, variable is not used internally + integer(I4B), private :: inunit !< file unit number + integer(I4B), private :: iuext !< external file unit number + integer(I4B), private :: iout !< listing file unit number + integer(I4B), private :: linesRead !< number of lines read + integer(I4B), private :: lloc !< line location counter + character(len=LINELENGTH), private :: blockName !< block name + character(len=LINELENGTH), private :: blockNameFound !< block name found + character(len=LENHUGELINE), private :: laststring !< last string read + character(len=:), allocatable, private :: line !< current line contains procedure, public :: Initialize procedure, public :: Clear @@ -49,7 +49,7 @@ module BlockParserModule procedure, public :: DevOpt procedure, private :: ReadScalarError end type BlockParserType - + contains !> @ brief Initialize the block parser @@ -59,9 +59,9 @@ module BlockParserModule !< subroutine Initialize(this, inunit, iout) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - integer(I4B), intent(in) :: inunit !< input file unit number - integer(I4B), intent(in) :: iout !< listing file unit number + class(BlockParserType), intent(inout) :: this !< BlockParserType object + integer(I4B), intent(in) :: inunit !< input file unit number + integer(I4B), intent(in) :: iout !< listing file unit number ! ! -- initialize values this%inunit = inunit @@ -74,7 +74,7 @@ subroutine Initialize(this, inunit, iout) ! -- return return end subroutine Initialize - + !> @ brief Close the block parser !! !! Method to clear the block parser, which closes file(s) and clears member @@ -83,24 +83,24 @@ end subroutine Initialize !< subroutine Clear(this) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! -- local variables logical :: lop ! ! Close any connected files if (this%inunit > 0) then - inquire(unit=this%inunit, opened=lop) + inquire (unit=this%inunit, opened=lop) if (lop) then - close(this%inunit) - endif - endif + close (this%inunit) + end if + end if ! if (this%iuext /= this%inunit .and. this%iuext > 0) then - inquire(unit=this%iuext, opened=lop) + inquire (unit=this%iuext, opened=lop) if (lop) then - close(this%iuext) - endif - endif + close (this%iuext) + end if + end if ! ! Clear all member variables this%inunit = 0 @@ -111,12 +111,12 @@ subroutine Clear(this) this%linesRead = 0 this%blockName = '' this%line = '' - deallocate(this%line) + deallocate (this%line) ! ! -- return return end subroutine Clear - + !> @ brief Get block !! !! Method to get the block from a file. The file is read until the blockname @@ -126,13 +126,13 @@ end subroutine Clear subroutine GetBlock(this, blockName, isFound, ierr, supportOpenClose, & blockRequired, blockNameFound) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=*), intent(in) :: blockName !< block name to search for - logical, intent(out) :: isFound !< boolean indicating if the block name was found - integer(I4B), intent(out) :: ierr !< return error code, 0 indicates block was found - logical, intent(in), optional :: supportOpenClose !< boolean indicating if the block supports open/close, default false - logical, intent(in), optional :: blockRequired !< boolean indicating if the block is required, default true - character(len=*), intent(inout), optional :: blockNameFound !< optional return value of block name found + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=*), intent(in) :: blockName !< block name to search for + logical, intent(out) :: isFound !< boolean indicating if the block name was found + integer(I4B), intent(out) :: ierr !< return error code, 0 indicates block was found + logical, intent(in), optional :: supportOpenClose !< boolean indicating if the block supports open/close, default false + logical, intent(in), optional :: blockRequired !< boolean indicating if the block is required, default true + character(len=*), intent(inout), optional :: blockNameFound !< optional return value of block name found ! -- local variables logical :: continueRead logical :: supportOpenCloseLocal @@ -143,13 +143,13 @@ subroutine GetBlock(this, blockName, isFound, ierr, supportOpenClose, & supportOpenCloseLocal = supportOpenClose else supportOpenCloseLocal = .false. - endif + end if ! if (present(blockRequired)) then blockRequiredLocal = blockRequired else blockRequiredLocal = .true. - endif + end if continueRead = blockRequiredLocal this%blockName = blockName this%blockNameFound = '' @@ -162,13 +162,13 @@ subroutine GetBlock(this, blockName, isFound, ierr, supportOpenClose, & ierr = 0 else ierr = 1 - endif + end if else call uget_block(this%inunit, this%iout, this%blockName, ierr, isFound, & this%lloc, this%line, this%iuext, continueRead, & supportOpenCloseLocal) if (isFound) this%blockNameFound = this%blockName - endif + end if this%iuactive = this%iuext this%linesRead = 0 ! @@ -183,8 +183,8 @@ end subroutine GetBlock !< subroutine GetNextLine(this, endOfBlock) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - logical, intent(out) :: endOfBlock !< boolean indicating if the end of the block was read + class(BlockParserType), intent(inout) :: this !< BlockParserType object + logical, intent(out) :: endOfBlock !< boolean indicating if the end of the block was read ! -- local variables integer(I4B) :: ierr integer(I4B) :: ival @@ -216,24 +216,24 @@ subroutine GetNextLine(this, endOfBlock) endOfBlock = .true. lineread = .true. elseif (key == '') then - ! End of file reached. - ! If this is an OPEN/CLOSE file, close the file and read the next + ! End of file reached. + ! If this is an OPEN/CLOSE file, close the file and read the next ! line from this%inunit. if (this%iuext /= this%inunit) then - close(this%iuext) + close (this%iuext) this%iuext = this%inunit this%iuactive = this%inunit else errmsg = 'Unexpected end of file reached.' call store_error(errmsg) call this%StoreErrorUnit() - endif + end if else this%lloc = 1 this%linesRead = this%linesRead + 1 lineread = .true. - endif - enddo loop1 + end if + end do loop1 ! ! -- return return @@ -246,9 +246,9 @@ end subroutine GetNextLine !< function GetInteger(this) result(i) ! -- return variable - integer(I4B) :: i !< integer variable + integer(I4B) :: i !< integer variable ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! -- local variables integer(I4B) :: istart integer(I4B) :: istop @@ -261,12 +261,12 @@ function GetInteger(this) result(i) ! -- Make sure variable was read before end of line if (istart == istop .and. istop == len(this%line)) then call this%ReadScalarError('INTEGER') - endif + end if ! ! -- return return end function GetInteger - + !> @ brief Get the number of lines read !! !! Function to get the number of lines read from the current block. @@ -274,28 +274,28 @@ end function GetInteger !< function GetLinesRead(this) result(nlines) ! -- return variable - integer(I4B) :: nlines !< number of lines read + integer(I4B) :: nlines !< number of lines read ! -- dummy variable - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! ! -- number of lines read - nlines = this%linesRead + nlines = this%linesRead ! ! -- return return end function GetLinesRead - + !> @ brief Get a double precision real !! - !! Function to get adouble precision floating point number from + !! Function to get adouble precision floating point number from !! the current line. !! !< function GetDouble(this) result(r) ! -- return variable - real(DP) :: r !< double precision real variable + real(DP) :: r !< double precision real variable ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! -- local variables integer(I4B) :: istart integer(I4B) :: istop @@ -308,12 +308,12 @@ function GetDouble(this) result(r) ! -- Make sure variable was read before end of line if (istart == istop .and. istop == len(this%line)) then call this%ReadScalarError('DOUBLE PRECISION') - endif + end if ! ! -- return return end function GetDouble - + !> @ brief Issue a read error !! !! Method to issue an unable to read error. @@ -321,20 +321,20 @@ end function GetDouble !< subroutine ReadScalarError(this, vartype) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=*), intent(in) :: vartype !< string of variable type + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=*), intent(in) :: vartype !< string of variable type ! -- local variables - character(len=MAXCHARLEN-100) :: linetemp + character(len=MAXCHARLEN - 100) :: linetemp ! ! -- use linetemp as line may be longer than MAXCHARLEN linetemp = this%line ! ! -- write the message - write(errmsg, '(3a)') 'Error in block ', trim(this%blockName), '.' - write(errmsg, '(4a)') & - trim(errmsg), ' Could not read variable of type ', trim(vartype), & - " from the following line: '" - write(errmsg, '(3a)') & + write (errmsg, '(3a)') 'Error in block ', trim(this%blockName), '.' + write (errmsg, '(4a)') & + trim(errmsg), ' Could not read variable of type ', trim(vartype), & + " from the following line: '" + write (errmsg, '(3a)') & trim(errmsg), trim(adjustl(this%line)), "'." call store_error(errmsg) call this%StoreErrorUnit() @@ -342,7 +342,7 @@ subroutine ReadScalarError(this, vartype) ! -- return return end subroutine ReadScalarError - + !> @ brief Get a string !! !! Method to get a string from the current line and optionally convert it @@ -351,8 +351,8 @@ end subroutine ReadScalarError !< subroutine GetString(this, string, convertToUpper) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=*), intent(out) :: string !< string + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=*), intent(out) :: string !< string logical, optional, intent(in) :: convertToUpper !< boolean indicating if the string should be converted to upper case, default false ! -- local variables integer(I4B) :: istart @@ -367,10 +367,10 @@ subroutine GetString(this, string, convertToUpper) ncode = 1 else ncode = 0 - endif + end if else ncode = 0 - endif + end if ! call urword(this%line, this%lloc, istart, istop, ncode, & ival, rval, this%iout, this%iuext) @@ -389,8 +389,8 @@ end subroutine GetString !< subroutine GetStringCaps(this, string) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=*), intent(out) :: string !< upper case string + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=*), intent(out) :: string !< upper case string ! ! -- call base GetString method with convertToUpper variable call this%GetString(string, convertToUpper=.true.) @@ -406,8 +406,8 @@ end subroutine GetStringCaps !< subroutine GetRemainingLine(this, line) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=:), allocatable, intent(out) :: line !< remainder of the line + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=:), allocatable, intent(out) :: line !< remainder of the line ! -- local variables integer(I4B) :: lastpos integer(I4B) :: newlinelen @@ -416,14 +416,14 @@ subroutine GetRemainingLine(this, line) lastpos = len_trim(this%line) newlinelen = lastpos - this%lloc + 2 newlinelen = max(newlinelen, 1) - allocate(character(len=newlinelen) :: line) - line(:) = this%line(this%lloc:lastpos) + allocate (character(len=newlinelen) :: line) + line(:) = this%line(this%lloc:lastpos) line(newlinelen:newlinelen) = ' ' ! ! -- return return end subroutine GetRemainingLine - + !> @ brief Ensure that the block is closed !! !! Method to ensure that the block is closed with an "end". @@ -431,18 +431,18 @@ end subroutine GetRemainingLine !< subroutine terminateblock(this) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! -- local variables logical :: endofblock ! ! -- look for block termination call this%GetNextLine(endofblock) if (.not. endofblock) then - errmsg = "LOOKING FOR 'END " // trim(this%blockname) // & - "'. FOUND: " // "'" // trim(this%line) // "'." + errmsg = "LOOKING FOR 'END "//trim(this%blockname)// & + "'. FOUND: "//"'"//trim(this%line)//"'." call store_error(errmsg) call this%StoreErrorUnit() - endif + end if ! ! -- return return @@ -455,10 +455,10 @@ end subroutine terminateblock !< subroutine GetCellid(this, ndim, cellid, flag_string) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - integer(I4B), intent(in) :: ndim !< number of dimensions (1, 2, or 3) - character(len=*), intent(out) :: cellid !< cell =id - logical, optional, intent(in) :: flag_string !< boolean indicating id cellid is a string + class(BlockParserType), intent(inout) :: this !< BlockParserType object + integer(I4B), intent(in) :: ndim !< number of dimensions (1, 2, or 3) + character(len=*), intent(out) :: cellid !< cell =id + logical, optional, intent(in) :: flag_string !< boolean indicating id cellid is a string ! -- local variables integer(I4B) :: i integer(I4B) :: j @@ -477,24 +477,24 @@ subroutine GetCellid(this, ndim, cellid, flag_string) call urword(this%line, lloc, istart, istop, 0, ival, rval, this%iout, & this%iuext) firsttoken = this%line(istart:istop) - read(firsttoken,*,iostat=istat) ival + read (firsttoken, *, iostat=istat) ival if (istat > 0) then call upcase(firsttoken) cellid = firsttoken return - endif - endif + end if + end if ! cellid = '' - do i=1,ndim + do i = 1, ndim j = this%GetInteger() - write(cint,'(i0)') j + write (cint, '(i0)') j if (i == 1) then cellid = cint else - cellid = trim(cellid) // ' ' // cint - endif - enddo + cellid = trim(cellid)//' '//cint + end if + end do ! ! -- return return @@ -507,8 +507,8 @@ end subroutine GetCellid !< subroutine GetCurrentLine(this, line) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object - character(len=*), intent(out) :: line !< current line + class(BlockParserType), intent(inout) :: this !< BlockParserType object + character(len=*), intent(out) :: line !< current line ! ! -- get the current line line = this%line @@ -525,8 +525,8 @@ end subroutine GetCurrentLine !< subroutine StoreErrorUnit(this, terminate) ! -- dummy variable - class(BlockParserType), intent(inout) :: this !< BlockParserType object - logical, intent(in), optional :: terminate !< boolean indicating if the simulation should be terminated + class(BlockParserType), intent(inout) :: this !< BlockParserType object + logical, intent(in), optional :: terminate !< boolean indicating if the simulation should be terminated ! -- loacl variables logical :: lterminate ! @@ -536,7 +536,7 @@ subroutine StoreErrorUnit(this, terminate) else lterminate = .TRUE. end if - ! + ! ! -- store error unit call store_error_unit(this%iuext, terminate=lterminate) ! @@ -551,9 +551,9 @@ end subroutine StoreErrorUnit !< function GetUnit(this) result(i) ! -- return variable - integer(I4B) :: i !< unit number for the block parser + integer(I4B) :: i !< unit number for the block parser ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! ! -- block parser unit number i = this%iuext @@ -564,7 +564,7 @@ end function GetUnit !> @ brief Development option !! - !! Method that will cause the program to terminate with an error if the + !! Method that will cause the program to terminate with an error if the !! IDEVELOPMODE flag is set to 1. This is used to allow develop options !! to be specified for development testing but not for the public release. !! For the public release, IDEVELOPMODE is set to zero. @@ -572,16 +572,16 @@ end function GetUnit !< subroutine DevOpt(this) ! -- dummy variables - class(BlockParserType), intent(inout) :: this !< BlockParserType object + class(BlockParserType), intent(inout) :: this !< BlockParserType object ! ! -- If release mode (not develop mode), then option not available. ! Terminate with an error. if (IDEVELOPMODE == 0) then - errmsg = "Invalid keyword '" // trim(this%laststring) // & - "' detected in block '" // trim(this%blockname) // "'." + errmsg = "Invalid keyword '"//trim(this%laststring)// & + "' detected in block '"//trim(this%blockname)//"'." call store_error(errmsg) call this%StoreErrorUnit() - endif + end if ! ! -- Return return diff --git a/src/Utilities/Budget.f90 b/src/Utilities/Budget.f90 index 7098d3a2714..e3947909e80 100644 --- a/src/Utilities/Budget.f90 +++ b/src/Utilities/Budget.f90 @@ -1,14 +1,14 @@ -!> @brief This module contains the BudgetModule +!> @brief This module contains the BudgetModule !! !! New entries can be added for each time step, however, the same number of !! entries must be provided, and they must be provided in the same order. If not, !! the module will terminate with an error. -!! +!! !! Maxsize is required as part of the df method and the arrays will be allocated !! to maxsize. If additional entries beyond maxsize are added, the arrays !! will dynamically increase in size, however, to avoid allocation and copying, !! it is best to set maxsize large enough up front. -!! +!! !! vbvl(1, :) contains cumulative rate in !! vbvl(2, :) contains cumulative rate out !! vbvl(3, :) contains rate in @@ -20,20 +20,20 @@ module BudgetModule use KindModule, only: DP, I4B - use SimModule, only: store_error, count_errors + use SimModule, only: store_error, count_errors use ConstantsModule, only: LINELENGTH, LENBUDTXT, LENBUDROWLABEL, DZERO, & DTWO, DHUNDRED - + implicit none private public :: BudgetType public :: budget_cr public :: rate_accumulator - !> @brief Derived type for the Budget object + !> @brief Derived type for the Budget object !! - !! This derived type stores and prints information about a - !! model budget. + !! This derived type stores and prints information about a + !! model budget. !! !< type BudgetType @@ -41,11 +41,12 @@ module BudgetModule integer(I4B), pointer :: maxsize => null() real(DP), pointer :: budperc => null() logical, pointer :: written_once => null() - real(DP), dimension(:,:), pointer :: vbvl => null() + real(DP), dimension(:, :), pointer :: vbvl => null() character(len=LENBUDTXT), dimension(:), pointer, contiguous :: vbnm => null() character(len=20), pointer :: bdtype => null() character(len=5), pointer :: bddim => null() - character(len=LENBUDROWLABEL), dimension(:), pointer, contiguous :: rowlabel => null() + character(len=LENBUDROWLABEL), & + dimension(:), pointer, contiguous :: rowlabel => null() character(len=16), pointer :: labeltitle => null() character(len=20), pointer :: bdzone => null() logical, pointer :: labeled => null() @@ -53,7 +54,7 @@ module BudgetModule ! -- csv output integer(I4B), pointer :: ibudcsv => null() integer(I4B), pointer :: icsvheader => null() - + contains procedure :: budget_df procedure :: budget_ot @@ -65,28 +66,28 @@ module BudgetModule generic :: addentry => add_single_entry, add_multi_entry procedure :: writecsv ! -- private - procedure :: allocate_scalars + procedure :: allocate_scalars procedure, private :: allocate_arrays procedure, private :: resize procedure, private :: write_csv_header end type BudgetType - contains +contains !> @ brief Create a new budget object !! - !! Create a new budget object. + !! Create a new budget object. !! !< subroutine budget_cr(this, name_model) ! -- modules ! -- dummy - type(BudgetType), pointer :: this !< BudgetType object - character(len=*), intent(in) :: name_model !< name of the model + type(BudgetType), pointer :: this !< BudgetType object + character(len=*), intent(in) :: name_model !< name of the model ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(this) + allocate (this) ! ! -- Allocate scalars call this%allocate_scalars(name_model) @@ -97,16 +98,16 @@ end subroutine budget_cr !> @ brief Define information for this object !! - !! Allocate arrays and set member variables + !! Allocate arrays and set member variables !! !< subroutine budget_df(this, maxsize, bdtype, bddim, labeltitle, bdzone) - class(BudgetType) :: this !< BudgetType object - integer(I4B), intent(in) :: maxsize !< maximum size of budget arrays - character(len=*), optional :: bdtype !< type of budget, default is VOLUME - character(len=*), optional :: bddim !< dimensions of terms, default is L**3 - character(len=*), optional :: labeltitle !< budget label, default is PACKAGE NAME - character(len=*), optional :: bdzone !< corresponding zone, default is ENTIRE MODEL + class(BudgetType) :: this !< BudgetType object + integer(I4B), intent(in) :: maxsize !< maximum size of budget arrays + character(len=*), optional :: bdtype !< type of budget, default is VOLUME + character(len=*), optional :: bddim !< dimensions of terms, default is L**3 + character(len=*), optional :: labeltitle !< budget label, default is PACKAGE NAME + character(len=*), optional :: bdzone !< corresponding zone, default is ENTIRE MODEL ! ! -- Set values this%maxsize = maxsize @@ -115,62 +116,62 @@ subroutine budget_df(this, maxsize, bdtype, bddim, labeltitle, bdzone) call this%allocate_arrays() ! ! -- Set the budget type - if(present(bdtype)) then + if (present(bdtype)) then this%bdtype = bdtype else this%bdtype = 'VOLUME' - endif + end if ! ! -- Set the budget dimension - if(present(bddim)) then + if (present(bddim)) then this%bddim = bddim else this%bddim = 'L**3' - endif + end if ! ! -- Set the budget zone - if(present(bdzone)) then + if (present(bdzone)) then this%bdzone = bdzone else this%bdzone = 'ENTIRE MODEL' - endif + end if ! ! -- Set the label title - if(present(labeltitle)) then + if (present(labeltitle)) then this%labeltitle = labeltitle else this%labeltitle = 'PACKAGE NAME' - endif + end if ! ! -- Return return end subroutine budget_df - + !> @ brief Convert a number to a string !! - !! This is sometimes needed to avoid numbers that do not fit + !! This is sometimes needed to avoid numbers that do not fit !! correctly into a text string !! !< subroutine value_to_string(val, string, big, small) - real(DP), intent(in) :: val !< value to convert - character(len=*), intent(out) :: string !< string to fill - real(DP), intent(in) :: big !< big value - real(DP), intent(in) :: small !< small value + real(DP), intent(in) :: val !< value to convert + character(len=*), intent(out) :: string !< string to fill + real(DP), intent(in) :: big !< big value + real(DP), intent(in) :: small !< small value real(DP) :: absval ! absval = abs(val) if (val /= DZERO .and. (absval >= big .or. absval < small)) then if (absval >= 1.D100 .or. absval <= 1.D-100) then - ! -- if exponent has 3 digits, then need to explicitly use the ES + ! -- if exponent has 3 digits, then need to explicitly use the ES ! format to force writing the E character - write(string, '(es17.4E3)') val + write (string, '(es17.4E3)') val else - write(string, '(1pe17.4)') val + write (string, '(1pe17.4)') val end if else ! -- value is within range where number looks good with F format - write(string, '(f17.4)') val + write (string, '(f17.4)') val end if return end subroutine value_to_string @@ -182,14 +183,14 @@ end subroutine value_to_string !! !< subroutine budget_ot(this, kstp, kper, iout) - class(BudgetType) :: this !< BudgetType object - integer(I4B), intent(in) :: kstp !< time step - integer(I4B), intent(in) :: kper !< stress period - integer(I4B), intent(in) :: iout !< output unit number + class(BudgetType) :: this !< BudgetType object + integer(I4B), intent(in) :: kstp !< time step + integer(I4B), intent(in) :: kper !< stress period + integer(I4B), intent(in) :: iout !< output unit number character(len=17) :: val1, val2 integer(I4B) :: msum1, l - real(DP) :: two, hund, bigvl1, bigvl2, small, & - totrin, totrot, totvin, totvot, diffr, adiffr, & + real(DP) :: two, hund, bigvl1, bigvl2, small, & + totrin, totrot, totvin, totvot, diffr, adiffr, & pdiffr, pdiffv, avgrat, diffv, adiffv, avgvol ! ! -- Set constants @@ -202,7 +203,7 @@ subroutine budget_ot(this, kstp, kper, iout) ! -- Determine number of individual budget entries. this%budperc = DZERO msum1 = this%msum - 1 - if(msum1 <= 0) return + if (msum1 <= 0) return ! ! -- Clear rate and volume accumulators. totrin = DZERO @@ -211,65 +212,65 @@ subroutine budget_ot(this, kstp, kper, iout) totvot = DZERO ! ! -- Add rates and volumes (in and out) to accumulators. - do l=1,msum1 - totrin = totrin + this%vbvl(3,l) - totrot = totrot + this%vbvl(4,l) - totvin = totvin + this%vbvl(1,l) - totvot = totvot + this%vbvl(2,l) - enddo + do l = 1, msum1 + totrin = totrin + this%vbvl(3, l) + totrot = totrot + this%vbvl(4, l) + totvin = totvin + this%vbvl(1, l) + totvot = totvot + this%vbvl(2, l) + end do ! ! -- Print time step number and stress period number. - if(this%labeled) then - write(iout,261) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), & - kstp, kper - write(iout,266) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), & - trim(adjustl(this%bddim)),this%labeltitle + if (this%labeled) then + write (iout, 261) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), & + kstp, kper + write (iout, 266) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), & + trim(adjustl(this%bddim)), this%labeltitle else - write(iout,260) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), & - kstp, kper - write(iout,265) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), & - trim(adjustl(this%bddim)) - endif + write (iout, 260) trim(adjustl(this%bdtype)), trim(adjustl(this%bdzone)), & + kstp, kper + write (iout, 265) trim(adjustl(this%bdtype)), trim(adjustl(this%bddim)), & + trim(adjustl(this%bddim)) + end if ! ! -- Print individual inflow rates and volumes and their totals. - do l=1,msum1 + do l = 1, msum1 call value_to_string(this%vbvl(1, l), val1, bigvl1, small) call value_to_string(this%vbvl(3, l), val2, bigvl1, small) - if(this%labeled) then - write(iout,276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l) + if (this%labeled) then + write (iout, 276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l) else - write(iout,275) this%vbnm(l), val1, this%vbnm(l), val2 - endif - enddo + write (iout, 275) this%vbnm(l), val1, this%vbnm(l), val2 + end if + end do call value_to_string(totvin, val1, bigvl1, small) call value_to_string(totrin, val2, bigvl1, small) - write(iout,286) val1, val2 + write (iout, 286) val1, val2 ! ! -- Print individual outflow rates and volumes and their totals. - write(iout,287) - do l=1,msum1 - call value_to_string(this%vbvl(2,l), val1, bigvl1, small) - call value_to_string(this%vbvl(4,l), val2, bigvl1, small) - if(this%labeled) then - write(iout,276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l) + write (iout, 287) + do l = 1, msum1 + call value_to_string(this%vbvl(2, l), val1, bigvl1, small) + call value_to_string(this%vbvl(4, l), val2, bigvl1, small) + if (this%labeled) then + write (iout, 276) this%vbnm(l), val1, this%vbnm(l), val2, this%rowlabel(l) else - write(iout,275) this%vbnm(l), val1, this%vbnm(l), val2 - endif - enddo + write (iout, 275) this%vbnm(l), val1, this%vbnm(l), val2 + end if + end do call value_to_string(totvot, val1, bigvl1, small) call value_to_string(totrot, val2, bigvl1, small) - write(iout,298) val1, val2 + write (iout, 298) val1, val2 ! ! -- Calculate the difference between inflow and outflow. ! ! -- Calculate difference between rate in and rate out. - diffr=totrin-totrot - adiffr=abs(diffr) + diffr = totrin - totrot + adiffr = abs(diffr) ! ! -- Calculate percent difference between rate in and rate out. pdiffr = DZERO - avgrat=(totrin+totrot)/two - if(avgrat /= DZERO) pdiffr = hund * diffr / avgrat + avgrat = (totrin + totrot) / two + if (avgrat /= DZERO) pdiffr = hund * diffr / avgrat this%budperc = pdiffr ! ! -- Calculate difference between volume in and volume out. @@ -278,42 +279,42 @@ subroutine budget_ot(this, kstp, kper, iout) ! ! -- Get percent difference between volume in and volume out. pdiffv = DZERO - avgvol=(totvin+totvot)/two - if(avgvol /= DZERO) pdiffv= hund * diffv / avgvol + avgvol = (totvin + totvot) / two + if (avgvol /= DZERO) pdiffv = hund * diffv / avgvol ! ! -- Print differences and percent differences between input ! -- and output rates and volumes. call value_to_string(diffv, val1, bigvl2, small) call value_to_string(diffr, val2, bigvl2, small) - write(iout,299) val1, val2 - write(iout,300) pdiffv, pdiffr + write (iout, 299) val1, val2 + write (iout, 300) pdiffv, pdiffr ! ! -- flush the file - flush(iout) + flush (iout) ! ! -- set written_once to .true. this%written_once = .true. ! ! -- formats - 260 FORMAT(//2X,a,' BUDGET FOR ',a,' AT END OF' & - ,' TIME STEP',I5,', STRESS PERIOD',I4/2X,78('-')) - 261 FORMAT(//2X,a,' BUDGET FOR ',a,' AT END OF' & - ,' TIME STEP',I5,', STRESS PERIOD',I4/2X,99('-')) - 265 FORMAT(1X,/5X,'CUMULATIVE ',a,6X,a,7X & - ,'RATES FOR THIS TIME STEP',6X,a,'/T'/5X,18('-'),17X,24('-') & - //11X,'IN:',38X,'IN:'/11X,'---',38X,'---') - 266 FORMAT(1X,/5X,'CUMULATIVE ',a,6X,a,7X & - ,'RATES FOR THIS TIME STEP',6X,a,'/T',10X,A16, & - /5X,18('-'),17X,24('-'),21X,16('-') & - //11X,'IN:',38X,'IN:'/11X,'---',38X,'---') - 275 FORMAT(1X,3X,A16,' =',A17,6X,A16,' =',A17) - 276 FORMAT(1X,3X,A16,' =',A17,6X,A16,' =',A17,5X,A) - 286 FORMAT(1X,/12X,'TOTAL IN =',A,14X,'TOTAL IN =',A) - 287 FORMAT(1X,/10X,'OUT:',37X,'OUT:'/10X,4('-'),37X,4('-')) - 298 FORMAT(1X,/11X,'TOTAL OUT =',A,13X,'TOTAL OUT =',A) - 299 FORMAT(1X,/12X,'IN - OUT =',A,14X,'IN - OUT =',A) - 300 FORMAT(1X,/1X,'PERCENT DISCREPANCY =',F15.2 & - ,5X,'PERCENT DISCREPANCY =',F15.2/) +260 FORMAT(//2X, a, ' BUDGET FOR ', a, ' AT END OF' & + , ' TIME STEP', I5, ', STRESS PERIOD', I4 / 2X, 78('-')) +261 FORMAT(//2X, a, ' BUDGET FOR ', a, ' AT END OF' & + , ' TIME STEP', I5, ', STRESS PERIOD', I4 / 2X, 99('-')) +265 FORMAT(1X, /5X, 'CUMULATIVE ', a, 6X, a, 7X & + , 'RATES FOR THIS TIME STEP', 6X, a, '/T'/5X, 18('-'), 17X, 24('-') & + //11X, 'IN:', 38X, 'IN:'/11X, '---', 38X, '---') +266 FORMAT(1X, /5X, 'CUMULATIVE ', a, 6X, a, 7X & + , 'RATES FOR THIS TIME STEP', 6X, a, '/T', 10X, A16, & + /5X, 18('-'), 17X, 24('-'), 21X, 16('-') & + //11X, 'IN:', 38X, 'IN:'/11X, '---', 38X, '---') +275 FORMAT(1X, 3X, A16, ' =', A17, 6X, A16, ' =', A17) +276 FORMAT(1X, 3X, A16, ' =', A17, 6X, A16, ' =', A17, 5X, A) +286 FORMAT(1X, /12X, 'TOTAL IN =', A, 14X, 'TOTAL IN =', A) +287 FORMAT(1X, /10X, 'OUT:', 37X, 'OUT:'/10X, 4('-'), 37X, 4('-')) +298 FORMAT(1X, /11X, 'TOTAL OUT =', A, 13X, 'TOTAL OUT =', A) +299 FORMAT(1X, /12X, 'IN - OUT =', A, 14X, 'IN - OUT =', A) +300 FORMAT(1X, /1X, 'PERCENT DISCREPANCY =', F15.2 & + , 5X, 'PERCENT DISCREPANCY =', F15.2/) ! ! -- Return return @@ -325,25 +326,25 @@ end subroutine budget_ot !! !< subroutine budget_da(this) - class(BudgetType) :: this !< BudgetType object + class(BudgetType) :: this !< BudgetType object ! ! -- Scalars - deallocate(this%msum) - deallocate(this%maxsize) - deallocate(this%budperc) - deallocate(this%written_once) - deallocate(this%labeled) - deallocate(this%bdtype) - deallocate(this%bddim) - deallocate(this%labeltitle) - deallocate(this%bdzone) - deallocate(this%ibudcsv) - deallocate(this%icsvheader) + deallocate (this%msum) + deallocate (this%maxsize) + deallocate (this%budperc) + deallocate (this%written_once) + deallocate (this%labeled) + deallocate (this%bdtype) + deallocate (this%bddim) + deallocate (this%labeltitle) + deallocate (this%bdzone) + deallocate (this%ibudcsv) + deallocate (this%icsvheader) ! ! -- Arrays - deallocate(this%vbvl) - deallocate(this%vbnm) - deallocate(this%rowlabel) + deallocate (this%vbvl) + deallocate (this%vbnm) + deallocate (this%rowlabel) ! ! -- Return return @@ -357,7 +358,7 @@ end subroutine budget_da subroutine reset(this) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object + class(BudgetType) :: this !< BudgetType object ! -- local integer(I4B) :: i ! @@ -366,13 +367,13 @@ subroutine reset(this) do i = 1, this%maxsize this%vbvl(3, i) = DZERO this%vbvl(4, i) = DZERO - enddo + end do ! ! -- Return return end subroutine reset - !> @ brief Add a single row of information + !> @ brief Add a single row of information !! !! Add information corresponding to one row in the budget table !! rin the inflow rate @@ -381,32 +382,32 @@ end subroutine reset !! text is the name of the entry !! isupress_accumulate is an optional flag. If specified as 1, then !! the volume is NOT added to the accumulators on vbvl(1, :) and vbvl(2, :). - !! rowlabel is a LENBUDROWLABEL character text entry that is written to the - !! right of the table. It can be used for adding package names to budget + !! rowlabel is a LENBUDROWLABEL character text entry that is written to the + !! right of the table. It can be used for adding package names to budget !! entries. !! !< - subroutine add_single_entry(this, rin, rout, delt, text, & + subroutine add_single_entry(this, rin, rout, delt, text, & isupress_accumulate, rowlabel) ! -- dummy - class(BudgetType) :: this !< BudgetType object - real(DP), intent(in) :: rin !< inflow rate - real(DP), intent(in) :: rout !< outflow rate - real(DP), intent(in) :: delt !< time step length - character(len=LENBUDTXT), intent(in) :: text !< name of the entry - integer(I4B), optional, intent(in) :: isupress_accumulate !< accumulate flag - character(len=*), optional, intent(in) :: rowlabel !< row label + class(BudgetType) :: this !< BudgetType object + real(DP), intent(in) :: rin !< inflow rate + real(DP), intent(in) :: rout !< outflow rate + real(DP), intent(in) :: delt !< time step length + character(len=LENBUDTXT), intent(in) :: text !< name of the entry + integer(I4B), optional, intent(in) :: isupress_accumulate !< accumulate flag + character(len=*), optional, intent(in) :: rowlabel !< row label ! -- local character(len=LINELENGTH) :: errmsg character(len=*), parameter :: fmtbuderr = & - "('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )" + &"('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )" integer(I4B) :: iscv integer(I4B) :: maxsize ! iscv = 0 - if(present(isupress_accumulate)) then + if (present(isupress_accumulate)) then iscv = isupress_accumulate - endif + end if ! ! -- ensure budget arrays are large enough maxsize = this%msum @@ -416,33 +417,33 @@ subroutine add_single_entry(this, rin, rout, delt, text, & ! ! -- If budget has been written at least once, then make sure that the present ! text entry matches the last text entry - if(this%written_once) then - if(trim(adjustl(this%vbnm(this%msum))) /= trim(adjustl(text))) then - write(errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), & - trim(adjustl(text)) + if (this%written_once) then + if (trim(adjustl(this%vbnm(this%msum))) /= trim(adjustl(text))) then + write (errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), & + trim(adjustl(text)) call store_error(errmsg, terminate=.TRUE.) - endif - endif + end if + end if ! - if(iscv == 0) then - this%vbvl(1, this%msum)=this%vbvl(1,this%msum) + rin * delt - this%vbvl(2, this%msum)=this%vbvl(2,this%msum) + rout * delt - endif + if (iscv == 0) then + this%vbvl(1, this%msum) = this%vbvl(1, this%msum) + rin * delt + this%vbvl(2, this%msum) = this%vbvl(2, this%msum) + rout * delt + end if ! this%vbvl(3, this%msum) = rin this%vbvl(4, this%msum) = rout this%vbnm(this%msum) = adjustr(text) - if(present(rowlabel)) then + if (present(rowlabel)) then this%rowlabel(this%msum) = adjustl(rowlabel) this%labeled = .true. - endif + end if this%msum = this%msum + 1 ! ! -- Return return end subroutine add_single_entry - !> @ brief Add multiple rows of information + !> @ brief Add multiple rows of information !! !! Add information corresponding to one multiple rows in the budget table !! budterm is an array with inflow in column 1 and outflow in column 2 @@ -451,31 +452,31 @@ end subroutine add_single_entry !! row in budterm !! isupress_accumulate is an optional flag. If specified as 1, then !! the volume is NOT added to the accumulators on vbvl(1, :) and vbvl(2, :). - !! rowlabel is a LENBUDROWLABEL character text entry that is written to the - !! right of the table. It can be used for adding package names to budget + !! rowlabel is a LENBUDROWLABEL character text entry that is written to the + !! right of the table. It can be used for adding package names to budget !! entries. For multiple entries, the same rowlabel is used for each entry. !! !< - subroutine add_multi_entry(this, budterm, delt, budtxt, & + subroutine add_multi_entry(this, budterm, delt, budtxt, & isupress_accumulate, rowlabel) ! -- dummy - class(BudgetType) :: this !< BudgetType object - real(DP), dimension(:, :), intent(in) :: budterm !< array of budget terms - real(DP), intent(in) :: delt !< time step length - character(len=LENBUDTXT), dimension(:), intent(in) :: budtxt !< name of the entries - integer(I4B), optional, intent(in) :: isupress_accumulate !< suppress accumulate - character(len=*), optional, intent(in) :: rowlabel !< row label + class(BudgetType) :: this !< BudgetType object + real(DP), dimension(:, :), intent(in) :: budterm !< array of budget terms + real(DP), intent(in) :: delt !< time step length + character(len=LENBUDTXT), dimension(:), intent(in) :: budtxt !< name of the entries + integer(I4B), optional, intent(in) :: isupress_accumulate !< suppress accumulate + character(len=*), optional, intent(in) :: rowlabel !< row label ! -- local character(len=LINELENGTH) :: errmsg character(len=*), parameter :: fmtbuderr = & - "('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )" + &"('Error in MODFLOW 6.', 'Entries do not match: ', (a), (a) )" integer(I4B) :: iscv, i integer(I4B) :: nbudterms, maxsize ! iscv = 0 - if(present(isupress_accumulate)) then + if (present(isupress_accumulate)) then iscv = isupress_accumulate - endif + end if ! ! -- ensure budget arrays are large enough nbudterms = size(budtxt) @@ -489,35 +490,35 @@ subroutine add_multi_entry(this, budterm, delt, budtxt, & ! ! -- If budget has been written at least once, then make sure that the present ! text entry matches the last text entry - if(this%written_once) then - if(trim(adjustl(this%vbnm(this%msum))) /= & - trim(adjustl(budtxt(i)))) then - write(errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), & - trim(adjustl(budtxt(i))) - call store_error(errmsg) - endif - endif + if (this%written_once) then + if (trim(adjustl(this%vbnm(this%msum))) /= & + trim(adjustl(budtxt(i)))) then + write (errmsg, fmtbuderr) trim(adjustl(this%vbnm(this%msum))), & + trim(adjustl(budtxt(i))) + call store_error(errmsg) + end if + end if ! - if(iscv == 0) then - this%vbvl(1, this%msum)=this%vbvl(1,this%msum) + budterm(1, i) * delt - this%vbvl(2, this%msum)=this%vbvl(2,this%msum) + budterm(2, i) * delt - endif + if (iscv == 0) then + this%vbvl(1, this%msum) = this%vbvl(1, this%msum) + budterm(1, i) * delt + this%vbvl(2, this%msum) = this%vbvl(2, this%msum) + budterm(2, i) * delt + end if ! this%vbvl(3, this%msum) = budterm(1, i) this%vbvl(4, this%msum) = budterm(2, i) this%vbnm(this%msum) = adjustr(budtxt(i)) - if(present(rowlabel)) then + if (present(rowlabel)) then this%rowlabel(this%msum) = adjustl(rowlabel) this%labeled = .true. - endif + end if this%msum = this%msum + 1 ! - enddo + end do ! ! -- Check for errors - if(count_errors() > 0) then + if (count_errors() > 0) then call store_error('Could not add multi-entry', terminate=.TRUE.) - endif + end if ! ! -- Return return @@ -531,20 +532,20 @@ end subroutine add_multi_entry subroutine allocate_scalars(this, name_model) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object - character(len=*), intent(in) :: name_model !< name of the model - ! - allocate(this%msum) - allocate(this%maxsize) - allocate(this%budperc) - allocate(this%written_once) - allocate(this%labeled) - allocate(this%bdtype) - allocate(this%bddim) - allocate(this%labeltitle) - allocate(this%bdzone) - allocate(this%ibudcsv) - allocate(this%icsvheader) + class(BudgetType) :: this !< BudgetType object + character(len=*), intent(in) :: name_model !< name of the model + ! + allocate (this%msum) + allocate (this%maxsize) + allocate (this%budperc) + allocate (this%written_once) + allocate (this%labeled) + allocate (this%bdtype) + allocate (this%bddim) + allocate (this%labeltitle) + allocate (this%bdzone) + allocate (this%ibudcsv) + allocate (this%icsvheader) ! ! -- Initialize values this%msum = 0 @@ -569,26 +570,26 @@ end subroutine allocate_scalars subroutine allocate_arrays(this) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object + class(BudgetType) :: this !< BudgetType object ! ! -- If redefining, then need to deallocate/reallocate - if(associated(this%vbvl)) then - deallocate(this%vbvl) - nullify(this%vbvl) - endif - if(associated(this%vbnm)) then - deallocate(this%vbnm) - nullify(this%vbnm) - endif - if(associated(this%rowlabel)) then - deallocate(this%rowlabel) - nullify(this%rowlabel) - endif + if (associated(this%vbvl)) then + deallocate (this%vbvl) + nullify (this%vbvl) + end if + if (associated(this%vbnm)) then + deallocate (this%vbnm) + nullify (this%vbnm) + end if + if (associated(this%rowlabel)) then + deallocate (this%rowlabel) + nullify (this%rowlabel) + end if ! ! -- Allocate - allocate(this%vbvl(4, this%maxsize)) - allocate(this%vbnm(this%maxsize)) - allocate(this%rowlabel(this%maxsize)) + allocate (this%vbvl(4, this%maxsize)) + allocate (this%vbnm(this%maxsize)) + allocate (this%rowlabel(this%maxsize)) ! ! -- Initialize values this%vbvl(:, :) = DZERO @@ -597,7 +598,7 @@ subroutine allocate_arrays(this) ! return end subroutine allocate_arrays - + !> @ brief Resize the budget object !! !! If the size wasn't allocated to be large enough, then the budget object @@ -607,8 +608,8 @@ end subroutine allocate_arrays subroutine resize(this, maxsize) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object - integer(I4B), intent(in) :: maxsize !< maximum size + class(BudgetType) :: this !< BudgetType object + integer(I4B), intent(in) :: maxsize !< maximum size ! -- local real(DP), dimension(:, :), allocatable :: vbvl character(len=LENBUDTXT), dimension(:), allocatable :: vbnm @@ -617,9 +618,9 @@ subroutine resize(this, maxsize) ! ! -- allocate and copy into local storage maxsizeold = this%maxsize - allocate(vbvl(4, maxsizeold)) - allocate(vbnm(maxsizeold)) - allocate(rowlabel(maxsizeold)) + allocate (vbvl(4, maxsizeold)) + allocate (vbnm(maxsizeold)) + allocate (rowlabel(maxsizeold)) vbvl(:, :) = this%vbvl(:, :) vbnm(:) = this%vbnm(:) rowlabel(:) = this%rowlabel(:) @@ -634,14 +635,14 @@ subroutine resize(this, maxsize) this%rowlabel(1:maxsizeold) = rowlabel(1:maxsizeold) ! ! - deallocate local copies - deallocate(vbvl) - deallocate(vbnm) - deallocate(rowlabel) + deallocate (vbvl) + deallocate (vbnm) + deallocate (rowlabel) ! ! -- return return end subroutine resize - + !> @ brief Rate accumulator subroutine !! !! Routing for tallying inflows and outflows of an array @@ -650,9 +651,9 @@ end subroutine resize subroutine rate_accumulator(flow, rin, rout) ! -- modules ! -- dummy - real(DP), dimension(:), contiguous, intent(in) :: flow !< array of flows - real(DP), intent(out) :: rin !< calculated sum of inflows - real(DP), intent(out) :: rout !< calculated sum of outflows + real(DP), dimension(:), contiguous, intent(in) :: flow !< array of flows + real(DP), intent(out) :: rin !< calculated sum of inflows + real(DP), intent(out) :: rout !< calculated sum of outflows integer(I4B) :: n ! rin = DZERO @@ -666,7 +667,7 @@ subroutine rate_accumulator(flow, rin, rout) end do return end subroutine rate_accumulator - + !> @ brief Set unit number for csv output file !! !! This routine can be used to activate csv output @@ -676,12 +677,12 @@ end subroutine rate_accumulator subroutine set_ibudcsv(this, ibudcsv) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object - integer(I4B), intent(in) :: ibudcsv !< unit number for csv budget output + class(BudgetType) :: this !< BudgetType object + integer(I4B), intent(in) :: ibudcsv !< unit number for csv budget output this%ibudcsv = ibudcsv return end subroutine set_ibudcsv - + !> @ brief Write csv output !! !! This routine will write a row of output to the @@ -692,8 +693,8 @@ end subroutine set_ibudcsv subroutine writecsv(this, totim) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object - real(DP), intent(in) :: totim !< time corresponding to this data + class(BudgetType) :: this !< BudgetType object + real(DP), intent(in) :: totim !< time corresponding to this data ! -- local integer(I4B) :: i real(DP) :: totrin @@ -727,19 +728,20 @@ subroutine writecsv(this, totim) end if ! ! -- write data - write(this%ibudcsv, '(*(G0,:,","))') totim, & - (this%vbvl(3, i), i=1,this%msum-1), & - (this%vbvl(4, i), i=1,this%msum-1), & - totrin, totrout, pdiffr + write (this%ibudcsv, '(*(G0,:,","))') & + totim, & + (this%vbvl(3, i), i=1, this%msum - 1), & + (this%vbvl(4, i), i=1, this%msum - 1), & + totrin, totrout, pdiffr ! ! -- flush the file - flush(this%ibudcsv) + flush (this%ibudcsv) end if ! ! -- return return end subroutine writecsv - + !> @ brief Write csv header !! !! This routine will write the csv header based on the @@ -749,21 +751,21 @@ end subroutine writecsv subroutine write_csv_header(this) ! -- modules ! -- dummy - class(BudgetType) :: this !< BudgetType object + class(BudgetType) :: this !< BudgetType object ! -- local integer(I4B) :: l character(len=LINELENGTH) :: txt, txtl - write(this%ibudcsv, '(a)', advance='NO') 'time,' + write (this%ibudcsv, '(a)', advance='NO') 'time,' ! ! -- first write IN do l = 1, this%msum - 1 txt = this%vbnm(l) txtl = '' if (this%labeled) then - txtl = '(' // trim(adjustl(this%rowlabel(l))) // ')' + txtl = '('//trim(adjustl(this%rowlabel(l)))//')' end if - txt = trim(adjustl(txt)) // trim(adjustl(txtl)) // '_IN,' - write(this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt)) + txt = trim(adjustl(txt))//trim(adjustl(txtl))//'_IN,' + write (this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt)) end do ! ! -- then write OUT @@ -771,12 +773,12 @@ subroutine write_csv_header(this) txt = this%vbnm(l) txtl = '' if (this%labeled) then - txtl = '(' // trim(adjustl(this%rowlabel(l))) // ')' + txtl = '('//trim(adjustl(this%rowlabel(l)))//')' end if - txt = trim(adjustl(txt)) // trim(adjustl(txtl)) // '_OUT,' - write(this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt)) + txt = trim(adjustl(txt))//trim(adjustl(txtl))//'_OUT,' + write (this%ibudcsv, '(a)', advance='NO') trim(adjustl(txt)) end do - write(this%ibudcsv, '(a)') 'TOTAL_IN,TOTAL_OUT,PERCENT_DIFFERENCE' + write (this%ibudcsv, '(a)') 'TOTAL_IN,TOTAL_OUT,PERCENT_DIFFERENCE' ! ! -- return return diff --git a/src/Utilities/BudgetFileReader.f90 b/src/Utilities/BudgetFileReader.f90 index be959e66efa..413ded4faa9 100644 --- a/src/Utilities/BudgetFileReader.f90 +++ b/src/Utilities/BudgetFileReader.f90 @@ -5,12 +5,12 @@ module BudgetFileReaderModule use ConstantsModule, only: LINELENGTH implicit none - + private public :: BudgetFileReaderType - + type :: BudgetFileReaderType - + logical :: hasimeth1flowja = .false. integer(I4B) :: inunit integer(I4B) :: nbudterms @@ -45,17 +45,17 @@ module BudgetFileReaderModule character(len=16) :: dstmodelname character(len=16) :: dstpackagename character(len=16), dimension(:), allocatable :: dstpackagenamearray - + contains - + procedure :: initialize procedure :: read_record procedure :: finalize - + end type BudgetFileReaderType - - contains - + +contains + subroutine initialize(this, iu, iout, ncrbud) ! ****************************************************************************** ! initialize @@ -82,8 +82,8 @@ subroutine initialize(this, iu, iout, ncrbud) ! ! -- Determine number of budget terms within a time step if (iout > 0) & - write(iout, '(a)') & - 'Reading budget file to determine number of terms per time step.' + write (iout, '(a)') & + 'Reading budget file to determine number of terms per time step.' ! ! -- Read through the first set of data for time step 1 and stress period 1 do @@ -96,13 +96,13 @@ subroutine initialize(this, iu, iout, ncrbud) end do kstp_last = this%kstp kper_last = this%kper - allocate(this%budtxtarray(this%nbudterms)) - allocate(this%imetharray(this%nbudterms)) - allocate(this%dstpackagenamearray(this%nbudterms)) - allocate(this%nauxarray(this%nbudterms)) - allocate(this%auxtxtarray(maxaux, this%nbudterms)) + allocate (this%budtxtarray(this%nbudterms)) + allocate (this%imetharray(this%nbudterms)) + allocate (this%dstpackagenamearray(this%nbudterms)) + allocate (this%nauxarray(this%nbudterms)) + allocate (this%auxtxtarray(maxaux, this%nbudterms)) this%auxtxtarray(:, :) = '' - rewind(this%inunit) + rewind (this%inunit) ! ! -- Now read through again and store budget text names do ibudterm = 1, this%nbudterms @@ -116,18 +116,18 @@ subroutine initialize(this, iu, iout, ncrbud) this%auxtxtarray(1:this%naux, ibudterm) = this%auxtxt(:) end if if (this%srcmodelname == this%dstmodelname) then - if(allocated(this%nodesrc)) ncrbud = max(ncrbud, maxval(this%nodesrc)) - endif - enddo - rewind(this%inunit) + if (allocated(this%nodesrc)) ncrbud = max(ncrbud, maxval(this%nodesrc)) + end if + end do + rewind (this%inunit) if (iout > 0) & - write(iout, '(a, i0, a)') 'Detected ', this%nbudterms, & + write (iout, '(a, i0, a)') 'Detected ', this%nbudterms, & ' unique flow terms in budget file.' ! ! -- return return end subroutine initialize - + subroutine read_record(this, success, iout_opt) ! ****************************************************************************** ! read_record @@ -150,7 +150,7 @@ subroutine read_record(this, success, iout_opt) iout = iout_opt else iout = 0 - endif + end if ! this%kstp = 0 this%kper = 0 @@ -163,83 +163,83 @@ subroutine read_record(this, success, iout_opt) this%srcpackagename = '' this%dstmodelname = '' this%dstpackagename = '' - + success = .true. this%kstpnext = 0 this%kpernext = 0 - read(this%inunit, iostat=iostat) this%kstp, this%kper, this%budtxt, & + read (this%inunit, iostat=iostat) this%kstp, this%kper, this%budtxt, & this%nval, this%idum1, this%idum2 if (iostat /= 0) then success = .false. if (iostat < 0) this%endoffile = .true. return - endif - read(this%inunit) this%imeth, this%delt, this%pertim, this%totim - if(this%imeth == 1) then + end if + read (this%inunit) this%imeth, this%delt, this%pertim, this%totim + if (this%imeth == 1) then if (trim(adjustl(this%budtxt)) == 'FLOW-JA-FACE') then - if(allocated(this%flowja)) deallocate(this%flowja) - allocate(this%flowja(this%nval)) - read(this%inunit) this%flowja + if (allocated(this%flowja)) deallocate (this%flowja) + allocate (this%flowja(this%nval)) + read (this%inunit) this%flowja this%hasimeth1flowja = .true. else this%nval = this%nval * this%idum1 * abs(this%idum2) - if(allocated(this%flow)) deallocate(this%flow) - allocate(this%flow(this%nval)) - if(allocated(this%nodesrc)) deallocate(this%nodesrc) - allocate(this%nodesrc(this%nval)) - read(this%inunit) this%flow + if (allocated(this%flow)) deallocate (this%flow) + allocate (this%flow(this%nval)) + if (allocated(this%nodesrc)) deallocate (this%nodesrc) + allocate (this%nodesrc(this%nval)) + read (this%inunit) this%flow do i = 1, this%nval this%nodesrc(i) = i - enddo - endif + end do + end if elseif (this%imeth == 6) then ! -- method code 6 - read(this%inunit) this%srcmodelname - read(this%inunit) this%srcpackagename - read(this%inunit) this%dstmodelname - read(this%inunit) this%dstpackagename - read(this%inunit) this%ndat + read (this%inunit) this%srcmodelname + read (this%inunit) this%srcpackagename + read (this%inunit) this%dstmodelname + read (this%inunit) this%dstpackagename + read (this%inunit) this%ndat this%naux = this%ndat - 1 - if(allocated(this%auxtxt)) deallocate(this%auxtxt) - allocate(this%auxtxt(this%naux)) - read(this%inunit) this%auxtxt - read(this%inunit) this%nlist - if(allocated(this%nodesrc)) deallocate(this%nodesrc) - allocate(this%nodesrc(this%nlist)) - if(allocated(this%nodedst)) deallocate(this%nodedst) - allocate(this%nodedst(this%nlist)) - if(allocated(this%flow)) deallocate(this%flow) - allocate(this%flow(this%nlist)) - if(allocated(this%auxvar)) deallocate(this%auxvar) - allocate(this%auxvar(this%naux, this%nlist)) - read(this%inunit) (this%nodesrc(n), this%nodedst(n), this%flow(n), & - (this%auxvar(i, n), i = 1, this%naux), n = 1, this%nlist) + if (allocated(this%auxtxt)) deallocate (this%auxtxt) + allocate (this%auxtxt(this%naux)) + read (this%inunit) this%auxtxt + read (this%inunit) this%nlist + if (allocated(this%nodesrc)) deallocate (this%nodesrc) + allocate (this%nodesrc(this%nlist)) + if (allocated(this%nodedst)) deallocate (this%nodedst) + allocate (this%nodedst(this%nlist)) + if (allocated(this%flow)) deallocate (this%flow) + allocate (this%flow(this%nlist)) + if (allocated(this%auxvar)) deallocate (this%auxvar) + allocate (this%auxvar(this%naux, this%nlist)) + read (this%inunit) (this%nodesrc(n), this%nodedst(n), this%flow(n), & + (this%auxvar(i, n), i=1, this%naux), n=1, this%nlist) else - write(errmsg, '(a, a)') 'ERROR READING: ', trim(this%budtxt) + write (errmsg, '(a, a)') 'ERROR READING: ', trim(this%budtxt) call store_error(errmsg) - write(errmsg, '(a, i0)') 'INVALID METHOD CODE DETECTED: ', this%imeth + write (errmsg, '(a, i0)') 'INVALID METHOD CODE DETECTED: ', this%imeth call store_error(errmsg) call store_error_unit(this%inunit) - endif + end if if (iout > 0) then - write(iout, '(1pg15.6, a, 1x, a)') this%totim, this%budtxt, & + write (iout, '(1pg15.6, a, 1x, a)') this%totim, this%budtxt, & this%dstpackagename - endif + end if ! ! -- look ahead to next kstp and kper, then backup if read successfully if (.not. this%endoffile) then - read(this%inunit, iostat=iostat) this%kstpnext, this%kpernext + read (this%inunit, iostat=iostat) this%kstpnext, this%kpernext if (iostat == 0) then call fseek_stream(this%inunit, -2 * I4B, 1, iostat) else if (iostat < 0) then this%endoffile = .true. end if - endif + end if ! ! -- return return end subroutine read_record - + subroutine finalize(this) ! ****************************************************************************** ! budgetdata_finalize @@ -249,16 +249,16 @@ subroutine finalize(this) ! ------------------------------------------------------------------------------ class(BudgetFileReaderType) :: this ! ------------------------------------------------------------------------------ - close(this%inunit) - if(allocated(this%auxtxt)) deallocate(this%auxtxt) - if(allocated(this%flowja)) deallocate(this%flowja) - if(allocated(this%nodesrc)) deallocate(this%nodesrc) - if(allocated(this%nodedst)) deallocate(this%nodedst) - if(allocated(this%flow)) deallocate(this%flow) - if(allocated(this%auxvar)) deallocate(this%auxvar) + close (this%inunit) + if (allocated(this%auxtxt)) deallocate (this%auxtxt) + if (allocated(this%flowja)) deallocate (this%flowja) + if (allocated(this%nodesrc)) deallocate (this%nodesrc) + if (allocated(this%nodedst)) deallocate (this%nodedst) + if (allocated(this%flow)) deallocate (this%flow) + if (allocated(this%auxvar)) deallocate (this%auxvar) ! ! -- return return end subroutine finalize - + end module BudgetFileReaderModule diff --git a/src/Utilities/BudgetObject.f90 b/src/Utilities/BudgetObject.f90 index eefd3e243a0..35836bf50b6 100644 --- a/src/Utilities/BudgetObject.f90 +++ b/src/Utilities/BudgetObject.f90 @@ -1,25 +1,25 @@ -! Comprehensive budget object that stores all of the -! intercell flows, and the inflows and the outflows for +! Comprehensive budget object that stores all of the +! intercell flows, and the inflows and the outflows for ! an advanced package. module BudgetObjectModule - + use KindModule, only: I4B, DP - use ConstantsModule, only: LENBUDTXT, LINELENGTH, & - TABLEFT, TABCENTER, TABRIGHT, & - TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & + use ConstantsModule, only: LENBUDTXT, LINELENGTH, & + TABLEFT, TABCENTER, TABRIGHT, & + TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & DZERO, DHALF, DHUNDRED - use BudgetModule, only : BudgetType, budget_cr + use BudgetModule, only: BudgetType, budget_cr use BudgetTermModule, only: BudgetTermType use TableModule, only: TableType, table_cr use BaseDisModule, only: DisBaseType use BudgetFileReaderModule, only: BudgetFileReaderType - + implicit none - + public :: BudgetObjectType public :: budgetobject_cr public :: budgetobject_cr_bfr - + type :: BudgetObjectType ! ! -- name, number of control volumes, and number of budget terms @@ -47,20 +47,20 @@ module BudgetObjectModule ! -- budget table object, for writing the typical MODFLOW budget type(BudgetType), pointer :: budtable => null() ! - ! -- flow table object, for writing the flow budget for + ! -- flow table object, for writing the flow budget for ! each control volume logical, pointer :: add_cellids => null() integer(I4B), pointer :: icellid => null() integer(I4B), pointer :: nflowterms => null() integer(I4B), dimension(:), pointer :: istart => null() integer(I4B), dimension(:), pointer :: iflowterms => null() - type(TableType), pointer :: flowtab => null() + type(TableType), pointer :: flowtab => null() ! ! -- budget file reader, for reading flows from a binary file type(BudgetFileReaderType), pointer :: bfr => null() - + contains - + procedure :: budgetobject_df procedure :: flowtable_df procedure :: accumulate_terms @@ -72,10 +72,10 @@ module BudgetObjectModule procedure :: bfr_init procedure :: bfr_advance procedure :: fill_from_bfr - + end type BudgetObjectType - - contains + +contains subroutine budgetobject_cr(this, name) ! ****************************************************************************** @@ -91,7 +91,7 @@ subroutine budgetobject_cr(this, name) ! ------------------------------------------------------------------------------ ! ! -- Create the object - allocate(this) + allocate (this) ! ! -- initialize variables this%name = name @@ -142,31 +142,31 @@ subroutine budgetobject_df(this, ncv, nbudterm, iflowja, nsto, & this%nsto = nsto ! ! -- allocate space for budterm - allocate(this%budterm(nbudterm)) + allocate (this%budterm(nbudterm)) ! ! -- Set the budget type to name bdtype = this%name ! ! -- Set the budget dimension - if(present(bddim_opt)) then + if (present(bddim_opt)) then bddim = bddim_opt else bddim = 'L**3' - endif + end if ! ! -- Set the budget zone - if(present(bdzone_opt)) then + if (present(bdzone_opt)) then bdzone = bdzone_opt else bdzone = 'ENTIRE MODEL' - endif + end if ! ! -- Set the label title - if(present(labeltitle_opt)) then + if (present(labeltitle_opt)) then labeltitle = labeltitle_opt else labeltitle = 'PACKAGE NAME' - endif + end if ! ! -- setup the budget table object call this%budtable%budget_df(nbudterm, bdtype, bddim, labeltitle, bdzone) @@ -179,7 +179,7 @@ subroutine budgetobject_df(this, ncv, nbudterm, iflowja, nsto, & ! -- Return return end subroutine budgetobject_df - + subroutine flowtable_df(this, iout, cellids) ! ****************************************************************************** ! flowtable_df -- Define the new flow table object @@ -215,9 +215,9 @@ subroutine flowtable_df(this, iout, cellids) end if ! ! -- allocate scalars - allocate(this%add_cellids) - allocate(this%icellid) - allocate(this%nflowterms) + allocate (this%add_cellids) + allocate (this%icellid) + allocate (this%nflowterms) ! ! -- initialize scalars this%add_cellids = add_cellids @@ -250,11 +250,11 @@ subroutine flowtable_df(this, iout, cellids) end do ! ! -- allocate arrays - allocate(this%istart(this%nflowterms)) - allocate(this%iflowterms(this%nflowterms)) + allocate (this%istart(this%nflowterms)) + allocate (this%iflowterms(this%nflowterms)) ! ! -- set up flow tableobj - title = trim(this%name) // ' PACKAGE - SUMMARY OF FLOWS FOR ' // & + title = trim(this%name)//' PACKAGE - SUMMARY OF FLOWS FOR '// & 'EACH CONTROL VOLUME' call table_cr(this%flowtab, this%name, title) call this%flowtab%table_df(this%ncv, maxcol, iout, transient=.TRUE.) @@ -298,7 +298,7 @@ subroutine flowtable_df(this, iout, cellids) ! -- Return return end subroutine flowtable_df - + subroutine accumulate_terms(this) ! ****************************************************************************** ! accumulate_terms -- add up accumulators and submit to budget table @@ -311,7 +311,7 @@ subroutine accumulate_terms(this) ! -- dummy class(BudgetObjectType) :: this ! -- dummy - character(len=LENBUDTXT) :: flowtype + character(len=LENBUDTXT) :: flowtype integer(I4B) :: i real(DP) :: ratin, ratout ! ------------------------------------------------------------------------------ @@ -404,9 +404,9 @@ subroutine write_flowtable(this, dis, kstp, kper, cellidstr) cellid = cellidstr(icv) else ! - ! -- Determine the cellid for this entry. The cellid, such as + ! -- Determine the cellid for this entry. The cellid, such as ! (1, 10, 10), is assumed to be in the id2 column of this budterm. - j = this%icellid + j = this%icellid idx = this%iflowterms(j) i = this%istart(j) id2 = this%budterm(idx)%get_id2(i) @@ -427,7 +427,7 @@ subroutine write_flowtable(this, dis, kstp, kper, cellidstr) qinflow = DZERO qoutflow = DZERO ! - ! -- determine the index, flowtype and length of + ! -- determine the index, flowtype and length of ! the flowterm idx = this%iflowterms(j) flowtype = this%budterm(idx)%get_flowtype() @@ -438,7 +438,7 @@ subroutine write_flowtable(this, dis, kstp, kper, cellidstr) colterm: do i = this%istart(j), nlist id1 = this%budterm(idx)%get_id1(i) if (this%budterm(idx)%ordered_id1) then - if(id1 > icv) then + if (id1 > icv) then this%istart(j) = i exit colterm end if @@ -497,11 +497,11 @@ subroutine write_budtable(this, kstp, kper, iout, ibudfl, totim) ! -- modules ! -- dummy class(BudgetObjectType) :: this - integer(I4B),intent(in) :: kstp - integer(I4B),intent(in) :: kper - integer(I4B),intent(in) :: iout - integer(I4B),intent(in) :: ibudfl - real(DP),intent(in) :: totim + integer(I4B), intent(in) :: kstp + integer(I4B), intent(in) :: kper + integer(I4B), intent(in) :: iout + integer(I4B), intent(in) :: ibudfl + real(DP), intent(in) :: totim ! -- dummy ! ------------------------------------------------------------------------------ ! @@ -514,7 +514,7 @@ subroutine write_budtable(this, kstp, kper, iout, ibudfl, totim) ! -- return return end subroutine write_budtable - + subroutine save_flows(this, dis, ibinun, kstp, kper, delt, & pertim, totim, iout) ! ****************************************************************************** @@ -547,7 +547,7 @@ subroutine save_flows(this, dis, ibinun, kstp, kper, delt, & ! -- return return end subroutine save_flows - + subroutine read_flows(this, dis, ibinun) ! ****************************************************************************** ! read_flows -- Read froms from a binary file into this BudgetObjectType @@ -579,7 +579,7 @@ subroutine read_flows(this, dis, ibinun) ! -- return return end subroutine read_flows - + subroutine budgetobject_da(this) ! ****************************************************************************** ! budgetobject_da -- deallocate @@ -601,27 +601,27 @@ subroutine budgetobject_da(this) ! ! -- destroy the flow table if (associated(this%flowtab)) then - deallocate(this%add_cellids) - deallocate(this%icellid) - deallocate(this%nflowterms) - deallocate(this%istart) - deallocate(this%iflowterms) + deallocate (this%add_cellids) + deallocate (this%icellid) + deallocate (this%nflowterms) + deallocate (this%istart) + deallocate (this%iflowterms) call this%flowtab%table_da() - deallocate(this%flowtab) - nullify(this%flowtab) + deallocate (this%flowtab) + nullify (this%flowtab) end if ! ! -- destroy the budget object table if (associated(this%budtable)) then call this%budtable%budget_da() - deallocate(this%budtable) - nullify(this%budtable) + deallocate (this%budtable) + nullify (this%budtable) end if ! ! -- Return return end subroutine budgetobject_da - + subroutine budgetobject_cr_bfr(this, name, ibinun, iout, colconv1, colconv2) ! ****************************************************************************** ! budgetobject_cr_bfr -- Create a new budget object from a binary flow file @@ -681,7 +681,7 @@ subroutine budgetobject_cr_bfr(this, name, ibinun, iout, colconv1, colconv2) ! -- Return return end subroutine budgetobject_cr_bfr - + subroutine bfr_init(this, ibinun, ncv, nbudterm, iout) ! ****************************************************************************** ! bfr_init -- initialize the budget file reader @@ -700,14 +700,14 @@ subroutine bfr_init(this, ibinun, ncv, nbudterm, iout) ! ------------------------------------------------------------------------------ ! ! -- initialize budget file reader - allocate(this%bfr) + allocate (this%bfr) call this%bfr%initialize(ibinun, iout, ncv) nbudterm = this%bfr%nbudterms ! ! -- Return return end subroutine bfr_init - + subroutine bfr_advance(this, dis, iout) ! ****************************************************************************** ! bfr_advance -- copy the information from the binary file into budterms @@ -723,10 +723,10 @@ subroutine bfr_advance(this, dis, iout) integer(I4B), intent(in) :: iout ! -- dummy logical :: readnext - character(len=*), parameter :: fmtkstpkper = & - "(1x,/1x, a, ' READING BUDGET TERMS FOR KSTP ', i0, ' KPER ', i0)" + character(len=*), parameter :: fmtkstpkper = & + &"(1x,/1x, a, ' READING BUDGET TERMS FOR KSTP ', i0, ' KPER ', i0)" character(len=*), parameter :: fmtbudkstpkper = & - "(1x,/1x, a, ' SETTING BUDGET TERMS FOR KSTP ', i0, ' AND KPER ', & + "(1x,/1x, a, ' SETTING BUDGET TERMS FOR KSTP ', i0, ' AND KPER ', & &i0, ' TO BUDGET FILE TERMS FROM KSTP ', i0, ' AND KPER ', i0)" ! ------------------------------------------------------------------------------ ! @@ -743,28 +743,28 @@ subroutine bfr_advance(this, dis, iout) else if (this%bfr%kpernext == kper + 1 .and. this%bfr%kstpnext == 1) & readnext = .false. - endif - endif + end if + end if ! ! -- Read the next record if (readnext) then ! ! -- Write the current time step and stress period if (iout > 0) & - write(iout, fmtkstpkper) this%name, kstp, kper + write (iout, fmtkstpkper) this%name, kstp, kper ! ! -- read flows from the binary file and copy them into this%budterm(:) call this%fill_from_bfr(dis, iout) else if (iout > 0) & - write(iout, fmtbudkstpkper) trim(this%name), kstp, kper, & - this%bfr%kstp, this%bfr%kper - endif + write (iout, fmtbudkstpkper) trim(this%name), kstp, kper, & + this%bfr%kstp, this%bfr%kper + end if ! ! -- Return return end subroutine bfr_advance - + subroutine fill_from_bfr(this, dis, iout) ! ****************************************************************************** ! fill_from_bfr -- copy the information from the binary file into budterms @@ -791,5 +791,5 @@ subroutine fill_from_bfr(this, dis, iout) ! -- Return return end subroutine fill_from_bfr - -end module BudgetObjectModule \ No newline at end of file + +end module BudgetObjectModule diff --git a/src/Utilities/BudgetTerm.f90 b/src/Utilities/BudgetTerm.f90 index 79ca70697fd..e3aeb13a67a 100644 --- a/src/Utilities/BudgetTerm.f90 +++ b/src/Utilities/BudgetTerm.f90 @@ -1,6 +1,6 @@ ! A budget term is the information needed to describe flow. -! The budget object contains an array of budget terms. -! For an advanced package. The budget object describes all of +! The budget object contains an array of budget terms. +! For an advanced package. The budget object describes all of ! the flows. module BudgetTermModule @@ -12,29 +12,29 @@ module BudgetTermModule implicit none public :: BudgetTermType - + type :: BudgetTermType - - character(len=LENBUDTXT) :: flowtype ! type of flow (WEL, DRN, ...) - character(len=LENBUDTXT) :: text1id1 ! model - character(len=LENBUDTXT) :: text2id1 ! to model - character(len=LENBUDTXT) :: text1id2 ! package/model - character(len=LENBUDTXT) :: text2id2 ! to package/model - character(len=LENBUDTXT), dimension(:), pointer :: auxtxt => null() ! name of auxiliary variables - integer(I4B) :: maxlist ! allocated size of arrays - integer(I4B) :: naux ! number of auxiliary variables - integer(I4B) :: nlist ! size of arrays for this period - logical :: olconv1 = .false. ! convert id1 to user node upon output - logical :: olconv2 = .false. ! convert id2 to user node upon output - logical :: ordered_id1 ! the id1 array is ordered sequentially - integer(I4B), dimension(:), pointer :: id1 => null() ! first id (maxlist) - integer(I4B), dimension(:), pointer :: id2 => null() ! second id (maxlist) - real(DP), dimension(:), pointer :: flow => null() ! point this to simvals or simtomvr (maxlist) - real(DP), dimension(:, :), pointer :: auxvar => null() ! auxiliary variables (naux, maxlist) - integer(I4B) :: icounter ! counter variable - + + character(len=LENBUDTXT) :: flowtype ! type of flow (WEL, DRN, ...) + character(len=LENBUDTXT) :: text1id1 ! model + character(len=LENBUDTXT) :: text2id1 ! to model + character(len=LENBUDTXT) :: text1id2 ! package/model + character(len=LENBUDTXT) :: text2id2 ! to package/model + character(len=LENBUDTXT), dimension(:), pointer :: auxtxt => null() ! name of auxiliary variables + integer(I4B) :: maxlist ! allocated size of arrays + integer(I4B) :: naux ! number of auxiliary variables + integer(I4B) :: nlist ! size of arrays for this period + logical :: olconv1 = .false. ! convert id1 to user node upon output + logical :: olconv2 = .false. ! convert id2 to user node upon output + logical :: ordered_id1 ! the id1 array is ordered sequentially + integer(I4B), dimension(:), pointer :: id1 => null() ! first id (maxlist) + integer(I4B), dimension(:), pointer :: id2 => null() ! second id (maxlist) + real(DP), dimension(:), pointer :: flow => null() ! point this to simvals or simtomvr (maxlist) + real(DP), dimension(:, :), pointer :: auxvar => null() ! auxiliary variables (naux, maxlist) + integer(I4B) :: icounter ! counter variable + contains - + procedure :: initialize procedure :: allocate_arrays procedure :: reset @@ -49,11 +49,11 @@ module BudgetTermModule procedure :: read_flows procedure :: fill_from_bfr procedure :: deallocate_arrays - + end type BudgetTermType - contains - +contains + subroutine initialize(this, flowtype, text1id1, text2id1, & text1id2, text2id2, maxlist, olconv1, olconv2, & naux, auxtxt, ordered_id1) @@ -94,7 +94,7 @@ subroutine initialize(this, flowtype, text1id1, text2id1, & this%ordered_id1 = .true. if (present(ordered_id1)) this%ordered_id1 = ordered_id1 end subroutine initialize - + subroutine allocate_arrays(this) ! ****************************************************************************** ! allocate_arrays -- allocate budget term arrays @@ -106,13 +106,13 @@ subroutine allocate_arrays(this) ! -- dummy class(BudgetTermType) :: this ! ------------------------------------------------------------------------------ - allocate(this%id1(this%maxlist)) - allocate(this%id2(this%maxlist)) - allocate(this%flow(this%maxlist)) - allocate(this%auxvar(this%naux, this%maxlist)) - allocate(this%auxtxt(this%naux)) + allocate (this%id1(this%maxlist)) + allocate (this%id2(this%maxlist)) + allocate (this%flow(this%maxlist)) + allocate (this%auxvar(this%naux, this%maxlist)) + allocate (this%auxtxt(this%naux)) end subroutine allocate_arrays - + subroutine deallocate_arrays(this) ! ****************************************************************************** ! deallocate_arrays -- deallocate budget term arrays @@ -124,13 +124,13 @@ subroutine deallocate_arrays(this) ! -- dummy class(BudgetTermType) :: this ! ------------------------------------------------------------------------------ - deallocate(this%id1) - deallocate(this%id2) - deallocate(this%flow) - deallocate(this%auxvar) - deallocate(this%auxtxt) + deallocate (this%id1) + deallocate (this%id2) + deallocate (this%flow) + deallocate (this%auxvar) + deallocate (this%auxtxt) end subroutine deallocate_arrays - + subroutine reset(this, nlist) ! ****************************************************************************** ! reset -- reset the budget term and counter so terms can be updated @@ -146,10 +146,10 @@ subroutine reset(this, nlist) this%nlist = nlist this%icounter = 1 end subroutine reset - + subroutine update_term(this, id1, id2, flow, auxvar) ! ****************************************************************************** -! update_term -- replace the terms in position this%icounter +! update_term -- replace the terms in position this%icounter ! for id1, id2, flow, and aux ! ****************************************************************************** ! @@ -169,7 +169,7 @@ subroutine update_term(this, id1, id2, flow, auxvar) if (present(auxvar)) this%auxvar(:, this%icounter) = auxvar(1:this%naux) this%icounter = this%icounter + 1 end subroutine update_term - + subroutine accumulate_flow(this, ratin, ratout) ! ****************************************************************************** ! accumulate_flow -- calculate ratin and ratout for all the flow terms @@ -197,7 +197,7 @@ subroutine accumulate_flow(this, ratin, ratout) end if end do end subroutine accumulate_flow - + subroutine save_flows(this, dis, ibinun, kstp, kper, delt, pertim, totim, & iout) ! ****************************************************************************** @@ -254,7 +254,7 @@ subroutine save_flows(this, dis, ibinun, kstp, kper, delt, pertim, totim, & olconv2=this%olconv2) end do end subroutine save_flows - + function get_nlist(this) result(nlist) ! ****************************************************************************** ! get_nlist -- get the number of entries for the stress period @@ -264,7 +264,7 @@ function get_nlist(this) result(nlist) ! ------------------------------------------------------------------------------ ! -- modules ! -- return - integer(I4B) :: nlist + integer(I4B) :: nlist ! -- dummy class(BudgetTermType) :: this ! ------------------------------------------------------------------------------ @@ -273,7 +273,7 @@ function get_nlist(this) result(nlist) ! -- return return end function get_nlist - + function get_flowtype(this) result(flowtype) ! ****************************************************************************** ! get_flowtype -- get the flowtype for the budget term @@ -283,7 +283,7 @@ function get_flowtype(this) result(flowtype) ! ------------------------------------------------------------------------------ ! -- modules ! -- return - character(len=LENBUDTXT) :: flowtype + character(len=LENBUDTXT) :: flowtype ! -- dummy class(BudgetTermType) :: this ! ------------------------------------------------------------------------------ @@ -292,7 +292,7 @@ function get_flowtype(this) result(flowtype) ! -- return return end function get_flowtype - + function get_id1(this, icount) result(id1) ! ****************************************************************************** ! get_id1 -- get id1(icount) for the budget term @@ -302,7 +302,7 @@ function get_id1(this, icount) result(id1) ! ------------------------------------------------------------------------------ ! -- modules ! -- return - integer(I4B) :: id1 + integer(I4B) :: id1 ! -- dummy class(BudgetTermType) :: this integer(I4B), intent(in) :: icount @@ -312,7 +312,7 @@ function get_id1(this, icount) result(id1) ! -- return return end function get_id1 - + function get_id2(this, icount) result(id2) ! ****************************************************************************** ! get_id2 -- get id2(icount) for the budget term @@ -322,7 +322,7 @@ function get_id2(this, icount) result(id2) ! ------------------------------------------------------------------------------ ! -- modules ! -- return - integer(I4B) :: id2 + integer(I4B) :: id2 ! -- dummy class(BudgetTermType) :: this integer(I4B), intent(in) :: icount @@ -332,7 +332,7 @@ function get_id2(this, icount) result(id2) ! -- return return end function get_id2 - + function get_flow(this, icount) result(flow) ! ****************************************************************************** ! get_flow -- get flow(icount) for the budget term @@ -342,7 +342,7 @@ function get_flow(this, icount) result(flow) ! ------------------------------------------------------------------------------ ! -- modules ! -- return - real(DP) :: flow + real(DP) :: flow ! -- dummy class(BudgetTermType) :: this integer(I4B), intent(in) :: icount @@ -352,7 +352,7 @@ function get_flow(this, icount) result(flow) ! -- return return end function get_flow - + subroutine read_flows(this, dis, ibinun, kstp, kper, delt, pertim, totim) ! ****************************************************************************** ! read_flows -- read flows from a binary file @@ -377,48 +377,48 @@ subroutine read_flows(this, dis, ibinun, kstp, kper, delt, pertim, totim) integer(I4B) :: n2 real(DP) :: q ! ------------------------------------------------------------------------------ - read(ibinun) kstp, kper, this%flowtype, this%nlist, idum1, idum2 - read(ibinun) imeth, delt, pertim, totim - read(ibinun) this%text1id1 - read(ibinun) this%text2id1 - read(ibinun) this%text1id2 - read(ibinun) this%text2id2 - read(ibinun) this%naux + read (ibinun) kstp, kper, this%flowtype, this%nlist, idum1, idum2 + read (ibinun) imeth, delt, pertim, totim + read (ibinun) this%text1id1 + read (ibinun) this%text2id1 + read (ibinun) this%text1id2 + read (ibinun) this%text2id2 + read (ibinun) this%naux this%naux = this%naux - 1 if (.not. associated(this%auxtxt)) then - allocate(this%auxtxt(this%naux)) + allocate (this%auxtxt(this%naux)) else if (size(this%auxtxt) /= this%naux) then - deallocate(this%auxtxt) - allocate(this%auxtxt(this%naux)) + deallocate (this%auxtxt) + allocate (this%auxtxt(this%naux)) end if end if - if (this%naux > 0) read(ibinun) (this%auxtxt(j), j = 1, this%naux) - read(ibinun) this%nlist + if (this%naux > 0) read (ibinun) (this%auxtxt(j), j=1, this%naux) + read (ibinun) this%nlist if (.not. associated(this%id1)) then this%maxlist = this%nlist - allocate(this%id1(this%maxlist)) - allocate(this%id2(this%maxlist)) - allocate(this%flow(this%maxlist)) - allocate(this%auxvar(this%naux, this%maxlist)) + allocate (this%id1(this%maxlist)) + allocate (this%id2(this%maxlist)) + allocate (this%flow(this%maxlist)) + allocate (this%auxvar(this%naux, this%maxlist)) else if (this%nlist > this%maxlist) then this%maxlist = this%nlist - deallocate(this%id1) - deallocate(this%id2) - deallocate(this%flow) - deallocate(this%auxvar) - allocate(this%id1(this%maxlist)) - allocate(this%id2(this%maxlist)) - allocate(this%flow(this%maxlist)) - allocate(this%auxvar(this%naux, this%maxlist)) + deallocate (this%id1) + deallocate (this%id2) + deallocate (this%flow) + deallocate (this%auxvar) + allocate (this%id1(this%maxlist)) + allocate (this%id2(this%maxlist)) + allocate (this%flow(this%maxlist)) + allocate (this%auxvar(this%naux, this%maxlist)) end if end if do i = 1, this%nlist - read(ibinun) n1 - read(ibinun) n2 - read(ibinun) q - read(ibinun) (this%auxvar(j, i), j = 1, this%naux) + read (ibinun) n1 + read (ibinun) n2 + read (ibinun) q + read (ibinun) (this%auxvar(j, i), j=1, this%naux) if (this%olconv1) n1 = dis%get_nodenumber(n1, 0) if (this%olconv2) n2 = dis%get_nodenumber(n2, 0) this%id1(i) = n1 @@ -426,7 +426,7 @@ subroutine read_flows(this, dis, ibinun, kstp, kper, delt, pertim, totim) this%flow(i) = q end do end subroutine read_flows - + subroutine fill_from_bfr(this, bfr, dis) ! ****************************************************************************** ! fill_from_bfr -- copy the flow from the binary file reader into this budterm @@ -453,32 +453,32 @@ subroutine fill_from_bfr(this, bfr, dis) this%text2id2 = bfr%dstpackagename this%naux = bfr%naux if (.not. associated(this%auxtxt)) then - allocate(this%auxtxt(this%naux)) + allocate (this%auxtxt(this%naux)) else if (size(this%auxtxt) /= this%naux) then - deallocate(this%auxtxt) - allocate(this%auxtxt(this%naux)) + deallocate (this%auxtxt) + allocate (this%auxtxt(this%naux)) end if end if if (this%naux > 0) this%auxtxt(:) = bfr%auxtxt(:) this%nlist = bfr%nlist if (.not. associated(this%id1)) then this%maxlist = this%nlist - allocate(this%id1(this%maxlist)) - allocate(this%id2(this%maxlist)) - allocate(this%flow(this%maxlist)) - allocate(this%auxvar(this%naux, this%maxlist)) + allocate (this%id1(this%maxlist)) + allocate (this%id2(this%maxlist)) + allocate (this%flow(this%maxlist)) + allocate (this%auxvar(this%naux, this%maxlist)) else if (this%nlist > this%maxlist) then this%maxlist = this%nlist - deallocate(this%id1) - deallocate(this%id2) - deallocate(this%flow) - deallocate(this%auxvar) - allocate(this%id1(this%maxlist)) - allocate(this%id2(this%maxlist)) - allocate(this%flow(this%maxlist)) - allocate(this%auxvar(this%naux, this%maxlist)) + deallocate (this%id1) + deallocate (this%id2) + deallocate (this%flow) + deallocate (this%auxvar) + allocate (this%id1(this%maxlist)) + allocate (this%id2(this%maxlist)) + allocate (this%flow(this%maxlist)) + allocate (this%auxvar(this%naux, this%maxlist)) end if end if do i = 1, this%nlist @@ -493,5 +493,5 @@ subroutine fill_from_bfr(this, bfr, dis) this%flow(i) = q end do end subroutine fill_from_bfr - -end module BudgetTermModule \ No newline at end of file + +end module BudgetTermModule diff --git a/src/Utilities/CharString.f90 b/src/Utilities/CharString.f90 new file mode 100644 index 00000000000..c9de347e963 --- /dev/null +++ b/src/Utilities/CharString.f90 @@ -0,0 +1,115 @@ +module CharacterStringModule + + implicit none + private + public :: CharacterStringType + + !> This class is used to store a single deferred-length + !! character string. It was designed to work in an + !! array implementation so that a jagged character array + !! could be used in MODFLOW and stored in the memory + !! manager. + !! + !! The overloaded methods allow instances to behave like + !! a regular string and work with intrinsic Fortran + !! character strings. Ideas for the implmentation were + !! inspired by: + !! https://gitlab.com/everythingfunctional/iso_varying_string + ! + !! Can be improved as necessary to overload other string + !! functions, such as write_formatted, trim, len, ... + !! + !< + type :: CharacterStringType + private + character(len=:), allocatable :: charstring + contains + procedure, pass(lhs) :: assign_to_charstring + procedure, pass(rhs) :: assign_from_charstring + procedure, pass(rhs) :: character_eq_charstring + procedure, pass(lhs) :: charstring_eq_character + procedure :: write_unformatted + procedure :: strlen + generic :: assignment(=) => assign_to_charstring, assign_from_charstring + generic :: operator(==) => character_eq_charstring, charstring_eq_character + ! not supported by gfortran 5 and 6 + ! disable for now + ! generic :: write (unformatted) => write_unformatted + end type CharacterStringType + +contains + + subroutine assign_to_charstring(lhs, rhs) + class(CharacterStringType), intent(out) :: lhs + character(len=*), intent(in) :: rhs + logical :: allocate_charstring + allocate_charstring = .false. + if (allocated(lhs%charstring)) then + if (len(lhs%charstring) <= len(rhs)) then + lhs%charstring(:) = rhs + else + allocate_charstring = .true. + end if + else + allocate_charstring = .true. + end if + if (allocate_charstring) then + lhs%charstring = rhs + end if + end subroutine assign_to_charstring + + subroutine assign_from_charstring(lhs, rhs) + character(len=*), intent(out) :: lhs + class(CharacterStringType), intent(in) :: rhs + if (allocated(rhs%charstring)) then + lhs = rhs%charstring + else + lhs = '' + end if + end subroutine assign_from_charstring + + elemental function character_eq_charstring(lhs, rhs) result(equals) + character(len=*), intent(in) :: lhs + class(CharacterStringType), intent(in) :: rhs + logical :: equals + if (allocated(rhs%charstring)) then + equals = lhs == rhs%charstring + else + equals = lhs == '' + end if + end function character_eq_charstring + + elemental function charstring_eq_character(lhs, rhs) result(equals) + class(CharacterStringType), intent(in) :: lhs + character(len=*), intent(in) :: rhs + logical :: equals + if (allocated(lhs%charstring)) then + equals = lhs%charstring == rhs + else + equals = rhs == '' + end if + end function charstring_eq_character + + subroutine write_unformatted(this, unit, iostat, iomsg) + class(CharacterStringType), intent(in) :: this + integer, intent(in) :: unit + integer, intent(out) :: iostat + character(len=*), intent(inout) :: iomsg + iostat = 0 + if (allocated(this%charstring)) then + write (unit, iostat=iostat) this%charstring + end if + end subroutine write_unformatted + + function strlen(this) result(length) + class(CharacterStringType), intent(in) :: this + integer :: length + + if (allocated(this%charstring)) then + length = len(this%charstring) + else + length = 0 + end if + end function strlen + +end module CharacterStringModule diff --git a/src/Utilities/Constants.f90 b/src/Utilities/Constants.f90 index 0e64becc32e..f7c966916d5 100644 --- a/src/Utilities/Constants.f90 +++ b/src/Utilities/Constants.f90 @@ -10,167 +10,174 @@ module ConstantsModule use KindModule public ! -- constants - integer(I4B), parameter :: IUSERFORMATSTRIP = -99 !< default user format strip - integer(I4B), parameter :: IUSERFORMATWRAP = 99 !< default user format wrap - integer(I4B), parameter :: LENBIGLINE = 5000 !< maximum length of a big line - integer(I4B), parameter :: LENHUGELINE = 50000 !< maximum length of a huge line - integer(I4B), parameter :: LENVARNAME = 16 !< maximum length of a variable name - integer(I4B), parameter :: LENCOMPONENTNAME = 16 !< maximum length of a component name - integer(I4B), parameter :: LENSOLUTIONNAME = LENCOMPONENTNAME !< maximum length of the solution name - integer(I4B), parameter :: LENMODELNAME = LENCOMPONENTNAME !< maximum length of the model name - integer(I4B), parameter :: LENPACKAGENAME = LENCOMPONENTNAME !< maximum length of the package name - integer(I4B), parameter :: LENEXCHANGENAME = LENCOMPONENTNAME !< maximum length of the exchange name - integer(I4B), parameter :: LENBUDROWLABEL = 2 * LENPACKAGENAME + 1 !< maximum length of the rowlabel string used in the budget table - integer(I4B), parameter :: LENMEMSEPARATOR = 1 !< maximum length of the memory path separator used, currently a '/' - integer(I4B), parameter :: LENMEMPATH = 2*LENCOMPONENTNAME + LENMEMSEPARATOR !< maximum length of the memory path - integer(I4B), parameter :: LENMEMADDRESS = LENMEMPATH + LENMEMSEPARATOR + LENVARNAME !< maximum length of the full memory address, including variable name - integer(I4B), parameter :: LENAUXNAME = 16 !< maximum length of a aux variable - integer(I4B), parameter :: LENBOUNDNAME = 40 !< maximum length of a bound name - integer(I4B), parameter :: LENBUDTXT = 16 !< maximum length of a budget component names - integer(I4B), parameter :: LENPACKAGETYPE = 7 !< maximum length of a package type (DIS6, SFR6, CSUB6, etc.) - integer(I4B), parameter :: LENFTYPE = 5 !< maximum length of a package type (DIS, WEL, OC, etc.) - integer(I4B), parameter :: LENOBSNAME = 40 !< maximum length of a observation name - integer(I4B), parameter :: LENOBSTYPE = 30 !< maximum length of a observation type (CONTINUOUS) - integer(I4B), parameter :: LENTIMESERIESNAME = LENOBSNAME !< maximum length of a time series name - integer(I4B), parameter :: LENTIMESERIESTEXT = 16 !< maximum length of a time series text - integer(I4B), parameter :: LENDATETIME = 30 !< maximum length of a date time string - integer(I4B), parameter :: LINELENGTH = 300 !< maximum length of a standard line - integer(I4B), parameter :: LENLISTLABEL = 500 !< maximum length of a llist label - integer(I4B), parameter :: MAXCHARLEN = max(1000, LENBIGLINE) !< maximum length of char string - integer(I4B), parameter :: MAXOBSTYPES = 100 !< maximum number of observation types - integer(I4B), parameter :: NAMEDBOUNDFLAG = -9 !< named bound flag - integer(I4B), parameter :: LENPAKLOC = 34 !< maximum length of a package location - integer(I4B), parameter :: IZERO = 0 !< integer constant zero + integer(I4B), parameter :: IUSERFORMATSTRIP = -99 !< default user format strip + integer(I4B), parameter :: IUSERFORMATWRAP = 99 !< default user format wrap + integer(I4B), parameter :: LENBIGLINE = 5000 !< maximum length of a big line + integer(I4B), parameter :: LENHUGELINE = 50000 !< maximum length of a huge line + integer(I4B), parameter :: LENVARNAME = 16 !< maximum length of a variable name + integer(I4B), parameter :: LENCOMPONENTNAME = 16 !< maximum length of a component name + integer(I4B), parameter :: LENCONTEXTNAME = 16 !< maximum length of a memory manager context + integer(I4B), parameter :: LENSOLUTIONNAME = LENCOMPONENTNAME !< maximum length of the solution name + integer(I4B), parameter :: LENMODELNAME = LENCOMPONENTNAME !< maximum length of the model name + integer(I4B), parameter :: LENPACKAGENAME = LENCOMPONENTNAME !< maximum length of the package name + integer(I4B), parameter :: LENEXCHANGENAME = LENCOMPONENTNAME !< maximum length of the exchange name + integer(I4B), parameter :: LENBUDROWLABEL = 2 * LENPACKAGENAME + 1 !< maximum length of the rowlabel string used in the budget table + integer(I4B), parameter :: LENMEMSEPARATOR = 1 !< maximum length of the memory path separator used, currently a '/' + integer(I4B), parameter :: LENMEMPATH = & + LENCONTEXTNAME + & + 2 * LENCOMPONENTNAME + & + 2 * LENMEMSEPARATOR !< maximum length of the memory path + integer(I4B), parameter :: LENMEMADDRESS = & + LENMEMPATH + & + LENMEMSEPARATOR + & + LENVARNAME !< maximum length of the full memory address, including variable name + integer(I4B), parameter :: LENAUXNAME = 16 !< maximum length of a aux variable + integer(I4B), parameter :: LENBOUNDNAME = 40 !< maximum length of a bound name + integer(I4B), parameter :: LENBUDTXT = 16 !< maximum length of a budget component names + integer(I4B), parameter :: LENPACKAGETYPE = 7 !< maximum length of a package type (DIS6, SFR6, CSUB6, etc.) + integer(I4B), parameter :: LENFTYPE = 5 !< maximum length of a package type (DIS, WEL, OC, etc.) + integer(I4B), parameter :: LENOBSNAME = 40 !< maximum length of a observation name + integer(I4B), parameter :: LENOBSTYPE = 30 !< maximum length of a observation type (CONTINUOUS) + integer(I4B), parameter :: LENTIMESERIESNAME = LENOBSNAME !< maximum length of a time series name + integer(I4B), parameter :: LENTIMESERIESTEXT = 16 !< maximum length of a time series text + integer(I4B), parameter :: LENDATETIME = 30 !< maximum length of a date time string + integer(I4B), parameter :: LINELENGTH = 300 !< maximum length of a standard line + integer(I4B), parameter :: LENLISTLABEL = 500 !< maximum length of a llist label + integer(I4B), parameter :: MAXCHARLEN = max(1000, LENBIGLINE) !< maximum length of char string + integer(I4B), parameter :: MAXOBSTYPES = 100 !< maximum number of observation types + integer(I4B), parameter :: NAMEDBOUNDFLAG = -9 !< named bound flag + integer(I4B), parameter :: LENPAKLOC = 34 !< maximum length of a package location + integer(I4B), parameter :: IZERO = 0 !< integer constant zero ! ! -- file constants - integer(I4B), parameter :: IUOC = 999 !< open/close file unit number - integer(I4B), parameter :: IUSTART = 1000 !< starting file unit number - integer(I4B), parameter :: IULAST = 10000 !< maximum file unit number (this allows for 9000 open files) + integer(I4B), parameter :: IUOC = 999 !< open/close file unit number + integer(I4B), parameter :: IUSTART = 1000 !< starting file unit number + integer(I4B), parameter :: IULAST = 10000 !< maximum file unit number (this allows for 9000 open files) ! ! -- memory manager constants - integer(I4B), public, parameter :: MAXMEMRANK = 3 !< maximum memory manager length (up to 3-dimensional arrays) - integer(I4B), public, parameter :: LENMEMTYPE = 50 !< maximum length of a memory manager type + integer(I4B), public, parameter :: MAXMEMRANK = 3 !< maximum memory manager length (up to 3-dimensional arrays) + integer(I4B), public, parameter :: LENMEMTYPE = 50 !< maximum length of a memory manager type ! ! -- real constants - real(DP), parameter :: DZERO = 0.0_DP !< real constant zero - real(DP), parameter :: DQUARTER = 0.25_DP !< real constant 1/3 - real(DP), parameter :: DONETHIRD = 1.0_DP / 3.0_DP !< real constant 1/3 - real(DP), parameter :: DHALF = 0.5_DP !< real constant 1/2 - real(DP), parameter :: DP6 = 0.6_DP !< real constant 3/5 - real(DP), parameter :: DTWOTHIRDS = 2.0_DP / 3.0_DP !< real constant 2/3 - real(DP), parameter :: DP7 = 0.7_DP !< real constant 7/10 - real(DP), parameter :: DP9 = 0.9_DP !< real constant 9/10 - real(DP), parameter :: DP99 = 0.99_DP !< real constant 99/100 - real(DP), parameter :: DP999 = 0.999_DP !< real constant 999/1000 - - real(DP), parameter :: DONE = 1.0_DP !< real constant 1 - real(DP), parameter :: D1P1 = 1.1_DP !< real constant 1.1 - real(DP), parameter :: DFIVETHIRDS = 5.0_DP / 3.0_DP !< real constant 5/3 - real(DP), parameter :: DTWO = 2.0_DP !< real constant 2 - real(DP), parameter :: DTHREE = 3.0_DP !< real constant 3 - real(DP), parameter :: DFOUR = 4.0_DP !< real constant 4 - real(DP), parameter :: DSIX = 6.0_DP !< real constant 6 - real(DP), parameter :: DEIGHT = 8.0_DP !< real constant 8 - real(DP), parameter :: DTEN = 1.0e1_DP !< real constant 10 - real(DP), parameter :: DHUNDRED = 1.0e2_DP !< real constant 100 - - real(DP), parameter :: DEP3 = 1.0e3_DP !< real constant 1000 - real(DP), parameter :: DEP6 = 1.0e6_DP !< real constant 1000000 - real(DP), parameter :: DEP9 = 1.0e9_DP !< real constant 1e9 - real(DP), parameter :: DEP20 = 1.0e20_DP !< real constant 1e20 - - real(DP), parameter :: DHNOFLO = 1.e30_DP !< real no flow constant - real(DP), parameter :: DHDRY = -1.e30_DP !< real dry cell constant - real(DP), parameter :: DNODATA = 3.0e30_DP !< real no data constant - - real(DP), parameter :: DEM1 = 1.0e-1_DP !< real constant 1e-1 - real(DP), parameter :: D5EM2 = 5.0e-2_DP !< real constant 5e-2 - real(DP), parameter :: DEM2 = 1.0e-2_DP !< real constant 1e-2 - real(DP), parameter :: DEM3 = 1.0e-3_DP !< real constant 1e-3 - real(DP), parameter :: DEM4 = 1.0e-4_DP !< real constant 1e-4 - real(DP), parameter :: DEM5 = 1.0e-5_DP !< real constant 1e-5 - real(DP), parameter :: DEM6 = 1.0e-6_DP !< real constant 1e-6 - real(DP), parameter :: DEM7 = 1.0e-7_DP !< real constant 1e-7 - real(DP), parameter :: DEM8 = 1.0e-8_DP !< real constant 1e-8 - real(DP), parameter :: DEM9 = 1.0e-9_DP !< real constant 1e-9 - real(DP), parameter :: DEM10 = 1.0e-10_DP !< real constant 1e-10 - real(DP), parameter :: DEM12 = 1.0e-12_DP !< real constant 1e-12 - real(DP), parameter :: DEM14 = 1.0e-14_DP !< real constant 1e-14 - real(DP), parameter :: DEM15 = 1.0e-15_DP !< real constant 1e-15 - real(DP), parameter :: DEM20 = 1.0e-20_DP !< real constant 1e-20 - real(DP), parameter :: DEM30 = 1.0e-30_DP !< real constant 1e-30 - - real(DP), parameter :: DPREC = EPSILON(1.0_DP) !< real constant machine precision - real(DP), parameter :: DSAME = DHUNDRED * DPREC !< real constant for values that - !! are consider the same based on machine precision - - real(DP), parameter :: DLNLOW = 0.995_DP !< real constant low ratio used to calculate log mean of K - real(DP), parameter :: DLNHIGH = 1.005_DP !< real constant high ratio used to calculate log mean of K - - real(DP), parameter :: DPI = DFOUR * ATAN(DONE) !< real constant \f$\pi\f$ - real(DP), parameter :: DTWOPI = DTWO * DFOUR * ATAN(DONE) !< real constant \f$2 \pi\f$ - real(DP), parameter :: DPIO180 = datan(DONE)/4.5d1 !< real constant \f$\pi/180\f$ - - real(DP), parameter :: DGRAVITY = 9.80665_DP !< real constant gravitational acceleration (m/(s s)) - real(DP), parameter :: DCD = 0.61_DP !< real constant weir coefficient in SI units - - character(len=10), dimension(3, 3), parameter :: cidxnames = reshape ( & - [ ' NODE', ' ', ' ', & - ' LAYER', ' CELL2D', ' ', & - ' LAYER', ' ROW', ' COL'], [3,3]) !< cellid labels for DIS, DISV, and DISU discretizations - - + real(DP), parameter :: DZERO = 0.0_DP !< real constant zero + real(DP), parameter :: DQUARTER = 0.25_DP !< real constant 1/3 + real(DP), parameter :: DONETHIRD = 1.0_DP / 3.0_DP !< real constant 1/3 + real(DP), parameter :: DHALF = 0.5_DP !< real constant 1/2 + real(DP), parameter :: DP6 = 0.6_DP !< real constant 3/5 + real(DP), parameter :: DTWOTHIRDS = 2.0_DP / 3.0_DP !< real constant 2/3 + real(DP), parameter :: DP7 = 0.7_DP !< real constant 7/10 + real(DP), parameter :: DP9 = 0.9_DP !< real constant 9/10 + real(DP), parameter :: DP99 = 0.99_DP !< real constant 99/100 + real(DP), parameter :: DP999 = 0.999_DP !< real constant 999/1000 + + real(DP), parameter :: DONE = 1.0_DP !< real constant 1 + real(DP), parameter :: D1P1 = 1.1_DP !< real constant 1.1 + real(DP), parameter :: DFIVETHIRDS = 5.0_DP / 3.0_DP !< real constant 5/3 + real(DP), parameter :: DTWO = 2.0_DP !< real constant 2 + real(DP), parameter :: DTHREE = 3.0_DP !< real constant 3 + real(DP), parameter :: DFOUR = 4.0_DP !< real constant 4 + real(DP), parameter :: DSIX = 6.0_DP !< real constant 6 + real(DP), parameter :: DEIGHT = 8.0_DP !< real constant 8 + real(DP), parameter :: DTEN = 1.0e1_DP !< real constant 10 + real(DP), parameter :: DHUNDRED = 1.0e2_DP !< real constant 100 + + real(DP), parameter :: DEP3 = 1.0e3_DP !< real constant 1000 + real(DP), parameter :: DEP6 = 1.0e6_DP !< real constant 1000000 + real(DP), parameter :: DEP9 = 1.0e9_DP !< real constant 1e9 + real(DP), parameter :: DEP20 = 1.0e20_DP !< real constant 1e20 + + real(DP), parameter :: DHNOFLO = 1.e30_DP !< real no flow constant + real(DP), parameter :: DHDRY = -1.e30_DP !< real dry cell constant + real(DP), parameter :: DNODATA = 3.0e30_DP !< real no data constant + + real(DP), parameter :: DEM1 = 1.0e-1_DP !< real constant 1e-1 + real(DP), parameter :: D5EM2 = 5.0e-2_DP !< real constant 5e-2 + real(DP), parameter :: DEM2 = 1.0e-2_DP !< real constant 1e-2 + real(DP), parameter :: DEM3 = 1.0e-3_DP !< real constant 1e-3 + real(DP), parameter :: DEM4 = 1.0e-4_DP !< real constant 1e-4 + real(DP), parameter :: DEM5 = 1.0e-5_DP !< real constant 1e-5 + real(DP), parameter :: DEM6 = 1.0e-6_DP !< real constant 1e-6 + real(DP), parameter :: DEM7 = 1.0e-7_DP !< real constant 1e-7 + real(DP), parameter :: DEM8 = 1.0e-8_DP !< real constant 1e-8 + real(DP), parameter :: DEM9 = 1.0e-9_DP !< real constant 1e-9 + real(DP), parameter :: DEM10 = 1.0e-10_DP !< real constant 1e-10 + real(DP), parameter :: DEM12 = 1.0e-12_DP !< real constant 1e-12 + real(DP), parameter :: DEM14 = 1.0e-14_DP !< real constant 1e-14 + real(DP), parameter :: DEM15 = 1.0e-15_DP !< real constant 1e-15 + real(DP), parameter :: DEM20 = 1.0e-20_DP !< real constant 1e-20 + real(DP), parameter :: DEM30 = 1.0e-30_DP !< real constant 1e-30 + + real(DP), parameter :: DPREC = EPSILON(1.0_DP) !< real constant machine precision + real(DP), parameter :: DSAME = DHUNDRED * DPREC !< real constant for values that are considered + !! the same based on machine precision + + real(DP), parameter :: DLNLOW = 0.995_DP !< real constant low ratio used to calculate log mean of K + real(DP), parameter :: DLNHIGH = 1.005_DP !< real constant high ratio used to calculate log mean of K + + real(DP), parameter :: DPI = DFOUR * ATAN(DONE) !< real constant \f$\pi\f$ + real(DP), parameter :: DTWOPI = DTWO * DFOUR * ATAN(DONE) !< real constant \f$2 \pi\f$ + real(DP), parameter :: DPIO180 = datan(DONE) / 4.5d1 !< real constant \f$\pi/180\f$ + + real(DP), parameter :: DGRAVITY = 9.80665_DP !< real constant gravitational acceleration (m/(s s)) + real(DP), parameter :: DCD = 0.61_DP !< real constant weir coefficient in SI units + + character(len=10), dimension(3, 3), parameter :: & + cidxnames = reshape( & + [' NODE', ' ', ' ', & + ' LAYER', ' CELL2D', ' ', & + ' LAYER', ' ROW', ' COL'], [3, 3]) !< cellid labels for DIS, DISV, and DISU discretizations + ! -- enumerator used with TimeSeriesType ENUM, BIND(C) - ENUMERATOR :: UNDEFINED=0 !< 0 - ENUMERATOR :: STEPWISE=1 !< 1 - ENUMERATOR :: LINEAR=2 !< 2 - ENUMERATOR :: LINEAREND=3 !< 3 - END ENUM + ENUMERATOR :: UNDEFINED = 0 !< 0 + ENUMERATOR :: STEPWISE = 1 !< 1 + ENUMERATOR :: LINEAR = 2 !< 2 + ENUMERATOR :: LINEAREND = 3 !< 3 + END ENUM ! -- enumerator used with table objects ENUM, BIND(C) - ENUMERATOR :: TABLEFT=0 !< 0 - ENUMERATOR :: TABCENTER=1 !< 1 - ENUMERATOR :: TABRIGHT=2 !< 2 + ENUMERATOR :: TABLEFT = 0 !< 0 + ENUMERATOR :: TABCENTER = 1 !< 1 + ENUMERATOR :: TABRIGHT = 2 !< 2 END ENUM ! -- enumerator used to define table column data type ENUM, BIND(C) - ENUMERATOR :: TABSTRING=0 !< 0 - ENUMERATOR :: TABUCSTRING=1 !< 1 - ENUMERATOR :: TABINTEGER=2 !< 2 - ENUMERATOR :: TABREAL=3 !< 3 + ENUMERATOR :: TABSTRING = 0 !< 0 + ENUMERATOR :: TABUCSTRING = 1 !< 1 + ENUMERATOR :: TABINTEGER = 2 !< 2 + ENUMERATOR :: TABREAL = 3 !< 3 END ENUM ! -- enumerator used to define output option ENUM, BIND(C) - ENUMERATOR :: VSUMMARY=0 !< 0 - ENUMERATOR :: VALL=1 !< 1 - ENUMERATOR :: VDEBUG=2 !< 2 + ENUMERATOR :: VSUMMARY = 0 !< 0 + ENUMERATOR :: VALL = 1 !< 1 + ENUMERATOR :: VDEBUG = 2 !< 2 END ENUM ! -- enumerator that defines the operating system ENUM, BIND(C) - ENUMERATOR :: OSUNDEF=0 !< 0 - ENUMERATOR :: OSLINUX=1 !< 1 - ENUMERATOR :: OSMAC=2 !< 2 - ENUMERATOR :: OSWIN=3 !< 3 + ENUMERATOR :: OSUNDEF = 0 !< 0 + ENUMERATOR :: OSLINUX = 1 !< 1 + ENUMERATOR :: OSMAC = 2 !< 2 + ENUMERATOR :: OSWIN = 3 !< 3 END ENUM ! -- enumerator that defines the simulation mode ENUM, BIND(C) - ENUMERATOR :: MVALIDATE=0 !< 0 - ENUMERATOR :: MNORMAL=1 !< 1 - ENUMERATOR :: MRUN=2 !< 2 + ENUMERATOR :: MVALIDATE = 0 !< 0 + ENUMERATOR :: MNORMAL = 1 !< 1 + ENUMERATOR :: MRUN = 2 !< 2 END ENUM ! -- enumerator that defines the compiler ENUM, BIND(C) - ENUMERATOR :: CUNKNOWN=0 !< 0 - ENUMERATOR :: CGFORTRAN=1 !< 1 - ENUMERATOR :: CINTEL=3 !< 2 - ENUMERATOR :: CCRAYFTN=3 !< 3 + ENUMERATOR :: CUNKNOWN = 0 !< 0 + ENUMERATOR :: CGFORTRAN = 1 !< 1 + ENUMERATOR :: CINTEL = 3 !< 2 + ENUMERATOR :: CCRAYFTN = 3 !< 3 END ENUM end module ConstantsModule diff --git a/src/Utilities/HashTable.f90 b/src/Utilities/HashTable.f90 index 5e37abf94e5..51f90b04efd 100644 --- a/src/Utilities/HashTable.f90 +++ b/src/Utilities/HashTable.f90 @@ -1,5 +1,5 @@ ! HashTableType implements a hash table for storing integers, -! for use as an index for an array that could contain +! for use as an index for an array that could contain ! any data type. This HashTableModule was designed using the ! dictionary implementation by Arjen Markus of the Flibs ! collection of Fortran utilities. This hash table works @@ -7,37 +7,37 @@ ! strings and each string will be assigned a unique number ! between 1 and n, allowing an efficient way to store a ! unique integer index with a character string. - + module HashTableModule use KindModule, only: DP, I4B - + implicit none private public HashTableType public hash_table_cr public hash_table_da - - integer, parameter, private :: HASH_SIZE = 4993 + + integer, parameter, private :: HASH_SIZE = 4993 integer, parameter, private :: MULTIPLIER = 31 type :: ListDataType character(len=:), allocatable :: key integer(I4B) :: index end type ListDataType - + type :: ListType type(ListDataType) :: listdata type(ListType), pointer :: next => null() contains procedure :: add => listtype_add end type ListType - + type :: HashListType type(ListType), pointer :: list => null() end type HashListType - + type :: HashTableType private type(HashListType), dimension(:), pointer :: table => null() @@ -46,9 +46,9 @@ module HashTableModule procedure :: get_elem procedure :: get_index end type HashTableType - - contains - + +contains + subroutine hash_table_cr(ht) ! ****************************************************************************** ! hash_table_cr -- public subroutine to create the hash table object @@ -63,18 +63,18 @@ subroutine hash_table_cr(ht) ! ------------------------------------------------------------------------------ ! ! -- allocate - allocate(ht) - allocate(ht%table(HASH_SIZE)) + allocate (ht) + allocate (ht%table(HASH_SIZE)) ! ! -- nullify each list do i = 1, HASH_SIZE ht%table(i)%list => null() - enddo + end do ! ! -- return return end subroutine hash_table_cr - + subroutine hash_table_da(ht) ! ****************************************************************************** ! hash_table_da -- public subroutine to deallocate the hash table object @@ -90,19 +90,19 @@ subroutine hash_table_da(ht) ! ! -- deallocate the list for each hash do i = 1, size(ht%table) - if ( associated( ht%table(i)%list)) then + if (associated(ht%table(i)%list)) then call listtype_da(ht%table(i)%list) - endif - enddo + end if + end do ! ! -- deallocate the table and the hash table - deallocate(ht%table) - deallocate(ht) + deallocate (ht%table) + deallocate (ht) ! ! -- return return end subroutine hash_table_da - + subroutine add_entry(this, key, index) ! ****************************************************************************** ! add_entry -- hash table method to add a key/index entry @@ -157,16 +157,16 @@ function get_elem(this, key) result(elem) elem => this%table(ihash)%list do while (associated(elem)) if (elem%listdata%key == key) then - exit + exit else elem => elem%next end if - enddo + end do ! ! -- return return - end function get_elem - + end function get_elem + function get_index(this, key) result(index) ! ****************************************************************************** ! get_index -- get the integer index that corresponds to this hash. @@ -188,12 +188,12 @@ function get_index(this, key) result(index) index = elem%listdata%index else index = 0 - endif + end if ! ! -- return return end function get_index - + subroutine listtype_cr(list, key, index) ! ****************************************************************************** ! listtype_cr -- subroutine to create a list @@ -206,7 +206,7 @@ subroutine listtype_cr(list, key, index) character(len=*), intent(in) :: key integer(I4B), intent(in) :: index ! ------------------------------------------------------------------------------ - allocate(list) + allocate (list) list%next => null() list%listdata%key = key list%listdata%index = index @@ -229,7 +229,7 @@ subroutine listtype_add(this, key, index) ! -- local type(ListType), pointer :: next ! ------------------------------------------------------------------------------ - allocate(next) + allocate (next) next%listdata%key = key next%listdata%index = index next%next => this%next @@ -249,15 +249,15 @@ subroutine listtype_da(list) ! -- dummy type(ListType), pointer, intent(in) :: list ! -- local - type(ListType), pointer :: current - type(ListType), pointer :: elem + type(ListType), pointer :: current + type(ListType), pointer :: elem ! ------------------------------------------------------------------------------ elem => list - do while ( associated(elem) ) + do while (associated(elem)) current => elem elem => current%next - deallocate(current) - enddo + deallocate (current) + end do ! ! -- return return @@ -277,9 +277,9 @@ function hashfunc(key) result(ihash) integer(I4B) :: i ! ------------------------------------------------------------------------------ ihash = 0 - do i = 1,len(key) - ihash = modulo( MULTIPLIER * ihash + ichar(key(i:i)), HASH_SIZE) - enddo + do i = 1, len(key) + ihash = modulo(MULTIPLIER * ihash + ichar(key(i:i)), HASH_SIZE) + end do ihash = 1 + modulo(ihash - 1, HASH_SIZE) ! ! -- return diff --git a/src/Utilities/HeadFileReader.f90 b/src/Utilities/HeadFileReader.f90 index 6795dc60a6d..2e2253e2c1c 100644 --- a/src/Utilities/HeadFileReader.f90 +++ b/src/Utilities/HeadFileReader.f90 @@ -4,12 +4,12 @@ module HeadFileReaderModule use ConstantsModule, only: LINELENGTH implicit none - + private public :: HeadFileReaderType - + type :: HeadFileReaderType - + integer(I4B) :: inunit character(len=16) :: text integer(I4B) :: nlay @@ -22,17 +22,17 @@ module HeadFileReaderModule real(DP) :: pertim real(DP) :: totim real(DP), dimension(:), allocatable :: head - + contains - + procedure :: initialize procedure :: read_record procedure :: finalize - + end type HeadFileReaderType - - contains - + +contains + subroutine initialize(this, iu, iout) ! ****************************************************************************** ! initialize @@ -56,27 +56,27 @@ subroutine initialize(this, iu, iout) call this%read_record(success) kstp_last = this%kstp kper_last = this%kper - rewind(this%inunit) + rewind (this%inunit) ! ! -- Determine number of records within a time step if (iout > 0) & - write(iout, '(a)') & - 'Reading binary file to determine number of records per time step.' + write (iout, '(a)') & + 'Reading binary file to determine number of records per time step.' do call this%read_record(success, iout) if (.not. success) exit if (kstp_last /= this%kstp .or. kper_last /= this%kper) exit this%nlay = this%nlay + 1 - enddo - rewind(this%inunit) + end do + rewind (this%inunit) if (iout > 0) & - write(iout, '(a, i0, a)') 'Detected ', this%nlay, & + write (iout, '(a, i0, a)') 'Detected ', this%nlay, & ' unique records in binary file.' ! ! -- return return end subroutine initialize - + subroutine read_record(this, success, iout_opt) ! ****************************************************************************** ! read_record @@ -99,48 +99,48 @@ subroutine read_record(this, success, iout_opt) iout = iout_opt else iout = 0 - endif + end if ! this%kstp = 0 this%kper = 0 success = .true. this%kstpnext = 0 this%kpernext = 0 - read(this%inunit, iostat=iostat) this%kstp, this%kper, this%pertim, & + read (this%inunit, iostat=iostat) this%kstp, this%kper, this%pertim, & this%totim, this%text, ncol, nrow, ilay if (iostat /= 0) then success = .false. if (iostat < 0) this%endoffile = .true. return - endif + end if ! ! -- allocate head to proper size if (.not. allocated(this%head)) then - allocate(this%head(ncol*nrow)) + allocate (this%head(ncol * nrow)) else - if (size(this%head) /= ncol*nrow) then - deallocate(this%head) - allocate(this%head(ncol*nrow)) - endif - endif + if (size(this%head) /= ncol * nrow) then + deallocate (this%head) + allocate (this%head(ncol * nrow)) + end if + end if ! ! -- read the head array - read(this%inunit) this%head + read (this%inunit) this%head ! ! -- look ahead to next kstp and kper, then backup if read successfully if (.not. this%endoffile) then - read(this%inunit, iostat=iostat) this%kstpnext, this%kpernext + read (this%inunit, iostat=iostat) this%kstpnext, this%kpernext if (iostat == 0) then call fseek_stream(this%inunit, -2 * I4B, 1, iostat) else if (iostat < 0) then this%endoffile = .true. - endif - endif + end if + end if ! ! -- return return end subroutine read_record - + subroutine finalize(this) ! ****************************************************************************** ! budgetdata_finalize @@ -150,11 +150,11 @@ subroutine finalize(this) ! ------------------------------------------------------------------------------ class(HeadFileReaderType) :: this ! ------------------------------------------------------------------------------ - close(this%inunit) - if(allocated(this%head)) deallocate(this%head) + close (this%inunit) + if (allocated(this%head)) deallocate (this%head) ! ! -- return return end subroutine finalize - + end module HeadFileReaderModule diff --git a/src/Utilities/Idm/IdmLogger.f90 b/src/Utilities/Idm/IdmLogger.f90 new file mode 100644 index 00000000000..aa7f1f83cca --- /dev/null +++ b/src/Utilities/Idm/IdmLogger.f90 @@ -0,0 +1,209 @@ +!> @brief This module contains the Input Data Model Logger Module +!! +!! This module contains the subroutines for logging messages +!! to the list file as the input data model loads model input. +!! +!< +module IdmLoggerModule + + use KindModule, only: DP, LGP, I4B + + implicit none + private + public :: idm_log_header + public :: idm_log_close + public :: idm_log_var + + interface idm_log_var + module procedure idm_log_var_logical, idm_log_var_int, & + idm_log_var_int1d, idm_log_var_int2d, & + idm_log_var_int3d, idm_log_var_dbl, & + idm_log_var_dbl1d, idm_log_var_dbl2d, & + idm_log_var_dbl3d + end interface idm_log_var + +contains + + !> @ brief log a header message + !< + subroutine idm_log_header(component, subcomponent, iout) + character(len=*), intent(in) :: component !< component name + character(len=*), intent(in) :: subcomponent !< subcomponent name + integer(I4B), intent(in) :: iout + + if (iout > 0) then + write (iout, '(1x,a)') 'Loading input for '//trim(component)//& + &'/'//trim(subcomponent) + end if + end subroutine idm_log_header + + !> @ brief log the closing message + !< + subroutine idm_log_close(component, subcomponent, iout) + character(len=*), intent(in) :: component !< component name + character(len=*), intent(in) :: subcomponent !< subcomponent name + integer(I4B) :: iout + + write (iout, '(1x,a,/)') 'Loading input complete...' + end subroutine idm_log_close + + !> @brief Log type specific information logical + !< + subroutine idm_log_var_logical(p_mem, varname, mempath, iout) + logical(LGP), intent(in) :: p_mem !< logical scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + + write (iout, '(3x,a, " = ", l)') trim(varname), p_mem + end subroutine idm_log_var_logical + + !> @brief Log type specific information integer + !< + subroutine idm_log_var_int(p_mem, varname, mempath, iout) + integer(I4B), intent(in) :: p_mem !< int scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + + write (iout, '(3x,a, " = ", i0)') trim(varname), p_mem + end subroutine idm_log_var_int + + !> @brief Log type specific information int1d + !< + subroutine idm_log_var_int1d(p_mem, varname, mempath, iout) + integer(I4B), dimension(:), contiguous, intent(in) :: p_mem !< 1d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + integer(I4B) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", i0)') trim(varname), min_val + else + write (iout, '(3x, a, a, i0, a, i0)') & + trim(varname), & + ' = variable 1D integer array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_int1d + + !> @brief Log type specific information int2d + !< + subroutine idm_log_var_int2d(p_mem, varname, mempath, iout) + integer(I4B), dimension(:, :), contiguous, intent(in) :: p_mem !< 2d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + integer(I4B) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", i0)') trim(varname), min_val + else + write (iout, '(3x, a, a, i0, a, i0)') & + trim(varname), & + ' = variable 2D integer array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_int2d + + !> @brief Log type specific information int3d + !< + subroutine idm_log_var_int3d(p_mem, varname, mempath, iout) + integer(I4B), dimension(:, :, :), contiguous, intent(in) :: p_mem !< 3d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + integer(I4B) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", i0)') trim(varname), min_val + else + write (iout, '(3x, a, a, i0, a, i0)') & + trim(varname), & + ' = variable 3D integer array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_int3d + + !> @brief Log type specific information double + !< + subroutine idm_log_var_dbl(p_mem, varname, mempath, iout) + real(DP), intent(in) :: p_mem !< dbl scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + + write (iout, '(3x,a, " = ", G0)') trim(varname), p_mem + end subroutine idm_log_var_dbl + + !> @brief Log type specific information dbl1d + !< + subroutine idm_log_var_dbl1d(p_mem, varname, mempath, iout) + real(DP), dimension(:), contiguous, intent(in) :: p_mem !< 1d real array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + real(DP) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", G0)') trim(varname), min_val + else + write (iout, '(3x, a, a, G0, a, G0)') & + trim(varname), & + ' = variable 1D double precision array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_dbl1d + + !> @brief Log type specific information dbl2d + !< + subroutine idm_log_var_dbl2d(p_mem, varname, mempath, iout) + real(DP), dimension(:, :), contiguous, intent(in) :: p_mem !< 2d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + real(DP) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", G0)') trim(varname), min_val + else + write (iout, '(3x, a, a, G0, a, G0)') & + trim(varname), & + ' = variable 2D double precision array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_dbl2d + + !> @brief Log type specific information dbl3d + !< + subroutine idm_log_var_dbl3d(p_mem, varname, mempath, iout) + real(DP), dimension(:, :, :), contiguous, intent(in) :: p_mem !< 3d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mempath !< variable memory path + integer(I4B) :: iout + real(DP) :: min_val, max_val + + min_val = minval(p_mem) + max_val = maxval(p_mem) + if (min_val == max_val) then + write (iout, '(3x,a, " = ", G0)') trim(varname), min_val + else + write (iout, '(3x, a, a, G0, a, G0)') & + trim(varname), & + ' = variable 3D double precision array ranging from ', & + min_val, ' to ', max_val + end if + end subroutine idm_log_var_dbl3d + +end module IdmLoggerModule diff --git a/src/Utilities/Idm/IdmMf6FileLoader.f90 b/src/Utilities/Idm/IdmMf6FileLoader.f90 new file mode 100644 index 00000000000..dba8ef7ae0f --- /dev/null +++ b/src/Utilities/Idm/IdmMf6FileLoader.f90 @@ -0,0 +1,92 @@ +!> @brief This module contains the IdmMf6FileLoaderModule +!! +!! This module contains the high-level routines for loading +!! a MODFLOW input file into the __INPUT__ memory manager +!! space. +!! +!< +module IdmMf6FileLoaderModule + + use KindModule, only: DP, I4B, LGP + use BlockParserModule, only: BlockParserType + use ModflowInputModule, only: ModflowInputType, getModflowInput + + implicit none + private + public :: input_load + + !> @brief derived type for storing package loader + !! + !! This derived type is used to store a pointer to a + !! package load procedure. This could be used to write + !! a custom package loader as a way to override the + !! generic_mf6_load routine. + !! + !< + type :: PackageLoad + procedure(IPackageLoad), nopass, pointer, public :: load_package => null() !< procedure pointer to the load routine + end type PackageLoad + + abstract interface + subroutine IPackageLoad(parser, mf6_input, iout) + use KindModule, only: DP, I4B + use BlockParserModule, only: BlockParserType + use ModflowInputModule, only: ModflowInputType + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType object that describes the input + integer(I4B), intent(in) :: iout !< unit number for output + end subroutine IPackageLoad + end interface + +contains + + !> @brief generic procedure to MODFLOW 6 load routine + !< + subroutine generic_mf6_load(parser, mf6_input, iout) + use LoadMf6FileTypeModule, only: idm_load + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType object that describes the input + integer(I4B), intent(in) :: iout !< unit number for output + + call idm_load(parser, mf6_input%file_type, & + mf6_input%component_type, mf6_input%subcomponent_type, & + mf6_input%component_name, mf6_input%subcomponent_name, & + mf6_input%subpackages, iout) + + end subroutine generic_mf6_load + + !> @brief main entry to mf6 input load + !< + subroutine input_load(parser, filetype, & + component_type, subcomponent_type, & + component_name, subcomponent_name, & + subpackages, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + character(len=*), intent(in) :: filetype !< file type to load, such as DIS6, DISV6, NPF6 + character(len=*), intent(in) :: component_type !< component type, such as GWF or GWT + character(len=*), intent(in) :: subcomponent_type !< subcomponent type, such as DIS or NPF + character(len=*), intent(in) :: component_name !< component name, such as MYGWFMODEL + character(len=*), intent(in) :: subcomponent_name !< subcomponent name, such as MYWELLPACKAGE + character(len=*), dimension(:), intent(in) :: subpackages !< array of subpackage types, such as ["TVK6", "OBS6"] + integer(I4B), intent(in) :: iout !< unit number for output + type(ModflowInputType) :: mf6_input + type(PackageLoad) :: pkgloader + + mf6_input = getModflowInput(filetype, component_type, & + subcomponent_type, component_name, & + subcomponent_name, subpackages) + ! + ! -- set mf6 parser based package loader by file type + select case (filetype) + case default + pkgloader%load_package => generic_mf6_load + end select + ! + ! -- invoke the selected load routine + call pkgloader%load_package(parser, mf6_input, iout) + ! + ! -- release allocated memory + call mf6_input%destroy() + end subroutine input_load + +end module IdmMf6FileLoaderModule diff --git a/src/Utilities/Idm/InputDefinition.f90 b/src/Utilities/Idm/InputDefinition.f90 new file mode 100644 index 00000000000..01b67416734 --- /dev/null +++ b/src/Utilities/Idm/InputDefinition.f90 @@ -0,0 +1,48 @@ +!> @brief This module contains the InputDefinitionModule +!! +!! This module contains helper objects for storing +!! information about how to read modflow input files. +!! +!< +module InputDefinitionModule + + use KindModule, only: LGP + + implicit none + private + public :: InputParamDefinitionType, & + InputBlockDefinitionType + + !> @brief derived type for storing input definition + !! + !! This derived type is used to store information for + !! each modflow input record + !! + !< + type InputParamDefinitionType + character(len=100) :: component_type = '' + character(len=100) :: subcomponent_type = '' + character(len=100) :: blockname = '' + character(len=100) :: tagname = '' + character(len=100) :: mf6varname = '' + character(len=100) :: datatype = '' + character(len=100) :: shape = '' + logical(LGP) :: required = .false. + logical(LGP) :: in_record = .false. + logical(LGP) :: preserve_case = .false. + logical(LGP) :: layered = .false. + end type InputParamDefinitionType + + !> @brief derived type for storing block information + !! + !! This derived type is used to store information for + !! how to read a modflow block + !! + !< + type InputBlockDefinitionType + character(len=100) :: blockname = '' + logical(LGP) :: required = .false. + logical(LGP) :: aggregate = .false. + end type InputBlockDefinitionType + +end module InputDefinitionModule diff --git a/src/Utilities/Idm/InputDefinitionSelector.f90 b/src/Utilities/Idm/InputDefinitionSelector.f90 new file mode 100644 index 00000000000..17e030858b2 --- /dev/null +++ b/src/Utilities/Idm/InputDefinitionSelector.f90 @@ -0,0 +1,196 @@ +!> @brief This module contains the InputDefinitionSelectorModule +!! +!! This module contains the routines for getting parameter +!! definitions, aggregate definitions, and block definitions +!! for the different package types. +!! +!< +module InputDefinitionSelectorModule + + use KindModule, only: I4B + use SimVariablesModule, only: errmsg, warnmsg + use SimModule, only: store_error, store_warning + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + use GwfDisInputModule, only: gwf_dis_param_definitions, & + gwf_dis_aggregate_definitions, & + gwf_dis_block_definitions + use GwfDisuInputModule, only: gwf_disu_param_definitions, & + gwf_disu_aggregate_definitions, & + gwf_disu_block_definitions + use GwfDisvInputModule, only: gwf_disv_param_definitions, & + gwf_disv_aggregate_definitions, & + gwf_disv_block_definitions + use GwfNpfInputModule, only: gwf_npf_param_definitions, & + gwf_npf_aggregate_definitions, & + gwf_npf_block_definitions + use GwtDspInputModule, only: gwt_dsp_param_definitions, & + gwt_dsp_aggregate_definitions, & + gwt_dsp_block_definitions + + implicit none + private + public :: block_definitions + public :: aggregate_definitions + public :: param_definitions + public :: get_param_definition_type + public :: get_aggregate_definition_type + +contains + + !> @brief Return the parameter definition for the specified component + !< + function param_definitions(component) result(input_definition) + character(len=*), intent(in) :: component !< component type, such as GWF/DIS + type(InputParamDefinitionType), dimension(:), pointer :: input_definition !< InputParamDefinitionType for specified component + + select case (component) + case ('GWF/DIS') + call set_pointer(input_definition, gwf_dis_param_definitions) + case ('GWF/DISU') + call set_pointer(input_definition, gwf_disu_param_definitions) + case ('GWF/DISV') + call set_pointer(input_definition, gwf_disv_param_definitions) + case ('GWF/NPF') + call set_pointer(input_definition, gwf_npf_param_definitions) + case ('GWT/DSP') + call set_pointer(input_definition, gwt_dsp_param_definitions) + case default + write (warnmsg, '(a,a)') 'IDM Unsupported input type: ', trim(component) + call store_warning(warnmsg) + end select + + return + end function param_definitions + + !> @brief Return the aggregate definition for the specified component + !< + function aggregate_definitions(component) result(input_definition) + character(len=*), intent(in) :: component !< component type, such as GWF/DIS + type(InputParamDefinitionType), dimension(:), pointer :: input_definition !< InputParamDefinitionType for specified component + + select case (component) + case ('GWF/DIS') + call set_pointer(input_definition, gwf_dis_aggregate_definitions) + case ('GWF/DISU') + call set_pointer(input_definition, gwf_disu_aggregate_definitions) + case ('GWF/DISV') + call set_pointer(input_definition, gwf_disv_aggregate_definitions) + case ('GWF/NPF') + call set_pointer(input_definition, gwf_npf_aggregate_definitions) + case ('GWT/DSP') + call set_pointer(input_definition, gwt_dsp_aggregate_definitions) + case default + write (warnmsg, '(a,a)') 'IDM Unsupported input type: ', trim(component) + call store_warning(warnmsg) + end select + + return + end function aggregate_definitions + + !> @brief Return the block definition for the specified component + !< + function block_definitions(component) result(input_definition) + character(len=*), intent(in) :: component !< component type, such as GWF/DIS + type(InputBlockDefinitionType), dimension(:), pointer :: input_definition !< InputParamDefinitionType for specified component + + select case (component) + case ('GWF/DIS') + call set_block_pointer(input_definition, gwf_dis_block_definitions) + case ('GWF/DISU') + call set_block_pointer(input_definition, gwf_disu_block_definitions) + case ('GWF/DISV') + call set_block_pointer(input_definition, gwf_disv_block_definitions) + case ('GWF/NPF') + call set_block_pointer(input_definition, gwf_npf_block_definitions) + case ('GWT/DSP') + call set_block_pointer(input_definition, gwt_dsp_block_definitions) + case default + write (warnmsg, '(a,a)') 'IDM Unsupported input type: ', trim(component) + call store_warning(warnmsg) + end select + + return + end function block_definitions + + !> @brief Set pointer from input_definition to input_definition_target + !< + subroutine set_pointer(input_definition, input_definition_target) + type(InputParamDefinitionType), dimension(:), pointer :: input_definition !< InputParamDefinitionType source + type(InputParamDefinitionType), dimension(:), target :: & + input_definition_target !< InputParamDefinitionType target + input_definition => input_definition_target + end subroutine set_pointer + + !> @brief Set pointer from input_definition to input_definition_target + !< + subroutine set_block_pointer(input_definition, input_definition_target) + type(InputBlockDefinitionType), dimension(:), pointer :: input_definition !< InputParamDefinitionType source + type(InputBlockDefinitionType), dimension(:), target :: & + input_definition_target !< InputParamDefinitionType target + input_definition => input_definition_target + end subroutine set_block_pointer + + !> @brief Return parameter definition + !< + function get_param_definition_type(input_definition_types, component_type, & + subcomponent_type, tagname) result(idt) + type(InputParamDefinitionType), dimension(:), intent(in), target :: & + input_definition_types + character(len=*), intent(in) :: component_type !< component type, such as GWF or GWT + character(len=*), intent(in) :: subcomponent_type !< subcomponent type, such as DIS or NPF + character(len=*), intent(in) :: tagname !< name of the input tag + type(InputParamDefinitionType), pointer :: idt !< corresponding InputParameterDefinitionType for this tag + type(InputParamDefinitionType), pointer :: tmp_ptr + integer(I4B) :: i + + idt => null() + do i = 1, size(input_definition_types) + tmp_ptr => input_definition_types(i) + if (tmp_ptr%component_type == component_type .and. & + tmp_ptr%subcomponent_type == subcomponent_type .and. & + tmp_ptr%tagname == tagname) then + idt => input_definition_types(i) + exit + end if + end do + + if (.not. associated(idt)) then + write (errmsg, '(4x,a,a)') 'parameter definition not found: ', trim(tagname) + call store_error(errmsg) + end if + + end function get_param_definition_type + + !> @brief Return aggregate definition + !< + function get_aggregate_definition_type(input_definition_types, component_type, & + subcomponent_type, blockname) result(idt) + type(InputParamDefinitionType), dimension(:), intent(in), target :: & + input_definition_types + character(len=*), intent(in) :: component_type !< component type, such as GWF or GWT + character(len=*), intent(in) :: subcomponent_type !< subcomponent type, such as DIS or NPF + character(len=*), intent(in) :: blockname !< name of the block + type(InputParamDefinitionType), pointer :: idt !< corresponding InputParameterDefinitionType for this block + type(InputParamDefinitionType), pointer :: tmp_ptr + integer(I4B) :: i + + idt => null() + do i = 1, size(input_definition_types) + tmp_ptr => input_definition_types(i) + if (tmp_ptr%component_type == component_type .and. & + tmp_ptr%subcomponent_type == subcomponent_type .and. & + tmp_ptr%blockname == blockname) then + idt => input_definition_types(i) + exit + end if + end do + + if (.not. associated(idt)) then + write (errmsg, '(4x,a,a)') 'aggregate definition not found: ', & + trim(blockname) + call store_error(errmsg) + end if + end function get_aggregate_definition_type + +end module InputDefinitionSelectorModule diff --git a/src/Utilities/Idm/LoadMf6FileType.f90 b/src/Utilities/Idm/LoadMf6FileType.f90 new file mode 100644 index 00000000000..5f3038955b3 --- /dev/null +++ b/src/Utilities/Idm/LoadMf6FileType.f90 @@ -0,0 +1,762 @@ +!> @brief This module contains the LoadMf6FileTypeModule +!! +!! This module contains the input data model routines for +!! loading the data from a MODFLOW 6 input file using the +!! block parser. +!! +!< +module LoadMf6FileTypeModule + + use KindModule, only: DP, I4B, LGP + use ConstantsModule, only: LINELENGTH, LENMEMPATH + use SimVariablesModule, only: errmsg + use SimModule, only: store_error + use BlockParserModule, only: BlockParserType + use LayeredArrayReaderModule, only: read_dbl1d_layered, & + read_dbl2d_layered, & + read_dbl3d_layered, & + read_int1d_layered, & + read_int2d_layered, & + read_int3d_layered + use Double1dReaderModule, only: read_dbl1d + use Double2dReaderModule, only: read_dbl2d + use Integer1dReaderModule, only: read_int1d + use Integer2dReaderModule, only: read_int2d + use InputOutputModule, only: parseline + use InputDefinitionModule, only: InputParamDefinitionType + use InputDefinitionSelectorModule, only: get_param_definition_type, & + get_aggregate_definition_type + use ModflowInputModule, only: ModflowInputType, getModflowInput + use MemoryManagerModule, only: mem_allocate, mem_setptr + use MemoryHelperModule, only: create_mem_path + use IdmLoggerModule, only: idm_log_var, idm_log_header, idm_log_close + + implicit none + private + public :: idm_load + + interface idm_load + module procedure idm_load_from_blockparser + end interface idm_load + +contains + + !> @brief procedure to load a file + !! + !! Use parser to load information from an input file into the __INPUT__ + !! memory context location of the memory manager. + !! + !< + subroutine idm_load_from_blockparser(parser, filetype, & + component_type, subcomponent_type, & + component_name, subcomponent_name, & + subpackages, iout) + use SimVariablesModule, only: idm_context + type(BlockParserType), intent(inout) :: parser !< block parser + character(len=*), intent(in) :: filetype !< file type to load, such as DIS6, DISV6, NPF6 + character(len=*), intent(in) :: component_type !< component type, such as GWF or GWT + character(len=*), intent(in) :: subcomponent_type !< subcomponent type, such as DIS or NPF + character(len=*), intent(in) :: component_name !< component name, such as MYGWFMODEL + character(len=*), intent(in) :: subcomponent_name !< subcomponent name, such as MYWELLPACKAGE + character(len=*), dimension(:), intent(in) :: subpackages !< array of subpackage types, such as ["TVK6", "OBS6"] + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B) :: iblock !< consecutive block number as defined in definition file + type(ModflowInputType) :: mf6_input !< ModflowInputType + character(len=LENMEMPATH) :: componentMemPath + integer(I4B), dimension(:), contiguous, pointer :: mshape => null() + ! + ! -- construct input object + mf6_input = getModflowInput(filetype, component_type, & + subcomponent_type, component_name, & + subcomponent_name, subpackages) + ! + ! -- model shape memory path + componentMemPath = create_mem_path(component=mf6_input%component_name, & + context=idm_context) + ! + ! -- log lst file header + call idm_log_header(mf6_input%component_name, & + mf6_input%subcomponent_name, iout) + ! + ! -- process blocks + do iblock = 1, size(mf6_input%p_block_dfns) + call parse_block(parser, mf6_input, iblock, mshape, iout) + ! + ! -- set model shape if discretization dimensions have been read + if (mf6_input%p_block_dfns(iblock)%blockname == 'DIMENSIONS' .and. & + filetype(1:3) == 'DIS') then + call set_model_shape(mf6_input%file_type, componentMemPath, & + mf6_input%memoryPath, mshape) + end if + end do + ! + ! -- close logging statement + call idm_log_close(mf6_input%component_name, & + mf6_input%subcomponent_name, iout) + ! + ! -- release allocated memory + call mf6_input%destroy() + end subroutine idm_load_from_blockparser + + !> @brief procedure to load a block + !! + !! Use parser to load information from a block into the __INPUT__ + !! memory context location of the memory manager. + !! + !< + subroutine parse_block(parser, mf6_input, iblock, mshape, iout) + use MemoryTypeModule, only: MemoryType + use MemoryManagerModule, only: get_from_memorylist + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType + integer(I4B), intent(in) :: iblock !< consecutive block number as defined in definition file + integer(I4B), dimension(:), contiguous, pointer, intent(inout) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + logical(LGP) :: isblockfound + logical(LGP) :: endOfBlock + logical(LGP) :: supportOpenClose + integer(I4B) :: ierr + logical(LGP) :: found + type(MemoryType), pointer :: mt + ! + ! -- disu vertices/cell2d blocks are contingent on NVERT dimension + if (mf6_input%file_type == 'DISU6' .and. & + (mf6_input%p_block_dfns(iblock)%blockname == 'VERTICES' .or. & + mf6_input%p_block_dfns(iblock)%blockname == 'CELL2D')) then + call get_from_memorylist('NVERT', mf6_input%memoryPath, mt, found, .false.) + if (.not. found .or. mt%intsclr == 0) return + end if + ! + ! -- block open/close support + supportOpenClose = (mf6_input%p_block_dfns(iblock)%blockname /= 'GRIDDATA') + ! + ! -- parser search for block + call parser%GetBlock(mf6_input%p_block_dfns(iblock)%blockname, isblockfound, & + ierr, supportOpenClose=supportOpenClose, & + blockRequired=mf6_input%p_block_dfns(iblock)%required) + ! + ! -- process block + if (isblockfound) then + if (mf6_input%p_block_dfns(iblock)%aggregate) then + ! + ! -- process block recarray type, set of variable 1d/2d types + call parse_structarray_block(parser, mf6_input, iblock, mshape, iout) + else + do + ! process each line in block + call parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + ! + ! -- process line as tag(s) + call parse_tag(parser, mf6_input, iblock, mshape, iout, .false.) + end do + end if + end if + + return + end subroutine parse_block + + !> @brief check subpackage + !! + !! Check and make sure that the subpackage is valid for + !! this input file and load the filename of the subpackage + !! into the memory manager. + !! + !< + subroutine subpackage_check(parser, mf6_input, checktag, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType + character(len=LINELENGTH), intent(in) :: checktag !< subpackage string, such as TVK6 + integer(I4B), intent(in) :: iout !< unit number for output + character(len=LINELENGTH) :: tag, fname_tag + type(InputParamDefinitionType), pointer :: idt !< input data type object describing this record + integer(I4B) :: isubpkg + + do isubpkg = 1, size(mf6_input%subpackages) + if (checktag == mf6_input%subpackages(isubpkg)) then + fname_tag = trim(checktag)//'_FILENAME' + call parser%GetStringCaps(tag) + if (tag == 'FILEIN') then + idt => get_param_definition_type(mf6_input%p_param_dfns, & + mf6_input%component_type, & + mf6_input%subcomponent_type, & + fname_tag) + call load_string_type(parser, idt, mf6_input%memoryPath, iout) + else + errmsg = 'Subpackage keyword must be followed by "FILEIN" '// & + 'then by filename.' + call store_error(errmsg) + end if + end if + end do + end subroutine subpackage_check + + !> @brief load an individual input record into memory + !! + !! Load an individual input record into the memory + !! manager. Allow for recursive calls in the case that multiple + !! tags are on a single line. + !! + !< + recursive subroutine parse_tag(parser, mf6_input, iblock, mshape, iout, & + recursive_call) + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType + integer(I4B), intent(in) :: iblock !< consecutive block number as defined in definition file + integer(I4B), dimension(:), contiguous, pointer, intent(inout) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + logical(LGP), intent(in) :: recursive_call !< true if recursive call + character(len=LINELENGTH) :: tag + type(InputParamDefinitionType), pointer :: idt !< input data type object describing this record + ! + ! -- read tag name + call parser%GetStringCaps(tag) + if (recursive_call) then + if (tag == '') then + ! no data on line so return + return + end if + end if + ! + ! -- find keyword in input definition + idt => get_param_definition_type(mf6_input%p_param_dfns, & + mf6_input%component_type, & + mf6_input%subcomponent_type, & + tag) + ! + ! -- allocate and load data type + select case (idt%datatype) + case ('KEYWORD') + call load_keyword_type(parser, idt, mf6_input%memoryPath, iout) + ! + ! -- load filename if subpackage tag + call subpackage_check(parser, mf6_input, tag, iout) + ! + ! -- set as dev option + if (mf6_input%p_block_dfns(iblock)%blockname == 'OPTIONS' .and. & + idt%tagname(1:4) == 'DEV_') then + call parser%DevOpt() + end if + case ('STRING') + call load_string_type(parser, idt, mf6_input%memoryPath, iout) + case ('INTEGER') + call load_integer_type(parser, idt, mf6_input%memoryPath, iout) + case ('INTEGER1D') + call load_integer1d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case ('INTEGER2D') + call load_integer2d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case ('INTEGER3D') + call load_integer3d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case ('DOUBLE') + call load_double_type(parser, idt, mf6_input%memoryPath, iout) + case ('DOUBLE1D') + call load_double1d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case ('DOUBLE2D') + call load_double2d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case ('DOUBLE3D') + call load_double3d_type(parser, idt, mf6_input%memoryPath, mshape, iout) + case default + write (errmsg, '(4x,a,a)') 'Failure reading data for tag: ', trim(tag) + call store_error(errmsg) + call parser%StoreErrorUnit() + end select + ! + ! -- continue line if in same record + if (idt%in_record) then + ! recursively call parse tag again to read rest of line + call parse_tag(parser, mf6_input, iblock, mshape, iout, .true.) + end if + ! + ! -- + return + end subroutine parse_tag + + !> @brief parse a structured array record into memory manager + !! + !! A structarray is similar to a numpy recarray. It it used to + !! load a list of data in which each column in the list may be a + !! different type. Each column in the list is stored as a 1d + !! vector. + !! + !< + subroutine parse_structarray_block(parser, mf6_input, iblock, mshape, iout) + use StructArrayModule, only: StructArrayType, constructStructArray, & + destructStructArray + type(BlockParserType), intent(inout) :: parser !< block parser + type(ModflowInputType), intent(in) :: mf6_input !< ModflowInputType + integer(I4B), intent(in) :: iblock !< consecutive block number as defined in definition file + integer(I4B), dimension(:), contiguous, pointer, intent(inout) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + type(InputParamDefinitionType), pointer :: idt !< input data type object describing this record + integer(I4B), pointer :: nrow + integer(I4B) :: icol + integer(I4B) :: ncol + integer(I4B) :: nwords + character(len=16), dimension(:), allocatable :: words + type(StructArrayType), pointer :: struct_array + character(len=:), allocatable :: parse_str + ! + ! -- set input definition for this block + idt => get_aggregate_definition_type(mf6_input%p_aggregate_dfns, & + mf6_input%component_type, & + mf6_input%subcomponent_type, & + mf6_input%p_block_dfns(iblock)%blockname) + ! + ! -- identify variable names, ignore first RECARRAY column + parse_str = trim(idt%datatype)//' ' + call parseline(parse_str, nwords, words) + ncol = nwords - 1 + ! + ! -- use shape to set the max num of rows + call mem_setptr(nrow, idt%shape, mf6_input%memoryPath) + ! + ! -- create a structured array + struct_array => constructStructArray(ncol, nrow) + do icol = 1, ncol + ! + ! -- set pointer to input definition for this 1d vector + idt => get_param_definition_type(mf6_input%p_param_dfns, & + mf6_input%component_type, & + mf6_input%subcomponent_type, & + words(icol + 1)) + ! + ! -- allocate variable in memory manager + call struct_array%mem_create_vector(icol, idt%datatype, idt%mf6varname, & + mf6_input%memoryPath, idt%shape, & + idt%preserve_case) + end do + ! + ! -- read the structured array + call struct_array%read_from_parser(parser, iout) + call parser%terminateblock() + ! + ! -- destroy the structured array reader + call destructStructArray(struct_array) + ! + ! -- + return + end subroutine parse_structarray_block + + !> @brief load type keyword + !< + subroutine load_keyword_type(parser, idt, memoryPath, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B), pointer :: intvar + call mem_allocate(intvar, idt%mf6varname, memoryPath) + intvar = 1 + call idm_log_var(intvar, idt%mf6varname, memoryPath, iout) + return + end subroutine load_keyword_type + + !> @brief load type string + !< + subroutine load_string_type(parser, idt, memoryPath, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), intent(in) :: iout !< unit number for output + character(len=LINELENGTH), pointer :: cstr + integer(I4B) :: ilen + ilen = LINELENGTH + call mem_allocate(cstr, ilen, idt%mf6varname, memoryPath) + call parser%GetString(cstr, (.not. idt%preserve_case)) + return + end subroutine load_string_type + + !> @brief load type integer + !< + subroutine load_integer_type(parser, idt, memoryPath, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B), pointer :: intvar + call mem_allocate(intvar, idt%mf6varname, memoryPath) + intvar = parser%GetInteger() + call idm_log_var(intvar, idt%mf6varname, memoryPath, iout) + return + end subroutine load_integer_type + + !> @brief load type 1d integer + !< + subroutine load_integer1d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B), dimension(:), pointer, contiguous :: int1d + !integer(I4B), pointer :: nsize1 + integer(I4B) :: nlay + integer(I4B) :: nvals + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + + ! Check if it is a full grid sized array (NODES), otherwise use + ! idt%shape to construct shape from variables in memoryPath + if (idt%shape == 'NODES') then + nvals = product(mshape) + else + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nvals = array_shape(1) + end if + + ! allocate memory for the array + call mem_allocate(int1d, nvals, idt%mf6varname, memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_int1d_layered(parser, int1d, idt%mf6varname, nlay, layer_shape) + else + call read_int1d(parser, int1d, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(int1d, idt%mf6varname, memoryPath, iout) + return + end subroutine load_integer1d_type + + !> @brief load type 2d integer + !< + subroutine load_integer2d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B), dimension(:, :), pointer, contiguous :: int2d + integer(I4B) :: nlay + integer(I4B) :: nsize1, nsize2 + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + + ! determine the array shape from the input data defintion (idt%shape), + ! which looks like "NCOL, NROW, NLAY" + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nsize1 = array_shape(1) + nsize2 = array_shape(2) + + ! create a new 3d memory managed variable + call mem_allocate(int2d, nsize1, nsize2, idt%mf6varname, memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_int2d_layered(parser, int2d, idt%mf6varname, nlay, layer_shape) + else + call read_int2d(parser, int2d, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(int2d, idt%mf6varname, memoryPath, iout) + return + end subroutine load_integer2d_type + + !> @brief load type 3d integer + !< + subroutine load_integer3d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B), dimension(:, :, :), pointer, contiguous :: int3d + integer(I4B) :: nlay + integer(I4B) :: nsize1, nsize2, nsize3 + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + integer(I4B), dimension(:), pointer, contiguous :: int1d_ptr + + ! determine the array shape from the input data defintion (idt%shape), + ! which looks like "NCOL, NROW, NLAY" + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nsize1 = array_shape(1) + nsize2 = array_shape(2) + nsize3 = array_shape(3) + + ! create a new 3d memory managed variable + call mem_allocate(int3d, nsize1, nsize2, nsize3, idt%mf6varname, & + memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_int3d_layered(parser, int3d, idt%mf6varname, nlay, & + layer_shape) + else + int1d_ptr(1:nsize1 * nsize2 * nsize3) => int3d(:, :, :) + call read_int1d(parser, int1d_ptr, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(int3d, idt%mf6varname, memoryPath, iout) + + return + end subroutine load_integer3d_type + + !> @brief load type double + !< + subroutine load_double_type(parser, idt, memoryPath, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), intent(in) :: iout !< unit number for output + real(DP), pointer :: dblvar + call mem_allocate(dblvar, idt%mf6varname, memoryPath) + dblvar = parser%GetDouble() + call idm_log_var(dblvar, idt%mf6varname, memoryPath, iout) + return + end subroutine load_double_type + + !> @brief load type 1d double + !< + subroutine load_double1d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + real(DP), dimension(:), pointer, contiguous :: dbl1d + !integer(I4B), pointer :: nsize1 + integer(I4B) :: nlay + integer(I4B) :: nvals + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + + ! Check if it is a full grid sized array (NODES) + if (idt%shape == 'NODES') then + nvals = product(mshape) + else + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nvals = array_shape(1) + end if + + ! allocate memory for the array + call mem_allocate(dbl1d, nvals, idt%mf6varname, memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_dbl1d_layered(parser, dbl1d, idt%mf6varname, nlay, layer_shape) + else + call read_dbl1d(parser, dbl1d, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(dbl1d, idt%mf6varname, memoryPath, iout) + return + end subroutine load_double1d_type + + !> @brief load type 2d double + !< + subroutine load_double2d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + real(DP), dimension(:, :), pointer, contiguous :: dbl2d + integer(I4B) :: nlay + integer(I4B) :: nsize1, nsize2 + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + + ! determine the array shape from the input data defintion (idt%shape), + ! which looks like "NCOL, NROW, NLAY" + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nsize1 = array_shape(1) + nsize2 = array_shape(2) + + ! create a new 3d memory managed variable + call mem_allocate(dbl2d, nsize1, nsize2, idt%mf6varname, memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_dbl2d_layered(parser, dbl2d, idt%mf6varname, nlay, layer_shape) + else + call read_dbl2d(parser, dbl2d, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(dbl2d, idt%mf6varname, memoryPath, iout) + return + end subroutine load_double2d_type + + !> @brief load type 3d double + !< + subroutine load_double3d_type(parser, idt, memoryPath, mshape, iout) + type(BlockParserType), intent(inout) :: parser !< block parser + type(InputParamDefinitionType), intent(in) :: idt !< input data type object describing this record + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B), dimension(:), contiguous, pointer, intent(in) :: mshape !< model shape + integer(I4B), intent(in) :: iout !< unit number for output + real(DP), dimension(:, :, :), pointer, contiguous :: dbl3d + integer(I4B) :: nlay + integer(I4B) :: nsize1, nsize2, nsize3 + integer(I4B), dimension(:), allocatable :: array_shape + integer(I4B), dimension(:), allocatable :: layer_shape + character(len=LINELENGTH) :: keyword + real(DP), dimension(:), pointer, contiguous :: dbl1d_ptr + + ! determine the array shape from the input data defintion (idt%shape), + ! which looks like "NCOL, NROW, NLAY" + call get_shape_from_string(idt%shape, array_shape, memoryPath) + nsize1 = array_shape(1) + nsize2 = array_shape(2) + nsize3 = array_shape(3) + + ! create a new 3d memory managed variable + call mem_allocate(dbl3d, nsize1, nsize2, nsize3, idt%mf6varname, & + memoryPath) + + ! check to see if the user specified "LAYERED" input + keyword = '' + if (idt%layered) then + call parser%GetStringCaps(keyword) + end if + + ! read the array from the input file + if (keyword == 'LAYERED' .and. idt%layered) then + call get_layered_shape(mshape, nlay, layer_shape) + call read_dbl3d_layered(parser, dbl3d, idt%mf6varname, nlay, & + layer_shape) + else + dbl1d_ptr(1:nsize1 * nsize2 * nsize3) => dbl3d(:, :, :) + call read_dbl1d(parser, dbl1d_ptr, idt%mf6varname) + end if + + ! log information on the loaded array to the list file + call idm_log_var(dbl3d, idt%mf6varname, memoryPath, iout) + + return + end subroutine load_double3d_type + + !> @brief routine for setting the model shape + !! + !! The model shape must be set in the memory manager because + !! individual packages need to know the shape of the arrays + !! to read. + !! + !< + subroutine set_model_shape(ftype, model_mempath, dis_mempath, model_shape) + use MemoryTypeModule, only: MemoryType + use MemoryManagerModule, only: get_from_memorylist + character(len=*), intent(in) :: ftype + character(len=*), intent(in) :: model_mempath + character(len=*), intent(in) :: dis_mempath + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: model_shape + integer(I4B), pointer :: ndim1 + integer(I4B), pointer :: ndim2 + integer(I4B), pointer :: ndim3 + + select case (ftype) + case ('DIS6') + call mem_allocate(model_shape, 3, 'MODEL_SHAPE', model_mempath) + call mem_setptr(ndim1, 'NLAY', dis_mempath) + call mem_setptr(ndim2, 'NROW', dis_mempath) + call mem_setptr(ndim3, 'NCOL', dis_mempath) + model_shape = [ndim1, ndim2, ndim3] + case ('DISV6') + call mem_allocate(model_shape, 2, 'MODEL_SHAPE', model_mempath) + call mem_setptr(ndim1, 'NLAY', dis_mempath) + call mem_setptr(ndim2, 'NCPL', dis_mempath) + model_shape = [ndim1, ndim2] + case ('DISU6') + call mem_allocate(model_shape, 1, 'MODEL_SHAPE', model_mempath) + call mem_setptr(ndim1, 'NODES', dis_mempath) + model_shape = [ndim1] + end select + + return + end subroutine set_model_shape + + subroutine get_layered_shape(mshape, nlay, layer_shape) + integer(I4B), dimension(:), intent(in) :: mshape + integer(I4B), intent(out) :: nlay + integer(I4B), dimension(:), allocatable, intent(out) :: layer_shape + integer(I4B) :: ndim + + ndim = size(mshape) + nlay = 0 + + if (ndim == 1) then ! disu + nlay = 1 + allocate (layer_shape(1)) + layer_shape(1) = mshape(1) + else if (ndim == 2) then ! disv + nlay = mshape(1) + allocate (layer_shape(1)) + layer_shape(1) = mshape(2) + else if (ndim == 3) then ! disu + nlay = mshape(1) + allocate (layer_shape(2)) + layer_shape(1) = mshape(3) ! ncol + layer_shape(2) = mshape(2) ! nrow + end if + + end subroutine get_layered_shape + + subroutine get_shape_from_string(shape_string, array_shape, memoryPath) + character(len=*), intent(in) :: shape_string + integer(I4B), dimension(:), allocatable, intent(inout) :: array_shape + character(len=*), intent(in) :: memoryPath !< memorypath to put loaded information + integer(I4B) :: ndim + integer(I4B) :: i + integer(I4B), pointer :: int_ptr + character(len=16), dimension(:), allocatable :: array_shape_string + character(len=:), allocatable :: shape_string_copy + + ! parse the string into multiple words + shape_string_copy = trim(shape_string)//' ' + call ParseLine(shape_string_copy, ndim, array_shape_string) + allocate (array_shape(ndim)) + + ! find shape in memory manager and put into array_shape + do i = 1, ndim + call mem_setptr(int_ptr, array_shape_string(i), memoryPath) + array_shape(i) = int_ptr + end do + + end subroutine get_shape_from_string + +end module LoadMf6FileTypeModule diff --git a/src/Utilities/Idm/ModflowInput.f90 b/src/Utilities/Idm/ModflowInput.f90 new file mode 100644 index 00000000000..5ed0aaba08a --- /dev/null +++ b/src/Utilities/Idm/ModflowInput.f90 @@ -0,0 +1,93 @@ +!> @brief This module contains the ModflowInputModule +!! +!! This module contains a helper object and function +!! for accessing the ModflowInput, which is a +!! description of the structure of a modflow input +!! file. +!! +!< +module ModflowInputModule + + use KindModule, only: I4B, LGP + use ConstantsModule, only: LENMEMPATH, LENCOMPONENTNAME, & + LENPACKAGETYPE, LENFTYPE + use MemoryHelperModule, only: create_mem_path + use InputDefinitionModule, only: InputParamDefinitionType, & + InputBlockDefinitionType + use InputDefinitionSelectorModule, only: block_definitions, & + aggregate_definitions, & + param_definitions + use SimVariablesModule, only: idm_context + + implicit none + private + public :: ModflowInputType, getModflowInput + + !> @brief derived type for storing input definition for a file + !! + !! This derived type contains the information needed to read + !! a specific modflow input file, including block definitions, + !! aggregate definitions (structarrays), and individual + !! parameter definitions. + !! + !< + type ModflowInputType + character(len=LENFTYPE) :: file_type + character(len=LENCOMPONENTNAME) :: component_type + character(len=LENCOMPONENTNAME) :: subcomponent_type + character(len=LENCOMPONENTNAME) :: component_name + character(len=LENCOMPONENTNAME) :: subcomponent_name + character(len=LENMEMPATH) :: memoryPath + character(len=LENMEMPATH) :: component + character(len=LENPACKAGETYPE), allocatable, dimension(:) :: subpackages + type(InputBlockDefinitionType), dimension(:), pointer :: p_block_dfns + type(InputParamDefinitionType), dimension(:), pointer :: p_aggregate_dfns + type(InputParamDefinitionType), dimension(:), pointer :: p_param_dfns + contains + procedure :: destroy + end type ModflowInputType + +contains + + !> @brief function to return ModflowInputType + !< + function getModflowInput(ftype, component_type, & + subcomponent_type, component_name, subcomponent_name, & + subpackages) & + result(mf6_input) + character(len=*), intent(in) :: ftype !< file type to load, such as DIS6, DISV6, NPF6 + character(len=*), intent(in) :: component_type !< component type, such as GWF or GWT + character(len=*), intent(in) :: subcomponent_type !< subcomponent type, such as DIS or NPF + character(len=*), intent(in) :: component_name !< component name, such as MYGWFMODEL + character(len=*), intent(in) :: subcomponent_name !< subcomponent name, such as MYWELLPACKAGE + character(len=*), dimension(:), intent(in) :: subpackages !< array of subpackage types, such as ["TVK6", "OBS6"] + type(ModflowInputType) :: mf6_input + + mf6_input%file_type = trim(ftype) + mf6_input%component_type = trim(component_type) + mf6_input%subcomponent_type = trim(subcomponent_type) + mf6_input%component_name = trim(component_name) + mf6_input%subcomponent_name = trim(subcomponent_name) + allocate (mf6_input%subpackages(size(subpackages))) + mf6_input%subpackages = subpackages + + mf6_input%memoryPath = create_mem_path(component_name, subcomponent_name, & + idm_context) + mf6_input%component = trim(component_type)//'/'//trim(subcomponent_type) + + mf6_input%p_block_dfns => block_definitions(mf6_input%component) + mf6_input%p_aggregate_dfns => aggregate_definitions(mf6_input%component) + mf6_input%p_param_dfns => param_definitions(mf6_input%component) + end function getModflowInput + + !> @brief function to release ModflowInputType allocated memory + !< + subroutine destroy(this) + class(ModflowInputType) :: this !< ModflowInputType + + if (allocated(this%subpackages)) then + deallocate (this%subpackages) + end if + end subroutine destroy + +end module ModflowInputModule diff --git a/src/Utilities/Idm/StructArray.f90 b/src/Utilities/Idm/StructArray.f90 new file mode 100644 index 00000000000..a57a2e211a0 --- /dev/null +++ b/src/Utilities/Idm/StructArray.f90 @@ -0,0 +1,289 @@ +!> @brief This module contains the StructArrayModule +!! +!! This module contains the routines for reading a +!! structured list, which consists of a separate vector +!! for each column in the list. +!! +!< +module StructArrayModule + + use KindModule, only: I4B, DP, LGP + use ConstantsModule, only: DNODATA, LINELENGTH + use StructVectorModule, only: StructVectorType + use MemoryManagerModule, only: mem_allocate + use CharacterStringModule, only: CharacterStringType + use VectorIntModule, only: VectorInt + use IdmLoggerModule, only: idm_log_var + use MemoryManagerModule, only: mem_setptr + use BlockParserModule, only: BlockParserType + + implicit none + private + public :: StructArrayType + public :: constructStructArray, destructStructArray + + !> @brief derived type for structured array + !! + !! This derived type is used to read and store a + !! list that consists of multiple one-dimensional + !! vectors. + !! + !< + type StructArrayType + integer(I4B) :: ncol + integer(I4B) :: nrow + type(StructVectorType), dimension(:), allocatable :: struct_vector_1d + contains + procedure :: mem_create_vector + procedure :: add_vector_int1d + procedure :: add_vector_dbl1d + procedure :: add_vector_str1d + procedure :: add_vector_intvector + procedure :: read_from_parser + procedure :: load_intvector + procedure :: log_structarray_vars + + end type StructArrayType + +contains + + !> @brief constructor for a struct_array + !< + function constructStructArray(ncol, nrow) result(struct_array) + integer(I4B), intent(in) :: ncol !< number of columns in the StructArrayType + integer(I4B), intent(in) :: nrow !< number of rows in the StructArrayType + type(StructArrayType), pointer :: struct_array !< new StructArrayType + + allocate (struct_array) + struct_array%ncol = ncol + struct_array%nrow = nrow + allocate (struct_array%struct_vector_1d(ncol)) + end function constructStructArray + + !> @brief destructor for a struct_array + !< + subroutine destructStructArray(struct_array) + type(StructArrayType), pointer, intent(inout) :: struct_array !< StructArrayType to destroy + + deallocate (struct_array%struct_vector_1d) + deallocate (struct_array) + nullify (struct_array) + end subroutine destructStructArray + + !> @brief create new vector in StructArrayType + !< + subroutine mem_create_vector(this, icol, vartype, name, memoryPath, & + varname_shape, preserve_case) + class(StructArrayType) :: this !< StructArrayType + integer(I4B), intent(in) :: icol !< column to create + character(len=*), intent(in) :: vartype !< type of column to create + character(len=*), intent(in) :: name !< name of the column to create + character(len=*), intent(in) :: memoryPath !< memory path for storing the vector + character(len=*), intent(in) :: varname_shape !< shape + logical(LGP), optional, intent(in) :: preserve_case !< flag indicating whether or not to preserve case + integer(I4B), dimension(:), pointer, contiguous :: int1d + real(DP), dimension(:), pointer, contiguous :: dbl1d + type(CharacterStringType), dimension(:), pointer, contiguous :: cstr1d + type(VectorInt), pointer :: intvector + integer(I4B) :: j + integer(I4B) :: inodata = 999 !todo: create INODATA in constants? + + select case (vartype) + case ('INTEGER1D') + allocate (intvector) + call this%add_vector_intvector(name, memoryPath, varname_shape, icol, & + intvector) + case ('INTEGER') + call mem_allocate(int1d, this%nrow, name, memoryPath) + do j = 1, this%nrow + int1d(j) = inodata + end do + call this%add_vector_int1d(name, memoryPath, icol, int1d) + case ('DOUBLE') + call mem_allocate(dbl1d, this%nrow, name, memoryPath) + do j = 1, this%nrow + dbl1d(j) = DNODATA + end do + call this%add_vector_dbl1d(name, memoryPath, icol, dbl1d) + case ('STRING') + call mem_allocate(cstr1d, LINELENGTH, this%nrow, name, memoryPath) + do j = 1, this%nrow + cstr1d(j) = '' + end do + call this%add_vector_str1d(icol, cstr1d, preserve_case) + end select + + return + end subroutine mem_create_vector + + !> @brief add int1d to StructArrayType + !< + subroutine add_vector_int1d(this, varname, memoryPath, icol, int1d) + class(StructArrayType) :: this !< StructArrayType + character(len=*), intent(in) :: varname !< name of the variable + character(len=*), intent(in) :: memoryPath !< memory path to vector + integer(I4B), intent(in) :: icol !< column of the vector + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: int1d !< vector to add + type(StructVectorType) :: sv + sv%varname = varname + sv%memoryPath = memoryPath + sv%memtype = 1 + sv%int1d => int1d + this%struct_vector_1d(icol) = sv + return + end subroutine add_vector_int1d + + !> @brief add dbl1d to StructArrayType + !< + subroutine add_vector_dbl1d(this, varname, memoryPath, icol, dbl1d) + class(StructArrayType) :: this !< StructArrayType + character(len=*), intent(in) :: varname !< name of the variable + character(len=*), intent(in) :: memoryPath !< memory path to vector + integer(I4B), intent(in) :: icol !< column of the vector + real(DP), dimension(:), pointer, contiguous, intent(in) :: dbl1d !< vector to add + type(StructVectorType) :: sv + sv%varname = varname + sv%memoryPath = memoryPath + sv%memtype = 2 + sv%dbl1d => dbl1d + this%struct_vector_1d(icol) = sv + return + end subroutine add_vector_dbl1d + + !> @brief add str1d to StructArrayType + !< + subroutine add_vector_str1d(this, icol, str1d, preserve_case) + class(StructArrayType) :: this !< StructArrayType + integer(I4B), intent(in) :: icol !< column of the vector + type(CharacterStringType), dimension(:), pointer, contiguous, intent(in) :: & + str1d !< vector to add + logical(LGP), intent(in) :: preserve_case + type(StructVectorType) :: sv + sv%memtype = 3 + sv%preserve_case = preserve_case + sv%str1d => str1d + this%struct_vector_1d(icol) = sv + return + end subroutine add_vector_str1d + + !> @brief add VectorInt to StructArrayType + !< + subroutine add_vector_intvector(this, varname, memoryPath, varname_shape, & + icol, intvector) + class(StructArrayType) :: this !< StructArrayType + character(len=*), intent(in) :: varname !< name of the variable + character(len=*), intent(in) :: memoryPath !< memory path to vector + character(len=*), intent(in) :: varname_shape !< shape of variable + integer(I4B), intent(in) :: icol !< column of the vector + type(VectorInt), pointer, intent(in) :: intvector !< vector to add + type(StructVectorType) :: sv + + call intvector%init() + call mem_setptr(sv%intvector_shape, varname_shape, memoryPath) + + sv%varname = varname + sv%memoryPath = memoryPath + sv%memtype = 4 + sv%intvector => intvector + this%struct_vector_1d(icol) = sv + return + end subroutine add_vector_intvector + + !> @brief load integer vector into StructArrayType + !< + subroutine load_intvector(this) + class(StructArrayType) :: this !< StructArrayType + integer(I4B) :: i, j + integer(I4B), dimension(:), pointer, contiguous :: p_intvector + ! -- if an allocatable vector has been read, add to MemoryManager + do i = 1, this%ncol + if (this%struct_vector_1d(i)%memtype == 4) then + call this%struct_vector_1d(i)%intvector%shrink_to_fit() + call mem_allocate(p_intvector, this%struct_vector_1d(i)%intvector%size, & + this%struct_vector_1d(i)%varname, & + this%struct_vector_1d(i)%memoryPath) + do j = 1, this%struct_vector_1d(i)%intvector%size + p_intvector(j) = this%struct_vector_1d(i)%intvector%at(j) + end do + call this%struct_vector_1d(i)%intvector%destroy() + deallocate (this%struct_vector_1d(i)%intvector) + nullify (this%struct_vector_1d(i)%intvector_shape) + end if + end do + return + end subroutine load_intvector + + !> @brief log information about the StructArrayType + !< + subroutine log_structarray_vars(this, iout) + class(StructArrayType) :: this !< StructArrayType + integer(I4B), intent(in) :: iout !< unit number for output + integer(I4B) :: j + integer(I4B), dimension(:), pointer, contiguous :: int1d + ! + ! -- idm variable logging + do j = 1, this%ncol + select case (this%struct_vector_1d(j)%memtype) + case (1) + call idm_log_var(this%struct_vector_1d(j)%int1d, & + this%struct_vector_1d(j)%varname, & + this%struct_vector_1d(j)%memoryPath, iout) + case (2) + call idm_log_var(this%struct_vector_1d(j)%dbl1d, & + this%struct_vector_1d(j)%varname, & + this%struct_vector_1d(j)%memoryPath, iout) + case (4) + call mem_setptr(int1d, this%struct_vector_1d(j)%varname, & + this%struct_vector_1d(j)%memoryPath) + call idm_log_var(int1d, this%struct_vector_1d(j)%varname, & + this%struct_vector_1d(j)%memoryPath, iout) + + end select + end do + return + end subroutine log_structarray_vars + + !> @brief read from the block parser to fill the StructArrayType + !< + subroutine read_from_parser(this, parser, iout) + class(StructArrayType) :: this !< StructArrayType + type(BlockParserType) :: parser !< block parser to read from + integer(I4B), intent(in) :: iout !< unit number for output + logical(LGP) :: endOfBlock + integer(I4B) :: i, j, k + integer(I4B) :: intval, numval + character(len=LINELENGTH) :: str1d + ! + ! -- read block + do i = 1, this%nrow + call parser%GetNextLine(endOfBlock) + if (endOfBlock) exit + do j = 1, this%ncol + select case (this%struct_vector_1d(j)%memtype) + case (1) + this%struct_vector_1d(j)%int1d(i) = parser%GetInteger() + case (2) + this%struct_vector_1d(j)%dbl1d(i) = parser%GetDouble() + case (3) + call parser%GetString(str1d, & + (.not. this%struct_vector_1d(j)%preserve_case)) + this%struct_vector_1d(j)%str1d(i) = str1d + case (4) + numval = this%struct_vector_1d(j)%intvector_shape(i) + do k = 1, numval + intval = parser%GetInteger() + call this%struct_vector_1d(j)%intvector%push_back(intval) + end do + end select + end do + end do + ! + ! -- if jagged array was read, load to input path + call this%load_intvector() + ! + ! -- log loaded variables + call this%log_structarray_vars(iout) + + end subroutine read_from_parser + +end module StructArrayModule diff --git a/src/Utilities/Idm/StructVector.f90 b/src/Utilities/Idm/StructVector.f90 new file mode 100644 index 00000000000..60aa546255f --- /dev/null +++ b/src/Utilities/Idm/StructVector.f90 @@ -0,0 +1,38 @@ +!> @brief This module contains the StructVectorModule +!! +!! This module contains a generic type for storing +!! different types of vectors. +!! +!< +module StructVectorModule + + use KindModule, only: I4B, DP, LGP + use ConstantsModule, only: LENMEMPATH, LENVARNAME + use CharacterStringModule, only: CharacterStringType + use VectorIntModule, only: VectorInt + + implicit none + private + public :: StructVectorType + + !> @brief derived type for generic vector + !! + !! This derived type is used in the StructArrayType to + !! store any type of vector. + !! + !< + type StructVectorType + character(len=LENVARNAME) :: varname + character(len=LENMEMPATH) :: memoryPath + integer(I4B) :: memtype = 0 + logical(LGP) :: preserve_case = .false. + integer(I4B), dimension(:), pointer, contiguous :: int1d => null() + real(DP), dimension(:), pointer, contiguous :: dbl1d => null() + type(CharacterStringType), dimension(:), pointer, contiguous :: & + str1d => null() + type(VectorInt), pointer :: intvector => null() + integer(I4B), dimension(:), pointer, contiguous :: intvector_shape => null() + + end type StructVectorType + +end module StructVectorModule diff --git a/src/Utilities/InputOutput.f90 b/src/Utilities/InputOutput.f90 index a30122202ed..33340df950a 100644 --- a/src/Utilities/InputOutput.f90 +++ b/src/Utilities/InputOutput.f90 @@ -28,38 +28,26 @@ module InputOutputModule contains + !> @brief Open a file + !! + !! Subroutine to open a file using the specified arguments + !! + !< subroutine openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, & filstat_opt, mode_opt) -! ****************************************************************************** -! openfile -- Open a file using the specified arguments. -! -! iu is the unit number -! iout is the output unit number to write a message (iout=0 does not print) -! fname is the name of the file -! ftype is the type of the file (e.g. WEL) -! fmtarg_opt is the format, default is 'formatted' -! accarg_opt is the access, default is 'sequential' -! filstat_opt is the file status, default is 'old'. Use 'REPLACE' for an -! output file. -! mode_opt is a simulation mode that is evaluated to determine if the file -! should be opened -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules use OpenSpecModule, only: action implicit none - ! -- dummy - integer(I4B), intent(inout) :: iu - integer(I4B), intent(in) :: iout - character(len=*), intent(in) :: fname - character(len=*), intent(in) :: ftype - character(len=*), intent(in), optional :: fmtarg_opt - character(len=*), intent(in), optional :: accarg_opt - character(len=*), intent(in), optional :: filstat_opt - integer(I4B), intent(in), optional :: mode_opt - ! -- local + ! -- dummy variables + integer(I4B), intent(inout) :: iu !< unit number + integer(I4B), intent(in) :: iout !< output unit number to write a message (iout=0 does not print) + character(len=*), intent(in) :: fname !< name of the file + character(len=*), intent(in) :: ftype !< file type (e.g. WEL) + character(len=*), intent(in), optional :: fmtarg_opt !< file format, default is 'formatted' + character(len=*), intent(in), optional :: accarg_opt !< file access, default is 'sequential' + character(len=*), intent(in), optional :: filstat_opt !< file status, default is 'old'. Use 'REPLACE' for output file. + integer(I4B), intent(in), optional :: mode_opt !< simulation mode that is evaluated to determine if the file should be opened + ! -- local variables character(len=20) :: fmtarg character(len=20) :: accarg character(len=20) :: filstat @@ -74,15 +62,6 @@ subroutine openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, & 1X,'FORMAT:',A,3X,'ACCESS:',A/ & 1X,'ACTION:',A/) 60 FORMAT(1X,/1X,'DID NOT OPEN ',A,/) -2011 FORMAT('*** ERROR OPENING FILE "',A,'" ON UNIT ',I0) -2017 format('*** FILE ALREADY OPEN ON UNIT: ',I0) -2012 format(' SPECIFIED FILE STATUS: ',A) -2013 format(' SPECIFIED FILE FORMAT: ',A) -2014 format(' SPECIFIED FILE ACCESS: ',A) -2015 format(' SPECIFIED FILE ACTION: ',A) -2016 format(' IOSTAT ERROR NUMBER: ',I0) -2018 format(' -- STOP EXECUTION (openfile)') -! ------------------------------------------------------------------------------ ! ! -- process mode_opt if (present(mode_opt)) then @@ -141,22 +120,24 @@ subroutine openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, & ! ! -- Check for an error if(ivar /= 0) then - write(errmsg,2011) fname(1:iflen), iu + write (errmsg, '(3a,1x,i0,a)') & + 'Could not open "', fname(1:iflen), '" on unit', iu, '.' if(iuop > 0) then - write(errmsg, 2017) iuop - call store_error(errmsg) + write (errmsg, '(a,1x,a,1x,i0,a)') & + trim(errmsg), 'File already open on unit', iuop, '.' endif - write(errmsg,2012) filstat - call store_error(errmsg) - write(errmsg,2013) fmtarg - call store_error(errmsg) - write(errmsg,2014) accarg - call store_error(errmsg) - write(errmsg,2015) filact - call store_error(errmsg) - write(errmsg,2016) ivar - call store_error(errmsg) - write(errmsg,2018) + write (errmsg, '(a,1x,a,1x,a,a)') & + trim(errmsg), 'Specified file status', trim(filstat), '.' + write (errmsg, '(a,1x,a,1x,a,a)') & + trim(errmsg), 'Specified file format', trim(fmtarg), '.' + write (errmsg, '(a,1x,a,1x,a,a)') & + trim(errmsg), 'Specified file access', trim(accarg), '.' + write (errmsg, '(a,1x,a,1x,a,a)') & + trim(errmsg), 'Specified file action', trim(filact), '.' + write (errmsg, '(a,1x,a,1x,i0,a)') & + trim(errmsg), 'IOSTAT error number', ivar, '.' + write (errmsg, '(a,1x,a)') & + trim(errmsg), 'STOP EXECUTION in subroutine openfile().' call store_error(errmsg, terminate=.TRUE.) endif ! @@ -173,22 +154,21 @@ subroutine openfile(iu, iout, fname, ftype, fmtarg_opt, accarg_opt, & return end subroutine openfile + !> @brief Assign a free unopened unit number + !! + !! Subroutine to assign a free unopened unit number to the iu dummy argument + !! + !< subroutine freeunitnumber(iu) -! ****************************************************************************** -! Assign a free unopened unit number to the iu dummy argument. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules implicit none - ! -- dummy - integer(I4B),intent(inout) :: iu - ! -- local + ! -- dummy variables + integer(I4B),intent(inout) :: iu !< next free file unit number + ! -- local variables integer(I4B) :: i logical :: opened -! ------------------------------------------------------------------------------ - ! + ! + ! -- code do i = iunext, iulast inquire(unit=i, opened=opened) if(.not. opened) exit @@ -200,21 +180,20 @@ subroutine freeunitnumber(iu) return end subroutine freeunitnumber + !> @brief Get a free unit number + !! + !! Function to get a free unit number that hasn't been used + !! + !< function getunit() -! ****************************************************************************** -! Get a free unit number that hasn't been used yet. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- modules implicit none ! -- return - integer(I4B) :: getunit - ! -- local + integer(I4B) :: getunit !< free unit number + ! -- local variables integer(I4B) :: iunit -! ------------------------------------------------------------------------------ ! + ! -- code call freeunitnumber(iunit) getunit = iunit ! @@ -222,28 +201,26 @@ function getunit() return end function getunit + !> @brief Get the next non-comment line + !! + !! Subroutine to get the next non-comment line from a file + !! + !< subroutine u8rdcom(iin, iout, line, ierr) -! ****************************************************************************** -! Read until non-comment line found and then return line -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ use, intrinsic :: iso_fortran_env, only: IOSTAT_END implicit none - ! -- dummy - integer(I4B), intent(in) :: iin - integer(I4B), intent(in) :: iout - character (len=*), intent(inout) :: line - integer(I4B), intent(out) :: ierr - ! -- local definitions + ! -- dummy variables + integer(I4B), intent(in) :: iin !< file unit number + integer(I4B), intent(in) :: iout !< output listing file + character (len=*), intent(inout) :: line !< next non-comment line + integer(I4B), intent(out) :: ierr !< error code + ! -- local variables character (len=2), parameter :: comment = '//' character(len=1), parameter :: tab = CHAR(9) logical :: iscomment integer(I4B) :: i, l -! ------------------------------------------------------------------------------ - !code ! + ! -- code line = comment pcomments: do read (iin,'(a)', iostat=ierr) line @@ -264,7 +241,7 @@ subroutine u8rdcom(iin, iout, line, ierr) cycle end if ! - ! Ensure that any initial tab characters are treated as spaces + ! -- Ensure that any initial tab characters are treated as spaces cleartabs: do line = trim(adjustl(line)) iscomment = .false. @@ -304,24 +281,24 @@ subroutine u8rdcom(iin, iout, line, ierr) return end subroutine u8rdcom + !> @brief Get line from a block + !! + !! Subroutine to read and return a line from an external file or from + !! within a block. The line is read from an external file if iu is + !! not equal to iuext. + !! + !< subroutine uget_block_line(iu, iuext, iout, line, lloc, istart, istop) -! ****************************************************************************** -! Read and return line read from an external file or from within a block. -! The line is read from an external file if iu is not equal to iuext -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ implicit none - ! -- dummy - integer(I4B), intent(in) :: iu - integer(I4B), intent(in) :: iuext - integer(I4B), intent(in) :: iout - character (len=*), intent(inout) :: line - integer(I4B), intent(inout) :: lloc - integer(I4B), intent(inout) :: istart - integer(I4B), intent(inout) :: istop - ! -- local definitions + ! -- dummy variables + integer(I4B), intent(in) :: iu !< file unit number + integer(I4B), intent(in) :: iuext !< external file unit number + integer(I4B), intent(in) :: iout !< output listing file + character (len=*), intent(inout) :: line !< line + integer(I4B), intent(inout) :: lloc !< position in line + integer(I4B), intent(inout) :: istart !< starting position of a word + integer(I4B), intent(inout) :: istop !< ending position of a word + ! -- local variables integer(I4B) :: ierr integer(I4B) :: ival real(DP) :: rval @@ -343,27 +320,27 @@ subroutine uget_block_line(iu, iuext, iout, line, lloc, istart, istop) end subroutine uget_block_line + !> @brief Find a block in a file + !! + !! Subroutine to read from a file until the tag (ctag) for a block is + !! is found. Return isfound with true, if found. + !! + !< subroutine uget_block(iin, iout, ctag, ierr, isfound, lloc, line, iuext, & blockRequired, supportopenclose) -! ****************************************************************************** -! Read until the ctag block is found. Return isfound with true, if found. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ implicit none - ! -- dummy - integer(I4B), intent(in) :: iin - integer(I4B), intent(in) :: iout - character (len=*), intent(in) :: ctag - integer(I4B), intent(out) :: ierr - logical, intent(inout) :: isfound - integer(I4B), intent(inout) :: lloc - character (len=:), allocatable, intent(inout) :: line - integer(I4B), intent(inout) :: iuext - logical, optional, intent(in) :: blockRequired - logical, optional, intent(in) :: supportopenclose - ! -- local + ! -- dummy variables + integer(I4B), intent(in) :: iin !< file unit + integer(I4B), intent(in) :: iout !< output listing file unit + character (len=*), intent(in) :: ctag !< block tag + integer(I4B), intent(out) :: ierr !< error + logical, intent(inout) :: isfound !< boolean indicating if the block was found + integer(I4B), intent(inout) :: lloc !< position in line + character (len=:), allocatable, intent(inout) :: line !< line + integer(I4B), intent(inout) :: iuext !< external file unit number + logical, optional, intent(in) :: blockRequired !< boolean indicating if the block is required + logical, optional, intent(in) :: supportopenclose !< boolean indicating if the block supports open/close + ! -- local variables integer(I4B) :: istart integer(I4B) :: istop integer(I4B) :: ival @@ -373,8 +350,8 @@ subroutine uget_block(iin, iout, ctag, ierr, isfound, lloc, line, iuext, & character(len=LINELENGTH) :: fname character(len=MAXCHARLEN) :: ermsg logical :: supportoc, blockRequiredLocal -! ------------------------------------------------------------------------------ - !code + ! + ! -- code if (present(blockRequired)) then blockRequiredLocal = blockRequired else @@ -389,7 +366,16 @@ subroutine uget_block(iin, iout, ctag, ierr, isfound, lloc, line, iuext, & mainloop: do lloc = 1 call u9rdcom(iin, iout, line, ierr) - if (ierr < 0) exit + if (ierr < 0) then + if (blockRequiredLocal) then + ermsg = 'Required block "' // trim(ctag) // & + '" not found. Found end of file instead.' + call store_error(ermsg) + call store_error_unit(iuext) + end if + ! block not found so exit + exit + end if call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout) if (line(istart:istop) == 'BEGIN') then call urword(line, lloc, istart, istop, 1, ival, rval, iin, iout) @@ -444,35 +430,36 @@ subroutine uget_block(iin, iout, ctag, ierr, isfound, lloc, line, iuext, & endif end if end do mainloop + ! + ! -- return return end subroutine uget_block + !> @brief Find the next block in a file + !! + !! Subroutine to read from a file until next block is found. + !! Return isfound with true, if found, and return the block name. + !! + !< subroutine uget_any_block(iin,iout,isfound,lloc,line,ctagfound,iuext) -! ****************************************************************************** -! Read until any block is found. If found, return isfound as true and -! return block name in ctagfound. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ implicit none - ! -- dummy - integer(I4B), intent(in) :: iin - integer(I4B), intent(in) :: iout - logical, intent(inout) :: isfound - integer(I4B), intent(inout) :: lloc - character (len=:), allocatable, intent(inout) :: line - character(len=*), intent(out) :: ctagfound - integer(I4B), intent(inout) :: iuext - ! -- local + ! -- dummy variables + integer(I4B), intent(in) :: iin !< file unit number + integer(I4B), intent(in) :: iout !< output listing file unit + logical, intent(inout) :: isfound !< boolean indicating if a block was found + integer(I4B), intent(inout) :: lloc !< position in line + character (len=:), allocatable, intent(inout) :: line !< line + character(len=*), intent(out) :: ctagfound !< block name + integer(I4B), intent(inout) :: iuext !< external file unit number + ! -- local variables integer(I4B) :: ierr, istart, istop integer(I4B) :: ival, lloc2 real(DP) :: rval character(len=100) :: ermsg character (len=:), allocatable :: line2 character(len=LINELENGTH) :: fname -! ------------------------------------------------------------------------------ - !code + ! + ! -- code isfound = .false. ctagfound = '' iuext = iin @@ -509,25 +496,25 @@ subroutine uget_any_block(iin,iout,isfound,lloc,line,ctagfound,iuext) return end subroutine uget_any_block + !> @brief Evaluate if the end of a block has been found + !! + !! Subroutine to evaluate if the end of a block has been found. Abnormal + !! termination if 'begin' is found or if 'end' encountered with + !! incorrect tag. + !! + !< subroutine uterminate_block(iin,iout,key,ctag,lloc,line,ierr,iuext) -! ****************************************************************************** -! Possible abnormal block termination. Terminate if 'begin' found or if -! 'end' encountered with incorrect tag. -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ implicit none - ! -- dummy - integer(I4B), intent(in) :: iin - integer(I4B), intent(in) :: iout - character (len=*), intent(in) :: key - character (len=*), intent(in) :: ctag - integer(I4B), intent(inout) :: lloc - character (len=*), intent(inout) :: line - integer(I4B), intent(inout) :: ierr - integer(I4B), intent(inout) :: iuext - ! -- local + ! -- dummy variables + integer(I4B), intent(in) :: iin !< file unit number + integer(I4B), intent(in) :: iout !< output listing file unit number + character (len=*), intent(in) :: key !< keyword in block + character (len=*), intent(in) :: ctag !< block name + integer(I4B), intent(inout) :: lloc !< position in line + character (len=*), intent(inout) :: line !< line + integer(I4B), intent(inout) :: ierr !< error + integer(I4B), intent(inout) :: iuext !< external file unit number + ! -- local variables character(len=LENBIGLINE) :: ermsg integer(I4B) :: istart integer(I4B) :: istop @@ -538,20 +525,20 @@ subroutine uterminate_block(iin,iout,key,ctag,lloc,line,ierr,iuext) '" MUST BE USED TO END ',A,'.') 2 format('ERROR. "',A,'" DETECTED BEFORE "END',1X,A,'". ','"END',1X,A, & '" MUST BE USED TO END ',A,'.') -! ------------------------------------------------------------------------------ - !code + ! + ! -- code ierr = 1 select case(key) case ('END') call urword(line, lloc, istart, istop, 1, ival, rval, iout, iin) - if (line(istart:istop).ne.ctag) then + if (line(istart:istop) /= ctag) then write(ermsg, 1) trim(key), trim(ctag), trim(ctag), trim(ctag) call store_error(ermsg) call store_error_unit(iin) else ierr = 0 if (iuext /= iin) then - ! close external file + ! -- close external file close(iuext) iuext = iin endif @@ -561,354 +548,373 @@ subroutine uterminate_block(iin,iout,key,ctag,lloc,line,ierr,iuext) call store_error(ermsg) call store_error_unit(iin) end select + ! + ! -- return return end subroutine uterminate_block - SUBROUTINE UPCASE(WORD) -!C ****************************************************************** -!C CONVERT A CHARACTER STRING TO ALL UPPER CASE -!C ****************************************************************** -!C SPECIFICATIONS: -!C ------------------------------------------------------------------ - CHARACTER WORD*(*) -!C -!C1------Compute the difference between lowercase and uppercase. - L = LEN(WORD) - IDIFF=ICHAR('a')-ICHAR('A') -!C -!C2------Loop through the string and convert any lowercase characters. - DO 10 K=1,L - IF(WORD(K:K).GE.'a' .AND. WORD(K:K).LE.'z') & - & WORD(K:K)=CHAR(ICHAR(WORD(K:K))-IDIFF) -10 CONTINUE -!C -!C3------return. - RETURN - END SUBROUTINE upcase - - subroutine lowcase(word) -! ****************************************************************** -! Convert a character string to all lower case -! ****************************************************************** -! specifications: -! ------------------------------------------------------------------ - implicit none - ! -- dummy - character(len=*) :: word - ! -- local - integer(I4B) :: idiff, k, l -! -!------compute the difference between lowercase and uppercase. - l = len(word) - idiff=ichar('a')-ichar('A') -! -!------loop through the string and convert any uppercase characters. - do k=1,l - if(word(k:k).ge.'A' .and. word(k:k).le.'Z') then - word(k:k)=char(ichar(word(k:k))+idiff) - endif - enddo -! -!------return. - return - end subroutine lowcase - - subroutine UWWORD(LINE,ICOL,ILEN,NCODE,C,N,R,FMT,ALIGNMENT,SEP) - implicit none - ! -- dummy - character (len=*), intent(inout) :: LINE - integer(I4B), intent(inout) :: ICOL - integer(I4B), intent(in) :: ILEN - integer(I4B), intent(in) :: NCODE - character (len=*), intent(in) :: C - integer(I4B), intent(in) :: N - real(DP), intent(in) :: R - character (len=*), optional, intent(in) :: FMT - integer(I4B), optional, intent(in) :: ALIGNMENT - character (len=*), optional, intent(in) :: SEP - ! -- local - character (len=16) :: cfmt - character (len=16) :: cffmt - character (len=ILEN) :: cval - integer(I4B) :: ialign - integer(I4B) :: i - integer(I4B) :: ispace - integer(I4B) :: istop - integer(I4B) :: ipad - integer(I4B) :: ireal - ! -- code - ! - ! -- initialize locals - ipad = 0 - ireal = 0 - ! - ! -- process dummy variables - if (present(FMT)) then - CFMT = FMT - else - select case(NCODE) - case(TABSTRING, TABUCSTRING) - write(cfmt, '(A,I0,A)') '(A', ILEN, ')' - case(TABINTEGER) - write(cfmt, '(A,I0,A)') '(I', ILEN, ')' - case(TABREAL) - ireal = 1 - i = ILEN - 7 - write(cfmt, '(A,I0,A,I0,A)') '(1PG', ILEN, '.', i, ')' - if (R >= DZERO) then - ipad = 1 - end if - end select - end if - write(cffmt, '(A,I0,A)') '(A', ILEN, ')' + !> @brief Convert to upper case + !! + !! Subroutine to convert a character string to upper case. + !! + !< + subroutine upcase(word) + implicit none + ! -- dummy variables + character (len=*), intent(inout) :: word !< word to convert to upper case + ! -- local variables + integer(I4B) :: l + integer(I4B) :: idiff + integer(I4B) :: k + ! + ! -- Compute the difference between lowercase and uppercase. + l = len(word) + idiff = ichar('a') - ichar('A') + ! + ! -- Loop through the string and convert any lowercase characters. + do k = 1, l + IF (word(k:k) >= 'a' .and. word(k:k) <= 'z') & + word(k:k) = char(ichar(word(k:k)) - idiff) + end do + ! + ! -- return. + return + end subroutine upcase + + !> @brief Convert to lower case + !! + !! Subroutine to convert a character string to lower case. + !! + !< + subroutine lowcase(word) + implicit none + ! -- dummy variables + character(len=*) :: word !< + ! -- local variables + integer(I4B) :: idiff, k, l + ! + ! -- compute the difference between lowercase and uppercase. + l = len(word) + idiff = ichar('a') - ichar('A') + ! + ! -- loop through the string and convert any uppercase characters. + do k = 1, l + if(word(k:k) >= 'A' .and. word(k:k) <= 'Z') then + word(k:k)=char(ichar(word(k:k))+idiff) + endif + enddo + ! + ! -- return. + return + end subroutine lowcase + + !> @brief Create a formatted line + !! + !! Subroutine to create a formatted line with specified alignment + !! and column separators. Like URWORD, UWWORD works with strings, + !! integers, and floats. Can pass an optional format statement, + !! alignment, and column separator. + !! + !< + subroutine UWWORD(LINE,ICOL,ILEN,NCODE,C,N,R,FMT,ALIGNMENT,SEP) + implicit none + ! -- dummy variables + character (len=*), intent(inout) :: LINE !< line + integer(I4B), intent(inout) :: ICOL !< column to write to line + integer(I4B), intent(in) :: ILEN !< current length of line + integer(I4B), intent(in) :: NCODE !< code for data type to write + character (len=*), intent(in) :: C !< character data type + integer(I4B), intent(in) :: N !< integer data type + real(DP), intent(in) :: R !< float data type + character (len=*), optional, intent(in) :: FMT !< format statement + integer(I4B), optional, intent(in) :: ALIGNMENT !< alignment specifier + character (len=*), optional, intent(in) :: SEP !< column separator + ! -- local variables + character (len=16) :: cfmt + character (len=16) :: cffmt + character (len=ILEN) :: cval + integer(I4B) :: ialign + integer(I4B) :: i + integer(I4B) :: ispace + integer(I4B) :: istop + integer(I4B) :: ipad + integer(I4B) :: ireal + ! -- code + ! + ! -- initialize locals + ipad = 0 + ireal = 0 + ! + ! -- process dummy variables + if (present(FMT)) then + CFMT = FMT + else + select case(NCODE) + case(TABSTRING, TABUCSTRING) + write(cfmt, '(A,I0,A)') '(A', ILEN, ')' + case(TABINTEGER) + write(cfmt, '(A,I0,A)') '(I', ILEN, ')' + case(TABREAL) + ireal = 1 + i = ILEN - 7 + write(cfmt, '(A,I0,A,I0,A)') '(1PG', ILEN, '.', i, ')' + if (R >= DZERO) then + ipad = 1 + end if + end select + end if + write(cffmt, '(A,I0,A)') '(A', ILEN, ')' - if (present(ALIGNMENT)) then - ialign = ALIGNMENT - else - ialign = TABRIGHT - end if - ! - ! -- - if (NCODE == TABSTRING .or. NCODE == TABUCSTRING) then - cval = C - if (NCODE == TABUCSTRING) then - call UPCASE(cval) - end if - else if (NCODE == TABINTEGER) then - write(cval, cfmt) N - else if (NCODE == TABREAL) then - write(cval, cfmt) R - end if - ! - ! -- apply alignment to cval - if (len_trim(adjustl(cval)) > ILEN) then - cval = adjustl(cval) - else - cval = trim(adjustl(cval)) + if (present(ALIGNMENT)) then + ialign = ALIGNMENT + else + ialign = TABRIGHT + end if + ! + ! -- + if (NCODE == TABSTRING .or. NCODE == TABUCSTRING) then + cval = C + if (NCODE == TABUCSTRING) then + call UPCASE(cval) end if - if (ialign == TABCENTER) then - i = len_trim(cval) - ispace = (ILEN - i) / 2 - if (ireal > 0) then - if (ipad > 0) then - cval = ' ' //trim(adjustl(cval)) - else - cval = trim(adjustl(cval)) - end if - else - cval = repeat(' ', ispace) // trim(cval) - end if - else if (ialign == TABLEFT) then - cval = trim(adjustl(cval)) + else if (NCODE == TABINTEGER) then + write(cval, cfmt) N + else if (NCODE == TABREAL) then + write(cval, cfmt) R + end if + ! + ! -- apply alignment to cval + if (len_trim(adjustl(cval)) > ILEN) then + cval = adjustl(cval) + else + cval = trim(adjustl(cval)) + end if + if (ialign == TABCENTER) then + i = len_trim(cval) + ispace = (ILEN - i) / 2 + if (ireal > 0) then if (ipad > 0) then cval = ' ' //trim(adjustl(cval)) + else + cval = trim(adjustl(cval)) end if else - cval = adjustr(cval) + cval = repeat(' ', ispace) // trim(cval) end if - if (NCODE == TABUCSTRING) then - call UPCASE(cval) + else if (ialign == TABLEFT) then + cval = trim(adjustl(cval)) + if (ipad > 0) then + cval = ' ' //trim(adjustl(cval)) end if - ! - ! -- increment istop to the end of the column - istop = ICOL + ILEN - 1 - ! - ! -- write final string to line - write(LINE(ICOL:istop), cffmt) cval + else + cval = adjustr(cval) + end if + if (NCODE == TABUCSTRING) then + call UPCASE(cval) + end if + ! + ! -- increment istop to the end of the column + istop = ICOL + ILEN - 1 + ! + ! -- write final string to line + write(LINE(ICOL:istop), cffmt) cval - ICOL = istop + 1 + ICOL = istop + 1 - if (present(SEP)) then - i = len(SEP) - istop = ICOL + i - write(LINE(ICOL:istop), '(A)') SEP - ICOL = istop - end if - -! -!------return. - return - end subroutine UWWORD - - SUBROUTINE URWORD(LINE,ICOL,ISTART,ISTOP,NCODE,N,R,IOUT,IN) -!C ****************************************************************** -!C ROUTINE TO EXTRACT A WORD FROM A LINE OF TEXT, AND OPTIONALLY -!C CONVERT THE WORD TO A NUMBER. -!C ISTART AND ISTOP WILL BE RETURNED WITH THE STARTING AND -!C ENDING CHARACTER POSITIONS OF THE WORD. -!C THE LAST CHARACTER IN THE LINE IS SET TO BLANK SO THAT IF ANY -!C PROBLEMS OCCUR WITH FINDING A WORD, ISTART AND ISTOP WILL -!C POINT TO THIS BLANK CHARACTER. THUS, A WORD WILL ALWAYS BE -!C RETURNED UNLESS THERE IS A NUMERIC CONVERSION ERROR. BE SURE -!C THAT THE LAST CHARACTER IN LINE IS NOT AN IMPORTANT CHARACTER -!C BECAUSE IT WILL ALWAYS BE SET TO BLANK. -!C A WORD STARTS WITH THE FIRST CHARACTER THAT IS NOT A SPACE OR -!C COMMA, AND ENDS WHEN A SUBSEQUENT CHARACTER THAT IS A SPACE -!C OR COMMA. NOTE THAT THESE PARSING RULES DO NOT TREAT TWO -!C COMMAS SEPARATED BY ONE OR MORE SPACES AS A NULL WORD. -!C FOR A WORD THAT BEGINS WITH "'" OR '"', THE WORD STARTS WITH -!C THE CHARACTER AFTER THE QUOTE AND ENDS WITH THE CHARACTER -!C PRECEDING A SUBSEQUENT QUOTE. THUS, A QUOTED WORD CAN -!C INCLUDE SPACES AND COMMAS. THE QUOTED WORD CANNOT CONTAIN -!C A QUOTE CHARACTER OF THE SAME TYPE WITHIN THE WORD BUT -!C CAN CONTAIN A DIFFERENT QUOTE CHARACTER. FOR EXAMPLE, -!C "WORD'S" OR 'WORD"S'. -!C IF NCODE IS 1, THE WORD IS CONVERTED TO UPPER CASE. -!C IF NCODE IS 2, THE WORD IS CONVERTED TO AN INTEGER. -!C IF NCODE IS 3, THE WORD IS CONVERTED TO A REAL NUMBER. -!C NUMBER CONVERSION ERROR IS WRITTEN TO UNIT IOUT IF IOUT IS -!C POSITIVE; ERROR IS WRITTEN TO DEFAULT OUTPUT IF IOUT IS 0; -!C NO ERROR MESSAGE IS WRITTEN IF IOUT IS NEGATIVE. -!C ****************************************************************** -!C -!C SPECIFICATIONS: -!C ------------------------------------------------------------------ - integer(I4B), intent(inout) :: n - real(DP),intent(inout) :: r - CHARACTER(len=*) LINE - CHARACTER(len=20) STRING - CHARACTER(len=30) RW - CHARACTER(len=1) TAB - CHARACTER(len=1) CHAREND - character(len=200) :: msg - character(len=LINELENGTH) :: msg_line -!C ------------------------------------------------------------------ - TAB=CHAR(9) -!C -!C1------Set last char in LINE to blank and set ISTART and ISTOP to point -!C1------to this blank as a default situation when no word is found. If -!C1------starting location in LINE is out of bounds, do not look for a -!C1------word. - LINLEN=LEN(LINE) - LINE(LINLEN:LINLEN)=' ' - ISTART=LINLEN - ISTOP=LINLEN - LINLEN=LINLEN-1 - IF(ICOL.LT.1 .OR. ICOL.GT.LINLEN) GO TO 100 -!C -!C2------Find start of word, which is indicated by first character that -!C2------is not a blank, a comma, or a tab. - DO 10 I=ICOL,LINLEN - IF(LINE(I:I).NE.' ' .AND. LINE(I:I).NE.',' & - & .AND. LINE(I:I).NE.TAB) GO TO 20 -10 CONTINUE - ICOL=LINLEN+1 - GO TO 100 -!C -!C3------Found start of word. Look for end. -!C3A-----When word is quoted, only a quote can terminate it. -!C-------SEARCH FOR A SINGLE (CHAR(39)) OR DOUBLE (CHAR(34)) QUOTE -20 IF(LINE(I:I).EQ.CHAR(34) .OR. LINE(I:I).EQ.CHAR(39)) THEN - IF (LINE(I:I).EQ.CHAR(34)) THEN - CHAREND = CHAR(34) - ELSE - CHAREND = CHAR(39) - END IF - I=I+1 - IF(I.LE.LINLEN) THEN - DO 25 J=I,LINLEN - IF(LINE(J:J).EQ.CHAREND) GO TO 40 -25 CONTINUE - END IF -!C -!C3B-----When word is not quoted, space, comma, or tab will terminate. + if (present(SEP)) then + i = len(SEP) + istop = ICOL + i + write(LINE(ICOL:istop), '(A)') SEP + ICOL = istop + end if + ! + !-- return + return + end subroutine UWWORD + + !> @brief Extract a word from a string + !! + !! Subroutine to extract a word from a line of text, and optionally + !! convert the word to a number. The last character in the line is + !! set to blank so that if any problems occur with finding a word, + !! istart and istop will point to this blank character. Thus, a word + !! will always be returned unless there is a numeric conversion error. + !! Be sure that the last character in line is not an important character + !! because it will always be set to blank. + !! + !! A word starts with the first character that is not a space or + !! comma, and ends when a subsequent character that is a space + !! or comma. Note that these parsing rules do not treat two + !! commas separated by one or more spaces as a null word. + !! + !! For a word that begins with "'" or '"', the word starts with + !! the character after the quote and ends with the character preceding + !! a subsequent quote. Thus, a quoted word can include spaces and commas. + !! The quoted word cannot contain a quote character of the same type + !! within the word but can contain a different quote character. For + !! example, "WORD'S" or 'WORD"S'. + !! + !! Number conversion error is written to unit iout if iout is positive; + !! error is written to default output if iout is 0; no error message is + !! written if iout is negative. + !! + !< + SUBROUTINE URWORD(LINE,ICOL,ISTART,ISTOP,NCODE,N,R,IOUT,IN) + ! -- dummy variables + character(len=*) :: LINE !< line to parse + integer(I4B), intent(inout) :: icol !< current column in line + integer(I4B), intent(inout) :: istart !< starting character position of the word + integer(I4B), intent(inout) :: istop !< ending character position of the word + integer(I4B), intent(in) :: ncode !< word conversion flag (1) upper case, (2) integer, (3) real number + integer(I4B), intent(inout) :: n !< integer data type + real(DP), intent(inout) :: r !< float data type + integer(I4B), intent(in) :: iout !< output listing file unit + integer(I4B), intent(in) :: in !< input file unit number + ! -- local variables + CHARACTER(len=20) STRING + CHARACTER(len=30) RW + CHARACTER(len=1) TAB + CHARACTER(len=1) CHAREND + character(len=200) :: msg + character(len=LINELENGTH) :: msg_line + ! + ! -- code + TAB=CHAR(9) + ! + ! -- Set last char in LINE to blank and set ISTART and ISTOP to point + ! to this blank as a default situation when no word is found. If + ! starting location in LINE is out of bounds, do not look for a word. + LINLEN=LEN(LINE) + LINE(LINLEN:LINLEN)=' ' + ISTART=LINLEN + ISTOP=LINLEN + LINLEN=LINLEN-1 + IF(ICOL.LT.1 .OR. ICOL.GT.LINLEN) GO TO 100 + ! + ! -- Find start of word, which is indicated by first character that + ! is not a blank, a comma, or a tab. + DO 10 I=ICOL,LINLEN + IF(LINE(I:I).NE.' ' .AND. LINE(I:I).NE.',' .AND. & + LINE(I:I).NE.TAB) GO TO 20 +10 CONTINUE + ICOL=LINLEN+1 + GO TO 100 + ! + ! -- Found start of word. Look for end. + ! When word is quoted, only a quote can terminate it. + ! SEARCH FOR A SINGLE (CHAR(39)) OR DOUBLE (CHAR(34)) QUOTE +20 IF(LINE(I:I).EQ.CHAR(34) .OR. LINE(I:I).EQ.CHAR(39)) THEN + IF (LINE(I:I).EQ.CHAR(34)) THEN + CHAREND = CHAR(34) ELSE - DO 30 J=I,LINLEN - IF(LINE(J:J).EQ.' ' .OR. LINE(J:J).EQ.',' & - & .OR. LINE(J:J).EQ.TAB) GO TO 40 -30 CONTINUE + CHAREND = CHAR(39) END IF -!C -!C3C-----End of line without finding end of word; set end of word to -!C3C-----end of line. - J=LINLEN+1 -!C -!C4------Found end of word; set J to point to last character in WORD and -!C-------set ICOL to point to location for scanning for another word. -40 ICOL=J+1 - J=J-1 - IF(J.LT.I) GO TO 100 - ISTART=I - ISTOP=J -!C -!C5------Convert word to upper case and RETURN if NCODE is 1. - IF(NCODE.EQ.1) THEN - IDIFF=ICHAR('a')-ICHAR('A') - DO 50 K=ISTART,ISTOP - IF(LINE(K:K).GE.'a' .AND. LINE(K:K).LE.'z') & - & LINE(K:K)=CHAR(ICHAR(LINE(K:K))-IDIFF) -50 CONTINUE - RETURN - END IF -!C -!C6------Convert word to a number if requested. -100 IF(NCODE.EQ.2 .OR. NCODE.EQ.3) THEN - RW=' ' - L=30-ISTOP+ISTART - IF(L.LT.1) GO TO 200 - RW(L:30)=LINE(ISTART:ISTOP) - IF(NCODE.EQ.2) READ(RW,'(I30)',ERR=200) N - IF(NCODE.EQ.3) READ(RW,'(F30.0)',ERR=200) R + I=I+1 + IF(I.LE.LINLEN) THEN + DO 25 J=I,LINLEN + IF(LINE(J:J).EQ.CHAREND) GO TO 40 +25 CONTINUE END IF + ! + ! -- When word is not quoted, space, comma, or tab will terminate. + ELSE + DO 30 J=I,LINLEN + IF(LINE(J:J).EQ.' ' .OR. LINE(J:J).EQ.',' .OR. & + LINE(J:J).EQ.TAB) GO TO 40 +30 CONTINUE + END IF + ! + ! -- End of line without finding end of word; set end of word to + ! end of line. + J=LINLEN+1 + ! + ! -- Found end of word; set J to point to last character in WORD and + ! set ICOL to point to location for scanning for another word. +40 ICOL=J+1 + J=J-1 + IF(J.LT.I) GO TO 100 + ISTART=I + ISTOP=J + ! + ! -- Convert word to upper case and RETURN if NCODE is 1. + IF(NCODE.EQ.1) THEN + IDIFF=ICHAR('a')-ICHAR('A') + DO 50 K=ISTART,ISTOP + IF(LINE(K:K).GE.'a' .AND. LINE(K:K).LE.'z') & + LINE(K:K)=CHAR(ICHAR(LINE(K:K))-IDIFF) +50 CONTINUE RETURN -!C -!C7------Number conversion error. -200 IF(NCODE.EQ.3) THEN - STRING= 'A REAL NUMBER' - L=13 + END IF + ! + ! -- Convert word to a number if requested. +100 IF(NCODE.EQ.2 .OR. NCODE.EQ.3) THEN + RW=' ' + L=30-ISTOP+ISTART + IF(L.LT.1) GO TO 200 + RW(L:30)=LINE(ISTART:ISTOP) + IF(NCODE.EQ.2) READ(RW,'(I30)',ERR=200) N + IF(NCODE.EQ.3) READ(RW,'(F30.0)',ERR=200) R + END IF + RETURN + ! + ! -- Number conversion error. +200 IF(NCODE.EQ.3) THEN + STRING= 'A REAL NUMBER' + L=13 + ELSE + STRING= 'AN INTEGER' + L=10 + END IF + ! + ! -- If output unit is negative, set last character of string to 'E'. + IF(IOUT.LT.0) THEN + N=0 + R=0. + LINE(LINLEN+1:LINLEN+1)='E' + RETURN + ! + ! -- If output unit is positive; write a message to output unit. + ELSE IF(IOUT.GT.0) THEN + IF(IN.GT.0) THEN + write(msg_line,201) IN,LINE(ISTART:ISTOP),STRING(1:L) ELSE - STRING= 'AN INTEGER' - L=10 + WRITE(msg_line,202) LINE(ISTART:ISTOP),STRING(1:L) END IF -!C -!C7A-----If output unit is negative, set last character of string to 'E'. - IF(IOUT.LT.0) THEN - N=0 - R=0. - LINE(LINLEN+1:LINLEN+1)='E' - RETURN -!C -!C7B-----If output unit is positive; write a message to output unit. - ELSE IF(IOUT.GT.0) THEN - IF(IN.GT.0) THEN - write(msg_line,201) IN,LINE(ISTART:ISTOP),STRING(1:L) - ELSE - WRITE(msg_line,202) LINE(ISTART:ISTOP),STRING(1:L) - END IF - call sim_message(msg_line, iunit=IOUT, skipbefore=1) - call sim_message(LINE, iunit=IOUT, fmt='(1x,a)') -201 FORMAT(1X,'FILE UNIT ',I4,' : ERROR CONVERTING "',A, & - & '" TO ',A,' IN LINE:') -202 FORMAT(1X,'KEYBOARD INPUT : ERROR CONVERTING "',A, & - '" TO ',A,' IN LINE:') -!C -!C7C-----If output unit is 0; write a message to default output. + call sim_message(msg_line, iunit=IOUT, skipbefore=1) + call sim_message(LINE, iunit=IOUT, fmt='(1x,a)') +201 FORMAT(1X,'FILE UNIT ',I4,' : ERROR CONVERTING "',A, & + '" TO ',A,' IN LINE:') +202 FORMAT(1X,'KEYBOARD INPUT : ERROR CONVERTING "',A, & + '" TO ',A,' IN LINE:') + ! + ! -- If output unit is 0; write a message to default output. + ELSE + IF(IN.GT.0) THEN + write(msg_line,201) IN,LINE(ISTART:ISTOP),STRING(1:L) ELSE - IF(IN.GT.0) THEN - write(msg_line,201) IN,LINE(ISTART:ISTOP),STRING(1:L) - ELSE - WRITE(msg_line,202) LINE(ISTART:ISTOP),STRING(1:L) - END IF - call sim_message(msg_line, iunit=IOUT, skipbefore=1) - call sim_message(LINE, iunit=IOUT, fmt='(1x,a)') + WRITE(msg_line,202) LINE(ISTART:ISTOP),STRING(1:L) END IF -!C -!C7D-----STOP after storing error message. - call lowcase(string) - if (in > 0) then - write(msg,205) in,line(istart:istop),trim(string) - else - write(msg,207) line(istart:istop),trim(string) - endif -205 format('File unit ',I0,': Error converting "',A, & - & '" to ',A,' in following line:') -207 format('Keyboard input: Error converting "',A, & - & '" to ',A,' in following line:') - call store_error(msg) - call store_error(trim(line)) - call store_error_unit(in) - ! - END SUBROUTINE URWORD + call sim_message(msg_line, iunit=IOUT, skipbefore=1) + call sim_message(LINE, iunit=IOUT, fmt='(1x,a)') + END IF + ! + ! -- STOP after storing error message. + call lowcase(string) + if (in > 0) then + write(msg,205) in,line(istart:istop),trim(string) + else + write(msg,207) line(istart:istop),trim(string) + endif +205 format('File unit ',I0,': Error converting "',A, & + '" to ',A,' in following line:') +207 format('Keyboard input: Error converting "',A, & + '" to ',A,' in following line:') + call store_error(msg) + call store_error(trim(line)) + call store_error_unit(in) + ! + ! -- return +END SUBROUTINE URWORD SUBROUTINE ULSTLB(IOUT,LABEL,CAUX,NCAUX,NAUX) !C ****************************************************************** @@ -1349,7 +1355,7 @@ subroutine ubdsv06(kstp,kper,text, & real(DP), intent(in) :: delt real(DP), intent(in) :: pertim real(DP), intent(in) :: totim - ! -- local + ! -- local variables integer(I4B) :: n ! -- format character(len=*), parameter :: fmt = & @@ -1390,7 +1396,7 @@ subroutine ubdsvc(ibdchn, n, q, naux, aux) real(DP), intent(in) :: q integer(I4B), intent(in) :: naux real(DP), dimension(naux), intent(in) :: aux - ! -- local + ! -- local variables integer(I4B) :: nn ! ------------------------------------------------------------------------------ ! @@ -1420,7 +1426,7 @@ subroutine ubdsvd(ibdchn, n, n2, q, naux, aux) real(DP), intent(in) :: q integer(I4B), intent(in) :: naux real(DP), dimension(naux), intent(in) :: aux - ! -- local + ! -- local variables integer(I4B) :: nn ! ------------------------------------------------------------------------------ ! @@ -1438,9 +1444,9 @@ end subroutine ubdsvd logical function same_word(word1, word2) ! Perform a case-insensitive comparison of two words implicit none - ! -- dummy variables + ! -- dummy variables variables character(len=*), intent(in) :: word1, word2 - ! -- local + ! -- local variables character(len=200) :: upword1, upword2 ! upword1 = word1 @@ -1458,7 +1464,7 @@ function get_node(ilay, irow, icol, nlay, nrow, ncol) implicit none ! -- return integer(I4B) :: get_node - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: ilay, irow, icol, nlay, nrow, ncol ! if (nlay>0 .and. nrow>0 .and. ncol>0) then @@ -1480,7 +1486,7 @@ subroutine get_ijk(nodenumber, nrow, ncol, nlay, irow, icol, ilay) ! dimensions. If nodenumber is invalid, set irow, icol, and ! ilay to -1 implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: nodenumber integer(I4B), intent(in) :: nrow integer(I4B), intent(in) :: ncol @@ -1488,7 +1494,7 @@ subroutine get_ijk(nodenumber, nrow, ncol, nlay, irow, icol, ilay) integer(I4B), intent(out) :: irow integer(I4B), intent(out) :: icol integer(I4B), intent(out) :: ilay - ! -- local + ! -- local variables integer(I4B) :: nodes integer(I4B) :: ij ! @@ -1512,13 +1518,13 @@ subroutine get_jk(nodenumber, ncpl, nlay, icpl, ilay) ! dimensions. If nodenumber is invalid, set irow, icol, and ! ilay to -1 implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: nodenumber integer(I4B), intent(in) :: ncpl integer(I4B), intent(in) :: nlay integer(I4B), intent(out) :: icpl integer(I4B), intent(out) :: ilay - ! -- local + ! -- local variables integer(I4B) :: nodes ! nodes = ncpl * nlay @@ -1534,9 +1540,9 @@ subroutine get_jk(nodenumber, ncpl, nlay, icpl, ilay) end subroutine get_jk subroutine unitinquire(iu) - ! -- dummy + ! -- dummy variables integer(I4B) :: iu - ! -- local + ! -- local variables character(len=LINELENGTH) :: line character(len=100) :: fname, ac, act, fm, frm, seq, unf ! -- format @@ -1567,13 +1573,13 @@ subroutine ParseLine(line, nwords, words, inunit, filename) ! are not recognized as delimiters. use ConstantsModule, only: LINELENGTH implicit none - ! -- dummy + ! -- dummy variables character(len=*), intent(in) :: line integer(I4B), intent(inout) :: nwords character(len=*), allocatable, dimension(:), intent(inout) :: words integer(I4B), intent(in), optional :: inunit character(len=*), intent(in), optional :: filename - ! -- local + ! -- local variables integer(I4B) :: i, idum, istart, istop, linelen, lloc real(DP) :: rdum ! @@ -1607,14 +1613,14 @@ subroutine ulaprufw(ncol, nrow, kstp, kper, ilay, iout, buf, text, userfmt, & ! Specifications: ! -------------------------------------------------------------------------- implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: ncol, nrow, kstp, kper, ilay, iout real(DP),dimension(ncol,nrow), intent(in) :: buf character(len=*), intent(in) :: text character(len=*), intent(in) :: userfmt integer(I4B), intent(in) :: nvalues, nwidth character(len=1), intent(in) :: editdesc - ! -- local + ! -- local variables integer(I4B) :: i, j, nspaces ! formats 1 format('1',/2X,A,' IN LAYER ',I3,' AT END OF TIME STEP ',I3, & @@ -1648,35 +1654,6 @@ subroutine ulaprufw(ncol, nrow, kstp, kper, ilay, iout, buf, text, userfmt, & return end subroutine ulaprufw - ! function linear_interpolate(t0, t1, y0, y1, t) result(y) - ! implicit none - ! ! -- dummy - ! real(DP), intent(in) :: t, t0, t1, y0, y1 - ! real(DP) :: y - ! ! -- local - ! real(DP) :: delt, dely, slope - ! character(len=100) :: msg - ! ! - ! ! -- don't get bitten by rounding errors or divide-by-zero - ! if (is_same(t0, t1) .or. is_same(t, t1)) then - ! y = y1 - ! elseif (t == t0) then - ! y = y0 - ! elseif ((t0 < t .and. t < t1) .or. (t1 < t .and. t < t0)) then - ! ! -- perform linear interpolation - ! delt = t1 - t0 - ! dely = y1 - y0 - ! slope = dely / delt - ! y = y0 + slope * (t - t0) - ! else - ! ! -- t is outside range t0 to t1 - ! msg = 'Error: in linear_interpolate, t is outside range t0 to t1' - ! call store_error(msg, terminate=.TRUE.) - ! endif - ! ! - ! return - ! end function linear_interpolate - function read_line(iu, eof) result (astring) ! This function reads a line of arbitrary length and returns ! it. The returned string can be stored in a deferred-length @@ -1690,11 +1667,11 @@ function read_line(iu, eof) result (astring) ! my_string = read_line(iu, eof) ! implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: iu logical, intent(out) :: eof character(len=:), allocatable :: astring - ! -- local + ! -- local variables integer(I4B) :: isize, istat character(len=256) :: buffer character(len=1000) :: ermsg, fname @@ -1746,10 +1723,10 @@ end function read_line subroutine GetFileFromPath(pathname, filename) implicit none - ! -- dummy + ! -- dummy variables character(len=*), intent(in) :: pathname character(len=*), intent(out) :: filename - ! -- local + ! -- local variables integer(I4B) :: i, istart, istop, lenpath character(len=1) :: fs = '/' character(len=1) :: bs = '\' @@ -1781,12 +1758,12 @@ subroutine extract_idnum_or_bndname(line, icol, istart, istop, idnum, bndname) ! If token is not an integer(I4B), assume it is a boundary name, return NAMEDBOUNDFLAG ! in idnum, convert string to uppercase and return it in bndname. implicit none - ! -- dummy + ! -- dummy variables character(len=*), intent(inout) :: line integer(I4B), intent(inout) :: icol, istart, istop integer(I4B), intent(out) :: idnum character(len=LENBOUNDNAME), intent(out) :: bndname - ! -- local + ! -- local variables integer(I4B) :: istat, ndum, ncode=0 real(DP) :: rdum ! @@ -1816,7 +1793,7 @@ subroutine urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text) use ConstantsModule, only: LENAUXNAME ! -- implicit implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(inout) :: naux integer(I4B), intent(in) :: inunit integer(I4B), intent(in) :: iout @@ -1826,8 +1803,9 @@ subroutine urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text) character(len=LENAUXNAME), allocatable, dimension(:), intent(inout) :: auxname character(len=*), intent(inout) :: line character(len=*), intent(in) :: text - ! -- local + ! -- local variables integer(I4B) :: n, linelen + integer(I4B) :: iauxlen real(DP) :: rval ! ------------------------------------------------------------------------------ linelen = len(line) @@ -1839,8 +1817,17 @@ subroutine urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text) endif auxloop: do call urword(line, lloc, istart, istop, 1, n, rval, iout, inunit) - !if(lloc >= linelen) exit auxloop if (istart >= linelen) exit auxloop + iauxlen = istop - istart + 1 + if (iauxlen > LENAUXNAME) then + write (errmsg, '(a, a, a, i0, a, i0, a)') & + 'Found auxiliary variable (', line(istart:istop), & + ') with a name of size ', iauxlen, & + '. Auxiliary variable names must be len than or equal& + & to ', LENAUXNAME, ' characters.' + call store_error(errmsg) + call store_error_unit(inunit) + end if naux = naux + 1 call ExpandArray(auxname) auxname(naux) = line(istart:istop) @@ -1849,7 +1836,8 @@ subroutine urdaux(naux, inunit, iout, lloc, istart, istop, auxname, line, text) trim(adjustl(text)), auxname(naux) endif enddo auxloop - + ! + return end subroutine urdaux subroutine print_format(linein, cdatafmp, editdesc, nvaluesp, nwidthp, inunit) @@ -1875,14 +1863,14 @@ subroutine print_format(linein, cdatafmp, editdesc, nvaluesp, nwidthp, inunit) ! A default value should be passed in for editdesc as G, I, E, F, or S. ! If I is passed in, then the fortran format will be for an integer variable. ! ------------------------------------------------------------------------------ - ! -- dummy + ! -- dummy variables character(len=*), intent(in) :: linein character(len=*), intent(inout) :: cdatafmp character(len=*), intent(inout) :: editdesc integer(I4B), intent(inout) :: nvaluesp integer(I4B), intent(inout) :: nwidthp integer(I4B), intent(in) :: inunit - ! -- local + ! -- local variables character(len=len(linein)) :: line character(len=20), dimension(:), allocatable :: words character(len=100) :: ermsg @@ -1997,11 +1985,11 @@ end subroutine print_format subroutine BuildFixedFormat(nvalsp, nwidp, ndig, outfmt, prowcolnum) ! Build a fixed format for printing or saving a real array implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: nvalsp, nwidp, ndig character(len=*), intent(inout) :: outfmt logical, intent(in), optional :: prowcolnum ! default true - ! -- local + ! -- local variables character(len=8) :: cvalues, cwidth, cdigits character(len=60) :: ufmt logical :: prowcolnumlocal @@ -2048,12 +2036,12 @@ end subroutine BuildFixedFormat subroutine BuildFloatFormat(nvalsp, nwidp, ndig, editdesc, outfmt, prowcolnum) ! Build a floating-point format for printing or saving a real array implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: nvalsp, nwidp, ndig character(len=*), intent(in) :: editdesc character(len=*), intent(inout) :: outfmt logical, intent(in), optional :: prowcolnum ! default true - ! -- local + ! -- local variables character(len=8) :: cvalues, cwidth, cdigits character(len=60) :: ufmt logical :: prowcolnumlocal @@ -2111,11 +2099,11 @@ end subroutine BuildFloatFormat subroutine BuildIntFormat(nvalsp, nwidp, outfmt, prowcolnum) ! Build a format for printing or saving an integer array implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: nvalsp, nwidp character(len=*), intent(inout) :: outfmt logical, intent(in), optional :: prowcolnum ! default true - ! -- local + ! -- local variables character(len=8) :: cvalues, cwidth character(len=60) :: ufmt logical :: prowcolnumlocal @@ -2152,18 +2140,17 @@ subroutine BuildIntFormat(nvalsp, nwidp, outfmt, prowcolnum) end subroutine BuildIntFormat + !> @brief Get the number of words in a string + !! + !! Function to get the number of words in a string + !! + !< function get_nwords(line) -! ****************************************************************************** -! get_nwords -- return number of words in a string -! ****************************************************************************** -! -! SPECIFICATIONS: -! ------------------------------------------------------------------------------ ! -- return variable - integer(I4B) :: get_nwords - ! -- dummy - character(len=*), intent(in) :: line - ! -- local + integer(I4B) :: get_nwords !< number of words in a string + ! -- dummy variables + character(len=*), intent(in) :: line !< line + ! -- local variables integer(I4B) :: linelen integer(I4B) :: lloc integer(I4B) :: istart @@ -2241,12 +2228,12 @@ subroutine u9rdcom(iin, iout, line, ierr) ! ------------------------------------------------------------------------------ use, intrinsic :: iso_fortran_env, only: IOSTAT_END implicit none - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: iin integer(I4B), intent(in) :: iout character (len=:), allocatable, intent(inout) :: line integer(I4B), intent(out) :: ierr - ! -- local definitions + ! -- local variables character (len=:), allocatable :: linetemp character (len=2), parameter :: comment = '//' character(len=1), parameter :: tab = CHAR(9) @@ -2341,11 +2328,11 @@ subroutine get_line(lun, line, iostat) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- dummy + ! -- dummy variables integer(I4B), intent(in) :: lun character(len=:), intent(out), allocatable :: line integer(I4B), intent(out) :: iostat - ! -- local + ! -- local variables integer(I4B), parameter :: buffer_len = MAXCHARLEN character(len=buffer_len) :: buffer character(len=:), allocatable :: linetemp diff --git a/src/Utilities/Iunit.f90 b/src/Utilities/Iunit.f90 index 41f968a1311..0f109a0fe47 100644 --- a/src/Utilities/Iunit.f90 +++ b/src/Utilities/Iunit.f90 @@ -2,7 +2,7 @@ ! -- assigned to a single package type, as shown below. ! -- row(i) cunit(i) iunit(i)%nval iunit(i)%iunit iunit(i)%ipos ! -- 1 BCF6 1 (1000) (1) -! -- 2 WEL 3 (1001,1003,1005) (2,5,7) +! -- 2 WEL 3 (1001,1003,1005) (2,5,7) ! -- 3 GHB 1 (1002) (4) ! -- 4 EVT 2 (1004,1006) (6,10) ! -- 5 RIV 0 () () @@ -19,8 +19,8 @@ module IunitModule type :: IunitRowType integer(I4B) :: nval = 0 - integer(I4B), allocatable, dimension(:) :: iunit ! unit numbers for this row - integer(I4B), allocatable, dimension(:) :: ipos ! position in the input files character array + integer(I4B), allocatable, dimension(:) :: iunit ! unit numbers for this row + integer(I4B), allocatable, dimension(:) :: ipos ! position in the input files character array end type IunitRowType type :: IunitType @@ -33,7 +33,7 @@ module IunitModule procedure :: getunitnumber end type IunitType - contains +contains subroutine init(this, niunit, cunit) ! ****************************************************************************** @@ -51,12 +51,12 @@ subroutine init(this, niunit, cunit) integer(I4B) :: i ! ------------------------------------------------------------------------------ ! - allocate(this%cunit(niunit)) - allocate(this%iunit(niunit)) + allocate (this%cunit(niunit)) + allocate (this%iunit(niunit)) this%niunit = niunit - do i=1,niunit - this%cunit(i)=cunit(i) - enddo + do i = 1, niunit + this%cunit(i) = cunit(i) + end do ! ! -- Return return @@ -86,41 +86,41 @@ subroutine addfile(this, ftyp, iunit, ipos, namefilename) ! -- Find the row containing ftyp irow = 0 do i = 1, this%niunit - if(this%cunit(i) == ftyp) then + if (this%cunit(i) == ftyp) then irow = i exit - endif - enddo - if(irow == 0) then - write(errmsg, '(a,a)') 'Package type not supported: ', ftyp + end if + end do + if (irow == 0) then + write (errmsg, '(a,a)') 'Package type not supported: ', ftyp call store_error(errmsg) call store_error_filename(namefilename, terminate=.TRUE.) - endif + end if ! ! -- Store the iunit number for this ftyp - if(this%iunit(irow)%nval == 0) then - allocate(this%iunit(irow)%iunit(1)) - allocate(this%iunit(irow)%ipos(1)) - this%iunit(irow)%nval=1 + if (this%iunit(irow)%nval == 0) then + allocate (this%iunit(irow)%iunit(1)) + allocate (this%iunit(irow)%ipos(1)) + this%iunit(irow)%nval = 1 else ! ! -- increase size of iunit - allocate(itemp(this%iunit(irow)%nval)) + allocate (itemp(this%iunit(irow)%nval)) itemp(:) = this%iunit(irow)%iunit(:) - deallocate(this%iunit(irow)%iunit) + deallocate (this%iunit(irow)%iunit) this%iunit(irow)%nval = this%iunit(irow)%nval + 1 - allocate(this%iunit(irow)%iunit(this%iunit(irow)%nval)) + allocate (this%iunit(irow)%iunit(this%iunit(irow)%nval)) this%iunit(irow)%iunit(1:this%iunit(irow)%nval - 1) = itemp(:) ! ! -- increase size of ipos itemp(:) = this%iunit(irow)%ipos(:) - deallocate(this%iunit(irow)%ipos) - allocate(this%iunit(irow)%ipos(this%iunit(irow)%nval)) + deallocate (this%iunit(irow)%ipos) + allocate (this%iunit(irow)%ipos(this%iunit(irow)%nval)) this%iunit(irow)%ipos(1:this%iunit(irow)%nval - 1) = itemp(:) ! ! -- cleanup temp - deallocate(itemp) - endif + deallocate (itemp) + end if this%iunit(irow)%iunit(this%iunit(irow)%nval) = iunit this%iunit(irow)%ipos(this%iunit(irow)%nval) = ipos ! @@ -146,26 +146,26 @@ subroutine getunitnumber(this, ftyp, iunit, iremove) ! -- Find the row irow = 0 do i = 1, this%niunit - if(this%cunit(i) == ftyp) then + if (this%cunit(i) == ftyp) then irow = i exit - endif - enddo + end if + end do ! ! -- Find the unit number. iunit = 0 - if(irow > 0) then + if (irow > 0) then nval = this%iunit(irow)%nval - if(nval > 0) then + if (nval > 0) then iunit = this%iunit(irow)%iunit(nval) - if(iremove > 0) then + if (iremove > 0) then this%iunit(irow)%iunit(nval) = 0 this%iunit(irow)%nval = nval - 1 - endif + end if else iunit = 0 - endif - endif + end if + end if end subroutine getunitnumber end module IunitModule diff --git a/src/Utilities/List.f90 b/src/Utilities/List.f90 index 6b4dc6d5999..dbd807b22ec 100644 --- a/src/Utilities/List.f90 +++ b/src/Utilities/List.f90 @@ -24,13 +24,13 @@ module ListModule procedure, public :: DeallocateBackward procedure, public :: GetNextItem procedure, public :: GetPreviousItem - generic, public :: GetItem => get_item_by_index, get_current_item + generic, public :: GetItem => get_item_by_index, get_current_item procedure, public :: InsertAfter procedure, public :: InsertBefore procedure, public :: Next procedure, public :: Previous procedure, public :: Reset - generic, public :: RemoveNode => remove_node_by_index, remove_this_node + generic, public :: RemoveNode => remove_node_by_index, remove_this_node ! -- Private procedures procedure, private :: get_current_item procedure, private :: get_item_by_index @@ -46,21 +46,21 @@ module ListModule type(ListNodeType), pointer, public :: nextNode => null() type(ListNodeType), pointer, public :: prevNode => null() ! -- Private members - class(*), pointer, private :: Value => null() + class(*), pointer, private :: Value => null() contains ! -- Public procedure - procedure, public :: GetItem + procedure, public :: GetItem ! -- Private procedures procedure, private :: DeallocValue end type ListNodeType - + interface function isEqualIface(obj1, obj2) result(isEqual) class(*), pointer :: obj1, obj2 logical :: isEqual end function end interface - + contains ! -- Public type-bound procedures for ListType @@ -72,16 +72,16 @@ subroutine Add(this, objptr) class(*), pointer, intent(inout) :: objptr ! if (.not. associated(this%firstNode)) then - allocate(this%firstNode) + allocate (this%firstNode) this%firstNode%Value => objptr this%firstNode%prevNode => null() this%lastNode => this%firstNode else - allocate(this%lastNode%nextNode) + allocate (this%lastNode%nextNode) this%lastNode%nextNode%prevNode => this%lastNode this%lastNode%nextNode%value => objptr this%lastNode => this%lastNode%nextNode - endif + end if this%nodeCount = this%nodeCount + 1 return end subroutine Add @@ -106,14 +106,14 @@ subroutine Clear(this, destroy) destroyLocal = .false. if (present(destroy)) then destroyLocal = destroy - endif + end if ! if (.not. associated(this%firstNode)) return ! -- The last node will be deallocated in the loop below. ! Just nullify the pointer to the last node to avoid ! having a dangling pointer. Also nullify currentNode. - nullify(this%lastNode) - nullify(this%currentNode) + nullify (this%lastNode) + nullify (this%currentNode) ! current => this%firstNode do while (associated(current)) @@ -122,12 +122,12 @@ subroutine Clear(this, destroy) ! -- Deallocate the object stored in the current node call current%DeallocValue(destroyLocal) ! -- Deallocate the current node - deallocate(current) + deallocate (current) this%firstNode => next this%nodeCount = this%nodeCount - 1 ! -- Advance to the next node current => next - enddo + end do ! call this%Reset() ! @@ -160,7 +160,7 @@ function ContainsObject(this, obj, isEqual) result(hasObj) logical :: hasObj ! local type(ListNodeType), pointer :: current => null() - + hasObj = .false. current => this%firstNode do while (associated(current)) @@ -168,21 +168,21 @@ function ContainsObject(this, obj, isEqual) result(hasObj) hasObj = .true. return end if - + ! -- Advance to the next node current => current%nextNode - enddo - + end do + ! this means there is no match return - end function - + end function + function arePointersEqual(obj1, obj2) result(areIdentical) class(*), pointer :: obj1, obj2 logical :: areIdentical - areIdentical = associated(obj1, obj2) + areIdentical = associated(obj1, obj2) end function arePointersEqual - + subroutine DeallocateBackward(this, fromNode) ! ************************************************************************** ! DeallocateBackward @@ -205,18 +205,18 @@ subroutine DeallocateBackward(this, fromNode) this%firstNode => fromNode%nextNode else this%firstNode => null() - endif + end if ! -- deallocate fromNode and all previous nodes current => fromNode do while (associated(current)) prev => current%prevNode call current%DeallocValue(.true.) - deallocate(current) + deallocate (current) this%nodeCount = this%nodeCount - 1 current => prev - enddo + end do fromNode => null() - endif + end if ! return end subroutine DeallocateBackward @@ -263,7 +263,7 @@ subroutine InsertAfter(this, objptr, indx) precedingNode => this%get_node_by_index(indx) if (associated(precedingNode%nextNode)) then followingNode => precedingNode%nextNode - allocate(newNode) + allocate (newNode) newNode%Value => objptr newNode%nextNode => followingNode newNode%prevNode => precedingNode @@ -271,11 +271,11 @@ subroutine InsertAfter(this, objptr, indx) followingNode%prevNode => newNode this%nodeCount = this%nodeCount + 1 else - write(line,'(a)') 'Programming error in ListType%insert_after' + write (line, '(a)') 'Programming error in ListType%insert_after' call sim_message(line) call stop_with_error(1) - endif - endif + end if + end if ! return end subroutine InsertAfter @@ -292,10 +292,10 @@ subroutine InsertBefore(this, objptr, targetNode) ! if (.not. associated(targetNode)) then stop 'Programming error, likely in call to ListType%InsertBefore' - endif + end if ! ! Allocate a new list node and point its Value member to the object - allocate(newNode) + allocate (newNode) newNode%Value => objptr ! ! Do the insertion @@ -308,7 +308,7 @@ subroutine InsertBefore(this, objptr, targetNode) ! Insert before first node this%firstNode => newNode newNode%prevNode => null() - endif + end if targetNode%prevNode => newNode this%nodeCount = this%nodeCount + 1 ! @@ -326,7 +326,7 @@ subroutine Next(this) else this%currentNode => null() this%currentNodeIndex = 0 - endif + end if else if (associated(this%currentNode%nextNode)) then this%currentNode => this%currentNode%nextNode @@ -334,8 +334,8 @@ subroutine Next(this) else this%currentNode => null() this%currentNodeIndex = 0 - endif - endif + end if + end if return end subroutine Next @@ -348,7 +348,7 @@ subroutine Previous(this) else this%currentNode => this%currentNode%prevNode this%currentNodeIndex = this%currentNodeIndex - 1 - endif + end if return end subroutine Previous @@ -365,8 +365,8 @@ subroutine remove_node_by_index(this, i, destroyValue) implicit none ! -- dummy class(ListType), intent(inout) :: this - integer(I4B), intent(in) :: i - logical, intent(in) :: destroyValue + integer(I4B), intent(in) :: i + logical, intent(in) :: destroyValue ! -- local type(ListNodeType), pointer :: node ! @@ -374,7 +374,7 @@ subroutine remove_node_by_index(this, i, destroyValue) node => this%get_node_by_index(i) if (associated(node)) then call this%remove_this_node(node, destroyValue) - endif + end if ! return end subroutine remove_node_by_index @@ -382,9 +382,9 @@ end subroutine remove_node_by_index subroutine remove_this_node(this, node, destroyValue) implicit none ! -- dummy - class(ListType), intent(inout) :: this + class(ListType), intent(inout) :: this type(ListNodeType), pointer, intent(inout) :: node - logical, intent(in) :: destroyValue + logical, intent(in) :: destroyValue ! -- local ! logical :: first, last @@ -398,32 +398,32 @@ subroutine remove_this_node(this, node, destroyValue) else node%prevNode%nextNode => null() this%lastNode => node%prevNode - endif + end if else first = .true. - endif + end if if (associated(node%nextNode)) then if (associated(node%prevNode)) then node%prevNode%nextNode => node%nextNode else node%nextNode%prevNode => null() this%firstNode => node%nextNode - endif + end if else last = .true. - endif + end if if (destroyValue) then call node%DeallocValue(destroyValue) - endif - deallocate(node) + end if + deallocate (node) this%nodeCount = this%nodeCount - 1 if (first .and. last) then this%firstNode => null() this%lastNode => null() this%currentNode => null() - endif + end if call this%Reset() - endif + end if ! return end subroutine remove_this_node @@ -439,7 +439,7 @@ function get_current_item(this) result(resultobj) resultobj => null() if (associated(this%currentNode)) then resultobj => this%currentNode%Value - endif + end if return end function get_current_item @@ -466,13 +466,13 @@ function get_item_by_index(this, indx) result(resultobj) ! -- Ensure that this%currentNode is associated if (.not. associated(this%currentNode)) then this%currentNodeIndex = 0 - endif + end if if (this%currentNodeIndex == 0) then if (associated(this%firstNode)) then this%currentNode => this%firstNode this%currentNodeIndex = 1 - endif - endif + end if + end if ! ! -- Check indx position relative to current node index i = 0 @@ -483,28 +483,28 @@ function get_item_by_index(this, indx) result(resultobj) this%currentNode => this%firstNode this%currentNodeIndex = 1 i = 1 - endif + end if else i = this%currentNodeIndex - endif + end if if (i == 0) return ! ! -- If current node is requested node, ! assign pointer and return - if (i==indx) then + if (i == indx) then resultobj => this%currentNode%Value return - endif + end if ! ! -- Iterate from current node to requested node do while (associated(this%currentNode%nextNode)) this%currentNode => this%currentNode%nextNode this%currentNodeIndex = this%currentNodeIndex + 1 - if (this%currentNodeIndex==indx) then + if (this%currentNodeIndex == indx) then resultobj => this%currentNode%Value return - endif - enddo + end if + end do return end function get_item_by_index @@ -533,8 +533,8 @@ function get_node_by_index(this, indx) result(resultnode) if (associated(this%firstNode)) then this%currentNode => this%firstNode this%currentNodeIndex = 1 - endif - endif + end if + end if ! ! -- Check indx position relative to current node index i = 0 @@ -545,28 +545,28 @@ function get_node_by_index(this, indx) result(resultnode) this%currentNode => this%firstNode this%currentNodeIndex = 1 i = 1 - endif + end if else i = this%currentNodeIndex - endif + end if if (i == 0) return ! ! -- If current node is requested node, ! assign pointer and return - if (i==indx) then + if (i == indx) then resultnode => this%currentNode return - endif + end if ! ! -- Iterate from current node to requested node do while (associated(this%currentNode%nextNode)) this%currentNode => this%currentNode%nextNode this%currentNodeIndex = this%currentNodeIndex + 1 - if (this%currentNodeIndex==indx) then + if (this%currentNodeIndex == indx) then resultnode => this%currentNode return - endif - enddo + end if + end do return end function get_node_by_index @@ -602,11 +602,11 @@ subroutine DeallocValue(this, destroy) if (associated(this%Value)) then if (present(destroy)) then if (destroy) then - deallocate(this%Value) - endif - endif - nullify(this%Value) - endif + deallocate (this%Value) + end if + end if + nullify (this%Value) + end if return end subroutine DeallocValue diff --git a/src/Utilities/ListReader.f90 b/src/Utilities/ListReader.f90 index 8e97e0746ac..d40943f2e31 100644 --- a/src/Utilities/ListReader.f90 +++ b/src/Utilities/ListReader.f90 @@ -4,54 +4,54 @@ module ListReaderModule use KindModule, only: DP, I4B use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, LENTIMESERIESNAME, & LENAUXNAME, LENLISTLABEL, DONE - use SimModule, only: store_error_unit + use SimModule, only: store_error_unit implicit none private public ListReaderType - + type :: ListReaderType - integer(I4B) :: in = 0 ! unit number of file containing control record - integer(I4B) :: inlist = 0 ! unit number of file from which list will be read - integer(I4B) :: iout = 0 ! unit number to output messages - integer(I4B) :: inamedbound = 0 ! flag indicating boundary names are to be read - integer(I4B) :: ierr = 0 ! error flag - integer(I4B) :: nlist = 0 ! number of entries in list. -1 indicates number will be automatically determined - integer(I4B) :: ibinary = 0 ! flag indicating to read binary list - integer(I4B) :: istart = 0 ! string starting location - integer(I4B) :: istop = 0 ! string ending location - integer(I4B) :: lloc = 0 ! entry number in line - integer(I4B) :: iclose = 0 ! flag indicating whether or not to close file - integer(I4B) :: ndim = 0 ! number of dimensions in model - integer(I4B) :: ntxtrlist = 0 ! number of text entries found in rlist - integer(I4B) :: ntxtauxvar = 0 ! number of text entries found in auxvar - character(len=LENLISTLABEL) :: label = '' ! label for printing list - character(len=:), allocatable, private :: line ! current line - integer(I4B), dimension(:), pointer, contiguous :: mshape => null() ! pointer to model shape - integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() ! pointer to nodelist - real(DP), dimension(:, :), pointer, contiguous :: rlist => null() ! pointer to rlist - real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() ! pointer to auxvar - character(len=16), dimension(:), pointer :: auxname => null() ! pointer to aux names - character(len=LENBOUNDNAME), dimension(:), pointer, & - contiguous :: boundname => null() ! pointer to boundname - integer(I4B), dimension(:), allocatable :: idxtxtrow ! row locations of text in rlist - integer(I4B), dimension(:), allocatable :: idxtxtcol ! col locations of text in rlist - integer(I4B), dimension(:), allocatable :: idxtxtauxrow ! row locations of text in auxvar - integer(I4B), dimension(:), allocatable :: idxtxtauxcol ! col locations of text in auxvar - character(len=LENTIMESERIESNAME), dimension(:), allocatable :: txtrlist ! text found in rlist - character(len=LENTIMESERIESNAME), dimension(:), allocatable :: txtauxvar ! text found in auxvar + integer(I4B) :: in = 0 ! unit number of file containing control record + integer(I4B) :: inlist = 0 ! unit number of file from which list will be read + integer(I4B) :: iout = 0 ! unit number to output messages + integer(I4B) :: inamedbound = 0 ! flag indicating boundary names are to be read + integer(I4B) :: ierr = 0 ! error flag + integer(I4B) :: nlist = 0 ! number of entries in list. -1 indicates number will be automatically determined + integer(I4B) :: ibinary = 0 ! flag indicating to read binary list + integer(I4B) :: istart = 0 ! string starting location + integer(I4B) :: istop = 0 ! string ending location + integer(I4B) :: lloc = 0 ! entry number in line + integer(I4B) :: iclose = 0 ! flag indicating whether or not to close file + integer(I4B) :: ndim = 0 ! number of dimensions in model + integer(I4B) :: ntxtrlist = 0 ! number of text entries found in rlist + integer(I4B) :: ntxtauxvar = 0 ! number of text entries found in auxvar + character(len=LENLISTLABEL) :: label = '' ! label for printing list + character(len=:), allocatable, private :: line ! current line + integer(I4B), dimension(:), pointer, contiguous :: mshape => null() ! pointer to model shape + integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() ! pointer to nodelist + real(DP), dimension(:, :), pointer, contiguous :: rlist => null() ! pointer to rlist + real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() ! pointer to auxvar + character(len=16), dimension(:), pointer :: auxname => null() ! pointer to aux names + character(len=LENBOUNDNAME), dimension(:), pointer, & + contiguous :: boundname => null() ! pointer to boundname + integer(I4B), dimension(:), allocatable :: idxtxtrow ! row locations of text in rlist + integer(I4B), dimension(:), allocatable :: idxtxtcol ! col locations of text in rlist + integer(I4B), dimension(:), allocatable :: idxtxtauxrow ! row locations of text in auxvar + integer(I4B), dimension(:), allocatable :: idxtxtauxcol ! col locations of text in auxvar + character(len=LENTIMESERIESNAME), dimension(:), allocatable :: txtrlist ! text found in rlist + character(len=LENTIMESERIESNAME), dimension(:), allocatable :: txtauxvar ! text found in auxvar contains - procedure :: read_list - procedure :: write_list + procedure :: read_list + procedure :: write_list procedure, private :: read_control_record procedure, private :: read_data procedure, private :: set_openclose procedure, private :: read_ascii procedure, private :: read_binary end type ListReaderType - - contains - - subroutine read_list(this, in, iout, nlist, inamedbound, mshape, nodelist, & + +contains + + subroutine read_list(this, in, iout, nlist, inamedbound, mshape, nodelist, & rlist, auxvar, auxname, boundname, label) ! ****************************************************************************** ! init -- Initialize the reader @@ -72,7 +72,8 @@ subroutine read_list(this, in, iout, nlist, inamedbound, mshape, nodelist, & real(DP), dimension(:, :), intent(inout), contiguous, pointer :: rlist real(DP), dimension(:, :), intent(inout), contiguous, pointer :: auxvar character(len=LENAUXNAME), dimension(:), intent(inout), target :: auxname - character(len=LENBOUNDNAME), dimension(:), pointer, contiguous, intent(inout) :: boundname + character(len=LENBOUNDNAME), & + dimension(:), pointer, contiguous, intent(inout) :: boundname character(len=LENLISTLABEL), intent(in) :: label ! -- local ! ------------------------------------------------------------------------------ @@ -94,12 +95,12 @@ subroutine read_list(this, in, iout, nlist, inamedbound, mshape, nodelist, & this%boundname => boundname ! ! -- Allocate arrays for storing text and text locations - if(.not. allocated(this%idxtxtrow)) allocate(this%idxtxtrow(0)) - if(.not. allocated(this%idxtxtcol)) allocate(this%idxtxtcol(0)) - if(.not. allocated(this%idxtxtauxrow)) allocate(this%idxtxtauxrow(0)) - if(.not. allocated(this%idxtxtauxcol)) allocate(this%idxtxtauxcol(0)) - if(.not. allocated(this%txtrlist)) allocate(this%txtrlist(0)) - if(.not. allocated(this%txtauxvar)) allocate(this%txtauxvar(0)) + if (.not. allocated(this%idxtxtrow)) allocate (this%idxtxtrow(0)) + if (.not. allocated(this%idxtxtcol)) allocate (this%idxtxtcol(0)) + if (.not. allocated(this%idxtxtauxrow)) allocate (this%idxtxtauxrow(0)) + if (.not. allocated(this%idxtxtauxcol)) allocate (this%idxtxtauxcol(0)) + if (.not. allocated(this%txtrlist)) allocate (this%txtrlist(0)) + if (.not. allocated(this%txtauxvar)) allocate (this%txtauxvar(0)) ! ! -- Read control record call this%read_control_record() @@ -113,7 +114,7 @@ subroutine read_list(this, in, iout, nlist, inamedbound, mshape, nodelist, & ! -- return return end subroutine read_list - + subroutine read_control_record(this) ! ****************************************************************************** ! read_control_record -- Check for a control record, and parse if found @@ -130,7 +131,7 @@ subroutine read_control_record(this) real(DP) :: r ! -- formats character(len=*), parameter :: fmtlsf = & - "(1X,'LIST SCALING FACTOR=',1PG12.5)" + "(1X,'LIST SCALING FACTOR=',1PG12.5)" ! ------------------------------------------------------------------------------ ! ! -- Set default values, which may be changed by control record @@ -141,19 +142,19 @@ subroutine read_control_record(this) ! -- Read to the first non-commented line call u9rdcom(this%in, this%iout, this%line, this%ierr) this%lloc = 1 - call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & + call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & this%iout, this%in) ! ! -- Parse record - select case(this%line(this%istart:this%istop)) - case('OPEN/CLOSE') + select case (this%line(this%istart:this%istop)) + case ('OPEN/CLOSE') call this%set_openclose() end select ! ! -- return return end subroutine read_control_record - + subroutine set_openclose(this) ! ****************************************************************************** ! set_openclose -- set up for open/close file @@ -179,54 +180,54 @@ subroutine set_openclose(this) character(len=LINELENGTH) :: errmsg ! -- formats character(len=*), parameter :: fmtocne = & - "('Specified OPEN/CLOSE file ',(A),' does not exist')" + &"('Specified OPEN/CLOSE file ',(A),' does not exist')" character(len=*), parameter :: fmtobf = & - "(1X,/1X,'OPENING BINARY FILE ON UNIT ',I0,':',/1X,A)" + &"(1X,/1X,'OPENING BINARY FILE ON UNIT ',I0,':',/1X,A)" character(len=*), parameter :: fmtobfnlist = & - "(1X, 'TO READ ', I0, ' RECORDS.')" + &"(1X, 'TO READ ', I0, ' RECORDS.')" character(len=*), parameter :: fmtofnlist = & - "(1x,'TO READ ', I0, ' RECORDS.')" + &"(1x,'TO READ ', I0, ' RECORDS.')" character(len=*), parameter :: fmtof = & - "(1X,/1X,'OPENING FILE ON UNIT ',I0,':',/1X,A)" + &"(1X,/1X,'OPENING FILE ON UNIT ',I0,':',/1X,A)" ! ------------------------------------------------------------------------------ ! ! -- get filename - call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, r, & + call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, r, & this%iout, this%in) fname = this%line(this%istart:this%istop) ! ! -- check to see if file OPEN/CLOSE file exists - inquire(file=fname, exist=exists) + inquire (file=fname, exist=exists) if (.not. exists) then - write(errmsg, fmtocne) this%line(this%istart:this%istop) + write (errmsg, fmtocne) this%line(this%istart:this%istop) call store_error(errmsg) call store_error('Specified OPEN/CLOSE file does not exist') call store_error_unit(this%in) - endif + end if ! ! -- Check for (BINARY) keyword - call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & + call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & this%iout, this%in) - if(this%line(this%istart:this%istop) == '(BINARY)') this%ibinary = 1 + if (this%line(this%istart:this%istop) == '(BINARY)') this%ibinary = 1 ! ! -- Open the file depending on ibinary flag this%inlist = nunopn - if(this%ibinary == 1) then + if (this%ibinary == 1) then itmp = this%iout - if(this%iout > 0) then + if (this%iout > 0) then itmp = 0 - write(this%iout, fmtobf) this%inlist, trim(adjustl(fname)) - if(this%nlist > 0) write(this%iout, fmtobfnlist) this%nlist - endif - call openfile(this%inlist, itmp, fname, 'OPEN/CLOSE', fmtarg_opt=form, & + write (this%iout, fmtobf) this%inlist, trim(adjustl(fname)) + if (this%nlist > 0) write (this%iout, fmtobfnlist) this%nlist + end if + call openfile(this%inlist, itmp, fname, 'OPEN/CLOSE', fmtarg_opt=form, & accarg_opt=access) else itmp = this%iout - if(this%iout > 0) then + if (this%iout > 0) then itmp = 0 - write(this%iout, fmtof) this%inlist, trim(adjustl(fname)) - if(this%nlist > 0) write(this%iout, fmtofnlist) this%nlist - endif + write (this%iout, fmtof) this%inlist, trim(adjustl(fname)) + if (this%nlist > 0) write (this%iout, fmtofnlist) this%nlist + end if call openfile(this%inlist, itmp, fname, 'OPEN/CLOSE') end if ! @@ -236,13 +237,13 @@ subroutine set_openclose(this) ! ! -- Read the first line from inlist to be consistent with how the list is ! read when it is included in the package input file - if(this%ibinary /= 1) call u9rdcom(this%inlist, this%iout, this%line, & - this%ierr) + if (this%ibinary /= 1) call u9rdcom(this%inlist, this%iout, this%line, & + this%ierr) ! ! -- return return end subroutine set_openclose - + subroutine read_data(this) ! ****************************************************************************** ! read_data -- read the data @@ -258,20 +259,20 @@ subroutine read_data(this) ! ------------------------------------------------------------------------------ ! ! -- Read the list - if(this%ibinary == 1) then + if (this%ibinary == 1) then call this%read_binary() else call this%read_ascii() - endif + end if ! ! -- if open/close, then close file - if(this%iclose == 1) then - close(this%inlist) - endif + if (this%iclose == 1) then + close (this%inlist) + end if ! -- return return end subroutine read_data - + subroutine read_binary(this) ! ****************************************************************************** ! read_binary -- read the data from a binary file @@ -292,14 +293,14 @@ subroutine read_binary(this) integer(I4B), dimension(:), allocatable :: cellid ! -- formats character(len=*), parameter :: fmtmxlsterronly = & - "('ERROR READING LIST FROM FILE: '," // & - "a,' ON UNIT: ',I0," // & - "' THE NUMBER OF RECORDS ENCOUNTERED EXCEEDS THE MAXIMUM NUMBER " // & - "OF RECORDS. TRY INCREASING MAXBOUND FOR THIS LIST." // & - " NUMBER OF RECORDS: ',I0,' MAXBOUND: ',I0)" + "('ERROR READING LIST FROM FILE: ',& + &a,' ON UNIT: ',I0,& + &' THE NUMBER OF RECORDS ENCOUNTERED EXCEEDS THE MAXIMUM NUMBER & + &OF RECORDS. TRY INCREASING MAXBOUND FOR THIS LIST.& + & NUMBER OF RECORDS: ',I0,' MAXBOUND: ',I0)" character(len=*), parameter :: fmtlsterronly = & - "('ERROR READING LIST FROM FILE: '," // & - "1x,a,1x,' ON UNIT: ',I0)" + "('ERROR READING LIST FROM FILE: ',& + &1x,a,1x,' ON UNIT: ',I0)" ! ------------------------------------------------------------------------------ ! ! -- determine array sizes @@ -308,74 +309,74 @@ subroutine read_binary(this) naux = size(this%auxvar, 1) ! ! -- Allocate arrays - allocate(cellid(this%ndim)) + allocate (cellid(this%ndim)) ! ii = 1 readloop: do ! ! -- read layer, row, col, or cell number - read(this%inlist, iostat=this%ierr) cellid + read (this%inlist, iostat=this%ierr) cellid ! -- If not end of record, then store nodenumber, else ! calculate lstend and nlist, and exit readloop - select case(this%ierr) - case(0) + select case (this%ierr) + case (0) ! ! -- Check range - if(ii > mxlist) then - inquire(unit=this%inlist, name=fname) - write(errmsg, fmtmxlsterronly) fname, this%inlist, ii, mxlist + if (ii > mxlist) then + inquire (unit=this%inlist, name=fname) + write (errmsg, fmtmxlsterronly) fname, this%inlist, ii, mxlist call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- Store node number and read the remainder of the record - if(this%ndim == 1) then + if (this%ndim == 1) then nod = cellid(1) - elseif(this%ndim == 2) then - nod = get_node(cellid(1), 1, cellid(2), & + elseif (this%ndim == 2) then + nod = get_node(cellid(1), 1, cellid(2), & this%mshape(1), 1, this%mshape(2)) else - nod = get_node(cellid(1), cellid(2), cellid(3), & + nod = get_node(cellid(1), cellid(2), cellid(3), & this%mshape(1), this%mshape(2), this%mshape(3)) - endif + end if this%nodelist(ii) = nod - read(this%inlist, iostat=this%ierr) (this%rlist(jj,ii),jj=1,ldim), & - (this%auxvar(ii,jj),jj=1,naux) - if(this%ierr /= 0) then - inquire(unit=this%inlist, name=fname) - write(errmsg, fmtlsterronly) trim(adjustl(fname)), this%inlist + read (this%inlist, iostat=this%ierr) (this%rlist(jj, ii), jj=1, ldim), & + (this%auxvar(ii, jj), jj=1, naux) + if (this%ierr /= 0) then + inquire (unit=this%inlist, name=fname) + write (errmsg, fmtlsterronly) trim(adjustl(fname)), this%inlist call store_error(errmsg, terminate=.TRUE.) - endif + end if ! - case(:-1) + case (:-1) ! ! -- End of record was encountered this%nlist = ii - 1 exit readloop ! - case(1:) + case (1:) ! ! -- Error - inquire(unit=this%inlist, name=fname) - write(errmsg, fmtlsterronly) trim(adjustl(fname)), this%inlist + inquire (unit=this%inlist, name=fname) + write (errmsg, fmtlsterronly) trim(adjustl(fname)), this%inlist call store_error(errmsg, terminate=.TRUE.) ! end select ! ! -- If nlist is known, then exit when nlist values have been read - if(this%nlist > 0) then - if(ii == this%nlist) exit readloop - endif + if (this%nlist > 0) then + if (ii == this%nlist) exit readloop + end if ! ! -- increment ii ii = ii + 1 ! - enddo readloop + end do readloop ! ! -- return return end subroutine read_binary - + subroutine read_ascii(this) ! ****************************************************************************** ! read_ascii -- read the data from an ascii file @@ -390,7 +391,7 @@ subroutine read_ascii(this) use ArrayHandlersModule, only: ExpandArray ! -- dummy class(ListReaderType) :: this - ! -- local + ! -- local integer(I4B) :: mxlist, ldim, naux integer(I4B) :: ii, jj, idum, nod, istat, increment real(DP) :: r @@ -400,8 +401,8 @@ subroutine read_ascii(this) ! -- formats character(len=*), parameter :: fmtmxlsterronly = & "('***ERROR READING LIST. & - &THE NUMBER OF RECORDS ENCOUNTERED EXCEEDS THE MAXIMUM NUMBER " // & - "OF RECORDS. TRY INCREASING MAXBOUND FOR THIS LIST." // & + &THE NUMBER OF RECORDS ENCOUNTERED EXCEEDS THE MAXIMUM NUMBER "// & + "OF RECORDS. TRY INCREASING MAXBOUND FOR THIS LIST."// & " NUMBER OF RECORDS: ',I0,' MAXBOUND: ',I0)" ! ------------------------------------------------------------------------------ ! @@ -413,116 +414,116 @@ subroutine read_ascii(this) this%ntxtauxvar = 0 ! ! -- Allocate arrays - allocate(cellid(this%ndim)) + allocate (cellid(this%ndim)) ! ii = 1 readloop: do ! ! -- First line was already read, so don't read again - if(ii /= 1) call u9rdcom(this%inlist, 0, this%line, this%ierr) + if (ii /= 1) call u9rdcom(this%inlist, 0, this%line, this%ierr) ! ! -- If this is an unknown-length list, then check for END. ! If found, then backspace, set nlist, and exit readloop. - if(this%nlist < 0) then + if (this%nlist < 0) then this%lloc = 1 call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & this%iout, this%inlist) - if(this%line(this%istart:this%istop) == 'END' .or. this%ierr < 0) then + if (this%line(this%istart:this%istop) == 'END' .or. this%ierr < 0) then ! If ierr < 0, backspace was already performed in u9rdcom, so only ! need to backspace if END was found. if (this%ierr == 0) then - backspace(this%inlist) - endif + backspace (this%inlist) + end if this%nlist = ii - 1 exit readloop - endif - endif + end if + end if ! ! -- Check range - if(ii > mxlist) then - inquire(unit=this%inlist, name=fname) - write(errmsg, fmtmxlsterronly) ii, mxlist + if (ii > mxlist) then + inquire (unit=this%inlist, name=fname) + write (errmsg, fmtmxlsterronly) ii, mxlist call store_error(errmsg) - errmsg = 'Error occurred reading line: ' // trim(this%line) + errmsg = 'Error occurred reading line: '//trim(this%line) call store_error(errmsg) call store_error_unit(this%inlist) - endif + end if ! ! -- Read layer, row, column or cell number and assign to nodelist this%lloc = 1 - if(this%ndim == 3) then + if (this%ndim == 3) then ! ! -- Grid is structured; read layer, row, column - call urword(this%line, this%lloc, this%istart, this%istop, 2, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, & cellid(1), r, this%iout, this%inlist) - call urword(this%line, this%lloc, this%istart, this%istop, 2, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, & cellid(2), r, this%iout, this%inlist) - call urword(this%line, this%lloc, this%istart, this%istop, 2, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, & cellid(3), r, this%iout, this%inlist) ! ! -- Check for illegal grid location - if(cellid(1) < 1 .or. cellid(1) > this%mshape(1)) then - write(errmsg, *) ' Layer number in list is outside of the grid', & - cellid(1) - call store_error(errmsg) + if (cellid(1) < 1 .or. cellid(1) > this%mshape(1)) then + write (errmsg, *) ' Layer number in list is outside of the grid', & + cellid(1) + call store_error(errmsg) end if - if(cellid(2) < 1 .or. cellid(2) > this%mshape(2)) then - write(errmsg, *) ' Row number in list is outside of the grid', & - cellid(2) - call store_error(errmsg) + if (cellid(2) < 1 .or. cellid(2) > this%mshape(2)) then + write (errmsg, *) ' Row number in list is outside of the grid', & + cellid(2) + call store_error(errmsg) end if - if(cellid(3) < 1 .or. cellid(3) > this%mshape(3)) then - write(errmsg, *) ' Column number in list is outside of the grid', & - cellid(3) - call store_error(errmsg) + if (cellid(3) < 1 .or. cellid(3) > this%mshape(3)) then + write (errmsg, *) ' Column number in list is outside of the grid', & + cellid(3) + call store_error(errmsg) end if ! ! -- Calculate nodenumber and put in nodelist - nod = get_node(cellid(1), cellid(2), cellid(3), & + nod = get_node(cellid(1), cellid(2), cellid(3), & this%mshape(1), this%mshape(2), this%mshape(3)) - elseif(this%ndim == 2) then + elseif (this%ndim == 2) then ! ! -- Grid is disv - call urword(this%line, this%lloc, this%istart, this%istop, 2, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, & cellid(1), r, this%iout, this%inlist) - call urword(this%line, this%lloc, this%istart, this%istop, 2, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, & cellid(2), r, this%iout, this%inlist) ! ! -- Check for illegal grid location - if(cellid(1) < 1 .or. cellid(1) > this%mshape(1)) then - write(errmsg, *) ' Layer number in list is outside of the grid', & - cellid(1) - call store_error(errmsg) + if (cellid(1) < 1 .or. cellid(1) > this%mshape(1)) then + write (errmsg, *) ' Layer number in list is outside of the grid', & + cellid(1) + call store_error(errmsg) end if - if(cellid(2) < 1 .or. cellid(2) > this%mshape(2)) then - write(errmsg, *) ' Cell2d number in list is outside of the grid', & - cellid(2) - call store_error(errmsg) + if (cellid(2) < 1 .or. cellid(2) > this%mshape(2)) then + write (errmsg, *) ' Cell2d number in list is outside of the grid', & + cellid(2) + call store_error(errmsg) end if ! ! -- Calculate nodenumber and put in nodelist - nod = get_node(cellid(1), 1, cellid(2), & + nod = get_node(cellid(1), 1, cellid(2), & this%mshape(1), 1, this%mshape(2)) else ! ! -- Grid is unstructured; read layer and celld2d number - call urword(this%line, this%lloc, this%istart, this%istop, 2, nod, r, & + call urword(this%line, this%lloc, this%istart, this%istop, 2, nod, r, & this%iout, this%inlist) - if(nod < 1 .or. nod > this%mshape(1)) then - write(errmsg, *) ' Node number in list is outside of the grid', nod - call store_error(errmsg) + if (nod < 1 .or. nod > this%mshape(1)) then + write (errmsg, *) ' Node number in list is outside of the grid', nod + call store_error(errmsg) end if ! - endif + end if ! ! -- Assign nod to nodelist this%nodelist(ii) = nod ! ! -- Read rlist do jj = 1, ldim - call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, & + call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, & r, this%iout, this%inlist) - read(this%line(this%istart:this%istop), *, iostat=istat) r + read (this%line(this%istart:this%istop), *, iostat=istat) r ! ! -- If a double precision value, then store in rlist, otherwise store ! the text name and location @@ -531,25 +532,25 @@ subroutine read_ascii(this) else this%rlist(jj, ii) = DZERO this%ntxtrlist = this%ntxtrlist + 1 - if(this%ntxtrlist > size(this%txtrlist)) then + if (this%ntxtrlist > size(this%txtrlist)) then increment = int(size(this%txtrlist) * 0.2) increment = max(100, increment) call ExpandArray(this%txtrlist, increment) call ExpandArray(this%idxtxtrow, increment) call ExpandArray(this%idxtxtcol, increment) - endif + end if this%txtrlist(this%ntxtrlist) = this%line(this%istart:this%istop) this%idxtxtrow(this%ntxtrlist) = ii this%idxtxtcol(this%ntxtrlist) = jj - endif + end if ! - enddo + end do ! ! -- Read auxvar do jj = 1, naux - call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, & + call urword(this%line, this%lloc, this%istart, this%istop, 0, idum, & r, this%iout, this%inlist) - read(this%line(this%istart:this%istop), *, iostat=istat) r + read (this%line(this%istart:this%istop), *, iostat=istat) r ! ! -- If a double precision value, then store in auxvar, otherwise store ! the text name and location @@ -558,46 +559,46 @@ subroutine read_ascii(this) else this%auxvar(jj, ii) = DZERO this%ntxtauxvar = this%ntxtauxvar + 1 - if(this%ntxtauxvar > size(this%txtauxvar)) then + if (this%ntxtauxvar > size(this%txtauxvar)) then increment = int(size(this%txtauxvar) * 0.2) increment = max(100, increment) call ExpandArray(this%txtauxvar, increment) call ExpandArray(this%idxtxtauxrow, increment) call ExpandArray(this%idxtxtauxcol, increment) - endif + end if this%txtauxvar(this%ntxtauxvar) = this%line(this%istart:this%istop) this%idxtxtauxrow(this%ntxtauxvar) = ii this%idxtxtauxcol(this%ntxtauxvar) = jj - endif + end if ! - enddo + end do ! ! -- Read the boundary names (only supported for ascii input) if (this%inamedbound > 0) then call urword(this%line, this%lloc, this%istart, this%istop, 1, idum, r, & this%iout, this%inlist) this%boundname(ii) = this%line(this%istart:this%istop) - endif + end if ! ! -- If nlist is known, then exit when nlist values have been read - if(this%nlist > 0) then - if(ii == this%nlist) exit readloop - endif + if (this%nlist > 0) then + if (ii == this%nlist) exit readloop + end if ! ! -- increment ii row counter ii = ii + 1 ! - enddo readloop + end do readloop ! ! -- Stop if errors were detected - if(count_errors() > 0) then + if (count_errors() > 0) then call store_error_unit(this%inlist) - endif + end if ! ! -- return return end subroutine read_ascii - + subroutine write_list(this) ! ****************************************************************************** ! write_list -- Write input data to a list @@ -606,7 +607,7 @@ subroutine write_list(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- modules - use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, & + use ConstantsModule, only: LINELENGTH, LENBOUNDNAME, & TABLEFT, TABCENTER use InputOutputModule, only: ulstlb, get_ijk use TableModule, only: TableType, table_cr @@ -638,51 +639,51 @@ subroutine write_list(this) ! contains the column headers (except for boundname and auxnames) ipos = index(this%label, 'NO.') if (ipos /= 0) then - write(cpos,'(i10)') ipos + 3 - fmtlstbn = '(a' // trim(adjustl(cpos)) + write (cpos, '(i10)') ipos + 3 + fmtlstbn = '(a'//trim(adjustl(cpos)) else fmtlstbn = '(a7' end if ! -- sequence number, layer, row, and column. - if(size(this%mshape) == 3) then + if (size(this%mshape) == 3) then ntabcols = 4 - fmtlstbn = trim(fmtlstbn) // ',a7,a7,a7' - ! - ! -- sequence number, layer, and cell2d. - else if(size(this%mshape) == 2) then + fmtlstbn = trim(fmtlstbn)//',a7,a7,a7' + ! + ! -- sequence number, layer, and cell2d. + else if (size(this%mshape) == 2) then ntabcols = 3 - fmtlstbn = trim(fmtlstbn) // ',a7,a7' - ! - ! -- sequence number and node. + fmtlstbn = trim(fmtlstbn)//',a7,a7' + ! + ! -- sequence number and node. else ntabcols = 2 - fmtlstbn = trim(fmtlstbn) // ',a7' + fmtlstbn = trim(fmtlstbn)//',a7' end if ! ! -- Add fields for non-optional real values ntabcols = ntabcols + ldim do i = 1, ldim - fmtlstbn = trim(fmtlstbn) // ',a16' + fmtlstbn = trim(fmtlstbn)//',a16' end do ! ! -- Add field for boundary name if (this%inamedbound == 1) then ntabcols = ntabcols + 1 - fmtlstbn = trim(fmtlstbn) // ',a16' + fmtlstbn = trim(fmtlstbn)//',a16' end if ! ! -- Add fields for auxiliary variables ntabcols = ntabcols + naux do i = 1, naux - fmtlstbn = trim(fmtlstbn) // ',a16' + fmtlstbn = trim(fmtlstbn)//',a16' end do - fmtlstbn = trim(fmtlstbn) // ')' + fmtlstbn = trim(fmtlstbn)//')' ! ! -- allocate words - allocate(words(ntabcols)) + allocate (words(ntabcols)) ! ! -- parse this%label into words - read(this%label, fmtlstbn) (words(i), i=1, ntabcols) + read (this%label, fmtlstbn) (words(i), i=1, ntabcols) ! ! -- initialize the input table object call table_cr(inputtab, ' ', ' ') @@ -723,7 +724,7 @@ subroutine write_list(this) ! -- discretization if (size(this%mshape) == 3) then nod = this%nodelist(ii) - call get_ijk(nod, this%mshape(2), this%mshape(3), this%mshape(1), & + call get_ijk(nod, this%mshape(2), this%mshape(3), this%mshape(1), & i, j, k) call inputtab%add_term(k) call inputtab%add_term(i) @@ -740,7 +741,7 @@ subroutine write_list(this) ! ! -- non-optional variables do jj = 1, ldim - call inputtab%add_term(this%rlist(jj,ii)) + call inputtab%add_term(this%rlist(jj, ii)) end do ! ! -- boundname @@ -750,18 +751,18 @@ subroutine write_list(this) ! ! -- aux variables do jj = 1, naux - call inputtab%add_term(this%auxvar(jj,ii)) + call inputtab%add_term(this%auxvar(jj, ii)) end do - end do + end do ! ! -- deallocate the local variables call inputtab%table_da() - deallocate(inputtab) - nullify(inputtab) - deallocate(words) + deallocate (inputtab) + nullify (inputtab) + deallocate (words) ! ! -- return return end subroutine write_list - + end module ListReaderModule diff --git a/src/Utilities/Memory/Memory.f90 b/src/Utilities/Memory/Memory.f90 index 6e403377845..00597edf1fc 100644 --- a/src/Utilities/Memory/Memory.f90 +++ b/src/Utilities/Memory/Memory.f90 @@ -1,44 +1,51 @@ module MemoryTypeModule - + use KindModule, only: DP, LGP, I4B - use ConstantsModule, only: LENMEMPATH, LENMEMADDRESS, LENTIMESERIESNAME, & - LENVARNAME, MAXMEMRANK, LENMEMTYPE, & - TABSTRING, TABINTEGER, & + use ConstantsModule, only: LENMEMPATH, LENMEMADDRESS, LENTIMESERIESNAME, & + LENVARNAME, MAXMEMRANK, LENMEMTYPE, & + TABSTRING, TABINTEGER, & TABCENTER, TABLEFT, TABRIGHT + use CharacterStringModule, only: CharacterStringType use TableModule, only: TableType use MemoryHelperModule, only: create_mem_address - + implicit none private public :: MemoryType - + type MemoryType - character(len=LENVARNAME) :: name !< name of the array - character(len=LENVARNAME) :: mastername = 'none' !< name of the master array - character(len=LENMEMPATH) :: path !< path to memory object - character(len=LENMEMPATH) :: masterPath = 'none' !< path to master memory object - character(len=LENMEMTYPE) :: memtype !< type (INTEGER or DOUBLE) - integer(I4B) :: id !< id, not used - integer(I4B) :: nrealloc = 0 !< number of times reallocated - integer(I4B) :: isize !< size of the array - integer(I4B) :: set_handler_idx = 0 !< index of side effect handler for external access - logical(LGP) :: master = .true. !< master copy, others point to this one - logical(LGP), pointer :: logicalsclr => null() !< pointer to the logical - integer(I4B), pointer :: intsclr => null() !< pointer to the integer - real(DP), pointer :: dblsclr => null() !< pointer to the double - integer(I4B), dimension(:), pointer, contiguous :: aint1d => null() !< pointer to 1d integer array - integer(I4B), dimension(:, :), pointer, contiguous :: aint2d => null() !< pointer to 2d integer array - integer(I4B), dimension(:, :, :), pointer, contiguous :: aint3d => null() !< pointer to 3d integer array - real(DP), dimension(:), pointer, contiguous :: adbl1d => null() !< pointer to 1d double array - real(DP), dimension(:, :), pointer, contiguous :: adbl2d => null() !< pointer to 2d double array - real(DP), dimension(:, :, :), pointer, contiguous :: adbl3d => null() !< pointer to 3d double array + character(len=LENVARNAME) :: name !< name of the array + character(len=LENVARNAME) :: mastername = 'none' !< name of the master array + character(len=LENMEMPATH) :: path !< path to memory object + character(len=LENMEMPATH) :: masterPath = 'none' !< path to master memory object + character(len=LENMEMTYPE) :: memtype !< type (INTEGER or DOUBLE) + integer(I4B) :: id !< id, not used + integer(I4B) :: nrealloc = 0 !< number of times reallocated + integer(I4B) :: isize = -1 !< size of the array, equal to the number of array elements; 1 for scalars + integer(I4B) :: element_size = 0 !< byte size of an element; string length + integer(I4B) :: set_handler_idx = 0 !< index of side effect handler for external access + logical(LGP) :: master = .true. !< master copy, others point to this one + character(len=:), pointer :: strsclr => null() !< pointer to the character string + logical(LGP), pointer :: logicalsclr => null() !< pointer to the logical + integer(I4B), pointer :: intsclr => null() !< pointer to the integer + real(DP), pointer :: dblsclr => null() !< pointer to the double + character(len=:), dimension(:), pointer, contiguous :: astr1d => null() !< pointer to the 1d character string array + integer(I4B), dimension(:), pointer, contiguous :: aint1d => null() !< pointer to 1d integer array + integer(I4B), dimension(:, :), pointer, contiguous :: aint2d => null() !< pointer to 2d integer array + integer(I4B), dimension(:, :, :), pointer, contiguous :: aint3d => null() !< pointer to 3d integer array + real(DP), dimension(:), pointer, contiguous :: adbl1d => null() !< pointer to 1d double array + real(DP), dimension(:, :), pointer, contiguous :: adbl2d => null() !< pointer to 2d double array + real(DP), dimension(:, :, :), pointer, contiguous :: adbl3d => null() !< pointer to 3d double array + type(CharacterStringType), dimension(:), pointer, contiguous :: & + acharstr1d => null() !< pointer to the 1d character string array contains procedure :: table_entry procedure :: mt_associated + procedure :: mt_deallocate end type - - contains - + +contains + subroutine table_entry(this, memtab) ! -- dummy class(MemoryType) :: this @@ -54,7 +61,7 @@ subroutine table_entry(this, memtab) if (ipos < 1) then ipos = 16 else - ipos = min(16,ipos-1) + ipos = min(16, ipos - 1) end if cmem = this%memtype(1:ipos) ! @@ -79,15 +86,82 @@ function mt_associated(this) result(al) class(MemoryType) :: this logical :: al al = .false. - if(associated(this%logicalsclr)) al = .true. - if(associated(this%intsclr)) al = .true. - if(associated(this%dblsclr)) al = .true. - if(associated(this%aint1d)) al = .true. - if(associated(this%aint2d)) al = .true. - if(associated(this%aint3d)) al = .true. - if(associated(this%adbl1d)) al = .true. - if(associated(this%adbl2d)) al = .true. - if(associated(this%adbl3d)) al = .true. + if (associated(this%strsclr)) al = .true. + if (associated(this%logicalsclr)) al = .true. + if (associated(this%intsclr)) al = .true. + if (associated(this%dblsclr)) al = .true. + if (associated(this%astr1d)) al = .true. + if (associated(this%aint1d)) al = .true. + if (associated(this%aint2d)) al = .true. + if (associated(this%aint3d)) al = .true. + if (associated(this%adbl1d)) al = .true. + if (associated(this%adbl2d)) al = .true. + if (associated(this%adbl3d)) al = .true. + if (associated(this%acharstr1d)) al = .true. end function mt_associated - -end module MemoryTypeModule \ No newline at end of file + + subroutine mt_deallocate(this) + class(MemoryType) :: this + + if (associated(this%strsclr)) then + if (this%master) deallocate (this%strsclr) + nullify (this%strsclr) + end if + + if (associated(this%logicalsclr)) then + if (this%master) deallocate (this%logicalsclr) + nullify (this%logicalsclr) + end if + + if (associated(this%intsclr)) then + if (this%master) deallocate (this%intsclr) + nullify (this%intsclr) + end if + + if (associated(this%dblsclr)) then + if (this%master) deallocate (this%dblsclr) + nullify (this%dblsclr) + end if + + if (associated(this%astr1d)) then + if (this%master) deallocate (this%astr1d) + nullify (this%astr1d) + end if + + if (associated(this%aint1d)) then + if (this%master) deallocate (this%aint1d) + nullify (this%aint1d) + end if + + if (associated(this%aint2d)) then + if (this%master) deallocate (this%aint2d) + nullify (this%aint2d) + end if + + if (associated(this%aint3d)) then + if (this%master) deallocate (this%aint3d) + nullify (this%aint3d) + end if + + if (associated(this%adbl1d)) then + if (this%master) deallocate (this%adbl1d) + nullify (this%adbl1d) + end if + + if (associated(this%adbl2d)) then + if (this%master) deallocate (this%adbl2d) + nullify (this%adbl2d) + end if + + if (associated(this%adbl3d)) then + if (this%master) deallocate (this%adbl3d) + nullify (this%adbl3d) + end if + + if (associated(this%acharstr1d)) then + if (this%master) deallocate (this%acharstr1d) + nullify (this%acharstr1d) + end if + end subroutine mt_deallocate + +end module MemoryTypeModule diff --git a/src/Utilities/Memory/MemoryHelper.f90 b/src/Utilities/Memory/MemoryHelper.f90 index a06d20c2255..17b96a89947 100644 --- a/src/Utilities/Memory/MemoryHelper.f90 +++ b/src/Utilities/Memory/MemoryHelper.f90 @@ -1,6 +1,7 @@ module MemoryHelperModule use KindModule, only: I4B, LGP - use ConstantsModule, only: LENMEMPATH, LENMEMSEPARATOR, LENMEMADDRESS, LENVARNAME, LENCOMPONENTNAME + use ConstantsModule, only: LENMEMPATH, LENMEMSEPARATOR, LENMEMADDRESS, & + LENVARNAME, LENCOMPONENTNAME, LENCONTEXTNAME use SimModule, only: store_error use SimVariablesModule, only: errmsg @@ -13,24 +14,30 @@ module MemoryHelperModule !> @brief returns the path to the memory object !! !! Returns the path to the location in the memory manager where - !! the variables for this (sub)component are stored, the 'memoryPath' + !! the variables for this (sub)component are stored, the 'memoryPath' !! !! NB: no need to trim the input parameters !< - function create_mem_path(component, subcomponent) result(memory_path) - character(len=*), intent(in) :: component !< name of the solution, model, or exchange - character(len=*), intent(in), optional :: subcomponent !< name of the package (optional) - character(len=LENMEMPATH) :: memory_path !< the memory path - + function create_mem_path(component, subcomponent, context) result(memory_path) + character(len=*), intent(in) :: component !< name of the solution, model, or exchange + character(len=*), intent(in), optional :: subcomponent !< name of the package (optional) + character(len=*), intent(in), optional :: context !< name of the context (optional) + character(len=LENMEMPATH) :: memory_path !< the memory path + call mem_check_length(component, LENCOMPONENTNAME, "solution/model/exchange") - call mem_check_length(subcomponent, LENCOMPONENTNAME, "package") - + call mem_check_length(subcomponent, LENCOMPONENTNAME, "package") + call mem_check_length(context, LENCONTEXTNAME, "context") + + memory_path = trim(component) + if (present(subcomponent)) then - memory_path = trim(component) // memPathSeparator // trim(subcomponent) - else - memory_path = trim(component) + memory_path = trim(memory_path)//memPathSeparator//trim(subcomponent) end if - + + if (present(context)) then + memory_path = trim(context)//memPathSeparator//trim(memory_path) + end if + end function create_mem_path !> @brief returns the address string of the memory object @@ -40,24 +47,24 @@ end function create_mem_path !! NB: no need to trim the input parameters !< function create_mem_address(mem_path, var_name) result(mem_address) - character(len=*), intent(in) :: mem_path !< path to the memory object - character(len=*), intent(in) :: var_name !< name of the stored variable + character(len=*), intent(in) :: mem_path !< path to the memory object + character(len=*), intent(in) :: var_name !< name of the stored variable character(len=LENMEMADDRESS) :: mem_address !< full address string to the memory object call mem_check_length(mem_path, LENMEMPATH, "memory path") call mem_check_length(var_name, LENVARNAME, "variable") - mem_address = trim(mem_path) // memPathSeparator // trim(var_name) + mem_address = trim(mem_path)//memPathSeparator//trim(var_name) - end function create_mem_address + end function create_mem_address !> @brief Split a memory address string into memory path and variable name !< subroutine split_mem_address(mem_address, mem_path, var_name, success) - character(len=*), intent(in) :: mem_address !< the full memory address string - character(len=LENMEMPATH), intent(out) :: mem_path !< the memory path - character(len=LENVARNAME), intent(out) :: var_name !< the variable name - logical(LGP), intent(out) :: success !< true when successful + character(len=*), intent(in) :: mem_address !< the full memory address string + character(len=LENMEMPATH), intent(out) :: mem_path !< the memory path + character(len=LENVARNAME), intent(out) :: var_name !< the variable name + logical(LGP), intent(out) :: success !< true when successful ! local integer(I4B) :: idx @@ -65,61 +72,74 @@ subroutine split_mem_address(mem_address, mem_path, var_name, success) ! if no separator, or it's at the end of the string, ! the memory address is not valid: - if(idx < 1 .or. idx == len(mem_address)) then + if (idx < 1 .or. idx == len(mem_address)) then success = .false. mem_path = '' var_name = '' else success = .true. - mem_path = mem_address(:idx-1) - var_name = mem_address(idx+1:) + mem_path = mem_address(:idx - 1) + var_name = mem_address(idx + 1:) end if - + + ! remove context specifier if prepended to mempath + !if (success) then + ! idx = index(mem_path, memPathSeparator, back=.true.) + ! if (idx > 0 .and. mem_path(1:2) == '__') then + ! mem_path = mem_path(idx + 1:) + ! end if + !end if + end subroutine split_mem_address !> @brief Split the memory path into component(s) !! - !! NB: when there is no subcomponent in the path, the + !! NB: when there is no subcomponent in the path, the !! value for @par subcomponent is set to an empty string. !< - subroutine split_mem_path(mem_path, component, subcomponent) - character(len=*), intent(in) :: mem_path !< path to the memory object - character(len=LENCOMPONENTNAME), intent(out) :: component !< name of the component (solution, model, exchange) - character(len=LENCOMPONENTNAME), intent(out) :: subcomponent !< name of the subcomponent (package) - + subroutine split_mem_path(mem_path, component, subcomponent) + character(len=*), intent(in) :: mem_path !< path to the memory object + character(len=LENCOMPONENTNAME), intent(out) :: component !< name of the component (solution, model, exchange) + character(len=LENCOMPONENTNAME), intent(out) :: subcomponent !< name of the subcomponent (package) + ! local integer(I4B) :: idx idx = index(mem_path, memPathSeparator, back=.true.) ! if the separator is found at the end of the string, ! the path is invalid: - if(idx == len(mem_path)) then - write(errmsg, '(*(G0))') & + if (idx == len(mem_path)) then + write (errmsg, '(*(G0))') & 'Fatal error in Memory Manager, cannot split invalid memory path: ', & - mem_path + mem_path ! -- store error and stop program execution call store_error(errmsg, terminate=.TRUE.) end if - if (idx > 0) then ! when found: - component = mem_path(:idx-1) - subcomponent = mem_path(idx+1:) + component = mem_path(:idx - 1) + subcomponent = mem_path(idx + 1:) else ! when not found, there apparently is no subcomponent: component = mem_path subcomponent = '' end if + ! remove context specifier if prepended to component + idx = index(component, memPathSeparator, back=.true.) + if (idx > 0 .and. component(1:2) == '__') then + component = component(idx + 1:) + end if + end subroutine split_mem_path !> @brief Generic routine to check the length of (parts of) the memory address !! !! The string will be trimmed before the measurement. !! - !! @warning{if the length exceeds the maximum, a message is recorded + !! @warning{if the length exceeds the maximum, a message is recorded !! and the program will be stopped} !! !! The description should describe the part of the address that is checked @@ -127,13 +147,13 @@ end subroutine split_mem_path !! itself !< subroutine mem_check_length(name, max_length, description) - character(len=*), intent(in) :: name !< string to be checked - integer(I4B), intent(in) :: max_length !< maximum length + character(len=*), intent(in) :: name !< string to be checked + integer(I4B), intent(in) :: max_length !< maximum length character(len=*), intent(in) :: description !< a descriptive string - - if(len(trim(name)) > max_length) then - write(errmsg, '(*(G0))') & - 'Fatal error in Memory Manager, length of ', description, ' must be ', & + + if (len(trim(name)) > max_length) then + write (errmsg, '(*(G0))') & + 'Fatal error in Memory Manager, length of ', description, ' must be ', & max_length, ' characters or less: ', name, '(len=', len(trim(name)), ')' ! -- store error and stop program execution @@ -141,4 +161,4 @@ subroutine mem_check_length(name, max_length, description) end if end subroutine mem_check_length -end module MemoryHelperModule \ No newline at end of file +end module MemoryHelperModule diff --git a/src/Utilities/Memory/MemoryList.f90 b/src/Utilities/Memory/MemoryList.f90 index 15210b6135f..badafb519fd 100644 --- a/src/Utilities/Memory/MemoryList.f90 +++ b/src/Utilities/Memory/MemoryList.f90 @@ -4,7 +4,7 @@ module MemoryListModule use ListModule, only: ListType private public :: MemoryListType - + type :: MemoryListType type(ListType), private :: list contains @@ -12,10 +12,11 @@ module MemoryListModule procedure :: get procedure :: count procedure :: clear + procedure :: remove end type MemoryListType - - contains - + +contains + subroutine add(this, mt) class(MemoryListType) :: this type(MemoryType), pointer :: mt @@ -23,7 +24,7 @@ subroutine add(this, mt) obj => mt call this%list%add(obj) end subroutine add - + function get(this, ipos) result(res) class(MemoryListType) :: this integer(I4B), intent(in) :: ipos @@ -36,7 +37,7 @@ function get(this, ipos) result(res) end select return end function get - + function count(this) result(nval) class(MemoryListType) :: this integer(I4B) :: nval @@ -48,5 +49,12 @@ subroutine clear(this) class(MemoryListType) :: this call this%list%Clear() end subroutine clear - -end module MemoryListModule \ No newline at end of file + + subroutine remove(this, ipos, destroyValue) + class(MemoryListType) :: this + integer(I4B), intent(in) :: ipos + logical, intent(in) :: destroyValue + call this%list%RemoveNode(ipos, destroyValue) + end subroutine remove + +end module MemoryListModule diff --git a/src/Utilities/Memory/MemoryManager.f90 b/src/Utilities/Memory/MemoryManager.f90 index dce1bdddc99..fd16b0012b4 100644 --- a/src/Utilities/Memory/MemoryManager.f90 +++ b/src/Utilities/Memory/MemoryManager.f90 @@ -1,20 +1,21 @@ module MemoryManagerModule - use KindModule, only: DP, LGP, I4B, I8B - use ConstantsModule, only: DZERO, DONE, & - DEM3, DEM6, DEM9, DEP3, DEP6, DEP9, & - LENMEMPATH, LENMEMSEPARATOR, LENVARNAME, & - LENCOMPONENTNAME, LINELENGTH, LENMEMTYPE, & - LENMEMADDRESS, TABSTRING, TABUCSTRING, & - TABINTEGER, TABREAL, TABCENTER, TABLEFT, & - TABRIGHT - use SimVariablesModule, only: errmsg - use SimModule, only: store_error, count_errors - use MemoryTypeModule, only: MemoryType - use MemoryListModule, only: MemoryListType - use MemoryHelperModule, only: mem_check_length, split_mem_path - use TableModule, only: TableType, table_cr - + use KindModule, only: DP, LGP, I4B, I8B + use ConstantsModule, only: DZERO, DONE, & + DEM3, DEM6, DEM9, DEP3, DEP6, DEP9, & + LENMEMPATH, LENMEMSEPARATOR, LENVARNAME, & + LENCOMPONENTNAME, LINELENGTH, LENMEMTYPE, & + LENMEMADDRESS, TABSTRING, TABUCSTRING, & + TABINTEGER, TABREAL, TABCENTER, TABLEFT, & + TABRIGHT + use SimVariablesModule, only: errmsg + use SimModule, only: store_error, count_errors + use MemoryTypeModule, only: MemoryType + use MemoryListModule, only: MemoryListType + use MemoryHelperModule, only: mem_check_length, split_mem_path + use TableModule, only: TableType, table_cr + use CharacterStringModule, only: CharacterStringType + implicit none private public :: mem_allocate @@ -28,7 +29,7 @@ module MemoryManagerModule public :: mem_da public :: mem_set_print_option public :: get_from_memorylist - + public :: get_mem_type public :: get_mem_rank public :: get_mem_elem_size @@ -37,7 +38,7 @@ module MemoryManagerModule public :: copy_dbl1d public :: memorylist - + type(MemoryListType) :: memorylist type(TableType), pointer :: memtab => null() integer(I8B) :: nvalues_alogical = 0 @@ -47,65 +48,102 @@ module MemoryManagerModule integer(I4B) :: iprmem = 0 interface mem_allocate - module procedure allocate_logical, & - allocate_str, allocate_str1d, & - allocate_int, allocate_int1d, allocate_int2d, & - allocate_int3d, & - allocate_dbl, allocate_dbl1d, allocate_dbl2d, & - allocate_dbl3d + module procedure & + allocate_logical, & + allocate_str, & + allocate_str1d, & + allocate_int, & + allocate_int1d, & + allocate_int2d, & + allocate_int3d, & + allocate_dbl, & + allocate_dbl1d, & + allocate_dbl2d, & + allocate_dbl3d, & + allocate_charstr1d end interface mem_allocate - + interface mem_checkin - module procedure checkin_int1d, & - checkin_dbl1d + module procedure & + checkin_int1d, & + checkin_dbl1d, & + checkin_dbl2d end interface mem_checkin - + interface mem_reallocate - module procedure reallocate_int1d, reallocate_int2d, reallocate_dbl1d, & - reallocate_dbl2d, reallocate_str1d + module procedure & + reallocate_int1d, & + reallocate_int2d, & + reallocate_dbl1d, & + reallocate_dbl2d, & + reallocate_str1d, & + reallocate_charstr1d end interface mem_reallocate - + interface mem_setptr - module procedure setptr_logical, & - setptr_int, setptr_int1d, setptr_int2d, setptr_int3d, & - setptr_dbl, setptr_dbl1d, setptr_dbl2d, setptr_dbl3d + module procedure & + setptr_logical, & + setptr_int, & + setptr_int1d, & + setptr_int2d, & + setptr_int3d, & + setptr_dbl, & + setptr_dbl1d, & + setptr_dbl2d, & + setptr_dbl3d, & + setptr_str, & + setptr_str1d, & + setptr_charstr1d end interface mem_setptr - + interface mem_copyptr - module procedure copyptr_int1d, copyptr_int2d, & - copyptr_dbl1d, copyptr_dbl2d + module procedure & + copyptr_int1d, & + copyptr_int2d, & + copyptr_dbl1d, & + copyptr_dbl2d end interface mem_copyptr interface mem_reassignptr - module procedure reassignptr_int, & - reassignptr_int1d, reassignptr_int2d, & - reassignptr_dbl1d, reassignptr_dbl2d + module procedure & + reassignptr_int, & + reassignptr_int1d, & + reassignptr_int2d, & + reassignptr_dbl1d, & + reassignptr_dbl2d end interface mem_reassignptr interface mem_deallocate - module procedure deallocate_logical, & - deallocate_str, deallocate_str1d, & - deallocate_int, deallocate_int1d, deallocate_int2d, & - deallocate_int3d, & - deallocate_dbl, deallocate_dbl1d, deallocate_dbl2d, & - deallocate_dbl3d + module procedure & + deallocate_logical, & + deallocate_str, & + deallocate_str1d, & + deallocate_charstr1d, & + deallocate_int, & + deallocate_int1d, & + deallocate_int2d, & + deallocate_int3d, & + deallocate_dbl, & + deallocate_dbl1d, & + deallocate_dbl2d, & + deallocate_dbl3d end interface mem_deallocate - contains - +contains + !> @ brief Get the variable memory type !! !! Returns any of 'LOGICAL', 'INTEGER', 'DOUBLE', 'STRING'. !! returns 'UNKNOWN' when the variable is not found. !< subroutine get_mem_type(name, mem_path, var_type) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - character(len=LENMEMTYPE), intent(out) :: var_type !< memory type + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + character(len=LENMEMTYPE), intent(out) :: var_type !< memory type ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found - ! -- code + ! -- code mt => null() var_type = 'UNKNOWN' call get_from_memorylist(name, mem_path, mt, found) @@ -116,19 +154,19 @@ subroutine get_mem_type(name, mem_path, var_type) ! -- return return end subroutine get_mem_type - + !> @ brief Get the variable rank !! !! Returns rank = -1 when not found. !< subroutine get_mem_rank(name, mem_path, rank) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< mem_path - integer(I4B), intent(out) :: rank !< rank + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< mem_path + integer(I4B), intent(out) :: rank !< rank ! -- local type(MemoryType), pointer :: mt => null() logical(LGP) :: found - ! -- code + ! -- code ! ! -- initialize rank to a value to communicate failure rank = -1 @@ -138,29 +176,32 @@ subroutine get_mem_rank(name, mem_path, rank) ! ! -- set rank if (found) then - if(associated(mt%logicalsclr)) rank = 0 - if(associated(mt%intsclr)) rank = 0 - if(associated(mt%dblsclr)) rank = 0 - if(associated(mt%aint1d)) rank = 1 - if(associated(mt%aint2d)) rank = 2 - if(associated(mt%aint3d)) rank = 3 - if(associated(mt%adbl1d)) rank = 1 - if(associated(mt%adbl2d)) rank = 2 - if(associated(mt%adbl3d)) rank = 3 - end if + if (associated(mt%logicalsclr)) rank = 0 + if (associated(mt%intsclr)) rank = 0 + if (associated(mt%dblsclr)) rank = 0 + if (associated(mt%aint1d)) rank = 1 + if (associated(mt%aint2d)) rank = 2 + if (associated(mt%aint3d)) rank = 3 + if (associated(mt%adbl1d)) rank = 1 + if (associated(mt%adbl2d)) rank = 2 + if (associated(mt%adbl3d)) rank = 3 + if (associated(mt%strsclr)) rank = 0 + if (associated(mt%astr1d)) rank = 1 + if (associated(mt%acharstr1d)) rank = 1 + end if ! ! -- return return - end subroutine get_mem_rank - + end subroutine get_mem_rank + !> @ brief Get the memory size of a single element of the stored variable !! - !! Memory size in bytes, returns size = -1 when not found. - !< + !! Memory size in bytes, returns size = -1 when not found. This is + !< also string length. subroutine get_mem_elem_size(name, mem_path, size) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - integer(I4B), intent(out) :: size !< size of the variable in bytes + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + integer(I4B), intent(out) :: size !< size of the variable in bytes ! -- local type(MemoryType), pointer :: mt => null() logical(LGP) :: found @@ -173,32 +214,23 @@ subroutine get_mem_elem_size(name, mem_path, size) call get_from_memorylist(name, mem_path, mt, found) ! ! -- set memory size - if (found) then - select case(mt%memtype(1:index(mt%memtype,' '))) - case ('STRING') - size = 1 - case ('LOGICAL') - size = 4 - case ('INTEGER') - size = 4 - case ('DOUBLE') - size = 8 - end select + if (found) then + size = mt%element_size end if ! ! -- return return end subroutine get_mem_elem_size - + !> @ brief Get the variable memory shape !! !! Returns an integer array with the shape (Fortran ordering), !! and set shape(1) = -1 when not found. !< subroutine get_mem_shape(name, mem_path, mem_shape) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - integer(I4B), dimension(:), intent(out) :: mem_shape !< shape of the variable + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + integer(I4B), dimension(:), intent(out) :: mem_shape !< shape of the variable ! -- local type(MemoryType), pointer :: mt => null() logical(LGP) :: found @@ -209,16 +241,19 @@ subroutine get_mem_shape(name, mem_path, mem_shape) ! ! -- set shape if (found) then - if(associated(mt%logicalsclr)) mem_shape = shape(mt%logicalsclr) - if(associated(mt%intsclr)) mem_shape = shape(mt%logicalsclr) - if(associated(mt%dblsclr)) mem_shape = shape(mt%dblsclr) - if(associated(mt%aint1d)) mem_shape = shape(mt%aint1d) - if(associated(mt%aint2d)) mem_shape = shape(mt%aint2d) - if(associated(mt%aint3d)) mem_shape = shape(mt%aint3d) - if(associated(mt%adbl1d)) mem_shape = shape(mt%adbl1d) - if(associated(mt%adbl2d)) mem_shape = shape(mt%adbl2d) - if(associated(mt%adbl3d)) mem_shape = shape(mt%adbl3d) - ! -- to communicate failure + if (associated(mt%logicalsclr)) mem_shape = shape(mt%logicalsclr) + if (associated(mt%intsclr)) mem_shape = shape(mt%logicalsclr) + if (associated(mt%dblsclr)) mem_shape = shape(mt%dblsclr) + if (associated(mt%aint1d)) mem_shape = shape(mt%aint1d) + if (associated(mt%aint2d)) mem_shape = shape(mt%aint2d) + if (associated(mt%aint3d)) mem_shape = shape(mt%aint3d) + if (associated(mt%adbl1d)) mem_shape = shape(mt%adbl1d) + if (associated(mt%adbl2d)) mem_shape = shape(mt%adbl2d) + if (associated(mt%adbl3d)) mem_shape = shape(mt%adbl3d) + if (associated(mt%strsclr)) mem_shape = shape(mt%strsclr) + if (associated(mt%astr1d)) mem_shape = shape(mt%astr1d) + if (associated(mt%acharstr1d)) mem_shape = shape(mt%acharstr1d) + ! -- to communicate failure else mem_shape(1) = -1 end if @@ -226,19 +261,20 @@ subroutine get_mem_shape(name, mem_path, mem_shape) ! -- return return end subroutine get_mem_shape - + !> @ brief Get the number of elements for this variable !! !! Returns with isize = -1 when not found. + !! Return 1 for scalars. !< subroutine get_isize(name, mem_path, isize) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - integer(I4B), intent(out) :: isize !< number of elements (flattened) + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + integer(I4B), intent(out) :: isize !< number of elements (flattened) ! -- local type(MemoryType), pointer :: mt => null() logical(LGP) :: found - ! -- code + ! -- code ! ! -- initialize isize to a value to communicate failure isize = -1 @@ -254,19 +290,19 @@ subroutine get_isize(name, mem_path, isize) ! -- return return end subroutine get_isize - + !> @ brief Get a memory type entry from the memory list !! !! Default value for @par check is .true. which means that this !! routine will kill the program when the memory entry cannot be found. !< subroutine get_from_memorylist(name, mem_path, mt, found, check) - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - type(MemoryType), pointer, intent(inout) :: mt !< memory type entry - logical(LGP),intent(out) :: found !< set to .true. when found - logical(LGP), intent(in), optional :: check !< to suppress aborting the program when not found, - !! set check = .false. + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + type(MemoryType), pointer, intent(inout) :: mt !< memory type entry + logical(LGP), intent(out) :: found !< set to .true. when found + logical(LGP), intent(in), optional :: check !< to suppress aborting the program when not found, + !! set check = .false. ! -- local integer(I4B) :: ipos logical(LGP) check_opt @@ -279,7 +315,7 @@ subroutine get_from_memorylist(name, mem_path, mt, found, check) ! -- iterate over the memory list do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(mt%name == name .and. mt%path == mem_path) then + if (mt%name == name .and. mt%path == mem_path) then found = .true. exit end if @@ -290,9 +326,9 @@ subroutine get_from_memorylist(name, mem_path, mt, found, check) end if if (check_opt) then if (.not. found) then - errmsg = "Programming error in memory manager. Variable '" // & - trim(name) // "' in '" // trim(mem_path) // "' cannot be " // & - "assigned because it does not exist in memory manager." + errmsg = "Programming error in memory manager. Variable '"// & + trim(name)//"' in '"//trim(mem_path)//"' cannot be "// & + "assigned because it does not exist in memory manager." call store_error(errmsg, terminate=.TRUE.) end if end if @@ -300,50 +336,50 @@ subroutine get_from_memorylist(name, mem_path, mt, found, check) ! -- return return end subroutine get_from_memorylist - + !> @brief Issue allocation error message and stop program execution !< subroutine allocate_error(varname, mem_path, istat, isize) - character(len=*), intent(in) :: varname !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored - integer(I4B), intent(in) :: istat !< status code - integer(I4B), intent(in) :: isize !< size of allocation + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + integer(I4B), intent(in) :: istat !< status code + integer(I4B), intent(in) :: isize !< size of allocation ! -- local - character(len=20) :: csize - character(len=20) :: cstat + character(len=20) :: csize + character(len=20) :: cstat ! -- code ! ! -- initialize character variables - write(csize, '(i0)') isize - write(cstat, '(i0)') istat + write (csize, '(i0)') isize + write (cstat, '(i0)') istat ! ! -- create error message - errmsg = "Error trying to allocate memory. Path '" // trim(mem_path) // & - "' variable name '" // trim(varname) // "' size '" // trim(csize) // & - "'. Error message is '" // trim(adjustl(errmsg)) // & - "'. Status code is " // trim(cstat) // '.' + errmsg = "Error trying to allocate memory. Path '"//trim(mem_path)// & + "' variable name '"//trim(varname)//"' size '"//trim(csize)// & + "'. Error message is '"//trim(adjustl(errmsg))// & + "'. Status code is "//trim(cstat)//'.' ! ! -- store error and stop program execution call store_error(errmsg, terminate=.TRUE.) - end subroutine allocate_error + end subroutine allocate_error !> @brief Allocate a logical scalar !< subroutine allocate_logical(sclr, name, mem_path) - logical(LGP), pointer, intent(inout) :: sclr !< variable for allocation - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored + logical(LGP), pointer, intent(inout) :: sclr !< variable for allocation + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored ! -- local integer(I4B) :: istat type(MemoryType), pointer :: mt ! -- code ! - ! -- check varible name length + ! -- check variable name length call mem_check_length(name, LENVARNAME, "variable") ! ! -- allocate the logical scalar - allocate(sclr, stat=istat, errmsg=errmsg) - if(istat /= 0) then + allocate (sclr, stat=istat, errmsg=errmsg) + if (istat /= 0) then call allocate_error(name, mem_path, istat, 1) end if ! @@ -351,14 +387,15 @@ subroutine allocate_logical(sclr, name, mem_path) nvalues_alogical = nvalues_alogical + 1 ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%logicalsclr => sclr + mt%element_size = LGP mt%isize = 1 mt%name = name mt%path = mem_path - write(mt%memtype, "(a)") 'LOGICAL' + write (mt%memtype, "(a)") 'LOGICAL' ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -370,10 +407,10 @@ end subroutine allocate_logical !> @brief Allocate a character string !< subroutine allocate_str(sclr, ilen, name, mem_path) - integer(I4B), intent(in) :: ilen !< string length + integer(I4B), intent(in) :: ilen !< string length character(len=ilen), pointer, intent(inout) :: sclr !< variable for allocation - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored ! -- local integer(I4B) :: istat type(MemoryType), pointer :: mt @@ -382,7 +419,7 @@ subroutine allocate_str(sclr, ilen, name, mem_path) ! ! -- make sure ilen is greater than 0 if (ilen < 1) then - errmsg = 'Programming error in allocate_str. ILEN must be greater than 0.' + errmsg = 'Programming error in allocate_str. ILEN must be greater than 0.' call store_error(errmsg, terminate=.TRUE.) end if ! @@ -390,7 +427,7 @@ subroutine allocate_str(sclr, ilen, name, mem_path) call mem_check_length(name, LENVARNAME, "variable") ! ! -- allocate string - allocate(character(len=ilen) :: sclr, stat=istat, errmsg=errmsg) + allocate (character(len=ilen) :: sclr, stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, 1) end if @@ -402,13 +439,15 @@ subroutine allocate_str(sclr, ilen, name, mem_path) nvalues_astr = nvalues_astr + ilen ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type - mt%isize = ilen + mt%strsclr => sclr + mt%element_size = ilen + mt%isize = 1 mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' LEN=',i0)") 'STRING', ilen + write (mt%memtype, "(a,' LEN=',i0)") 'STRING', ilen ! ! -- add defined length string to the memory manager list call memorylist%add(mt) @@ -416,15 +455,16 @@ subroutine allocate_str(sclr, ilen, name, mem_path) ! -- return return end subroutine allocate_str - - !> @brief Allocate a 1-dimensional defined length string array - !< - subroutine allocate_str1d(astr, ilen, nrow, name, mem_path) - integer(I4B), intent(in) :: ilen !< string length - character(len=ilen), dimension(:), pointer, contiguous, intent(inout) :: astr !< variable for allocation - integer(I4B), intent(in) :: nrow !< number of strings in array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored + + !> @brief Allocate a 1-dimensional defined length string array + !< + subroutine allocate_str1d(astr1d, ilen, nrow, name, mem_path) + integer(I4B), intent(in) :: ilen !< string length + character(len=ilen), dimension(:), & + pointer, contiguous, intent(inout) :: astr1d !< variable for allocation + integer(I4B), intent(in) :: nrow !< number of strings in array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored ! -- local variables type(MemoryType), pointer :: mt character(len=ilen) :: string @@ -438,8 +478,8 @@ subroutine allocate_str1d(astr, ilen, nrow, name, mem_path) ! ! -- make sure ilen is greater than 0 if (ilen < 1) then - errmsg = 'Programming error in allocate_str1d. ' // & - 'ILEN must be greater than 0.' + errmsg = 'Programming error in allocate_str1d. '// & + 'ILEN must be greater than 0.' call store_error(errmsg, terminate=.TRUE.) end if ! @@ -447,10 +487,10 @@ subroutine allocate_str1d(astr, ilen, nrow, name, mem_path) call mem_check_length(name, LENVARNAME, "variable") ! ! -- calculate isize - isize = ilen * nrow + isize = nrow ! ! -- allocate defined length string array - allocate(character(len=ilen) :: astr(nrow), stat=istat, errmsg=errmsg) + allocate (character(len=ilen) :: astr1d(nrow), stat=istat, errmsg=errmsg) ! ! -- check for error condition if (istat /= 0) then @@ -459,20 +499,24 @@ subroutine allocate_str1d(astr, ilen, nrow, name, mem_path) ! ! -- fill deferred length string with empty string do n = 1, nrow - astr(n) = string + astr1d(n) = string end do ! ! -- update counter nvalues_astr = nvalues_astr + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type + ! this does not work with gfortran 11.3 and 12.1 + ! so we have to disable the pointing to astr1d + ! mt%astr1d => astr1d + mt%element_size = ilen mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow + write (mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow ! ! -- add deferred length character array to the memory manager list call memorylist%add(mt) @@ -481,12 +525,72 @@ subroutine allocate_str1d(astr, ilen, nrow, name, mem_path) return end subroutine allocate_str1d + !> @brief Allocate a 1-dimensional array of deferred-length CharacterStringType + !< + subroutine allocate_charstr1d(acharstr1d, ilen, nrow, name, mem_path) + type(CharacterStringType), dimension(:), & + pointer, contiguous, intent(inout) :: acharstr1d !< variable for allocation + integer(I4B), intent(in) :: ilen !< string length + integer(I4B), intent(in) :: nrow !< number of strings in array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored + ! -- local variables + character(len=ilen) :: string + type(MemoryType), pointer :: mt + integer(I4B) :: n + integer(I4B) :: istat + integer(I4B) :: isize + ! -- code + ! + ! -- initialize string + string = '' + ! + ! -- check variable name length + call mem_check_length(name, LENVARNAME, "variable") + ! + ! -- calculate isize + isize = nrow + ! + ! -- allocate deferred length string array + allocate (acharstr1d(nrow), stat=istat, errmsg=errmsg) + ! + ! -- check for error condition + if (istat /= 0) then + call allocate_error(name, mem_path, istat, isize) + end if + ! + ! -- fill deferred length string with empty string + do n = 1, nrow + acharstr1d(n) = string + end do + ! + ! -- update counter + nvalues_astr = nvalues_astr + isize + ! + ! -- allocate memory type + allocate (mt) + ! + ! -- set memory type + mt%acharstr1d => acharstr1d + mt%element_size = ilen + mt%isize = isize + mt%name = name + mt%path = mem_path + write (mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow + ! + ! -- add deferred length character array to the memory manager list + call memorylist%add(mt) + ! + ! -- return + return + end subroutine allocate_charstr1d + !> @brief Allocate a integer scalar !< subroutine allocate_int(sclr, name, mem_path) - integer(I4B), pointer, intent(inout) :: sclr !< variable for allocation - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where the variable is stored + integer(I4B), pointer, intent(inout) :: sclr !< variable for allocation + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where the variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -496,7 +600,7 @@ subroutine allocate_int(sclr, name, mem_path) call mem_check_length(name, LENVARNAME, "variable") ! ! -- allocate integer scalar - allocate(sclr, stat=istat, errmsg=errmsg) + allocate (sclr, stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, 1) end if @@ -505,14 +609,15 @@ subroutine allocate_int(sclr, name, mem_path) nvalues_aint = nvalues_aint + 1 ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%intsclr => sclr + mt%element_size = I4B mt%isize = 1 mt%name = name mt%path = mem_path - write(mt%memtype, "(a)") 'INTEGER' + write (mt%memtype, "(a)") 'INTEGER' ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -520,14 +625,14 @@ subroutine allocate_int(sclr, name, mem_path) ! -- return return end subroutine allocate_int - + !> @brief Allocate a 1-dimensional integer array !< subroutine allocate_int1d(aint, nrow, name, mem_path) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< variable for allocation - integer(I4B), intent(in) :: nrow !< integer array number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< variable for allocation + integer(I4B), intent(in) :: nrow !< integer array number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! --local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -541,7 +646,7 @@ subroutine allocate_int1d(aint, nrow, name, mem_path) isize = nrow ! ! -- allocate integer array - allocate(aint(nrow), stat=istat, errmsg=errmsg) + allocate (aint(nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -550,14 +655,15 @@ subroutine allocate_int1d(aint, nrow, name, mem_path) nvalues_aint = nvalues_aint + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%aint1d => aint + mt%element_size = I4B mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,')')") 'INTEGER', isize + write (mt%memtype, "(a,' (',i0,')')") 'INTEGER', isize ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -565,15 +671,15 @@ subroutine allocate_int1d(aint, nrow, name, mem_path) ! -- return return end subroutine allocate_int1d - + !> @brief Allocate a 2-dimensional integer array !< subroutine allocate_int2d(aint, ncol, nrow, name, mem_path) - integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< variable for allocation - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< variable for allocation + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -587,7 +693,7 @@ subroutine allocate_int2d(aint, ncol, nrow, name, mem_path) isize = ncol * nrow ! ! -- allocate the integer array - allocate(aint(ncol, nrow), stat=istat, errmsg=errmsg) + allocate (aint(ncol, nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -596,30 +702,31 @@ subroutine allocate_int2d(aint, ncol, nrow, name, mem_path) nvalues_aint = nvalues_aint + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%aint2d => aint + mt%element_size = I4B mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow ! ! -- add memory type to the memory list call memorylist%add(mt) ! ! -- return end subroutine allocate_int2d - + !> @brief Allocate a 3-dimensional integer array !< subroutine allocate_int3d(aint, ncol, nrow, nlay, name, mem_path) - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: aint !< variable for allocation - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - integer(I4B), intent(in) :: nlay !< number of layers - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: aint !< variable for allocation + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + integer(I4B), intent(in) :: nlay !< number of layers + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -633,24 +740,25 @@ subroutine allocate_int3d(aint, ncol, nrow, nlay, name, mem_path) isize = ncol * nrow * nlay ! ! -- allocate integer array - allocate(aint(ncol, nrow, nlay), stat=istat, errmsg=errmsg) - if(istat /= 0) then + allocate (aint(ncol, nrow, nlay), stat=istat, errmsg=errmsg) + if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if ! - ! -- update counter + ! -- update counter nvalues_aint = nvalues_aint + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%aint3d => aint + mt%element_size = I4B mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,',',i0,',',i0,')')") 'INTEGER', ncol, & - nrow, nlay + write (mt%memtype, "(a,' (',i0,',',i0,',',i0,')')") 'INTEGER', ncol, & + nrow, nlay ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -662,9 +770,9 @@ end subroutine allocate_int3d !> @brief Allocate a real scalar !< subroutine allocate_dbl(sclr, name, mem_path) - real(DP), pointer, intent(inout) :: sclr !< variable for allocation - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), pointer, intent(inout) :: sclr !< variable for allocation + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -674,7 +782,7 @@ subroutine allocate_dbl(sclr, name, mem_path) call mem_check_length(name, LENVARNAME, "variable") ! ! -- allocate real scalar - allocate(sclr, stat=istat, errmsg=errmsg) + allocate (sclr, stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, 1) end if @@ -683,14 +791,15 @@ subroutine allocate_dbl(sclr, name, mem_path) nvalues_aint = nvalues_aint + 1 ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%dblsclr => sclr + mt%element_size = DP mt%isize = 1 mt%name = name mt%path = mem_path - write(mt%memtype, "(a)") 'DOUBLE' + write (mt%memtype, "(a)") 'DOUBLE' ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -698,14 +807,14 @@ subroutine allocate_dbl(sclr, name, mem_path) ! -- return return end subroutine allocate_dbl - + !> @brief Allocate a 1-dimensional real array !< subroutine allocate_dbl1d(adbl, nrow, name, mem_path) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< variable for allocation - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< variable for allocation + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -719,7 +828,7 @@ subroutine allocate_dbl1d(adbl, nrow, name, mem_path) isize = nrow ! ! -- allocate the real array - allocate(adbl(nrow), stat=istat, errmsg=errmsg) + allocate (adbl(nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -728,14 +837,15 @@ subroutine allocate_dbl1d(adbl, nrow, name, mem_path) nvalues_adbl = nvalues_adbl + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%adbl1d => adbl + mt%element_size = DP mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize + write (mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -743,15 +853,15 @@ subroutine allocate_dbl1d(adbl, nrow, name, mem_path) ! -- return return end subroutine allocate_dbl1d - + !> @brief Allocate a 2-dimensional real array !< subroutine allocate_dbl2d(adbl, ncol, nrow, name, mem_path) real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< variable for allocation - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -765,7 +875,7 @@ subroutine allocate_dbl2d(adbl, ncol, nrow, name, mem_path) isize = ncol * nrow ! ! -- allocate the real array - allocate(adbl(ncol, nrow), stat=istat, errmsg=errmsg) + allocate (adbl(ncol, nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -774,14 +884,15 @@ subroutine allocate_dbl2d(adbl, ncol, nrow, name, mem_path) nvalues_adbl = nvalues_adbl + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%adbl2d => adbl + mt%element_size = DP mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -789,16 +900,16 @@ subroutine allocate_dbl2d(adbl, ncol, nrow, name, mem_path) ! -- return return end subroutine allocate_dbl2d - + !> @brief Allocate a 3-dimensional real array !< subroutine allocate_dbl3d(adbl, ncol, nrow, nlay, name, mem_path) - real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: adbl !< variable for allocation - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - integer(I4B), intent(in) :: nlay !< number of layers - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: adbl !< variable for allocation + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + integer(I4B), intent(in) :: nlay !< number of layers + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -812,7 +923,7 @@ subroutine allocate_dbl3d(adbl, ncol, nrow, nlay, name, mem_path) isize = ncol * nrow * nlay ! ! -- allocate the real array - allocate(adbl(ncol, nrow, nlay), stat=istat, errmsg=errmsg) + allocate (adbl(ncol, nrow, nlay), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -821,15 +932,16 @@ subroutine allocate_dbl3d(adbl, ncol, nrow, nlay, name, mem_path) nvalues_adbl = nvalues_adbl + isize ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%adbl3d => adbl + mt%element_size = DP mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,',',i0,',',i0,')')") 'DOUBLE', ncol, & - nrow, nlay + write (mt%memtype, "(a,' (',i0,',',i0,',',i0,')')") 'DOUBLE', ncol, & + nrow, nlay ! ! -- add memory type to the memory list call memorylist%add(mt) @@ -837,15 +949,15 @@ subroutine allocate_dbl3d(adbl, ncol, nrow, nlay, name, mem_path) ! -- return return end subroutine allocate_dbl3d - + !> @brief Check in an existing 1d integer array with a new address (name + path) !< subroutine checkin_int1d(aint, name, mem_path, name2, mem_path2) integer(I4B), dimension(:), pointer, contiguous, intent(in) :: aint !< the existing array - character(len=*), intent(in) :: name !< new variable name - character(len=*), intent(in) :: mem_path !< new path where variable is stored - character(len=*), intent(in) :: name2 !< existing variable name - character(len=*), intent(in) :: mem_path2 !< existing path where variable is stored + character(len=*), intent(in) :: name !< new variable name + character(len=*), intent(in) :: mem_path !< new path where variable is stored + character(len=*), intent(in) :: name2 !< existing variable name + character(len=*), intent(in) :: mem_path2 !< existing path where variable is stored ! --local type(MemoryType), pointer :: mt integer(I4B) :: isize @@ -858,14 +970,15 @@ subroutine checkin_int1d(aint, name, mem_path, name2, mem_path2) isize = size(aint) ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%aint1d => aint + mt%element_size = I4B mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,')')") 'INTEGER', isize + write (mt%memtype, "(a,' (',i0,')')") 'INTEGER', isize ! ! -- set master information mt%master = .false. @@ -882,11 +995,11 @@ end subroutine checkin_int1d !> @brief Check in an existing 1d double precision array with a new address (name + path) !< subroutine checkin_dbl1d(adbl, name, mem_path, name2, mem_path2) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< the existing array - character(len=*), intent(in) :: name !< new variable name - character(len=*), intent(in) :: mem_path !< new path where variable is stored - character(len=*), intent(in) :: name2 !< existing variable name - character(len=*), intent(in) :: mem_path2 !< existing path where variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< the existing array + character(len=*), intent(in) :: name !< new variable name + character(len=*), intent(in) :: mem_path !< new path where variable is stored + character(len=*), intent(in) :: name2 !< existing variable name + character(len=*), intent(in) :: mem_path2 !< existing path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: isize @@ -899,14 +1012,15 @@ subroutine checkin_dbl1d(adbl, name, mem_path, name2, mem_path2) isize = size(adbl) ! ! -- allocate memory type - allocate(mt) + allocate (mt) ! ! -- set memory type mt%adbl1d => adbl + mt%element_size = DP mt%isize = isize mt%name = name mt%path = mem_path - write(mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize + write (mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize ! ! -- set master information mt%master = .false. @@ -919,15 +1033,58 @@ subroutine checkin_dbl1d(adbl, name, mem_path, name2, mem_path2) ! -- return return end subroutine checkin_dbl1d - + + !> @brief Check in an existing 2d double precision array with a new address (name + path) + !< + subroutine checkin_dbl2d(adbl2d, name, mem_path, name2, mem_path2) + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl2d !< the existing 2d array + character(len=*), intent(in) :: name !< new variable name + character(len=*), intent(in) :: mem_path !< new path where variable is stored + character(len=*), intent(in) :: name2 !< existing variable name + character(len=*), intent(in) :: mem_path2 !< existing path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + integer(I4B) :: ncol, nrow, isize + ! -- code + ! + ! -- check the variable name length + call mem_check_length(name, LENVARNAME, "variable") + ! + ! -- set isize + ncol = size(adbl2d, dim=1) + nrow = size(adbl2d, dim=2) + isize = ncol * nrow + ! + ! -- allocate memory type + allocate (mt) + ! + ! -- set memory type + mt%adbl2d => adbl2d + mt%isize = isize + mt%name = name + mt%path = mem_path + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow + ! + ! -- set master information + mt%master = .false. + mt%mastername = name2 + mt%masterPath = mem_path2 + ! + ! -- add memory type to the memory list + call memorylist%add(mt) + ! + ! -- return + return + end subroutine checkin_dbl2d + !> @brief Reallocate a 1-dimensional defined length string array !< subroutine reallocate_str1d(astr, ilen, nrow, name, mem_path) - integer(I4B), intent(in) :: ilen !< string length - integer(I4B), intent(in) :: nrow !< number of rows + integer(I4B), intent(in) :: ilen !< string length + integer(I4B), intent(in) :: nrow !< number of rows character(len=ilen), dimension(:), pointer, contiguous, intent(inout) :: astr !< the reallocated string array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -951,10 +1108,10 @@ subroutine reallocate_str1d(astr, ilen, nrow, name, mem_path) end if ! ! -- calculate isize - isize = ilen * nrow + isize = nrow ! ! -- allocate astrtemp - allocate(astrtemp(nrow), stat=istat, errmsg=errmsg) + allocate (astrtemp(nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if @@ -970,46 +1127,136 @@ subroutine reallocate_str1d(astr, ilen, nrow, name, mem_path) end do ! ! -- deallocate mt pointer, repoint, recalculate isize - deallocate(astr) + deallocate (astr) ! ! -- allocate astr1d - allocate(astr(nrow), stat=istat, errmsg=errmsg) + allocate (astr(nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if ! ! -- fill the reallocate character array do n = 1, nrow - astr(n) = astrtemp(n) + astr(n) = astrtemp(n) end do ! ! -- deallocate temporary storage - deallocate(astrtemp) + deallocate (astrtemp) ! ! -- reset memory manager values + mt%element_size = ilen mt%isize = isize mt%nrealloc = mt%nrealloc + 1 mt%master = .true. nvalues_astr = nvalues_astr + isize - isize_old - write(mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow + write (mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow else - errmsg = "Programming error, varible '" // trim(name) // "' from '" // & - trim(mem_path) // "' is not defined in the memory manager. Use " // & - "mem_allocate instead." + errmsg = "Programming error, variable '"//trim(name)//"' from '"// & + trim(mem_path)//"' is not defined in the memory manager. Use "// & + "mem_allocate instead." call store_error(errmsg, terminate=.TRUE.) end if ! ! -- return return end subroutine reallocate_str1d - + + !> @brief Reallocate a 1-dimensional deferred length string array + !< + subroutine reallocate_charstr1d(acharstr1d, ilen, nrow, name, mem_path) + type(CharacterStringType), dimension(:), pointer, contiguous, & + intent(inout) :: acharstr1d !< the reallocated charstring array + integer(I4B), intent(in) :: ilen !< string length + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + logical(LGP) :: found + type(CharacterStringType), dimension(:), allocatable :: astrtemp + character(len=ilen) :: string + integer(I4B) :: istat + integer(I4B) :: isize + integer(I4B) :: isize_old + integer(I4B) :: nrow_old + integer(I4B) :: n + ! + ! -- Initialize string + string = '' + ! + ! -- Find and assign mt + call get_from_memorylist(name, mem_path, mt, found) + ! + ! -- reallocate astr1d + if (found) then + isize_old = mt%isize + if (isize_old > 0) then + nrow_old = size(acharstr1d) + else + nrow_old = 0 + end if + ! + ! -- calculate isize + isize = nrow + ! + ! -- allocate astrtemp + allocate (astrtemp(nrow), stat=istat, errmsg=errmsg) + if (istat /= 0) then + call allocate_error(name, mem_path, istat, isize) + end if + ! + ! -- copy existing values + do n = 1, nrow_old + astrtemp(n) = acharstr1d(n) + end do + ! + ! -- fill new values with missing values + do n = nrow_old + 1, nrow + astrtemp(n) = string + end do + ! + ! -- deallocate mt pointer, repoint, recalculate isize + deallocate (acharstr1d) + ! + ! -- allocate astr1d + allocate (acharstr1d(nrow), stat=istat, errmsg=errmsg) + if (istat /= 0) then + call allocate_error(name, mem_path, istat, isize) + end if + ! + ! -- fill the reallocated character array + do n = 1, nrow + acharstr1d(n) = astrtemp(n) + end do + ! + ! -- deallocate temporary storage + deallocate (astrtemp) + ! + ! -- reset memory manager values + mt%element_size = ilen + mt%isize = isize + mt%nrealloc = mt%nrealloc + 1 + mt%master = .true. + nvalues_astr = nvalues_astr + isize - isize_old + write (mt%memtype, "(a,' LEN=',i0,' (',i0,')')") 'STRING', ilen, nrow + else + errmsg = "Programming error, variable '"//trim(name)//"' from '"// & + trim(mem_path)//"' is not defined in the memory manager. Use "// & + "mem_allocate instead." + call store_error(errmsg, terminate=.TRUE.) + end if + ! + ! -- return + return + end subroutine reallocate_charstr1d + !> @brief Reallocate a 1-dimensional integer array !< subroutine reallocate_int1d(aint, nrow, name, mem_path) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< the reallocated integer array - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< the reallocated integer array + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1027,17 +1274,18 @@ subroutine reallocate_int1d(aint, nrow, name, mem_path) isize = nrow isizeold = size(mt%aint1d) ifill = min(isizeold, isize) - allocate(aint(nrow), stat=istat, errmsg=errmsg) - if(istat /= 0) then + allocate (aint(nrow), stat=istat, errmsg=errmsg) + if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if do i = 1, ifill aint(i) = mt%aint1d(i) - enddo + end do ! ! -- deallocate mt pointer, repoint, recalculate isize - deallocate(mt%aint1d) + deallocate (mt%aint1d) mt%aint1d => aint + mt%element_size = I4B mt%isize = isize mt%nrealloc = mt%nrealloc + 1 mt%master = .true. @@ -1046,15 +1294,15 @@ subroutine reallocate_int1d(aint, nrow, name, mem_path) ! -- return return end subroutine reallocate_int1d - + !> @brief Reallocate a 2-dimensional integer array !< subroutine reallocate_int2d(aint, ncol, nrow, name, mem_path) integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< the reallocated 2d integer array - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1073,36 +1321,37 @@ subroutine reallocate_int2d(aint, ncol, nrow, name, mem_path) ishape = shape(mt%aint2d) isize = nrow * ncol isizeold = ishape(1) * ishape(2) - allocate(aint(ncol, nrow), stat=istat, errmsg=errmsg) + allocate (aint(ncol, nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if do i = 1, ishape(2) do j = 1, ishape(1) aint(j, i) = mt%aint2d(j, i) - enddo - enddo + end do + end do ! ! -- deallocate mt pointer, repoint, recalculate isize - deallocate(mt%aint2d) + deallocate (mt%aint2d) mt%aint2d => aint + mt%element_size = I4B mt%isize = isize mt%nrealloc = mt%nrealloc + 1 mt%master = .true. nvalues_aint = nvalues_aint + isize - isizeold - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow ! ! -- return return end subroutine reallocate_int2d - + !> @brief Reallocate a 1-dimensional real array !< subroutine reallocate_dbl1d(adbl, nrow, name, mem_path) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< the reallocated 1d real array - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< the reallocated 1d real array + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt integer(I4B) :: istat @@ -1120,35 +1369,36 @@ subroutine reallocate_dbl1d(adbl, nrow, name, mem_path) isize = nrow isizeold = size(mt%adbl1d) ifill = min(isizeold, isize) - allocate(adbl(nrow), stat=istat, errmsg=errmsg) + allocate (adbl(nrow), stat=istat, errmsg=errmsg) if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if do i = 1, ifill adbl(i) = mt%adbl1d(i) - enddo + end do ! ! -- deallocate mt pointer, repoint, recalculate isize - deallocate(mt%adbl1d) + deallocate (mt%adbl1d) mt%adbl1d => adbl + mt%element_size = DP mt%isize = isize mt%nrealloc = mt%nrealloc + 1 mt%master = .true. nvalues_adbl = nvalues_adbl + isize - isizeold - write(mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize + write (mt%memtype, "(a,' (',i0,')')") 'DOUBLE', isize ! ! -- return return end subroutine reallocate_dbl1d - + !> @brief Reallocate a 2-dimensional real array !< subroutine reallocate_dbl2d(adbl, ncol, nrow, name, mem_path) real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< the reallocated 2d real array - integer(I4B), intent(in) :: ncol !< number of columns - integer(I4B), intent(in) :: nrow !< number of rows - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), intent(in) :: ncol !< number of columns + integer(I4B), intent(in) :: nrow !< number of rows + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1167,8 +1417,8 @@ subroutine reallocate_dbl2d(adbl, ncol, nrow, name, mem_path) ishape = shape(mt%adbl2d) isize = nrow * ncol isizeold = ishape(1) * ishape(2) - allocate(adbl(ncol, nrow), stat=istat, errmsg=errmsg) - if(istat /= 0) then + allocate (adbl(ncol, nrow), stat=istat, errmsg=errmsg) + if (istat /= 0) then call allocate_error(name, mem_path, istat, isize) end if do i = 1, ishape(2) @@ -1178,193 +1428,247 @@ subroutine reallocate_dbl2d(adbl, ncol, nrow, name, mem_path) end do ! ! -- deallocate mt pointer, repoint, recalculate isize - deallocate(mt%adbl2d) + deallocate (mt%adbl2d) mt%adbl2d => adbl + mt%element_size = DP mt%isize = isize mt%nrealloc = mt%nrealloc + 1 mt%master = .true. nvalues_adbl = nvalues_adbl + isize - isizeold - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow ! ! -- return return end subroutine reallocate_dbl2d - + !> @brief Set pointer to a logical scalar !< subroutine setptr_logical(sclr, name, mem_path) - logical(LGP), pointer, intent(inout) :: sclr !< pointer to logical scalar - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + logical(LGP), pointer, intent(inout) :: sclr !< pointer to logical scalar + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) sclr => mt%logicalsclr ! ! -- return return end subroutine setptr_logical - + !> @brief Set pointer to integer scalar !< subroutine setptr_int(sclr, name, mem_path) - integer(I4B), pointer, intent(inout) :: sclr !< pointer to integer scalar - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), pointer, intent(inout) :: sclr !< pointer to integer scalar + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) sclr => mt%intsclr ! ! -- return return end subroutine setptr_int - + !> @brief Set pointer to 1d integer array !< subroutine setptr_int1d(aint, name, mem_path) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< pointer to 1d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< pointer to 1d integer array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) aint => mt%aint1d ! ! -- return return end subroutine setptr_int1d - + !> @brief Set pointer to 2d integer array !< subroutine setptr_int2d(aint, name, mem_path) integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< pointer to 2d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) aint => mt%aint2d ! ! -- return return end subroutine setptr_int2d - + !> @brief Set pointer to 3d integer array !< subroutine setptr_int3d(aint, name, mem_path) integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: aint !< pointer to 3d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) aint => mt%aint3d ! ! -- return return end subroutine setptr_int3d - + !> @brief Set pointer to a real scalar !< subroutine setptr_dbl(sclr, name, mem_path) - real(DP), pointer, intent(inout) :: sclr !< pointer to a real scalar - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), pointer, intent(inout) :: sclr !< pointer to a real scalar + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) sclr => mt%dblsclr ! ! -- return return end subroutine setptr_dbl - + !> @brief Set pointer to a 1d real array !< subroutine setptr_dbl1d(adbl, name, mem_path) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< pointer to 1d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< pointer to 1d real array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) adbl => mt%adbl1d ! ! -- return return end subroutine setptr_dbl1d - + !> @brief Set pointer to a 2d real array !< subroutine setptr_dbl2d(adbl, name, mem_path) real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< pointer to 2d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) adbl => mt%adbl2d ! ! -- return return end subroutine setptr_dbl2d - - !> @brief Set pointer to a 3d real array + + !> @brief Set pointer to a 3d real array !< subroutine setptr_dbl3d(adbl, name, mem_path) real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: adbl !< pointer to 3d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) adbl => mt%adbl3d ! ! -- return return end subroutine setptr_dbl3d + !> @brief Set pointer to a string (scalar) + !< + subroutine setptr_str(asrt, name, mem_path) + character(len=:), pointer :: asrt !< pointer to the character string + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + logical(LGP) :: found + ! -- code + call get_from_memorylist(name, mem_path, mt, found) + asrt => mt%strsclr + ! + ! -- return + return + end subroutine setptr_str + + !> @brief Set pointer to a fixed-length string array + !< + subroutine setptr_str1d(astr1d, name, mem_path) + character(len=:), dimension(:), & + pointer, contiguous, intent(inout) :: astr1d !< pointer to the string array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + logical(LGP) :: found + ! -- code + call get_from_memorylist(name, mem_path, mt, found) + astr1d => mt%astr1d + ! + ! -- return + return + end subroutine setptr_str1d + + !> @brief Set pointer to an array of CharacterStringType + !< + subroutine setptr_charstr1d(acharstr1d, name, mem_path) + type(CharacterStringType), dimension(:), pointer, contiguous, & + intent(inout) :: acharstr1d !< the reallocated charstring array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + logical(LGP) :: found + ! -- code + call get_from_memorylist(name, mem_path, mt, found) + acharstr1d => mt%acharstr1d + ! + ! -- return + return + end subroutine setptr_charstr1d + !> @brief Make a copy of a 1-dimensional integer array !< subroutine copyptr_int1d(aint, name, mem_path, mem_path_copy) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< returned copy of 1d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, - !! if passed then the copy is added to the - !! memory manager + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< returned copy of 1d integer array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, + !! if passed then the copy is added to the + !! memory manager ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found integer(I4B) :: n ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) aint => null() ! -- check the copy into the memory manager if (present(mem_path_copy)) then call allocate_int1d(aint, size(mt%aint1d), mt%name, mem_path_copy) - ! -- create a local copy + ! -- create a local copy else - allocate(aint(size(mt%aint1d))) + allocate (aint(size(mt%aint1d))) end if do n = 1, size(mt%aint1d) aint(n) = mt%aint1d(n) @@ -1377,12 +1681,12 @@ end subroutine copyptr_int1d !> @brief Make a copy of a 2-dimensional integer array !< subroutine copyptr_int2d(aint, name, mem_path, mem_path_copy) - integer(I4B), dimension(:,:), pointer, contiguous, intent(inout) :: aint !< returned copy of 2d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, - !! if passed then the copy is added to the - !! memory manager + integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< returned copy of 2d integer array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, + !! if passed then the copy is added to the + !! memory manager ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1391,20 +1695,20 @@ subroutine copyptr_int2d(aint, name, mem_path, mem_path_copy) integer(I4B) :: ncol integer(I4B) :: nrow ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) aint => null() ncol = size(mt%aint2d, dim=1) nrow = size(mt%aint2d, dim=2) ! -- check the copy into the memory manager if (present(mem_path_copy)) then call allocate_int2d(aint, ncol, nrow, mt%name, mem_path_copy) - ! -- create a local copy + ! -- create a local copy else - allocate(aint(ncol,nrow)) + allocate (aint(ncol, nrow)) end if do i = 1, nrow do j = 1, ncol - aint(j,i) = mt%aint2d(j,i) + aint(j, i) = mt%aint2d(j, i) end do end do ! @@ -1415,25 +1719,25 @@ end subroutine copyptr_int2d !> @brief Make a copy of a 1-dimensional real array !< subroutine copyptr_dbl1d(adbl, name, mem_path, mem_path_copy) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< returned copy of 1d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, - !! if passed then the copy is added to the - !! memory manager + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< returned copy of 1d real array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, + !! if passed then the copy is added to the + !! memory manager ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found integer(I4B) :: n ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) adbl => null() ! -- check the copy into the memory manager if (present(mem_path_copy)) then call allocate_dbl1d(adbl, size(mt%adbl1d), mt%name, mem_path_copy) - ! -- create a local copy + ! -- create a local copy else - allocate(adbl(size(mt%adbl1d))) + allocate (adbl(size(mt%adbl1d))) end if do n = 1, size(mt%adbl1d) adbl(n) = mt%adbl1d(n) @@ -1446,12 +1750,12 @@ end subroutine copyptr_dbl1d !> @brief Make a copy of a 2-dimensional real array !< subroutine copyptr_dbl2d(adbl, name, mem_path, mem_path_copy) - real(DP), dimension(:,:), pointer, contiguous, intent(inout) :: adbl !< returned copy of 2d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, - !! if passed then the copy is added to the - !! memory manager + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< returned copy of 2d real array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in), optional :: mem_path_copy !< optional path where the copy wil be stored, + !! if passed then the copy is added to the + !! memory manager ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1460,33 +1764,33 @@ subroutine copyptr_dbl2d(adbl, name, mem_path, mem_path_copy) integer(I4B) :: ncol integer(I4B) :: nrow ! -- code - call get_from_memorylist(name, mem_path, mt, found) + call get_from_memorylist(name, mem_path, mt, found) adbl => null() ncol = size(mt%adbl2d, dim=1) nrow = size(mt%adbl2d, dim=2) ! -- check the copy into the memory manager if (present(mem_path_copy)) then call allocate_dbl2d(adbl, ncol, nrow, mt%name, mem_path_copy) - ! -- create a local copy + ! -- create a local copy else - allocate(adbl(ncol,nrow)) + allocate (adbl(ncol, nrow)) end if do i = 1, nrow do j = 1, ncol - adbl(j,i) = mt%adbl2d(j,i) + adbl(j, i) = mt%adbl2d(j, i) end do end do ! ! -- return return end subroutine copyptr_dbl2d - + !> @brief Copy values from a 1-dimensional real array in the memory !< manager to a passed 1-dimensional real array subroutine copy_dbl1d(adbl, name, mem_path) real(DP), dimension(:), intent(inout) :: adbl !< target array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1500,15 +1804,15 @@ subroutine copy_dbl1d(adbl, name, mem_path) ! -- return return end subroutine copy_dbl1d - - !> @brief Set the pointer for an integer scalar to + + !> @brief Set the pointer for an integer scalar to !< a target array already stored in the memory manager subroutine reassignptr_int(sclr, name, mem_path, name_target, mem_path_target) - integer(I4B), pointer, intent(inout) :: sclr !< pointer to integer scalar - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in) :: name_target !< name of target variable - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + integer(I4B), pointer, intent(inout) :: sclr !< pointer to integer scalar + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name_target !< name of target variable + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! -- local type(MemoryType), pointer :: mt type(MemoryType), pointer :: mt2 @@ -1518,12 +1822,13 @@ subroutine reassignptr_int(sclr, name, mem_path, name_target, mem_path_target) call get_from_memorylist(name_target, mem_path_target, mt2, found) if (associated(sclr)) then nvalues_aint = nvalues_aint - 1 - deallocate(sclr) + deallocate (sclr) end if sclr => mt2%intsclr mt%intsclr => sclr - mt%isize = 1 - write(mt%memtype, "(a,' (',i0,')')") 'INTEGER', mt%isize + mt%element_size = I4B + mt%isize = 1 + write (mt%memtype, "(a,' (',i0,')')") 'INTEGER', mt%isize ! ! -- set master information mt%master = .false. @@ -1534,14 +1839,14 @@ subroutine reassignptr_int(sclr, name, mem_path, name_target, mem_path_target) return end subroutine reassignptr_int - !> @brief Set the pointer for a 1-dimensional integer array to + !> @brief Set the pointer for a 1-dimensional integer array to !< a target array already stored in the memory manager subroutine reassignptr_int1d(aint, name, mem_path, name_target, mem_path_target) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< pointer to 1d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in) :: name_target !< name of target variable - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< pointer to 1d integer array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name_target !< name of target variable + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! -- local type(MemoryType), pointer :: mt type(MemoryType), pointer :: mt2 @@ -1551,12 +1856,13 @@ subroutine reassignptr_int1d(aint, name, mem_path, name_target, mem_path_target) call get_from_memorylist(name_target, mem_path_target, mt2, found) if (size(aint) > 0) then nvalues_aint = nvalues_aint - size(aint) - deallocate(aint) + deallocate (aint) end if aint => mt2%aint1d mt%aint1d => aint - mt%isize = size(aint) - write(mt%memtype, "(a,' (',i0,')')") 'INTEGER', mt%isize + mt%element_size = I4B + mt%isize = size(aint) + write (mt%memtype, "(a,' (',i0,')')") 'INTEGER', mt%isize ! ! -- set master information mt%master = .false. @@ -1567,14 +1873,14 @@ subroutine reassignptr_int1d(aint, name, mem_path, name_target, mem_path_target) return end subroutine reassignptr_int1d - !> @brief Set the pointer for a 2-dimensional integer array to + !> @brief Set the pointer for a 2-dimensional integer array to !< a target array already stored in the memory manager subroutine reassignptr_int2d(aint, name, mem_path, name_target, mem_path_target) - integer(I4B), dimension(:,:), pointer, contiguous, intent(inout) :: aint !< pointer to 2d integer array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in) :: name_target !< name of target variable - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< pointer to 2d integer array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name_target !< name of target variable + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! -- local type(MemoryType), pointer :: mt type(MemoryType), pointer :: mt2 @@ -1586,14 +1892,15 @@ subroutine reassignptr_int2d(aint, name, mem_path, name_target, mem_path_target) call get_from_memorylist(name_target, mem_path_target, mt2, found) if (size(aint) > 0) then nvalues_aint = nvalues_aint - size(aint) - deallocate(aint) + deallocate (aint) end if aint => mt2%aint2d mt%aint2d => aint + mt%element_size = I4B mt%isize = size(aint) ncol = size(aint, dim=1) nrow = size(aint, dim=2) - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'INTEGER', ncol, nrow ! ! -- set master information mt%master = .false. @@ -1604,14 +1911,14 @@ subroutine reassignptr_int2d(aint, name, mem_path, name_target, mem_path_target) return end subroutine reassignptr_int2d - !> @brief Set the pointer for a 1-dimensional real array to + !> @brief Set the pointer for a 1-dimensional real array to !< a target array already stored in the memory manager subroutine reassignptr_dbl1d(adbl, name, mem_path, name_target, mem_path_target) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< pointer to 1d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in) :: name_target !< name of target variable - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< pointer to 1d real array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name_target !< name of target variable + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! -- local type(MemoryType), pointer :: mt type(MemoryType), pointer :: mt2 @@ -1621,12 +1928,13 @@ subroutine reassignptr_dbl1d(adbl, name, mem_path, name_target, mem_path_target) call get_from_memorylist(name_target, mem_path_target, mt2, found) if (size(adbl) > 0) then nvalues_adbl = nvalues_adbl - size(adbl) - deallocate(adbl) + deallocate (adbl) end if adbl => mt2%adbl1d mt%adbl1d => adbl - mt%isize = size(adbl) - write(mt%memtype, "(a,' (',i0,')')") 'DOUBLE', mt%isize + mt%element_size = DP + mt%isize = size(adbl) + write (mt%memtype, "(a,' (',i0,')')") 'DOUBLE', mt%isize ! ! -- set master information mt%master = .false. @@ -1637,14 +1945,14 @@ subroutine reassignptr_dbl1d(adbl, name, mem_path, name_target, mem_path_target) return end subroutine reassignptr_dbl1d - !> @brief Set the pointer for a 2-dimensional real array to + !> @brief Set the pointer for a 2-dimensional real array to !< a target array already stored in the memory manager subroutine reassignptr_dbl2d(adbl, name, mem_path, name_target, mem_path_target) - real(DP), dimension(:,:), pointer, contiguous, intent(inout) :: adbl !< pointer to 2d real array - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored - character(len=*), intent(in) :: name_target !< name of target variable - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< pointer to 2d real array + character(len=*), intent(in) :: name !< variable name + character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), intent(in) :: name_target !< name of target variable + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! -- local type(MemoryType), pointer :: mt type(MemoryType), pointer :: mt2 @@ -1656,14 +1964,15 @@ subroutine reassignptr_dbl2d(adbl, name, mem_path, name_target, mem_path_target) call get_from_memorylist(name_target, mem_path_target, mt2, found) if (size(adbl) > 0) then nvalues_adbl = nvalues_adbl - size(adbl) - deallocate(adbl) + deallocate (adbl) end if adbl => mt2%adbl2d mt%adbl2d => adbl + mt%element_size = DP mt%isize = size(adbl) ncol = size(adbl, dim=1) nrow = size(adbl, dim=2) - write(mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow + write (mt%memtype, "(a,' (',i0,',',i0,')')") 'DOUBLE', ncol, nrow ! ! -- set master information mt%master = .false. @@ -1677,47 +1986,77 @@ end subroutine reassignptr_dbl2d !> @brief Deallocate a variable-length character string !< subroutine deallocate_str(sclr, name, mem_path) - character(len=*), pointer, intent(inout) :: sclr !< pointer to string - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + character(len=*), pointer, intent(inout) :: sclr !< pointer to string + character(len=*), intent(in), optional :: name !< variable name + character(len=*), intent(in), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found + integer(I4B) :: ipos ! -- code - if (associated(sclr)) then - call get_from_memorylist(name, mem_path, mt, found, check=.FALSE.) - if (.not. found) then - call store_error('Programming error in deallocate_str.', terminate=.TRUE.) + found = .false. + if (present(name) .and. present(mem_path)) then + call get_from_memorylist(name, mem_path, mt, found) + nullify (mt%strsclr) + else + do ipos = 1, memorylist%count() + mt => memorylist%Get(ipos) + if (associated(mt%strsclr, sclr)) then + nullify (mt%strsclr) + found = .true. + exit + end if + end do + end if + if (.not. found) then + call store_error('Programming error in deallocate_str.', terminate=.TRUE.) + else + if (mt%master) then + deallocate (sclr) else - deallocate(sclr) + nullify (sclr) end if end if ! ! -- return return end subroutine deallocate_str - - !> @brief Deallocate an array of variable-length character strings + + !> @brief Deallocate an array of defined-length character strings !! - !! @todo confirm this description versus the previous doc !< - subroutine deallocate_str1d(astr, name, mem_path) - character(len=*), dimension(:), pointer, contiguous, intent(inout) :: astr !< array of strings - character(len=*), intent(in) :: name !< variable name - character(len=*), intent(in) :: mem_path !< path where variable is stored + subroutine deallocate_str1d(astr1d, name, mem_path) + character(len=*), dimension(:), pointer, contiguous, intent(inout) :: astr1d !< array of strings + character(len=*), optional, intent(in) :: name !< variable name + character(len=*), optional, intent(in) :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found + integer(I4B) :: ipos ! -- code - if (associated(astr)) then - call get_from_memorylist(name, mem_path, mt, found, check=.FALSE.) - if (.not. found) then - errmsg = "Programming error in deallocate_str1d. Variable '" // & - trim(name) // "' in '" // trim(mem_path) // "' is not " // & - "present in the memory manager but is associated." - call store_error(errmsg, terminate=.TRUE.) + ! + ! -- process optional variables + found = .false. + if (present(name) .and. present(mem_path)) then + call get_from_memorylist(name, mem_path, mt, found) + nullify (mt%astr1d) + else + do ipos = 1, memorylist%count() + mt => memorylist%Get(ipos) + if (associated(mt%astr1d, astr1d)) then + nullify (mt%astr1d) + found = .true. + exit + end if + end do + end if + if (.not. found .and. size(astr1d) > 0) then + call store_error('programming error in deallocate_str1d', terminate=.TRUE.) + else + if (mt%master) then + deallocate (astr1d) else - deallocate(astr) + nullify (astr1d) end if end if ! @@ -1725,10 +2064,54 @@ subroutine deallocate_str1d(astr, name, mem_path) return end subroutine deallocate_str1d + !> @brief Deallocate an array of deferred-length character strings + !! + !< + subroutine deallocate_charstr1d(astr1d, name, mem_path) + type(CharacterStringType), dimension(:), pointer, contiguous, & + intent(inout) :: astr1d !< array of strings + character(len=*), optional, intent(in) :: name !< variable name + character(len=*), optional, intent(in) :: mem_path !< path where variable is stored + ! -- local + type(MemoryType), pointer :: mt + logical(LGP) :: found + integer(I4B) :: ipos + ! -- code + ! + ! -- process optional variables + found = .false. + if (present(name) .and. present(mem_path)) then + call get_from_memorylist(name, mem_path, mt, found) + nullify (mt%acharstr1d) + else + do ipos = 1, memorylist%count() + mt => memorylist%Get(ipos) + if (associated(mt%acharstr1d, astr1d)) then + nullify (mt%acharstr1d) + found = .true. + exit + end if + end do + end if + if (.not. found .and. size(astr1d) > 0) then + call store_error('programming error in deallocate_charstr1d', & + terminate=.TRUE.) + else + if (mt%master) then + deallocate (astr1d) + else + nullify (astr1d) + end if + end if + ! + ! -- return + return + end subroutine deallocate_charstr1d + !> @brief Deallocate a logical scalar !< subroutine deallocate_logical(sclr) - logical(LGP), pointer, intent(inout) :: sclr !< logical scalar to deallocate + logical(LGP), pointer, intent(inout) :: sclr !< logical scalar to deallocate ! -- local class(MemoryType), pointer :: mt logical(LGP) :: found @@ -1737,30 +2120,31 @@ subroutine deallocate_logical(sclr) found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%logicalsclr, sclr)) then - nullify(mt%logicalsclr) + if (associated(mt%logicalsclr, sclr)) then + nullify (mt%logicalsclr) found = .true. exit end if end do if (.not. found) then - call store_error('programming error in deallocate_logical', terminate=.TRUE.) + call store_error('programming error in deallocate_logical', & + terminate=.TRUE.) else if (mt%master) then - deallocate(sclr) + deallocate (sclr) else - nullify(sclr) + nullify (sclr) end if end if ! ! -- return return end subroutine deallocate_logical - + !> @brief Deallocate a integer scalar !< subroutine deallocate_int(sclr) - integer(I4B), pointer, intent(inout) :: sclr !< integer variable to deallocate + integer(I4B), pointer, intent(inout) :: sclr !< integer variable to deallocate ! -- local class(MemoryType), pointer :: mt logical(LGP) :: found @@ -1769,8 +2153,8 @@ subroutine deallocate_int(sclr) found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%intsclr, sclr)) then - nullify(mt%intsclr) + if (associated(mt%intsclr, sclr)) then + nullify (mt%intsclr) found = .true. exit end if @@ -1779,20 +2163,20 @@ subroutine deallocate_int(sclr) call store_error('Programming error in deallocate_int.', terminate=.TRUE.) else if (mt%master) then - deallocate(sclr) + deallocate (sclr) else - nullify(sclr) + nullify (sclr) end if end if ! ! -- return return end subroutine deallocate_int - + !> @brief Deallocate a real scalar !< subroutine deallocate_dbl(sclr) - real(DP), pointer, intent(inout) :: sclr !< real variable to deallocate + real(DP), pointer, intent(inout) :: sclr !< real variable to deallocate ! -- local class(MemoryType), pointer :: mt logical(LGP) :: found @@ -1801,8 +2185,8 @@ subroutine deallocate_dbl(sclr) found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%dblsclr, sclr)) then - nullify(mt%dblsclr) + if (associated(mt%dblsclr, sclr)) then + nullify (mt%dblsclr) found = .true. exit end if @@ -1811,7 +2195,7 @@ subroutine deallocate_dbl(sclr) call store_error('Programming error in deallocate_dbl.', terminate=.TRUE.) else if (mt%master) then - deallocate(sclr) + deallocate (sclr) else nullify (sclr) end if @@ -1820,13 +2204,13 @@ subroutine deallocate_dbl(sclr) ! -- return return end subroutine deallocate_dbl - + !> @brief Deallocate a 1-dimensional integer array !< subroutine deallocate_int1d(aint, name, mem_path) - integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< 1d integer array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: aint !< 1d integer array to deallocate + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1834,40 +2218,40 @@ subroutine deallocate_int1d(aint, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%aint1d) + nullify (mt%aint1d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) if (associated(mt%aint1d, aint)) then - nullify(mt%aint1d) + nullify (mt%aint1d) found = .true. exit end if end do end if - if (.not. found .and. size(aint) > 0 ) then + if (.not. found .and. size(aint) > 0) then call store_error('programming error in deallocate_int1d', terminate=.TRUE.) else if (mt%master) then - deallocate(aint) + deallocate (aint) else - nullify(aint) + nullify (aint) end if end if ! ! -- return return end subroutine deallocate_int1d - + !> @brief Deallocate a 2-dimensional integer array !< subroutine deallocate_int2d(aint, name, mem_path) integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: aint !< 2d integer array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1875,40 +2259,40 @@ subroutine deallocate_int2d(aint, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%aint2d) + nullify (mt%aint2d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%aint2d, aint)) then - nullify(mt%aint2d) + if (associated(mt%aint2d, aint)) then + nullify (mt%aint2d) found = .true. exit end if end do end if - if (.not. found .and. size(aint) > 0 ) then + if (.not. found .and. size(aint) > 0) then call store_error('programming error in deallocate_int2d', terminate=.TRUE.) else if (mt%master) then - deallocate(aint) + deallocate (aint) else - nullify(aint) + nullify (aint) end if end if ! ! -- return return end subroutine deallocate_int2d - + !> @brief Deallocate a 3-dimensional integer array !< subroutine deallocate_int3d(aint, name, mem_path) - integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: aint !< 3d integer array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: aint !< 3d integer array to deallocate + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1916,40 +2300,40 @@ subroutine deallocate_int3d(aint, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%aint3d) + nullify (mt%aint3d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%aint3d, aint)) then - nullify(mt%aint3d) + if (associated(mt%aint3d, aint)) then + nullify (mt%aint3d) found = .true. exit end if end do end if - if (.not. found .and. size(aint) > 0 ) then + if (.not. found .and. size(aint) > 0) then call store_error('programming error in deallocate_int3d', terminate=.TRUE.) else if (mt%master) then - deallocate(aint) + deallocate (aint) else - nullify(aint) + nullify (aint) end if end if ! ! -- return return end subroutine deallocate_int3d - + !> @brief Deallocate a 1-dimensional real array !< subroutine deallocate_dbl1d(adbl, name, mem_path) - real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< 1d real array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + real(DP), dimension(:), pointer, contiguous, intent(inout) :: adbl !< 1d real array to deallocate + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1957,40 +2341,40 @@ subroutine deallocate_dbl1d(adbl, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%adbl1d) + nullify (mt%adbl1d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%adbl1d, adbl)) then - nullify(mt%adbl1d) + if (associated(mt%adbl1d, adbl)) then + nullify (mt%adbl1d) found = .true. exit end if end do end if - if (.not. found .and. size(adbl) > 0 ) then + if (.not. found .and. size(adbl) > 0) then call store_error('programming error in deallocate_dbl1d', terminate=.TRUE.) else if (mt%master) then - deallocate(adbl) + deallocate (adbl) else - nullify(adbl) + nullify (adbl) end if end if ! ! -- return return end subroutine deallocate_dbl1d - + !> @brief Deallocate a 2-dimensional real array !< subroutine deallocate_dbl2d(adbl, name, mem_path) real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: adbl !< 2d real array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -1998,40 +2382,40 @@ subroutine deallocate_dbl2d(adbl, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%adbl2d) + nullify (mt%adbl2d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%adbl2d, adbl)) then - nullify(mt%adbl2d) + if (associated(mt%adbl2d, adbl)) then + nullify (mt%adbl2d) found = .true. exit end if end do end if - if (.not. found .and. size(adbl) > 0 ) then + if (.not. found .and. size(adbl) > 0) then call store_error('programming error in deallocate_dbl2d', terminate=.TRUE.) else if (mt%master) then - deallocate(adbl) + deallocate (adbl) else - nullify(adbl) + nullify (adbl) end if end if ! ! -- return return end subroutine deallocate_dbl2d - + !> @brief Deallocate a 3-dimensional real array !< subroutine deallocate_dbl3d(adbl, name, mem_path) - real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: adbl !< 3d real array to deallocate - character(len=*), optional :: name !< variable name - character(len=*), optional :: mem_path !< path where variable is stored + real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: adbl !< 3d real array to deallocate + character(len=*), optional :: name !< variable name + character(len=*), optional :: mem_path !< path where variable is stored ! -- local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -2039,27 +2423,27 @@ subroutine deallocate_dbl3d(adbl, name, mem_path) ! -- code ! ! -- process optional variables + found = .false. if (present(name) .and. present(mem_path)) then call get_from_memorylist(name, mem_path, mt, found) - nullify(mt%adbl3d) + nullify (mt%adbl3d) else - found = .false. do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) - if(associated(mt%adbl3d, adbl)) then - nullify(mt%adbl3d) + if (associated(mt%adbl3d, adbl)) then + nullify (mt%adbl3d) found = .true. exit end if end do end if - if (.not. found .and. size(adbl) > 0 ) then + if (.not. found .and. size(adbl) > 0) then call store_error('programming error in deallocate_dbl3d', terminate=.TRUE.) else if (mt%master) then - deallocate(adbl) + deallocate (adbl) else - nullify(adbl) + nullify (adbl) end if end if ! @@ -2070,37 +2454,37 @@ end subroutine deallocate_dbl3d !> @brief Set the memory print option !< subroutine mem_set_print_option(iout, keyword, error_msg) - integer(I4B), intent(in) :: iout !< unit number for mfsim.lst - character(len=*), intent(in) :: keyword !< memory print option - character(len=*), intent(inout) :: error_msg !< returned error message if keyword is not valid option + integer(I4B), intent(in) :: iout !< unit number for mfsim.lst + character(len=*), intent(in) :: keyword !< memory print option + character(len=*), intent(inout) :: error_msg !< returned error message if keyword is not valid option ! -- local ! -- format ! -- code select case (keyword) - case ('NONE') - iprmem = 0 - write(iout, '(4x, a)') & - 'LIMITED MEMORY INFORMATION WILL BE WRITTEN.' - case ('SUMMARY') - iprmem = 1 - write(iout, '(4x, a)') & - 'A SUMMARY OF SIMULATION MEMORY INFORMATION WILL BE WRITTEN.' - case ('ALL') - iprmem = 2 - write(iout, '(4x, a)') & - 'ALL SIMULATION MEMORY INFORMATION WILL BE WRITTEN.' - case default - error_msg = "Unknown memory print option '" // trim(keyword) // "." + case ('NONE') + iprmem = 0 + write (iout, '(4x, a)') & + 'LIMITED MEMORY INFORMATION WILL BE WRITTEN.' + case ('SUMMARY') + iprmem = 1 + write (iout, '(4x, a)') & + 'A SUMMARY OF SIMULATION MEMORY INFORMATION WILL BE WRITTEN.' + case ('ALL') + iprmem = 2 + write (iout, '(4x, a)') & + 'ALL SIMULATION MEMORY INFORMATION WILL BE WRITTEN.' + case default + error_msg = "Unknown memory print option '"//trim(keyword)//"." end select return end subroutine mem_set_print_option - + !> @brief Create a table if memory_print_option is 'SUMMARY' !< subroutine mem_summary_table(iout, nrows, cunits) - integer(I4B), intent(in) :: iout !< unit number for mfsim.lst - integer(I4B), intent(in) :: nrows !< number of table rows - character(len=*), intent(in) :: cunits !< memory units (bytes, kilobytes, megabytes, or gigabytes) + integer(I4B), intent(in) :: iout !< unit number for mfsim.lst + integer(I4B), intent(in) :: nrows !< number of table rows + character(len=*), intent(in) :: cunits !< memory units (bytes, kilobytes, megabytes, or gigabytes) ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -2110,8 +2494,8 @@ subroutine mem_summary_table(iout, nrows, cunits) nterms = 6 ! ! -- set up table title - title = 'SUMMARY INFORMATION ON VARIABLES STORED IN THE MEMORY MANAGER, ' // & - 'IN ' // trim(cunits) + title = 'SUMMARY INFORMATION ON VARIABLES STORED IN THE MEMORY MANAGER, '// & + 'IN '//trim(cunits) ! ! -- set up stage tableobj call table_cr(memtab, 'MEM SUM', title) @@ -2143,13 +2527,13 @@ subroutine mem_summary_table(iout, nrows, cunits) ! ! -- return return - end subroutine mem_summary_table - - !> @brief Create a table if memory_print_option is 'ALL' + end subroutine mem_summary_table + + !> @brief Create a table if memory_print_option is 'ALL' !< subroutine mem_detailed_table(iout, nrows) - integer(I4B), intent(in) :: iout !< unit number for mfsim.lst - integer(I4B), intent(in) :: nrows !< number of table rows + integer(I4B), intent(in) :: iout !< unit number for mfsim.lst + integer(I4B), intent(in) :: nrows !< number of table rows ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -2187,17 +2571,17 @@ subroutine mem_detailed_table(iout, nrows) ! ! -- return return - end subroutine mem_detailed_table - + end subroutine mem_detailed_table + !> @brief Write a row for the memory_print_option 'SUMMARY' table !< subroutine mem_summary_line(component, rchars, rlog, rint, rreal, bytes) character(len=*), intent(in) :: component !< character defining the program component (e.g. solution) - real(DP), intent(in) :: rchars !< allocated size of characters (in common units) - real(DP), intent(in) :: rlog !< allocated size of logical (in common units) - real(DP), intent(in) :: rint !< allocated size of integer variables (in common units) - real(DP), intent(in) :: rreal !< allocated size of real variables (in common units) - real(DP), intent(in) :: bytes !< total allocated memory in memory manager (in common units) + real(DP), intent(in) :: rchars !< allocated size of characters (in common units) + real(DP), intent(in) :: rlog !< allocated size of logical (in common units) + real(DP), intent(in) :: rint !< allocated size of integer variables (in common units) + real(DP), intent(in) :: rreal !< allocated size of real variables (in common units) + real(DP), intent(in) :: bytes !< total allocated memory in memory manager (in common units) ! -- formats ! -- code ! @@ -2211,14 +2595,14 @@ subroutine mem_summary_line(component, rchars, rlog, rint, rreal, bytes) ! ! -- return return - end subroutine mem_summary_line + end subroutine mem_summary_line !> @brief Determine appropriate memory unit and conversion factor !< subroutine mem_units(bytes, fact, cunits) ! -- dummy - real(DP), intent(in) :: bytes !< total nr. of bytes - real(DP), intent(inout) :: fact !< conversion factor + real(DP), intent(in) :: bytes !< total nr. of bytes + real(DP), intent(inout) :: fact !< conversion factor character(len=*), intent(inout) :: cunits !< string with memory unit ! -- local ! -- formats @@ -2238,20 +2622,20 @@ subroutine mem_units(bytes, fact, cunits) else if (bytes < DEP9) then fact = DEM6 cunits = 'MEGABYTES' - else + else fact = DEM9 cunits = 'GIGABYTES' end if ! ! -- return return - end subroutine mem_units - - !> @brief Create and fill a table with the total allocated memory + end subroutine mem_units + + !> @brief Create and fill a table with the total allocated memory !< in the memory manager subroutine mem_summary_total(iout, bytes) - integer(I4B), intent(in) :: iout !< unit number for mfsim.lst - real(DP), intent(in) :: bytes !< total number of bytes allocated in the memory manager + integer(I4B), intent(in) :: iout !< unit number for mfsim.lst + real(DP), intent(in) :: bytes !< total number of bytes allocated in the memory manager ! -- local character(len=LINELENGTH) :: title character(len=LINELENGTH) :: text @@ -2271,7 +2655,7 @@ subroutine mem_summary_total(iout, bytes) nrows = 5 ! ! -- set up table title - title = 'MEMORY MANAGER TOTAL STORAGE BY DATA TYPE, IN ' // trim(cunits) + title = 'MEMORY MANAGER TOTAL STORAGE BY DATA TYPE, IN '//trim(cunits) ! ! -- set up stage tableobj call table_cr(memtab, 'MEM TOT', title) @@ -2318,8 +2702,8 @@ subroutine mem_summary_total(iout, bytes) ! ! -- return return - end subroutine mem_summary_total - + end subroutine mem_summary_total + !> @brief Generic function to clean a memory manager table !< subroutine mem_cleanup_table() @@ -2327,21 +2711,21 @@ subroutine mem_cleanup_table() ! -- formats ! -- code call memtab%table_da() - deallocate(memtab) - nullify(memtab) + deallocate (memtab) + nullify (memtab) ! ! -- return return - end subroutine mem_cleanup_table - - !> @brief Write memory manager memory usage based on the + end subroutine mem_cleanup_table + + !> @brief Write memory manager memory usage based on the !! user-specified memory_print_option !! !! The total memory usage by data types (int, real, etc.) !! is written for every simulation. !< subroutine mem_write_usage(iout) - integer(I4B), intent(in) :: iout !< unit number for mfsim.lst + integer(I4B), intent(in) :: iout !< unit number for mfsim.lst ! -- local class(MemoryType), pointer :: mt character(len=LENMEMPATH), allocatable, dimension(:) :: cunique @@ -2364,9 +2748,9 @@ subroutine mem_write_usage(iout) ! -- code ! ! -- Calculate simulation memory allocation - simbytes = (nvalues_astr + & - nvalues_alogical * LGP + & - nvalues_aint * I4B + & + simbytes = (nvalues_astr + & + nvalues_alogical * LGP + & + nvalues_aint * I4B + & nvalues_adbl * DP) simbytes = real(simbytes, DP) ! @@ -2391,7 +2775,7 @@ subroutine mem_write_usage(iout) if (cunique(icomp) /= mt%path(1:ilen)) cycle if (.not. mt%master) cycle if (mt%memtype(1:6) == 'STRING') then - nchars = nchars + mt%isize + nchars = nchars + mt%isize * mt%element_size else if (mt%memtype(1:7) == 'LOGICAL') then nlog = nlog + mt%isize else if (mt%memtype(1:7) == 'INTEGER') then @@ -2432,7 +2816,7 @@ subroutine mem_write_usage(iout) ! -- return return end subroutine mem_write_usage - + !> @brief Deallocate memory in the memory manager !< subroutine mem_da() @@ -2448,11 +2832,18 @@ subroutine mem_da() do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) if (IDEVELOPMODE == 1) then + ! + ! -- check if memory has been deallocated + if (mt%mt_associated() .and. mt%element_size == -1) then + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' has invalid element size' + call store_error(trim(error_msg)) + end if ! ! -- check if memory has been deallocated if (mt%mt_associated() .and. mt%isize > 0) then - error_msg = trim(adjustl(mt%path)) // ' ' // & - trim(adjustl(mt%name)) // ' not deallocated' + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' not deallocated' call store_error(trim(error_msg)) end if ! @@ -2460,15 +2851,15 @@ subroutine mem_da() ucname = mt%name call UPCASE(ucname) if (mt%name /= ucname) then - error_msg = trim(adjustl(mt%path)) // ' ' // & - trim(adjustl(mt%name)) // ' not upper case' + error_msg = trim(adjustl(mt%path))//' '// & + trim(adjustl(mt%name))//' not upper case' call store_error(trim(error_msg)) end if end if ! ! -- deallocate instance of memory type - deallocate(mt) - enddo + deallocate (mt) + end do call memorylist%clear() if (count_errors() > 0) then call store_error('Could not clear memory list.', terminate=.TRUE.) @@ -2477,7 +2868,7 @@ subroutine mem_da() ! -- return return end subroutine mem_da - + !> @brief Create a array with unique first components from all memory paths. !! Only the first component of the memory path is evaluated. !< @@ -2485,7 +2876,7 @@ subroutine mem_unique_origins(cunique) ! -- modules use ArrayHandlersModule, only: ExpandArray, ifind ! -- dummy - character(len=LENMEMPATH), allocatable, dimension(:), intent(inout) :: cunique !< array with unique first components + character(len=LENMEMPATH), allocatable, dimension(:), intent(inout) :: cunique !< array with unique first components ! -- local class(MemoryType), pointer :: mt character(len=LENCOMPONENTNAME) :: component @@ -2495,14 +2886,14 @@ subroutine mem_unique_origins(cunique) ! -- code ! ! -- initialize cunique - allocate(cunique(0)) + allocate (cunique(0)) ! ! -- find unique origins do ipos = 1, memorylist%count() mt => memorylist%Get(ipos) call split_mem_path(mt%path, component, subcomponent) ipa = ifind(cunique, component) - if(ipa < 1) then + if (ipa < 1) then call ExpandArray(cunique, 1) cunique(size(cunique)) = component end if @@ -2511,5 +2902,5 @@ subroutine mem_unique_origins(cunique) ! -- return return end subroutine mem_unique_origins - + end module MemoryManagerModule diff --git a/src/Utilities/Memory/MemoryManagerExt.f90 b/src/Utilities/Memory/MemoryManagerExt.f90 new file mode 100644 index 00000000000..d169449466b --- /dev/null +++ b/src/Utilities/Memory/MemoryManagerExt.f90 @@ -0,0 +1,369 @@ +module MemoryManagerExtModule + + use KindModule, only: DP, LGP, I4B, I8B + use SimModule, only: store_error + use MemoryTypeModule, only: MemoryType + use MemoryManagerModule, only: memorylist, get_from_memorylist + + implicit none + private + public :: mem_set_value + public :: memorylist_remove + + interface mem_set_value + module procedure mem_set_value_logical, mem_set_value_int, & + mem_set_value_int_setval, mem_set_value_str_mapped_int, & + mem_set_value_int1d, mem_set_value_int1d_mapped, & + mem_set_value_int2d, mem_set_value_int3d, mem_set_value_dbl, & + mem_set_value_dbl1d, mem_set_value_dbl1d_mapped, & + mem_set_value_dbl2d, mem_set_value_dbl3d, mem_set_value_str + end interface mem_set_value + +contains + + subroutine memorylist_remove(component, subcomponent, context) + use MemoryHelperModule, only: create_mem_path + use ConstantsModule, only: LENMEMPATH + character(len=*), intent(in) :: component !< name of the solution, model, or exchange + character(len=*), intent(in), optional :: subcomponent !< name of the package (optional) + character(len=*), intent(in), optional :: context !< name of the context (optional) + character(len=LENMEMPATH) :: memory_path !< the memory path + type(MemoryType), pointer :: mt + integer(I4B) :: ipos + logical(LGP) :: removed + + memory_path = create_mem_path(component, subcomponent, context) + removed = .true. !< initialize the loop + + do while (removed) + removed = .false. + do ipos = 1, memorylist%count() + mt => memorylist%Get(ipos) + if (mt%path == memory_path .and. mt%mt_associated()) then + call mt%mt_deallocate() + deallocate (mt) + call memorylist%remove(ipos, .false.) + removed = .true. + exit + end if + end do + end do + end subroutine memorylist_remove + + !> @brief Set pointer to value of memory list logical variable + !< + subroutine mem_set_value_logical(p_mem, varname, memory_path, found) + logical(LGP), pointer, intent(inout) :: p_mem !< pointer to logical scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'LOGICAL') then + p_mem = mt%logicalsclr + end if + end subroutine mem_set_value_logical + + !> @brief Set pointer to value of memory list int variable + !< + subroutine mem_set_value_int(p_mem, varname, memory_path, found) + integer(I4B), pointer, intent(inout) :: p_mem !< pointer to int scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'INTEGER') then + p_mem = mt%intsclr + end if + end subroutine mem_set_value_int + + subroutine mem_set_value_int_setval(p_mem, varname, memory_path, setval, found) + integer(I4B), pointer, intent(inout) :: p_mem !< pointer to int scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + integer(I4B), intent(in) :: setval !< set p_mem to setval if varname found + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found) then + p_mem = setval + end if + end subroutine mem_set_value_int_setval + + subroutine mem_set_value_str_mapped_int(p_mem, varname, memory_path, str_list, & + found) + integer(I4B), pointer, intent(inout) :: p_mem !< pointer to int scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + character(len=*), dimension(:), intent(in) :: str_list + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: i + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'STRING') then + do i = 1, size(str_list) + if (mt%strsclr == str_list(i)) then + p_mem = i + end if + end do + end if + end subroutine mem_set_value_str_mapped_int + + !> @brief Set pointer to value of memory list 1d int array variable + !< + subroutine mem_set_value_int1d(p_mem, varname, memory_path, found) + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: p_mem !< pointer to 1d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: n + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'INTEGER') then + if (size(mt%aint1d) /= size(p_mem)) then + call store_error('mem_set_value() size mismatch int1d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do n = 1, size(mt%aint1d) + p_mem(n) = mt%aint1d(n) + end do + end if + end subroutine mem_set_value_int1d + + !> @brief Set pointer to value of memory list 1d int array variable with mapping + !< + subroutine mem_set_value_int1d_mapped(p_mem, varname, memory_path, map, & + found) + integer(I4B), dimension(:), pointer, contiguous, intent(inout) :: p_mem !< pointer to 1d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: map !< pointer to 1d int mapping array + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: n + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'INTEGER') then + if (associated(map)) then + do n = 1, size(p_mem) + p_mem(n) = mt%aint1d(map(n)) + end do + else + if (size(mt%aint1d) /= size(p_mem)) then + call store_error('mem_set_value() size mismatch int1d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do n = 1, size(mt%aint1d) + p_mem(n) = mt%aint1d(n) + end do + end if + end if + end subroutine mem_set_value_int1d_mapped + + !> @brief Set pointer to value of memory list 2d int array variable + !< + subroutine mem_set_value_int2d(p_mem, varname, memory_path, found) + integer(I4B), dimension(:, :), pointer, contiguous, intent(inout) :: p_mem !< pointer to 2d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: i, j + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'INTEGER') then + if (size(mt%aint2d, dim=1) /= size(p_mem, dim=1) .or. & + size(mt%aint2d, dim=2) /= size(p_mem, dim=2)) then + call store_error('mem_set_value() size mismatch int2d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do j = 1, size(mt%aint2d, dim=2) + do i = 1, size(mt%aint2d, dim=1) + p_mem(i, j) = mt%aint2d(i, j) + end do + end do + end if + end subroutine mem_set_value_int2d + + !> @brief Set pointer to value of memory list 3d int array variable + !< + subroutine mem_set_value_int3d(p_mem, varname, memory_path, found) + integer(I4B), dimension(:, :, :), pointer, contiguous, intent(inout) :: p_mem !< pointer to 3d int array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: i, j, k + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'INTEGER') then + if (size(mt%aint3d, dim=1) /= size(p_mem, dim=1) .or. & + size(mt%aint3d, dim=2) /= size(p_mem, dim=2) .or. & + size(mt%aint3d, dim=3) /= size(p_mem, dim=3)) then + call store_error('mem_set_value() size mismatch int3d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do k = 1, size(mt%aint3d, dim=3) + do j = 1, size(mt%aint3d, dim=2) + do i = 1, size(mt%aint3d, dim=1) + p_mem(i, j, k) = mt%aint3d(i, j, k) + end do + end do + end do + end if + end subroutine mem_set_value_int3d + + !> @brief Set pointer to value of memory list double variable + !< + subroutine mem_set_value_dbl(p_mem, varname, memory_path, found) + real(DP), pointer, intent(inout) :: p_mem !< pointer to dbl scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'DOUBLE') then + p_mem = mt%dblsclr + end if + end subroutine mem_set_value_dbl + + !> @brief Set pointer to value of memory list 1d dbl array variable + !< + subroutine mem_set_value_dbl1d(p_mem, varname, memory_path, found) + real(DP), dimension(:), pointer, contiguous, intent(inout) :: p_mem !< pointer to 1d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: n + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'DOUBLE') then + if (size(mt%adbl1d) /= size(p_mem)) then + call store_error('mem_set_value() size mismatch dbl1d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do n = 1, size(mt%adbl1d) + p_mem(n) = mt%adbl1d(n) + end do + end if + end subroutine mem_set_value_dbl1d + + !> @brief Set pointer to value of memory list 1d dbl array variable with mapping + !< + subroutine mem_set_value_dbl1d_mapped(p_mem, varname, memory_path, map, & + found) + real(DP), dimension(:), pointer, contiguous, intent(inout) :: p_mem !< pointer to 1d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: map !< pointer to 1d int mapping array + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: n + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'DOUBLE') then + if (associated(map)) then + do n = 1, size(p_mem) + p_mem(n) = mt%adbl1d(map(n)) + end do + else + if (size(mt%adbl1d) /= size(p_mem)) then + call store_error('mem_set_value() size mismatch dbl1d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do n = 1, size(mt%adbl1d) + p_mem(n) = mt%adbl1d(n) + end do + end if + end if + end subroutine mem_set_value_dbl1d_mapped + + !> @brief Set pointer to value of memory list 2d dbl array variable + !< + subroutine mem_set_value_dbl2d(p_mem, varname, memory_path, found) + real(DP), dimension(:, :), pointer, contiguous, intent(inout) :: p_mem !< pointer to 2d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: i, j + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'DOUBLE') then + if (size(mt%adbl2d, dim=1) /= size(p_mem, dim=1) .or. & + size(mt%adbl2d, dim=2) /= size(p_mem, dim=2)) then + call store_error('mem_set_value() size mismatch dbl2d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do j = 1, size(mt%adbl2d, dim=2) + do i = 1, size(mt%adbl2d, dim=1) + p_mem(i, j) = mt%adbl2d(i, j) + end do + end do + end if + end subroutine mem_set_value_dbl2d + + !> @brief Set pointer to value of memory list 3d dbl array variable + !< + subroutine mem_set_value_dbl3d(p_mem, varname, memory_path, found) + real(DP), dimension(:, :, :), pointer, contiguous, intent(inout) :: p_mem !< pointer to 3d dbl array + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + integer(I4B) :: i, j, k + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'DOUBLE') then + if (size(mt%adbl3d, dim=1) /= size(p_mem, dim=1) .or. & + size(mt%adbl3d, dim=2) /= size(p_mem, dim=2) .or. & + size(mt%adbl3d, dim=3) /= size(p_mem, dim=3)) then + call store_error('mem_set_value() size mismatch dbl3d, varname='//& + &trim(varname), terminate=.TRUE.) + end if + do k = 1, size(mt%adbl3d, dim=3) + do j = 1, size(mt%adbl3d, dim=2) + do i = 1, size(mt%adbl3d, dim=1) + p_mem(i, j, k) = mt%adbl3d(i, j, k) + end do + end do + end do + end if + end subroutine mem_set_value_dbl3d + + subroutine mem_set_value_str(p_mem, varname, memory_path, found) + character(len=*), intent(inout) :: p_mem !< pointer to str scalar + character(len=*), intent(in) :: varname !< variable name + character(len=*), intent(in) :: memory_path !< path where variable is stored + logical(LGP), intent(inout) :: found + type(MemoryType), pointer :: mt + logical(LGP) :: checkfail = .false. + + call get_from_memorylist(varname, memory_path, mt, found, checkfail) + if (found .and. mt%memtype(1:index(mt%memtype, ' ')) == 'STRING') then + p_mem = mt%strsclr + end if + end subroutine mem_set_value_str + +end module MemoryManagerExtModule diff --git a/src/Utilities/Memory/MemorySetHandler.f90 b/src/Utilities/Memory/MemorySetHandler.f90 index c1756ec79c8..a9af706373b 100644 --- a/src/Utilities/Memory/MemorySetHandler.f90 +++ b/src/Utilities/Memory/MemorySetHandler.f90 @@ -1,6 +1,6 @@ -module MemorySetHandlerModule - use KindModule, only: I4B, LGP - use ListModule, only: ListType +module MemorySetHandlerModule + use KindModule, only: I4B, LGP + use ListModule, only: ListType use MemoryTypeModule, only: MemoryType use MemoryManagerModule, only: get_from_memorylist use ConstantsModule, only: LENMEMPATH, LENVARNAME @@ -27,20 +27,20 @@ subroutine set_handler_iface(owner, status) end subroutine end interface - contains +contains !> @brief Register the event handler and context for this variable !! !! The event handler and its ctx are called whenever the trigger - !! is given by calling @p on_set_memory(). This allows to handle - !! side effects, e.g. when a variable is from outside a class + !! is given by calling @p on_set_memory(). This allows to handle + !! side effects, e.g. when a variable is from outside a class !! (the context) such as happens with the BMI. !< subroutine mem_register_handler(var_name, mem_path, handler, ctx) - character(len=*), intent(in) :: var_name !< the variable name - character(len=*), intent(in) :: mem_path !< the memory path - procedure(set_handler_iface), pointer :: handler !< called after memory is set - class(*), pointer :: ctx !< the context with which the handler should be called + character(len=*), intent(in) :: var_name !< the variable name + character(len=*), intent(in) :: mem_path !< the memory path + procedure(set_handler_iface), pointer :: handler !< called after memory is set + class(*), pointer :: ctx !< the context with which the handler should be called ! local integer(I4B) :: handler_idx class(EventHandlerDataType), pointer :: handler_data => null() @@ -49,7 +49,7 @@ subroutine mem_register_handler(var_name, mem_path, handler, ctx) logical(LGP) :: found ! first store the handler data - allocate(handler_data) + allocate (handler_data) handler_data%handler => handler handler_data%handlerContext => ctx @@ -74,9 +74,9 @@ subroutine mem_register_handler(var_name, mem_path, handler, ctx) !! because the data in memory is no longer consistent... !< subroutine on_memory_set(var_name, mem_path, status) - character(len=*), intent(in) :: var_name !< the variable name - character(len=*), intent(in) :: mem_path !< the memory path - integer(I4B), intent(out) :: status !< status: 0 for success, -1 when failed + character(len=*), intent(in) :: var_name !< the variable name + character(len=*), intent(in) :: mem_path !< the memory path + integer(I4B), intent(out) :: status !< status: 0 for success, -1 when failed ! local type(MemoryType), pointer :: mt logical(LGP) :: found @@ -92,15 +92,15 @@ subroutine on_memory_set(var_name, mem_path, status) status = 0 return end if - + handler_data_genptr => handler_list%GetItem(mt%set_handler_idx) - select type(handler_data_genptr) + select type (handler_data_genptr) class is (EventHandlerDataType) evt_handler_data => handler_data_genptr end select - + ! call the function call evt_handler_data%handler(evt_handler_data%handlerContext, status) end subroutine -end module \ No newline at end of file +end module diff --git a/src/Utilities/Message.f90 b/src/Utilities/Message.f90 index 8298b3b6fdf..c4f40740dcb 100644 --- a/src/Utilities/Message.f90 +++ b/src/Utilities/Message.f90 @@ -1,36 +1,36 @@ !> @brief This module contains message methods !! -!! This module contains generic message methods that are used to +!! This module contains generic message methods that are used to !! create warning and error messages and notes. This module also has methods -!! for counting messages. The module does not have any dependencies on +!! for counting messages. The module does not have any dependencies on !! models, exchanges, or solutions in a simulation. !! !< module MessageModule - + use KindModule, only: LGP, I4B, DP - use ConstantsModule, only: LINELENGTH, MAXCHARLEN, DONE, & + use ConstantsModule, only: LINELENGTH, MAXCHARLEN, DONE, & VSUMMARY - use GenericUtilitiesModule, only: sim_message, write_message - use SimVariablesModule, only: istdout - use ArrayHandlersModule, only: ExpandArray - + use GenericUtilitiesModule, only: sim_message, write_message + use SimVariablesModule, only: istdout + use ArrayHandlersModule, only: ExpandArray + implicit none - + public :: MessageType - + type :: MessageType - character(len=LINELENGTH) :: title !< title of the message - character(len=LINELENGTH) :: name !< message name - integer(I4B) :: nmessage = 0 !< number of messages stored - integer(I4B) :: max_message = 1000 !< default maximum number of messages that can be stored - integer(I4B) :: max_exceeded = 0 !< flag indicating if the maximum number of messages has exceed the maximum number - integer(I4B) :: inc_message = 100 !< amount to increment message array by when calling ExpandArray - character(len=MAXCHARLEN), allocatable, dimension(:) :: message !< message array - - contains - + character(len=LINELENGTH) :: title !< title of the message + character(len=LINELENGTH) :: name !< message name + integer(I4B) :: nmessage = 0 !< number of messages stored + integer(I4B) :: max_message = 1000 !< default maximum number of messages that can be stored + integer(I4B) :: max_exceeded = 0 !< flag indicating if the maximum number of messages has exceed the maximum number + integer(I4B) :: inc_message = 100 !< amount to increment message array by when calling ExpandArray + character(len=MAXCHARLEN), allocatable, dimension(:) :: message !< message array + + contains + procedure :: init_message procedure :: count_message procedure :: set_max_message @@ -39,225 +39,224 @@ module MessageModule procedure :: deallocate_message end type MessageType - - contains - !> @brief Always initialize the message object +contains + + !> @brief Always initialize the message object !! - !! Subroutine that initializes the message object. Allocation of message + !! Subroutine that initializes the message object. Allocation of message !! array occurs on-the-fly. !! - !< - subroutine init_message(this) - ! -- dummy variables - class(MessageType) :: this !< MessageType object - ! - ! -- initialize message variables - this%nmessage = 0 - this%max_message = 1000 - this%max_exceeded = 0 - this%inc_message = 100 - ! - ! -- return - return - end subroutine init_message - - !> @brief Return number of messages + !< + subroutine init_message(this) + ! -- dummy variables + class(MessageType) :: this !< MessageType object + ! + ! -- initialize message variables + this%nmessage = 0 + this%max_message = 1000 + this%max_exceeded = 0 + this%inc_message = 100 + ! + ! -- return + return + end subroutine init_message + + !> @brief Return number of messages !! !! Function to return the number of messages that have been stored. !! !! @return ncount number of messages stored !! - !< - function count_message(this) result(nmessage) - ! -- dummy variables - class(MessageType) :: this !< MessageType object - ! -- return variable - integer(I4B) :: nmessage - ! - ! -- set nmessage - if (allocated(this%message)) then - nmessage = this%nmessage - else - nmessage = 0 - end if - ! - ! -- return - return - end function count_message - - !> @brief Set the maximum number of messages stored + !< + function count_message(this) result(nmessage) + ! -- dummy variables + class(MessageType) :: this !< MessageType object + ! -- return variable + integer(I4B) :: nmessage + ! + ! -- set nmessage + if (allocated(this%message)) then + nmessage = this%nmessage + else + nmessage = 0 + end if + ! + ! -- return + return + end function count_message + + !> @brief Set the maximum number of messages stored !! !! Subroutine to set the maximum number of messages that will be stored !! in a simulation. !! - !< - subroutine set_max_message(this, imax) - ! -- dummy variables - class(MessageType) :: this !< MessageType object - integer(I4B), intent(in) :: imax !< maximum number of messages that will be stored - ! - ! -- set max_message - this%max_message = imax - ! - ! -- return - return - end subroutine set_max_message - - !> @brief Store message + !< + subroutine set_max_message(this, imax) + ! -- dummy variables + class(MessageType) :: this !< MessageType object + integer(I4B), intent(in) :: imax !< maximum number of messages that will be stored + ! + ! -- set max_message + this%max_message = imax + ! + ! -- return + return + end subroutine set_max_message + + !> @brief Store message !! !! Subroutine to store a message for printing at the end of !! the simulation. !! - !< - subroutine store_message(this, msg, substring) - ! -- dummy variables - class(MessageType) :: this !< MessageType object - character(len=*), intent(in) :: msg !< message - character(len=*), intent(in), optional :: substring !< optional string that can be used - !! to prevent storing duplicate messages - ! -- local variables - logical(LGP) :: inc_array - logical(LGP) :: increment_message - integer(I4B) :: i - integer(I4B) :: idx - ! - ! -- determine if messages should be expanded - inc_array = .TRUE. - if (allocated(this%message)) then - i = this%nmessage - if (i < size(this%message)) then - inc_array = .FALSE. - end if - end if - ! - ! -- resize message - if (inc_array) then - call ExpandArray(this%message, increment=this%inc_message) - this%inc_message = int(this%inc_message * 1.1) - end if - ! - ! -- Determine if the substring exists in the passed message. - ! If substring is in passed message, do not add the duplicate - ! passed message. - increment_message = .TRUE. - if (present(substring)) then - do i = 1, this%nmessage - idx = index(this%message(i), substring) - if (idx > 0) then - increment_message = .FALSE. - exit - end if - end do + !< + subroutine store_message(this, msg, substring) + ! -- dummy variables + class(MessageType) :: this !< MessageType object + character(len=*), intent(in) :: msg !< message + character(len=*), intent(in), optional :: substring !< optional string that can be used + !! to prevent storing duplicate messages + ! -- local variables + logical(LGP) :: inc_array + logical(LGP) :: increment_message + integer(I4B) :: i + integer(I4B) :: idx + ! + ! -- determine if messages should be expanded + inc_array = .TRUE. + if (allocated(this%message)) then + i = this%nmessage + if (i < size(this%message)) then + inc_array = .FALSE. end if - ! - ! -- store this message and calculate nmessage - if (increment_message) then - i = this%nmessage + 1 - if (i <= this%max_message) then - this%nmessage = i - this%message(i) = msg - else - this%max_exceeded = this%max_exceeded + 1 + end if + ! + ! -- resize message + if (inc_array) then + call ExpandArray(this%message, increment=this%inc_message) + this%inc_message = int(this%inc_message * 1.1) + end if + ! + ! -- Determine if the substring exists in the passed message. + ! If substring is in passed message, do not add the duplicate + ! passed message. + increment_message = .TRUE. + if (present(substring)) then + do i = 1, this%nmessage + idx = index(this%message(i), substring) + if (idx > 0) then + increment_message = .FALSE. + exit end if + end do + end if + ! + ! -- store this message and calculate nmessage + if (increment_message) then + i = this%nmessage + 1 + if (i <= this%max_message) then + this%nmessage = i + this%message(i) = msg + else + this%max_exceeded = this%max_exceeded + 1 end if - ! - ! -- return - return - end subroutine store_message - - !> @brief Print messages + end if + ! + ! -- return + return + end subroutine store_message + + !> @brief Print messages !! !! Subroutine to print stored messages. !! - !< - subroutine print_message(this, title, name, iunit, level) - ! -- dummy variables - class(MessageType) :: this !< MessageType object - character(len=*), intent(in) :: title !< message title - character(len=*), intent(in) :: name !< message name - integer(I4B), intent(in), optional :: iunit !< optional file unit to save messages to - integer(I4B), intent(in), optional :: level !< optional level of messages to print - ! -- local - character(len=LINELENGTH) :: errmsg - character(len=LINELENGTH) :: cerr - integer(I4B) :: iu - integer(I4B) :: ilevel - integer(I4B) :: i - integer(I4B) :: isize - integer(I4B) :: iwidth - ! -- formats - character(len=*), parameter :: stdfmt = "(/,A,/)" - ! - ! -- process optional variables - if (present(iunit)) then - iu = iunit - else - iu = 0 - end if - if (present(level)) then - ilevel = level - else - ilevel = VSUMMARY - end if - ! - ! -- write the title and all message entries - if (allocated(this%message)) then - isize = this%nmessage - if (isize > 0) then - ! - ! -- calculate the maximum width of the prepended string - ! for the counter - write(cerr, '(i0)') isize - iwidth = len_trim(cerr) + 1 - ! - ! -- write title for message + !< + subroutine print_message(this, title, name, iunit, level) + ! -- dummy variables + class(MessageType) :: this !< MessageType object + character(len=*), intent(in) :: title !< message title + character(len=*), intent(in) :: name !< message name + integer(I4B), intent(in), optional :: iunit !< optional file unit to save messages to + integer(I4B), intent(in), optional :: level !< optional level of messages to print + ! -- local + character(len=LINELENGTH) :: errmsg + character(len=LINELENGTH) :: cerr + integer(I4B) :: iu + integer(I4B) :: ilevel + integer(I4B) :: i + integer(I4B) :: isize + integer(I4B) :: iwidth + ! -- formats + character(len=*), parameter :: stdfmt = "(/,A,/)" + ! + ! -- process optional variables + if (present(iunit)) then + iu = iunit + else + iu = 0 + end if + if (present(level)) then + ilevel = level + else + ilevel = VSUMMARY + end if + ! + ! -- write the title and all message entries + if (allocated(this%message)) then + isize = this%nmessage + if (isize > 0) then + ! + ! -- calculate the maximum width of the prepended string + ! for the counter + write (cerr, '(i0)') isize + iwidth = len_trim(cerr) + 1 + ! + ! -- write title for message + if (iu > 0) then + call sim_message(title, iunit=iu, fmt=stdfmt, level=ilevel) + end if + call sim_message(title, fmt=stdfmt, level=ilevel) + ! + ! -- write each message + do i = 1, isize + call write_message(this%message(i), icount=i, iwidth=iwidth, & + level=ilevel) if (iu > 0) then - call sim_message(title, iunit=iu, fmt=stdfmt, level=ilevel) - end if - call sim_message(title, fmt=stdfmt, level=ilevel) - ! - ! -- write each message - do i = 1, isize call write_message(this%message(i), icount=i, iwidth=iwidth, & - level=ilevel) - if (iu > 0) then - call write_message(this%message(i), icount=i, iwidth=iwidth, & - iunit=iu, level=ilevel) - end if - end do - ! - ! -- write the number of additional messages - if (this%max_exceeded > 0) then - write(errmsg, '(i0,3(1x,a))') & - this%max_exceeded, 'additional', trim(name), & - 'detected but not printed.' - call sim_message(trim(errmsg), fmt='(/,1x,a)', level=ilevel) - if (iu > 0) then - call sim_message(trim(errmsg), iunit=iu, fmt='(/,1x,a)', & - level=ilevel) - end if + iunit=iu, level=ilevel) + end if + end do + ! + ! -- write the number of additional messages + if (this%max_exceeded > 0) then + write (errmsg, '(i0,3(1x,a))') & + this%max_exceeded, 'additional', trim(name), & + 'detected but not printed.' + call sim_message(trim(errmsg), fmt='(/,1x,a)', level=ilevel) + if (iu > 0) then + call sim_message(trim(errmsg), iunit=iu, fmt='(/,1x,a)', & + level=ilevel) end if end if end if - ! - ! -- return - return - end subroutine print_message + end if + ! + ! -- return + return + end subroutine print_message - !> @ brief Deallocate message !! - !! Subroutine that deallocate the array of strings if it was allocated + !! Subroutine that deallocate the array of strings if it was allocated !! !< subroutine deallocate_message(this) ! -- dummy variables - class(MessageType) :: this !< MessageType object + class(MessageType) :: this !< MessageType object ! ! -- deallocate the message if (allocated(this%message)) then - deallocate(this%message) + deallocate (this%message) end if ! ! -- return diff --git a/src/Utilities/NameFile.f90 b/src/Utilities/NameFile.f90 index 6b6131b0401..115a8550c26 100644 --- a/src/Utilities/NameFile.f90 +++ b/src/Utilities/NameFile.f90 @@ -1,11 +1,11 @@ module NameFileModule use KindModule, only: DP, I4B - use InputOutputModule, only: ParseLine, openfile, getunit - use ConstantsModule, only: LINELENGTH, LENPACKAGENAME + use InputOutputModule, only: ParseLine, openfile, getunit + use ConstantsModule, only: LINELENGTH, LENPACKAGENAME use ArrayHandlersModule, only: ExpandArray, remove_character - use IunitModule, only: IunitType - use BlockParserModule, only: BlockParserType + use IunitModule, only: IunitType + use BlockParserModule, only: BlockParserType implicit none private public :: NameFileType @@ -18,17 +18,17 @@ module NameFileModule type(IunitType) :: iunit_obj type(BlockParserType) :: parser contains - procedure :: init => namefile_init - procedure :: add_cunit => namefile_add_cunit - procedure :: openlistfile => namefile_openlistfile - procedure :: openfiles => namefile_openfiles - procedure :: get_unitnumber => namefile_get_unitnumber - procedure :: get_nval_for_row => namefile_get_nval_for_row + procedure :: init => namefile_init + procedure :: add_cunit => namefile_add_cunit + procedure :: openlistfile => namefile_openlistfile + procedure :: openfiles => namefile_openfiles + procedure :: get_unitnumber => namefile_get_unitnumber + procedure :: get_nval_for_row => namefile_get_nval_for_row procedure :: get_unitnumber_rowcol => namefile_get_unitnumber_rowcol - procedure :: get_pakname => namefile_get_pakname + procedure :: get_pakname => namefile_get_pakname end type NameFileType - contains +contains subroutine namefile_init(this, filename, iout) ! ****************************************************************************** @@ -49,9 +49,9 @@ subroutine namefile_init(this, filename, iout) integer(I4B) :: i, ierr, inunit, n logical :: isFound, endOfBlock ! -- formats - character(len=*), parameter :: fmtfname = & - "(1x, 'NON-COMMENTED ENTRIES FOUND IN ', /, & - &4X, 'BLOCK: ', a, /, & + character(len=*), parameter :: fmtfname = & + "(1x, 'NON-COMMENTED ENTRIES FOUND IN ', /, & + &4X, 'BLOCK: ', a, /, & &4X, 'FILE: ', a)" character(len=*), parameter :: fmtbeg = "(/, 1x, A)" character(len=*), parameter :: fmtline = "(2x, a)" @@ -60,8 +60,8 @@ subroutine namefile_init(this, filename, iout) ! ! -- Store filename and initialize variables this%filename = filename - allocate(this%opts(0)) - allocate(this%input_files(0)) + allocate (this%opts(0)) + allocate (this%input_files(0)) ! ! -- Open the name file and initialize the block parser inunit = getunit() @@ -70,8 +70,8 @@ subroutine namefile_init(this, filename, iout) ! ! -- Read and set the options call this%parser%GetBlock('OPTIONS', isFound, ierr, & - supportOpenClose=.true., blockRequired=.false.) - if(isFound) then + supportOpenClose=.true., blockRequired=.false.) + if (isFound) then ! ! -- Populate this%opts n = 0 @@ -82,26 +82,26 @@ subroutine namefile_init(this, filename, iout) call ExpandArray(this%opts) n = n + 1 this%opts(n) = adjustl(line) - enddo getopts + end do getopts ! - if(iout > 0) then - write(iout, fmtfname) 'OPTIONS', trim(adjustl(filename)) - write(iout, fmtbeg) 'BEGIN OPTIONS' + if (iout > 0) then + write (iout, fmtfname) 'OPTIONS', trim(adjustl(filename)) + write (iout, fmtbeg) 'BEGIN OPTIONS' do i = 1, n - write(iout, fmtline) trim(adjustl(this%opts(i))) - enddo - write(iout, fmtend) 'END OPTIONS' - endif + write (iout, fmtline) trim(adjustl(this%opts(i))) + end do + write (iout, fmtend) 'END OPTIONS' + end if else - if(iout > 0) then - write(iout, '(/, A, /)') 'NO VALID OPTIONS BLOCK DETECTED' - endif - endif + if (iout > 0) then + write (iout, '(/, A, /)') 'NO VALID OPTIONS BLOCK DETECTED' + end if + end if ! ! -- Read and set the input_files call this%parser%GetBlock('PACKAGES', isFound, ierr, & - supportOpenClose=.true.) - if(isFound) then + supportOpenClose=.true.) + if (isFound) then ! ! -- Populate this%input_files n = 0 @@ -112,24 +112,24 @@ subroutine namefile_init(this, filename, iout) call ExpandArray(this%input_files) n = n + 1 this%input_files(n) = adjustl(line) - enddo getpaks + end do getpaks ! ! -- Write to list file - if(iout > 0) then - write(iout, fmtfname) 'PACKAGES', trim(adjustl(filename)) - write(iout, fmtbeg) 'BEGIN PACKAGES' + if (iout > 0) then + write (iout, fmtfname) 'PACKAGES', trim(adjustl(filename)) + write (iout, fmtbeg) 'BEGIN PACKAGES' do i = 1, n - write(iout, fmtline) trim(adjustl(this%input_files(i))) - enddo - write(iout, fmtend) 'END PACKAGES' - endif + write (iout, fmtline) trim(adjustl(this%input_files(i))) + end do + write (iout, fmtend) 'END PACKAGES' + end if else ! ! -- Package block not found. Terminate with error. - write(errmsg, '(a, a)') 'Error reading PACKAGES from file: ', & - trim(adjustl(filename)) + write (errmsg, '(a, a)') 'Error reading PACKAGES from file: ', & + trim(adjustl(filename)) call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- return return @@ -182,13 +182,13 @@ subroutine namefile_openlistfile(this, iout) findloop: do i = 1, size(this%opts) call ParseLine(this%opts(i), nwords, words) call upcase(words(1)) - if(words(1) == 'LIST') then + if (words(1) == 'LIST') then fname = words(2) ipos = i found = .true. exit findloop - endif - enddo findloop + end if + end do findloop ! ! -- remove list file from options list if (ipos > 0) then @@ -206,13 +206,13 @@ subroutine namefile_openlistfile(this, iout) if (this%filename(i:i) == '.') then istart = i exit - endif - enddo + end if + end do if (istart == 0) istart = istop + 1 fname = this%filename(1:istart) istop = istart + 3 fname(istart:istop) = '.lst' - endif + end if ! ! -- Open the list file iout = getunit() @@ -248,7 +248,7 @@ subroutine namefile_openfiles(this, iout) ! -- Parse the line and set defaults call ParseLine(this%input_files(i), nwords, words) call upcase(words(1)) - ftype = words(1)(1:20) + ftype = words(1) (1:20) accarg = 'SEQUENTIAL' fmtarg = 'FORMATTED' filstat = 'OLD' @@ -258,9 +258,9 @@ subroutine namefile_openfiles(this, iout) call this%iunit_obj%addfile(ftype, inunit, i, this%filename) ! ! -- Open the file - call openfile(inunit, iout, trim(adjustl(words(2))), & + call openfile(inunit, iout, trim(adjustl(words(2))), & ftype, fmtarg, accarg, filstat) - enddo + end do ! ! -- return return @@ -307,8 +307,8 @@ function namefile_get_nval_for_row(this, irow) result(nval) return end function namefile_get_nval_for_row - function namefile_get_unitnumber_rowcol(this, irow, jcol) & - result(iu) + function namefile_get_unitnumber_rowcol(this, irow, jcol) & + result(iu) ! ****************************************************************************** ! namefile_get_unitnumber_rowcol -- Get the unit number for entries in ! cunit(irow) and columns (icol). For example, return the unit number for @@ -358,23 +358,22 @@ subroutine namefile_get_pakname(this, irow, jcol, pakname) pakname = '' if (nwords > 2) then ilen = len(trim(adjustl(words(3)))) - if(ilen > LENPACKAGENAME) then - write(errmsg, "(a, i0, a)") & - 'ERROR. PACKAGENAME MUST NOT BE GREATER THAN ', & - LENPACKAGENAME, ' CHARACTERS.' + if (ilen > LENPACKAGENAME) then + write (errmsg, "(a, i0, a)") & + 'ERROR. PACKAGENAME MUST NOT BE GREATER THAN ', & + LENPACKAGENAME, ' CHARACTERS.' call store_error(errmsg) call store_error(trim(this%input_files(ipos))) - write(errmsg, '(a, a)') 'Error in PACKAGES block in file: ', & - trim(adjustl(this%filename)) + write (errmsg, '(a, a)') 'Error in PACKAGES block in file: ', & + trim(adjustl(this%filename)) call store_error(errmsg, terminate=.TRUE.) - endif + end if pakname = trim(adjustl(words(3))) call upcase(pakname) - endif + end if ! ! -- return return end subroutine namefile_get_pakname - end module NameFileModule diff --git a/src/Utilities/Observation/Obs3.f90 b/src/Utilities/Observation/Obs3.f90 index e0e883801c2..54c4cc8e4a2 100644 --- a/src/Utilities/Observation/Obs3.f90 +++ b/src/Utilities/Observation/Obs3.f90 @@ -126,34 +126,34 @@ !------------------------------------------------------------------------------- module ObsModule - use KindModule, only: DP, I4B + use KindModule, only: DP, I4B use ArrayHandlersModule, only: ExpandArray - use BaseDisModule, only: DisBaseType - use BlockParserModule, only: BlockParserType - use ConstantsModule, only: LENBIGLINE, LENFTYPE, LENOBSNAME, & - LENOBSTYPE, LENPACKAGENAME, LENBOUNDNAME, & - LINELENGTH, NAMEDBOUNDFLAG, MAXCHARLEN, & - MAXOBSTYPES, LENHUGELINE, DNODATA, & - TABLEFT - use TableModule, only: TableType, table_cr - use InputOutputModule, only: UPCASE, openfile, GetUnit, GetFileFromPath - use ListModule, only: ListType - use ObsContainerModule, only: ObsContainerType - use ObserveModule, only: ConstructObservation, ObsDataType, & - ObserveType, GetObsFromList, & - AddObsToList + use BaseDisModule, only: DisBaseType + use BlockParserModule, only: BlockParserType + use ConstantsModule, only: LENBIGLINE, LENFTYPE, LENOBSNAME, & + LENOBSTYPE, LENPACKAGENAME, LENBOUNDNAME, & + LINELENGTH, NAMEDBOUNDFLAG, MAXCHARLEN, & + MAXOBSTYPES, LENHUGELINE, DNODATA, & + TABLEFT + use TableModule, only: TableType, table_cr + use InputOutputModule, only: UPCASE, openfile, GetUnit, GetFileFromPath + use ListModule, only: ListType + use ObsContainerModule, only: ObsContainerType + use ObserveModule, only: ConstructObservation, ObsDataType, & + ObserveType, GetObsFromList, & + AddObsToList use ObsOutputListModule, only: ObsOutputListType - use ObsOutputModule, only: ObsOutputType - use ObsUtilityModule, only: write_fmtd_cont, write_unfmtd_cont - use OpenSpecModule, only: ACCESS, FORM - use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error, store_error_unit - use TdisModule, only: totim + use ObsOutputModule, only: ObsOutputType + use ObsUtilityModule, only: write_fmtd_cont, write_unfmtd_cont + use OpenSpecModule, only: ACCESS, FORM + use SimVariablesModule, only: errmsg + use SimModule, only: count_errors, store_error, store_error_unit + use TdisModule, only: totim implicit none private - public :: ObsType, DefaultObsIdProcessor, obs_cr + public :: ObsType, DefaultObsIdProcessor, obs_cr type :: ObsType ! -- Public members @@ -161,17 +161,17 @@ module ObsModule integer(I4B), public :: npakobs = 0 integer(I4B), pointer, public :: inUnitObs => null() character(len=LINELENGTH), pointer, public :: inputFilename => null() - character(len=2*LENPACKAGENAME+4), public :: pkgName = '' + character(len=2*LENPACKAGENAME + 4), public :: pkgName = '' character(len=LENFTYPE), public :: filtyp = '' logical, pointer, public :: active => null() type(ObsContainerType), dimension(:), pointer, public :: pakobs => null() type(ObsDataType), dimension(:), pointer, public :: obsData => null() ! -- Private members - integer(I4B), private :: iprecision = 2 ! 2=double; 1=single + integer(I4B), private :: iprecision = 2 ! 2=double; 1=single integer(I4B), private :: idigits = 0 character(len=LINELENGTH), private :: outputFilename = '' character(len=LINELENGTH), private :: blockTypeFound = '' - character(len=20), private:: obsfmtcont = '' + character(len=20), private :: obsfmtcont = '' logical, private :: echo = .false. logical, private :: more type(ListType), private :: obsList @@ -183,15 +183,15 @@ module ObsModule type(TableType), pointer :: obstab => null() contains ! -- Public procedures - procedure, public :: obs_df - procedure, public :: obs_ar - procedure, public :: obs_ad - procedure, public :: obs_bd_clear - procedure, public :: obs_ot - procedure, public :: obs_da - procedure, public :: SaveOneSimval - procedure, public :: StoreObsType - procedure, public :: allocate_scalars + procedure, public :: obs_df + procedure, public :: obs_ar + procedure, public :: obs_ad + procedure, public :: obs_bd_clear + procedure, public :: obs_ot + procedure, public :: obs_da + procedure, public :: SaveOneSimval + procedure, public :: StoreObsType + procedure, public :: allocate_scalars ! -- Private procedures procedure, private :: build_headers procedure, private :: define_fmts @@ -223,11 +223,11 @@ subroutine obs_cr(obs, inobs) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ObsType), pointer, intent(out) :: obs + type(ObsType), pointer, intent(out) :: obs integer(I4B), pointer, intent(in) :: inobs ! ------------------------------------------------------------------------------ ! - allocate(obs) + allocate (obs) call obs%allocate_scalars() obs%inUnitObs => inobs ! @@ -261,7 +261,7 @@ subroutine DefaultObsIdProcessor(obsrv, dis, inunitobs, iout) ! -- Initialize variables strng = obsrv%IDstring icol = 1 - flag_string = .true. ! Allow strng to contain a boundary name + flag_string = .true. ! Allow strng to contain a boundary name ! n = dis%noder_from_string(icol, istart, istop, inunitobs, & iout, strng, flag_string) @@ -280,7 +280,7 @@ subroutine DefaultObsIdProcessor(obsrv, dis, inunitobs, iout) errmsg = 'Error reading data from ID string' call store_error(errmsg) call store_error_unit(inunitobs) - endif + end if ! return end subroutine DefaultObsIdProcessor @@ -299,7 +299,7 @@ subroutine obs_df(this, iout, pkgname, filtyp, dis) integer(I4B), intent(in) :: iout character(len=*), intent(in) :: pkgname character(len=*), intent(in) :: filtyp - class(DisBaseType), pointer :: dis + class(DisBaseType), pointer :: dis ! ------------------------------------------------------------------------------ ! this%iout = iout @@ -329,7 +329,7 @@ subroutine obs_ar(this) call this%obs_ar1(this%pkgName) if (this%active) then call this%obs_ar2(this%dis) - endif + end if ! return end subroutine obs_ar @@ -350,10 +350,10 @@ subroutine obs_ad(this) ! ------------------------------------------------------------------------------ ! n = this%get_num() - do i=1,n + do i = 1, n obsrv => this%get_obs(i) call obsrv%ResetCurrent() - enddo + end do ! return end subroutine obs_ad @@ -396,7 +396,7 @@ subroutine obs_ot(this) if (this%npakobs > 0) then call this%write_continuous_simvals() call this%obsOutputList%WriteOutputLines() - endif + end if ! return end subroutine obs_ot @@ -415,15 +415,15 @@ subroutine obs_da(this) class(ObserveType), pointer :: obsrv => null() ! ------------------------------------------------------------------------------ ! - deallocate(this%active) - deallocate(this%inputFilename) - deallocate(this%obsData) + deallocate (this%active) + deallocate (this%inputFilename) + deallocate (this%obsData) ! ! -- obs table object if (associated(this%obstab)) then call this%obstab%table_da() - deallocate(this%obstab) - nullify(this%obstab) + deallocate (this%obstab) + nullify (this%obstab) end if ! ! -- deallocate pakobs components and pakobs @@ -431,21 +431,21 @@ subroutine obs_da(this) do i = 1, this%npakobs obsrv => this%pakobs(i)%obsrv call obsrv%da() - deallocate(obsrv) - nullify(this%pakobs(i)%obsrv) + deallocate (obsrv) + nullify (this%pakobs(i)%obsrv) end do - deallocate(this%pakobs) + deallocate (this%pakobs) end if ! ! -- deallocate obsOutputList call this%obsOutputList%DeallocObsOutputList() - deallocate(this%obsOutputList) + deallocate (this%obsOutputList) ! ! -- deallocate obslist call this%obslist%Clear() ! ! -- nullify - nullify(this%inUnitObs) + nullify (this%inUnitObs) ! return end subroutine obs_da @@ -460,9 +460,9 @@ subroutine SaveOneSimval(this, obsrv, simval) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(ObsType) :: this + class(ObsType) :: this class(ObserveType), intent(inout) :: obsrv - real(DP), intent(in) :: simval + real(DP), intent(in) :: simval ! -- local character(len=LENOBSTYPE) :: obsTypeID type(ObsDataType), pointer :: obsDatum => null() @@ -480,7 +480,7 @@ subroutine SaveOneSimval(this, obsrv, simval) obsrv%CurrentTimeStepEndValue = obsrv%CurrentTimeStepEndValue + simval else obsrv%CurrentTimeStepEndValue = simval - endif + end if ! return end subroutine SaveOneSimval @@ -497,37 +497,37 @@ subroutine StoreObsType(this, obsrvType, cumulative, indx) ! ------------------------------------------------------------------------------ ! -- dummy class(ObsType), intent(inout) :: this - character(len=*), intent(in) :: obsrvType + character(len=*), intent(in) :: obsrvType ! cumulative: Accumulate simulated values for multiple boundaries - logical, intent(in) :: cumulative - integer(I4B), intent(out) :: indx + logical, intent(in) :: cumulative + integer(I4B), intent(out) :: indx ! -- local integer(I4B) :: i - character(len=LENOBSTYPE) :: obsTypeUpper + character(len=LENOBSTYPE) :: obsTypeUpper character(len=100) :: msg ! ------------------------------------------------------------------------------ ! ! -- Ensure that obsrvType is not blank - if (obsrvType=='') then + if (obsrvType == '') then msg = 'Programmer error: Invalid argument in store_obs_type.' call store_error(msg, terminate=.TRUE.) - endif + end if ! ! -- Find first unused element indx = -1 - do i=1,MAXOBSTYPES + do i = 1, MAXOBSTYPES if (this%obsData(i)%ObsTypeID /= '') cycle indx = i exit - enddo + end do ! ! -- Ensure that array size is not exceeded if (indx == -1) then msg = 'Size of obsData array is insufficient; ' & - // 'need to increase MAXOBSTYPES.' + //'need to increase MAXOBSTYPES.' call store_error(msg) call store_error_unit(this%inUnitObs) - endif + end if ! ! -- Convert character argument to upper case obsTypeUpper = obsrvType @@ -553,10 +553,10 @@ subroutine allocate_scalars(this) class(ObsType) :: this ! ------------------------------------------------------------------------------ ! - allocate(this%active) - allocate(this%inputFilename) - allocate(this%obsOutputList) - allocate(this%obsData(MAXOBSTYPES)) + allocate (this%active) + allocate (this%inputFilename) + allocate (this%obsOutputList) + allocate (this%obsData(MAXOBSTYPES)) ! ! -- Initialize this%active = .false. @@ -578,21 +578,21 @@ subroutine obs_ar1(this, pkgname) class(ObsType), intent(inout) :: this character(len=*), intent(in) :: pkgname ! -- formats - 10 format(/,'The observation utility is active for "',a,'"') +10 format(/, 'The observation utility is active for "', a, '"') ! ------------------------------------------------------------------------------ ! if (this%inUnitObs > 0) then this%active = .true. ! ! -- Indicate that OBS is active - write(this%iout,10)trim(pkgname) + write (this%iout, 10) trim(pkgname) ! ! -- Read Options block call this%read_obs_options() ! ! -- define output formats call this%define_fmts() - endif + end if ! return end subroutine obs_ar1 @@ -608,11 +608,11 @@ subroutine obs_ar2(this, dis) ! ------------------------------------------------------------------------------ ! -- dummy class(ObsType), intent(inout) :: this - class(DisBaseType) :: dis + class(DisBaseType) :: dis ! -- local integer(I4B) :: i - type(ObsDataType), pointer :: obsDat => null() - character(len=LENOBSTYPE) :: obsTypeID + type(ObsDataType), pointer :: obsDat => null() + character(len=LENOBSTYPE) :: obsTypeID class(ObserveType), pointer :: obsrv => null() ! ------------------------------------------------------------------------------ ! @@ -620,19 +620,19 @@ subroutine obs_ar2(this, dis) ! -- allocate and populate observations array call this%get_obs_array(this%npakobs, this%pakobs) ! - do i=1,this%npakobs + do i = 1, this%npakobs obsrv => this%pakobs(i)%obsrv ! -- Call IDstring processor procedure provided by package obsTypeID = obsrv%ObsTypeId obsDat => this%get_obs_datum(obsTypeID) if (associated(obsDat%ProcessIdPtr)) then call obsDat%ProcessIdPtr(obsrv, dis, & - this%inUnitObs, this%iout) + this%inUnitObs, this%iout) else call DefaultObsIdProcessor(obsrv, dis, & - this%inUnitObs, this%iout) - endif - enddo + this%inUnitObs, this%iout) + end if + end do ! if (count_errors() > 0) then call store_error_unit(this%inunitobs) @@ -662,9 +662,9 @@ subroutine read_obs_options(this) logical :: continueread, found, endOfBlock ! -- formats 10 format('No options block found in OBS input. Defaults will be used.') -40 format('Text output number of digits of precision set to: ',i2) +40 format('Text output number of digits of precision set to: ', i2) 50 format('Text output number of digits set to internal representation (G0).') -60 format(/,'Processing observation options:',/) +60 format(/, 'Processing observation options:',/) ! ------------------------------------------------------------------------------ ! localprecision = 0 @@ -673,7 +673,7 @@ subroutine read_obs_options(this) ! ! -- Find and store file name iin = this%inUnitObs - inquire(unit=iin, name=fname) + inquire (unit=iin, name=fname) this%inputFilename = fname ! ! -- Read Options block @@ -682,22 +682,22 @@ subroutine read_obs_options(this) ! ! -- get BEGIN line of OPTIONS block call this%parser%GetBlock('OPTIONS', found, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) if (ierr /= 0) then ! end of file - errmsg = 'End-of-file encountered while searching for' // & - ' OPTIONS in OBS ' // & - 'input file "' // trim(this%inputFilename) // '"' + errmsg = 'End-of-file encountered while searching for'// & + ' OPTIONS in OBS '// & + 'input file "'//trim(this%inputFilename)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() elseif (.not. found) then this%blockTypeFound = '' - if (this%iout>0) write(this%iout,10) - endif + if (this%iout > 0) write (this%iout, 10) + end if ! ! -- parse OPTIONS entries if (found) then - write(this%iout,60) + write (this%iout, 60) readblockoptions: do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -720,33 +720,33 @@ subroutine read_obs_options(this) ! ! -- Set localdigits to valid value: 0, or 2 to 16 if (localdigits == 0) then - write(this%iout, 50) + write (this%iout, 50) else if (localdigits < 1) then - errmsg = 'Error in OBS input: Invalid value for DIGITS option' - call store_error(errmsg) - exit readblockoptions + errmsg = 'Error in OBS input: Invalid value for DIGITS option' + call store_error(errmsg) + exit readblockoptions else if (localdigits < 2) localdigits = 2 if (localdigits > 16) localdigits = 16 - write(this%iout, 40) localdigits + write (this%iout, 40) localdigits end if case ('PRINT_INPUT') this%echo = .true. - write(this%iout,'(a)')'The PRINT_INPUT option has been specified.' + write (this%iout, '(a)') 'The PRINT_INPUT option has been specified.' case default - errmsg = 'Error in OBS input: Unrecognized option: ' // & - trim(keyword) + errmsg = 'Error in OBS input: Unrecognized option: '// & + trim(keyword) call store_error(errmsg) exit readblockoptions end select - enddo readblockoptions - endif + end do readblockoptions + end if ! - if (count_errors()>0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! - write(this%iout,'(1x)') + write (this%iout, '(1x)') ! ! -- Assign type variables if (localprecision > 0) this%iprecision = localprecision @@ -766,13 +766,13 @@ subroutine define_fmts(this) ! -- dummy class(ObsType) :: this ! formats -50 format('(g',i2.2,'.',i2.2,')') +50 format('(g', i2.2, '.', i2.2, ')') ! ------------------------------------------------------------------------------ ! if (this%idigits == 0) then this%obsfmtcont = '(G0)' else - write(this%obsfmtcont,50) this%idigits+7, this%idigits + write (this%obsfmtcont, 50) this%idigits + 7, this%idigits end if return end subroutine define_fmts @@ -838,9 +838,9 @@ subroutine build_headers(this) integer(I4B) :: iu integer(I4B) :: num integer(int32) :: nobs - character(len=4) :: clenobsname - type(ObserveType), pointer :: obsrv => null() - type(ObsOutputType), pointer :: obsOutput => null() + character(len=4) :: clenobsname + type(ObserveType), pointer :: obsrv => null() + type(ObsOutputType), pointer :: obsOutput => null() ! ------------------------------------------------------------------------------ ! ! -- Cycle through ObsOutputList to write headers @@ -854,40 +854,40 @@ subroutine build_headers(this) ! ! -- write header information to the formatted file if (obsOutput%FormattedOutput) then - write(iu, '(a)', advance='NO') 'time' + write (iu, '(a)', advance='NO') 'time' else ! -- write header to unformatted file ! First 11 bytes are obs type and precision - if (this%iprecision==1) then + if (this%iprecision == 1) then ! -- single precision output - write(iu) 'cont single' - else if (this%iprecision==2) then + write (iu) 'cont single' + else if (this%iprecision == 2) then ! -- double precision output - write(iu) 'cont double' + write (iu) 'cont double' end if ! -- write LENOBSNAME to bytes 12-15 - write(clenobsname,'(i4)') LENOBSNAME - write(iu) clenobsname + write (clenobsname, '(i4)') LENOBSNAME + write (iu) clenobsname ! -- write blanks to complete 100-byte header do ii = 16, 100 - write(iu) ' ' + write (iu) ' ' end do ! -- write NOBS - write(iu) nobs + write (iu) nobs end if ! ! -- write observation name obsfile: do ii = 1, nobs obsrv => this%get_obs(idx) if (obsOutput%FormattedOutput) then - write(iu, '(a,a)', advance='NO') ',', trim(obsrv%Name) + write (iu, '(a,a)', advance='NO') ',', trim(obsrv%Name) ! ! -- terminate the line on the last observation in file if (ii == nobs) then - write(iu, '(a)', advance='YES') '' + write (iu, '(a)', advance='YES') '' end if else - write(iu) obsrv%Name + write (iu) obsrv%Name end if idx = idx + 1 end do obsfile @@ -907,19 +907,19 @@ subroutine get_obs_array(this, nObs, obsArray) ! ------------------------------------------------------------------------------ ! -- dummy class(ObsType), intent(inout) :: this - integer(I4B), intent(out) :: nObs + integer(I4B), intent(out) :: nObs type(ObsContainerType), dimension(:), pointer, intent(inout) :: obsArray ! -- local ! ------------------------------------------------------------------------------ ! nObs = this%get_num() - if (associated(obsArray)) deallocate(obsArray) - allocate(obsArray(nObs)) + if (associated(obsArray)) deallocate (obsArray) + allocate (obsArray(nObs)) ! ! Get observations if (nObs > 0) then call this%populate_obs_array(nObs, obsArray) - endif + end if ! return end subroutine get_obs_array @@ -941,18 +941,18 @@ function get_obs_datum(this, obsTypeID) result(obsDatum) ! ------------------------------------------------------------------------------ ! obsDatum => null() - do i=1,MAXOBSTYPES + do i = 1, MAXOBSTYPES if (this%obsData(i)%ObsTypeID == obsTypeID) then obsDatum => this%obsData(I) exit - endif - enddo + end if + end do ! if (.not. associated(obsDatum)) then - errmsg = 'Observation type not found: ' // trim(obsTypeID) + errmsg = 'Observation type not found: '//trim(obsTypeID) call store_error(errmsg) call store_error_unit(this%inUnitObs) - endif + end if ! return end function get_obs_datum @@ -967,7 +967,7 @@ subroutine populate_obs_array(this, nObs, obsArray) ! ------------------------------------------------------------------------------ ! -- dummy class(ObsType), intent(inout) :: this - integer(I4B), intent(in) :: nObs + integer(I4B), intent(in) :: nObs type(ObsContainerType), dimension(nObs), intent(inout) :: obsArray ! ------------------------------------------------------------------------------ ! @@ -976,10 +976,10 @@ subroutine populate_obs_array(this, nObs, obsArray) type(ObserveType), pointer :: obsrv => null() ! n = this%get_num() - do i=1,n + do i = 1, n obsrv => this%get_obs(i) obsArray(i)%obsrv => obsrv - enddo + end do ! return end subroutine populate_obs_array @@ -994,7 +994,7 @@ function get_obs(this, indx) result(obsrv) ! ------------------------------------------------------------------------------ ! -- dummy class(ObsType) :: this - integer(I4B), intent(in) :: indx + integer(I4B), intent(in) :: indx class(ObserveType), pointer :: obsrv ! -- local ! ------------------------------------------------------------------------------ @@ -1024,8 +1024,8 @@ subroutine read_obs_blocks(this, fname) character(len=LINELENGTH) :: title character(len=LINELENGTH) :: tag character(len=20) :: accarg, bin, fmtarg - type(ObserveType), pointer :: obsrv => null() - type(ObsOutputType), pointer :: obsOutput => null() + type(ObserveType), pointer :: obsrv => null() + type(ObsOutputType), pointer :: obsOutput => null() integer(I4B) :: ntabrows integer(I4B) :: ntabcols ! -- formats @@ -1035,7 +1035,7 @@ subroutine read_obs_blocks(this, fname) numspec = -1 errmsg = '' ! - inquire(unit=this%parser%iuactive, name=pnamein) + inquire (unit=this%parser%iuactive, name=pnamein) call GetFileFromPath(pnamein, fnamein) ! if (this%echo) then @@ -1046,18 +1046,18 @@ subroutine read_obs_blocks(this, fname) ntabcols = 5 ! ! -- initialize table and define columns - title = 'OBSERVATIONS READ FROM FILE "' // trim(fnamein) // '"' + title = 'OBSERVATIONS READ FROM FILE "'//trim(fnamein)//'"' call table_cr(this%obstab, fnamein, title) - call this%obstab%table_df(ntabrows, ntabcols, this%iout, & + call this%obstab%table_df(ntabrows, ntabcols, this%iout, & finalize=.FALSE.) tag = 'NAME' call this%obstab%initialize_column(tag, LENOBSNAME, alignment=TABLEFT) tag = 'TYPE' - call this%obstab%initialize_column(tag, LENOBSTYPE+12, alignment=TABLEFT) + call this%obstab%initialize_column(tag, LENOBSTYPE + 12, alignment=TABLEFT) tag = 'TIME' call this%obstab%initialize_column(tag, 12, alignment=TABLEFT) tag = 'LOCATION DATA' - call this%obstab%initialize_column(tag, LENBOUNDNAME+2, alignment=TABLEFT) + call this%obstab%initialize_column(tag, LENBOUNDNAME + 2, alignment=TABLEFT) tag = 'OUTPUT FILENAME' call this%obstab%initialize_column(tag, 80, alignment=TABLEFT) end if @@ -1075,8 +1075,8 @@ subroutine read_obs_blocks(this, fname) ! Get keyword, which should be FILEOUT call this%parser%GetStringCaps(word) if (word /= 'FILEOUT') then - call store_error('CONTINUOUS keyword must be followed by ' // & - '"FILEOUT" then by filename.') + call store_error('CONTINUOUS keyword must be followed by '// & + '"FILEOUT" then by filename.') cycle end if ! @@ -1084,13 +1084,13 @@ subroutine read_obs_blocks(this, fname) call this%parser%GetString(fname) ! Fname is the output file name defined in the BEGIN line of the block. if (fname == '') then - message = 'Error reading OBS input file, likely due to bad' // & + message = 'Error reading OBS input file, likely due to bad'// & ' block or missing file name.' call store_error(message) cycle else if (this%obsOutputList%ContainsFile(fname)) then - errmsg = 'OBS outfile "' // trim(fname) // & - '" is provided more than once.' + errmsg = 'OBS outfile "'//trim(fname)// & + '" is provided more than once.' call store_error(errmsg) cycle end if @@ -1105,16 +1105,16 @@ subroutine read_obs_blocks(this, fname) fmtarg = 'FORMATTED' accarg = 'SEQUENTIAL' fmtd = .true. - endif + end if ! ! -- open the output file numspec = 0 - call openfile(numspec, 0, fname, 'OBS OUTPUT', fmtarg, & + call openfile(numspec, 0, fname, 'OBS OUTPUT', fmtarg, & accarg, 'REPLACE') ! ! -- add output file to list of output files and assign its ! FormattedOutput member appropriately - call this%obsOutputList%Add(fname,numspec) + call this%obsOutputList%Add(fname, numspec) indexobsout = this%obsOutputList%Count() obsOutput => this%obsOutputList%Get(indexobsout) obsOutput%FormattedOutput = fmtd @@ -1144,8 +1144,8 @@ subroutine read_obs_blocks(this, fname) end if end do readblockcontinuous case default - errmsg = 'Error: Observation block type not recognized: ' // & - trim(btagfound) + errmsg = 'Error: Observation block type not recognized: '// & + trim(btagfound) call store_error(errmsg) end select end do readblocks @@ -1175,9 +1175,9 @@ subroutine write_continuous_simvals(this) ! -- dummy class(ObsType), intent(inout) :: this ! -- local - integer(I4B) :: i, iprec, numobs - character(len=20) :: fmtc - real(DP) :: simval + integer(I4B) :: i, iprec, numobs + character(len=20) :: fmtc + real(DP) :: simval class(ObserveType), pointer :: obsrv => null() ! ------------------------------------------------------------------------------ ! @@ -1186,7 +1186,7 @@ subroutine write_continuous_simvals(this) fmtc = this%obsfmtcont ! -- iterate through all observations numobs = this%obsList%Count() - do i=1,numobs + do i = 1, numobs obsrv => this%get_obs(i) ! -- continuous observation simval = obsrv%CurrentTimeStepEndValue @@ -1194,11 +1194,11 @@ subroutine write_continuous_simvals(this) call write_fmtd_cont(fmtc, obsrv, this%obsOutputList, simval) else call write_unfmtd_cont(obsrv, iprec, this%obsOutputList, simval) - endif + end if end do ! ! -- flush file - flush(obsrv%UnitNumber) + flush (obsrv%UnitNumber) ! ! --return return diff --git a/src/Utilities/Observation/ObsContainer.f90 b/src/Utilities/Observation/ObsContainer.f90 index ee36ab30d66..b59dac00617 100644 --- a/src/Utilities/Observation/ObsContainer.f90 +++ b/src/Utilities/Observation/ObsContainer.f90 @@ -16,7 +16,7 @@ module ObsContainerModule type :: ObsContainerType ! -- Public members - class(ObserveType), pointer, public :: obsrv => null() + class(ObserveType), pointer, public :: obsrv => null() end type ObsContainerType end module ObsContainerModule diff --git a/src/Utilities/Observation/ObsOutput.f90 b/src/Utilities/Observation/ObsOutput.f90 index 2109e61c449..a467031acbe 100644 --- a/src/Utilities/Observation/ObsOutput.f90 +++ b/src/Utilities/Observation/ObsOutput.f90 @@ -64,9 +64,9 @@ subroutine WriteLineout(this) implicit none ! -- dummy class(ObsOutputType), intent(inout) :: this - ! -- write a line return to end of observation output line + ! -- write a line return to end of observation output line ! for this totim - write(this%nunit,'(a)', advance='YES') '' + write (this%nunit, '(a)', advance='YES') '' ! return end subroutine WriteLineout @@ -115,7 +115,7 @@ subroutine ConstructObsOutput(newObsOutput, fname, nunit) character(len=*), intent(in) :: fname integer(I4B), intent(in) :: nunit ! - allocate(newObsOutput) + allocate (newObsOutput) newObsOutput%filename = fname newObsOutput%nunit = nunit return @@ -124,7 +124,7 @@ end subroutine ConstructObsOutput subroutine AddObsOutputToList(list, obsOutput) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(ObsOutputType), pointer, intent(inout) :: obsOutput ! -- local class(*), pointer :: obj @@ -135,12 +135,12 @@ subroutine AddObsOutputToList(list, obsOutput) return end subroutine AddObsOutputToList - function GetObsOutputFromList(list, idx) result (res) + function GetObsOutputFromList(list, idx) result(res) implicit none ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - type(ObsOutputType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + type(ObsOutputType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Utilities/Observation/ObsOutputList.f90 b/src/Utilities/Observation/ObsOutputList.f90 index 6a9f01b0598..55de0b7665f 100644 --- a/src/Utilities/Observation/ObsOutputList.f90 +++ b/src/Utilities/Observation/ObsOutputList.f90 @@ -10,7 +10,7 @@ module ObsOutputListModule use KindModule, only: DP, I4B use InputOutputModule, only: same_word use ListModule, only: ListType - use ObsOutputModule, only: ObsOutputType, ConstructObsOutput, & + use ObsOutputModule, only: ObsOutputType, ConstructObsOutput, & AddObsOutputToList, GetObsOutputFromList implicit none @@ -51,10 +51,10 @@ subroutine ClearOutputLines(this) type(ObsOutputType), pointer :: obsOutput => null() ! num = this%Count() - do i=1,num + do i = 1, num obsOutput => this%Get(i) call obsOutput%ClearLineout() - enddo + end do ! return end subroutine ClearOutputLines @@ -76,7 +76,7 @@ function Count(this) return end function Count - logical function ContainsFile(this,fname) + logical function ContainsFile(this, fname) ! ************************************************************************** ! ContainsFile -- return true if filename fname is included in list of ! ObsOutputType objects @@ -87,24 +87,24 @@ logical function ContainsFile(this,fname) implicit none ! -- dummy class(ObsOutputListType), intent(inout) :: this - character(len=*), intent(in) :: fname + character(len=*), intent(in) :: fname ! -- local type(ObsOutputType), pointer :: obsOutput => null() integer(I4B) :: i, n ! ContainsFile = .false. n = this%Count() - loop1: do i=1,n + loop1: do i = 1, n obsOutput => this%Get(i) - if (same_word(obsOutput%filename,fname)) then + if (same_word(obsOutput%filename, fname)) then ContainsFile = .true. exit loop1 - endif - enddo loop1 + end if + end do loop1 return end function ContainsFile - subroutine Add(this,fname,nunit) + subroutine Add(this, fname, nunit) ! ************************************************************************** ! Add -- construct a new ObsOutputType object with arguments assigned to ! its members, and add the new object to the list @@ -115,8 +115,8 @@ subroutine Add(this,fname,nunit) implicit none ! -- dummy class(ObsOutputListType), intent(inout) :: this - character(len=*), intent(in) :: fname - integer(I4B), intent(in) :: nunit + character(len=*), intent(in) :: fname + integer(I4B), intent(in) :: nunit ! -- local type(ObsOutputType), pointer :: obsOutput => null() ! @@ -143,12 +143,12 @@ subroutine WriteOutputLines(this) integer(I4B) :: i, num ! num = this%Count() - do i=1,num + do i = 1, num obsOutput => this%Get(i) if (obsOutput%FormattedOutput) then call obsOutput%WriteLineout() - endif - enddo + end if + end do ! return end subroutine WriteOutputLines @@ -196,10 +196,10 @@ subroutine DeallocObsOutputList(this) type(ObsOutputType), pointer :: obsoutput => null() ! n = this%Count() - do i=1,n + do i = 1, n obsoutput => GetObsOutputFromList(this%ObsOutputs, i) !call obsoutput%DeallocObsOutput() - enddo + end do ! call this%ObsOutputs%Clear(.true.) ! diff --git a/src/Utilities/Observation/ObsUtility.f90 b/src/Utilities/Observation/ObsUtility.f90 index b8e90576b6b..1b04c70a9c4 100644 --- a/src/Utilities/Observation/ObsUtility.f90 +++ b/src/Utilities/Observation/ObsUtility.f90 @@ -6,11 +6,11 @@ module ObsUtilityModule use KindModule, only: DP, I4B - use ConstantsModule, only: LENOBSNAME, LENBIGLINE - use ObserveModule, only: ObserveType + use ConstantsModule, only: LENOBSNAME, LENBIGLINE + use ObserveModule, only: ObserveType use ObsOutputListModule, only: ObsOutputListType - use ObsOutputModule, only: ObsOutputType - use TdisModule, only: totim + use ObsOutputModule, only: ObsOutputType + use TdisModule, only: totim implicit none @@ -32,16 +32,16 @@ subroutine write_fmtd_cont(fmtc, obsrv, obsOutputList, value) ! -------------------------------------------------------------------------- implicit none ! -- dummy - character(len=*), intent(in) :: fmtc - type(ObserveType), intent(inout) :: obsrv + character(len=*), intent(in) :: fmtc + type(ObserveType), intent(inout) :: obsrv type(ObsOutputListType), pointer, intent(inout) :: obsOutputList - real(DP), intent(in) :: value + real(DP), intent(in) :: value ! -- local - integer(I4B) :: indx - integer(I4B) :: nunit - character(len=50) :: cval + integer(I4B) :: indx + integer(I4B) :: nunit + character(len=50) :: cval character(len=LENOBSNAME), pointer :: linout => null() - type(ObsOutputType), pointer :: ObsOutput => null() + type(ObsOutputType), pointer :: ObsOutput => null() !--------------------------------------------------------------------------- ! -- format for totim 10 format(G20.13) @@ -52,13 +52,13 @@ subroutine write_fmtd_cont(fmtc, obsrv, obsOutputList, value) ObsOutput => obsOutputList%Get(indx) linout => obsOutput%lineout if (linout == '') then - write(linout,10) totim - write(cval,10) totim - write(nunit, '(a)', advance='NO') trim(adjustl(cval)) - endif + write (linout, 10) totim + write (cval, 10) totim + write (nunit, '(a)', advance='NO') trim(adjustl(cval)) + end if ! -- append value to output line - write(cval,fmtc)value - write(nunit, '(a,a)', advance='NO') ',', trim(adjustl(cval)) + write (cval, fmtc) value + write (nunit, '(a,a)', advance='NO') ',', trim(adjustl(cval)) ! ! -- return return @@ -86,11 +86,11 @@ subroutine write_unfmtd_cont(obsrv, iprec, obsOutputList, value) type(ObsOutputListType), pointer, intent(inout) :: obsOutputList real(DP), intent(in) :: value ! -- local - integer(I4B) :: indx, nunit + integer(I4B) :: indx, nunit character(len=LENOBSNAME), pointer :: linout => null() - real(real32) :: totimsngl, valsngl - real(real64) :: totimdbl, valdbl - type(ObsOutputType), pointer :: obsOutput => null() + real(real32) :: totimsngl, valsngl + real(real64) :: totimdbl, valdbl + type(ObsOutputType), pointer :: obsOutput => null() !--------------------------------------------------------------------------- ! -- formats 10 format(G20.13) @@ -101,23 +101,23 @@ subroutine write_unfmtd_cont(obsrv, iprec, obsOutputList, value) obsOutput => obsOutputList%Get(indx) linout => obsOutput%lineout if (linout == '') then - write(linout,10)totim + write (linout, 10) totim if (iprec == 1) then totimsngl = real(totim, real32) - write(nunit)totimsngl + write (nunit) totimsngl elseif (iprec == 2) then totimdbl = totim - write(nunit)totimdbl - endif - endif + write (nunit) totimdbl + end if + end if ! -- write value to unformatted output if (iprec == 1) then valsngl = real(value, real32) - write(nunit)valsngl + write (nunit) valsngl elseif (iprec == 2) then valdbl = value - write(nunit)valdbl - endif + write (nunit) valdbl + end if ! ! -- return return diff --git a/src/Utilities/Observation/Observe.f90 b/src/Utilities/Observation/Observe.f90 index e8f0a732653..cd34726e074 100644 --- a/src/Utilities/Observation/Observe.f90 +++ b/src/Utilities/Observation/Observe.f90 @@ -11,18 +11,18 @@ !----------------------------------------------------------------------- module ObserveModule - use KindModule, only: DP, I4B - use BaseDisModule, only: DisBaseType - use ConstantsModule, only: LENBOUNDNAME, LENOBSNAME, LENOBSTYPE, & - MAXOBSTYPES, DNODATA, DZERO - use TableModule, only: TableType - use InputOutputModule, only: urword - use ListModule, only: ListType - use SimModule, only: store_warning, store_error, & - store_error_unit - use TdisModule, only: totim, totalsimtime + use KindModule, only: DP, I4B + use BaseDisModule, only: DisBaseType + use ConstantsModule, only: LENBOUNDNAME, LENOBSNAME, LENOBSTYPE, & + MAXOBSTYPES, DNODATA, DZERO + use TableModule, only: TableType + use InputOutputModule, only: urword + use ListModule, only: ListType + use SimModule, only: store_warning, store_error, & + store_error_unit + use TdisModule, only: totim, totalsimtime use ArrayHandlersModule, only: ExpandArrayWrapper - + implicit none private @@ -68,11 +68,11 @@ module ObserveModule type(ObsDataType), pointer, private :: obsDatum => null() contains ! -- Public procedures - procedure, public :: ResetCurrent - procedure, public :: WriteTo - procedure, public :: AddObsIndex - procedure, public :: ResetObsIndex - procedure, public :: da + procedure, public :: ResetCurrent + procedure, public :: WriteTo + procedure, public :: AddObsIndex + procedure, public :: ResetObsIndex + procedure, public :: da end type ObserveType type :: ObsDataType @@ -96,10 +96,10 @@ subroutine ProcessIdSub(obsrv, dis, inunitobs, iout) import :: ObserveType import :: DisBaseType ! -- dummy - type(ObserveType), intent(inout) :: obsrv - class(DisBaseType), intent(in) :: dis - integer(I4B), intent(in) :: inunitobs - integer(I4B), intent(in) :: iout + type(ObserveType), intent(inout) :: obsrv + class(DisBaseType), intent(in) :: dis + integer(I4B), intent(in) :: inunitobs + integer(I4B), intent(in) :: iout end subroutine ProcessIdSub end interface @@ -143,21 +143,21 @@ subroutine WriteTo(this, obstab, btagfound, fnamein) if (len_trim(btagfound) > 12) then tag = btagfound(1:12) else - write(tag, '(a12)') btagfound + write (tag, '(a12)') btagfound end if ! ! -- write fnamein to fnameout if (len_trim(fnamein) > 80) then fnameout = fnamein(1:80) else - write(fnameout, '(a80)') fnamein + write (fnameout, '(a80)') fnamein end if ! ! -- write data to observation table call obstab%add_term(this%Name) - call obstab%add_term(tag // trim(this%ObsTypeId)) + call obstab%add_term(tag//trim(this%ObsTypeId)) call obstab%add_term('ALL TIMES') - call obstab%add_term('"' // trim(this%IDstring) // '"') + call obstab%add_term('"'//trim(this%IDstring)//'"') call obstab%add_term(fnameout) ! ! -- return @@ -179,11 +179,11 @@ subroutine ResetObsIndex(this) ! ! -- Deallocate observation index array, if necessary if (allocated(this%indxbnds)) then - deallocate(this%indxbnds) + deallocate (this%indxbnds) end if ! ! -- Allocate observation index array to size 0 - allocate(this%indxbnds(0)) + allocate (this%indxbnds(0)) ! ! -- return return @@ -192,7 +192,7 @@ end subroutine ResetObsIndex subroutine AddObsIndex(this, indx) ! ************************************************************************** ! AddObsIndex -- Add the observation index to the observation index array -! (indbnds). The observation index count (indxbnds_count) +! (indbnds). The observation index count (indxbnds_count) ! is also incremented by one and the observation index array ! is expanded, if necessary. ! ************************************************************************** @@ -226,7 +226,7 @@ subroutine da(this) ! -- dummy class(ObserveType), intent(inout) :: this if (allocated(this%indxbnds)) then - deallocate(this%indxbnds) + deallocate (this%indxbnds) end if ! ! -- return @@ -245,13 +245,13 @@ subroutine ConstructObservation(newObservation, defLine, numunit, & ! SPECIFICATIONS: ! -------------------------------------------------------------------------- ! -- dummy variables - type(ObserveType), pointer :: newObservation - character(len=*), intent(in) :: defLine - integer(I4B), intent(in) :: numunit ! Output unit number - logical, intent(in) :: formatted ! Formatted output? - integer(I4B), intent(in) :: indx ! Index in ObsOutput array + type(ObserveType), pointer :: newObservation + character(len=*), intent(in) :: defLine + integer(I4B), intent(in) :: numunit ! Output unit number + logical, intent(in) :: formatted ! Formatted output? + integer(I4B), intent(in) :: indx ! Index in ObsOutput array type(ObsDataType), dimension(:), pointer, intent(in) :: obsData - integer(I4B), intent(in) :: inunit + integer(I4B), intent(in) :: inunit ! -- local real(DP) :: r integer(I4B) :: i, icol, iout, istart, istop, n @@ -262,8 +262,8 @@ subroutine ConstructObservation(newObservation, defLine, numunit, & icol = 1 ! ! -- Allocate an ObserveType object. - allocate(newObservation) - allocate(newObservation%indxbnds(0)) + allocate (newObservation) + allocate (newObservation%indxbnds(0)) ! ! -- Set indxbnds_count to 0 newObservation%indxbnds_count = 0 @@ -272,22 +272,22 @@ subroutine ConstructObservation(newObservation, defLine, numunit, & ! contents of defLine. ! ! -- Get observation name and store it - call urword(defLine,icol,istart,istop,1,n,r,iout,inunit) + call urword(defLine, icol, istart, istop, 1, n, r, iout, inunit) newObservation%Name = defLine(istart:istop) ! ! -- Get observation type, convert it to uppercase, and store it. - call urword(defLine,icol,istart,istop,1,n,r,iout,inunit) + call urword(defLine, icol, istart, istop, 1, n, r, iout, inunit) newObservation%ObsTypeId = defLine(istart:istop) ! ! -- Look up package ID for this observation type and store it - do i=1,MAXOBSTYPES + do i = 1, MAXOBSTYPES if (obsData(i)%ObsTypeID == newObservation%ObsTypeId) then newObservation%obsDatum => obsData(i) exit elseif (obsData(i)%ObsTypeID == '') then exit - endif - enddo + end if + end do ! ! -- Remaining text is ID [and ID2]; store the remainder of the string istart = istop + 1 @@ -321,7 +321,7 @@ end function CastAsObserveType subroutine AddObsToList(list, obs) ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(ObserveType), pointer, intent(inout) :: obs ! -- local class(*), pointer :: obj @@ -332,11 +332,11 @@ subroutine AddObsToList(list, obs) return end subroutine AddObsToList - function GetObsFromList(list, idx) result (res) + function GetObsFromList(list, idx) result(res) ! -- dummy type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - type(ObserveType), pointer :: res + integer(I4B), intent(in) :: idx + type(ObserveType), pointer :: res ! -- local class(*), pointer :: obj ! diff --git a/src/Utilities/OpenSpec.f90 b/src/Utilities/OpenSpec.f90 index 224b6680cc2..2be8d7bf0d7 100644 --- a/src/Utilities/OpenSpec.f90 +++ b/src/Utilities/OpenSpec.f90 @@ -4,7 +4,7 @@ module OpenSpecModule ! specifiers is not included in ANSI FORTRAN 77. The included ! specifiers are ACCESS, FORM and ACTION. ! - CHARACTER(len=20) :: ACCESS,FORM,ACTION(2) + CHARACTER(len=20) :: ACCESS, FORM, ACTION(2) ! ! ! Specifiers for OPEN statements for unformatted files, which are @@ -15,14 +15,14 @@ module OpenSpecModule ! ! Standard Fortran -- Use unless there is a reason to do otherwise. ! DATA ACCESS/'SEQUENTIAL'/ - DATA ACCESS/'STREAM'/ + DATA ACCESS/'STREAM'/ ! ! ! FORM specifier -- ! ! Standard Fortran, which results in vendor dependent (non-portable) ! files. Use unless there is a reason to do otherwise. - DATA FORM/'UNFORMATTED'/ + DATA FORM/'UNFORMATTED'/ ! ! Non-standard Fortran that causes code compiled by Compaq (Digital) ! Fortran on personal computers to use unstructured non-formatted @@ -41,7 +41,7 @@ module OpenSpecModule ! ! Standard Fortran 90 and 95 -- Use unless there is a reason to do ! otherwise. - DATA (ACTION(IACT),IACT=1,2)/'READ','READWRITE'/ + DATA(ACTION(IACT), IACT=1, 2)/'READ', 'READWRITE'/ ! ! Non-standard Fortran that causes code compiled by the Lahey LF90 ! compiler to create files that can be shared. For use when parallel @@ -49,4 +49,4 @@ module OpenSpecModule ! while the program is running. ! DATA (ACTION(I),I=1,2)/'READ,DENYWRITE','READWRITE,DENYNONE'/ ! -end module OpenSpecModule \ No newline at end of file +end module OpenSpecModule diff --git a/src/Utilities/OutputControl/OutputControl.f90 b/src/Utilities/OutputControl/OutputControl.f90 index d6591f6fb7f..8e3f72874b6 100644 --- a/src/Utilities/OutputControl/OutputControl.f90 +++ b/src/Utilities/OutputControl/OutputControl.f90 @@ -7,13 +7,13 @@ !< module OutputControlModule - use KindModule, only: DP, I4B - use ConstantsModule, only: LENMODELNAME, LENMEMPATH - use SimVariablesModule, only: errmsg + use KindModule, only: DP, I4B + use ConstantsModule, only: LENMODELNAME, LENMEMPATH + use SimVariablesModule, only: errmsg use OutputControlDataModule, only: OutputControlDataType, ocd_cr - use BlockParserModule, only: BlockParserType + use BlockParserModule, only: BlockParserType use InputOutputModule, only: GetUnit, openfile - + implicit none private public OutputControlType, oc_cr @@ -22,16 +22,17 @@ module OutputControlModule !! !! Generalized output control package !< - type OutputControlType - character(len=LENMEMPATH) :: memoryPath !< path to data stored in the memory manager - character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model - integer(I4B), pointer :: inunit => null() !< unit number for input file - integer(I4B), pointer :: iout => null() !< unit number for output file - integer(I4B), pointer :: ibudcsv => null() !< unit number for budget csv output file - integer(I4B), pointer :: iperoc => null() !< stress period number for next output control - integer(I4B), pointer :: iocrep => null() !< output control repeat flag (period 0 step 0) - type(OutputControlDataType), dimension(:), pointer, contiguous :: ocdobj => null() !< output control objects - type(BlockParserType) :: parser + type OutputControlType + character(len=LENMEMPATH) :: memoryPath !< path to data stored in the memory manager + character(len=LENMODELNAME), pointer :: name_model => null() !< name of the model + integer(I4B), pointer :: inunit => null() !< unit number for input file + integer(I4B), pointer :: iout => null() !< unit number for output file + integer(I4B), pointer :: ibudcsv => null() !< unit number for budget csv output file + integer(I4B), pointer :: iperoc => null() !< stress period number for next output control + integer(I4B), pointer :: iocrep => null() !< output control repeat flag (period 0 step 0) + type(OutputControlDataType), dimension(:), & + pointer, contiguous :: ocdobj => null() !< output control objects + type(BlockParserType) :: parser contains procedure :: oc_df procedure :: oc_rp @@ -45,7 +46,7 @@ module OutputControlModule procedure :: set_print_flag end type OutputControlType - contains +contains !> @ brief Create OutputControlType !! @@ -55,13 +56,13 @@ module OutputControlModule !< subroutine oc_cr(ocobj, name_model, inunit, iout) ! -- dummy - type(OutputControlType), pointer :: ocobj !< OutputControlType object - character(len=*), intent(in) :: name_model !< name of the model - integer(I4B), intent(in) :: inunit !< unit number for input - integer(I4B), intent(in) :: iout !< unit number for output + type(OutputControlType), pointer :: ocobj !< OutputControlType object + character(len=*), intent(in) :: name_model !< name of the model + integer(I4B), intent(in) :: inunit !< unit number for input + integer(I4B), intent(in) :: iout !< unit number for output ! ! -- Create the object - allocate(ocobj) + allocate (ocobj) ! ! -- Allocate scalars call ocobj%allocate_scalars(name_model) @@ -84,7 +85,7 @@ end subroutine oc_cr !< subroutine oc_df(this) ! -- dummy - class(OutputControlType) :: this !< OutputControlType object + class(OutputControlType) :: this !< OutputControlType object ! ! -- Return return @@ -97,11 +98,11 @@ end subroutine oc_df !< subroutine oc_rp(this) ! -- modules - use TdisModule, only: kper, nper - use ConstantsModule, only: LINELENGTH + use TdisModule, only: kper, nper + use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_unit, count_errors ! -- dummy - class(OutputControlType) :: this !< OutputControlType object + class(OutputControlType) :: this !< OutputControlType object ! -- local integer(I4B) :: ierr, ival, ipos logical :: isfound, found, endOfBlock @@ -110,62 +111,63 @@ subroutine oc_rp(this) character(len=LINELENGTH) :: printsave class(OutputControlDataType), pointer :: ocdobjptr ! -- formats - character(len=*), parameter :: fmtboc = & - "(1X,/1X,'BEGIN READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)" - character(len=*), parameter :: fmteoc = & - "(/,1X,'END READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)" - character(len=*), parameter :: fmterr = & - "(' ERROR READING OUTPUT CONTROL PERIOD BLOCK: ')" - character(len=*), parameter :: fmtroc = & - "(1X,/1X,'OUTPUT CONTROL FOR STRESS PERIOD ',I0, & - &' IS REPEATED USING SETTINGS FROM A PREVIOUS STRESS PERIOD.')" - character(len=*), parameter :: fmtpererr = & - "(1x,'CURRENT STRESS PERIOD GREATER THAN PERIOD IN OUTPUT CONTROL.')" - character(len=*), parameter :: fmtpererr2 = & - "(1x,'CURRENT STRESS PERIOD: ',I0,' SPECIFIED STRESS PERIOD: ',I0)" + character(len=*), parameter :: fmtboc = & + &"(1X,/1X,'BEGIN READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)" + character(len=*), parameter :: fmteoc = & + &"(/,1X,'END READING OUTPUT CONTROL FOR STRESS PERIOD ',I0)" + character(len=*), parameter :: fmterr = & + &"(' ERROR READING OUTPUT CONTROL PERIOD BLOCK: ')" + character(len=*), parameter :: fmtroc = & + "(1X,/1X,'OUTPUT CONTROL FOR STRESS PERIOD ',I0, & + &' IS REPEATED USING SETTINGS FROM A PREVIOUS STRESS PERIOD.')" + character(len=*), parameter :: fmtpererr = & + &"(1x,'CURRENT STRESS PERIOD GREATER THAN PERIOD IN OUTPUT CONTROL.')" + character(len=*), parameter :: fmtpererr2 = & + &"(1x,'CURRENT STRESS PERIOD: ',I0,' SPECIFIED STRESS PERIOD: ',I0)" ! ! -- Read next block header if kper greater than last one read if (this%iperoc < kper) then ! ! -- Get period block call this%parser%GetBlock('PERIOD', isfound, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true., & + blockRequired=.false.) ! ! -- If end of file, set iperoc past kper, else parse line if (ierr < 0) then this%iperoc = nper + 1 - write(this%iout, '(/,1x,a)') 'END OF FILE DETECTED IN OUTPUT CONTROL.' - write(this%iout, '(1x,a)') 'CURRENT OUTPUT CONTROL SETTINGS WILL BE ' - write(this%iout, '(1x,a)') 'REPEATED UNTIL THE END OF THE SIMULATION.' + write (this%iout, '(/,1x,a)') 'END OF FILE DETECTED IN OUTPUT CONTROL.' + write (this%iout, '(1x,a)') 'CURRENT OUTPUT CONTROL SETTINGS WILL BE ' + write (this%iout, '(1x,a)') 'REPEATED UNTIL THE END OF THE SIMULATION.' else ! ! -- Read period number ival = this%parser%GetInteger() ! ! -- Check to see if this is a valid kper - if(ival <= 0 .or. ival > nper) then - write(ermsg, '(a,i0)') 'PERIOD NOT VALID IN OUTPUT CONTROL: ', ival + if (ival <= 0 .or. ival > nper) then + write (ermsg, '(a,i0)') 'PERIOD NOT VALID IN OUTPUT CONTROL: ', ival call store_error(ermsg) - write(ermsg, '(a, a)') 'LINE: ', trim(adjustl(line)) + write (ermsg, '(a, a)') 'LINE: ', trim(adjustl(line)) call store_error(ermsg) - endif + end if ! ! -- Check to see if specified is less than kper - if(ival < kper) then - write(ermsg, fmtpererr) + if (ival < kper) then + write (ermsg, fmtpererr) call store_error(ermsg) - write(ermsg, fmtpererr2) kper, ival + write (ermsg, fmtpererr2) kper, ival call store_error(ermsg) - write(ermsg, '(a, a)') 'LINE: ', trim(adjustl(line)) + write (ermsg, '(a, a)') 'LINE: ', trim(adjustl(line)) call store_error(ermsg) - endif + end if ! ! -- Stop or set iperoc and continue - if(count_errors() > 0) then + if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if this%iperoc = ival - endif + end if end if ! ! -- Read the stress period block @@ -175,10 +177,10 @@ subroutine oc_rp(this) do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) call ocdobjptr%psmobj%init() - enddo + end do ! ! -- Output control time step matches simulation time step. - write(this%iout,fmtboc) this%iperoc + write (this%iout, fmtboc) this%iperoc ! ! -- loop to read records recordloop: do @@ -199,33 +201,33 @@ subroutine oc_rp(this) found = .false. do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) - if(keyword2 == trim(ocdobjptr%cname)) then + if (keyword2 == trim(ocdobjptr%cname)) then found = .true. exit - endif - enddo + end if + end do if (.not. found) then call this%parser%GetCurrentLine(line) - write(ermsg, fmterr) + write (ermsg, fmterr) call store_error(ermsg) call store_error('UNRECOGNIZED KEYWORD: '//keyword2) call store_error(trim(line)) call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetRemainingLine(line) - call ocdobjptr%psmobj%rp(trim(printsave)//' '//line, & + call ocdobjptr%psmobj%rp(trim(printsave)//' '//line, & this%iout) call ocdobjptr%ocd_rp_check(this%parser%iuactive) ! ! -- End of recordloop - enddo recordloop - write(this%iout,fmteoc) this%iperoc + end do recordloop + write (this%iout, fmteoc) this%iperoc else ! ! -- Write message that output control settings are from a previous ! stress period. - write(this%iout, fmtroc) kper - endif + write (this%iout, fmtroc) kper + end if ! ! -- return return @@ -241,11 +243,11 @@ subroutine oc_ot(this, ipflg) ! -- modules use TdisModule, only: kstp, endofperiod ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - integer(I4B), intent(inout) :: ipflg !< flag indicating if data was printed + class(OutputControlType) :: this !< OutputControlType object + integer(I4B), intent(inout) :: ipflg !< flag indicating if data was printed ! -- local integer(I4B) :: ipos - type(OutputControlDataType), pointer :: ocdobjptr + type(OutputControlDataType), pointer :: ocdobjptr ! ! -- Clear printout flag(ipflg). This flag indicates that an array was ! printed to the listing file. @@ -254,7 +256,7 @@ subroutine oc_ot(this, ipflg) do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) call ocdobjptr%ocd_ot(ipflg, kstp, endofperiod, this%iout) - enddo + end do ! ! -- Return return @@ -269,16 +271,16 @@ subroutine oc_da(this) ! -- modules use MemoryManagerModule, only: mem_deallocate ! -- dummy - class(OutputControlType) :: this !< OutputControlType object + class(OutputControlType) :: this !< OutputControlType object ! -- local integer(I4B) :: i ! do i = 1, size(this%ocdobj) call this%ocdobj(i)%ocd_da() - enddo - deallocate(this%ocdobj) + end do + deallocate (this%ocdobj) ! - deallocate(this%name_model) + deallocate (this%name_model) call mem_deallocate(this%inunit) call mem_deallocate(this%iout) call mem_deallocate(this%ibudcsv) @@ -299,12 +301,12 @@ subroutine allocate_scalars(this, name_model) use MemoryManagerModule, only: mem_allocate use MemoryHelperModule, only: create_mem_path ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - character(len=*), intent(in) :: name_model !< name of model + class(OutputControlType) :: this !< OutputControlType object + character(len=*), intent(in) :: name_model !< name of model ! this%memoryPath = create_mem_path(name_model, 'OC') ! - allocate(this%name_model) + allocate (this%name_model) call mem_allocate(this%inunit, 'INUNIT', this%memoryPath) call mem_allocate(this%iout, 'IOUT', this%memoryPath) call mem_allocate(this%ibudcsv, 'IBUDCSV', this%memoryPath) @@ -332,7 +334,7 @@ subroutine read_options(this) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, store_error_unit ! -- dummy - class(OutputControlType) :: this !< OutputControlType object + class(OutputControlType) :: this !< OutputControlType object ! -- local character(len=LINELENGTH) :: keyword character(len=LINELENGTH) :: keyword2 @@ -341,15 +343,15 @@ subroutine read_options(this) integer(I4B) :: ierr integer(I4B) :: ipos logical :: isfound, found, endOfBlock - type(OutputControlDataType), pointer :: ocdobjptr + type(OutputControlDataType), pointer :: ocdobjptr ! ! -- get options block call this%parser%GetBlock('OPTIONS', isfound, ierr, & - supportOpenClose=.true., blockRequired=.false.) + supportOpenClose=.true., blockRequired=.false.) ! ! -- parse options block if detected if (isfound) then - write(this%iout,'(/,1x,a,/)') 'PROCESSING OC OPTIONS' + write (this%iout, '(/,1x,a,/)') 'PROCESSING OC OPTIONS' do call this%parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -359,34 +361,35 @@ subroutine read_options(this) call this%parser%GetStringCaps(keyword2) if (keyword2 /= 'FILEOUT') then errmsg = "BUDGETCSV must be followed by FILEOUT and then budget & - &csv file name. Found '" // trim(keyword2) // "'." + &csv file name. Found '"//trim(keyword2)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() end if call this%parser%GetString(fname) this%ibudcsv = GetUnit() - call openfile(this%ibudcsv, this%iout, fname, 'CSV', filstat_opt='REPLACE') + call openfile(this%ibudcsv, this%iout, fname, 'CSV', & + filstat_opt='REPLACE') found = .true. end if - + if (.not. found) then do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) - if(keyword == trim(ocdobjptr%cname)) then + if (keyword == trim(ocdobjptr%cname)) then found = .true. exit - endif - enddo + end if + end do if (.not. found) then - errmsg = "UNKNOWN OC OPTION '" // trim(keyword) // "'." + errmsg = "UNKNOWN OC OPTION '"//trim(keyword)//"'." call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetRemainingLine(line) call ocdobjptr%set_option(line, this%parser%iuactive, this%iout) end if end do - write(this%iout,'(1x,a)') 'END OF OC OPTIONS' + write (this%iout, '(1x,a)') 'END OF OC OPTIONS' end if ! ! -- return @@ -402,8 +405,8 @@ logical function oc_save(this, cname) ! -- modules use TdisModule, only: kstp, endofperiod ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - character(len=*), intent(in) :: cname !< character string for data name + class(OutputControlType) :: this !< OutputControlType object + character(len=*), intent(in) :: cname !< character string for data name ! -- local integer(I4B) :: ipos logical :: found @@ -413,14 +416,14 @@ logical function oc_save(this, cname) found = .false. do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) - if(cname == trim(ocdobjptr%cname)) then + if (cname == trim(ocdobjptr%cname)) then found = .true. exit - endif - enddo - if(found) then + end if + end do + if (found) then oc_save = ocdobjptr%psmobj%kstp_to_save(kstp, endofperiod) - endif + end if ! ! -- Return return @@ -435,8 +438,8 @@ logical function oc_print(this, cname) ! -- modules use TdisModule, only: kstp, endofperiod ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - character(len=*), intent(in) :: cname !< character string for data name + class(OutputControlType) :: this !< OutputControlType object + character(len=*), intent(in) :: cname !< character string for data name ! -- local integer(I4B) :: ipos logical :: found @@ -446,14 +449,14 @@ logical function oc_print(this, cname) found = .false. do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) - if(cname == trim(ocdobjptr%cname)) then + if (cname == trim(ocdobjptr%cname)) then found = .true. exit - endif - enddo - if(found) then + end if + end do + if (found) then oc_print = ocdobjptr%psmobj%kstp_to_print(kstp, endofperiod) - endif + end if ! ! -- Return return @@ -469,8 +472,8 @@ function oc_save_unit(this, cname) ! -- return integer(I4B) :: oc_save_unit ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - character(len=*), intent(in) :: cname !< character string for data name + class(OutputControlType) :: this !< OutputControlType object + character(len=*), intent(in) :: cname !< character string for data name ! -- local integer(I4B) :: ipos logical :: found @@ -480,14 +483,14 @@ function oc_save_unit(this, cname) found = .false. do ipos = 1, size(this%ocdobj) ocdobjptr => this%ocdobj(ipos) - if(cname == trim(ocdobjptr%cname)) then + if (cname == trim(ocdobjptr%cname)) then found = .true. exit - endif - enddo - if(found) then + end if + end do + if (found) then oc_save_unit = ocdobjptr%idataun - endif + end if ! ! -- Return return @@ -504,25 +507,25 @@ function set_print_flag(this, cname, icnvg, endofperiod) result(iprint_flag) ! -- return integer(I4B) :: iprint_flag ! -- dummy - class(OutputControlType) :: this !< OutputControlType object - character(len=*), intent(in) :: cname !< character string for data name - integer(I4B), intent(in) :: icnvg !< convergence flag - logical, intent(in) :: endofperiod !< end of period logical flag + class(OutputControlType) :: this !< OutputControlType object + character(len=*), intent(in) :: cname !< character string for data name + integer(I4B), intent(in) :: icnvg !< convergence flag + logical, intent(in) :: endofperiod !< end of period logical flag ! -- local ! ! -- default is to not print iprint_flag = 0 ! ! -- if the output control file indicates that cname should be printed - if(this%oc_print(cname)) iprint_flag = 1 + if (this%oc_print(cname)) iprint_flag = 1 ! ! -- if it is not a CONTINUE run, then set to print if not converged if (isimcontinue == 0) then - if(icnvg == 0) iprint_flag = 1 + if (icnvg == 0) iprint_flag = 1 end if ! ! -- if it's the end of the period, then set flag to print - if(endofperiod) iprint_flag = 1 + if (endofperiod) iprint_flag = 1 ! ! -- Return return diff --git a/src/Utilities/OutputControl/OutputControlData.f90 b/src/Utilities/OutputControl/OutputControlData.f90 index 5837980bdbf..adbbeee0ce1 100644 --- a/src/Utilities/OutputControl/OutputControlData.f90 +++ b/src/Utilities/OutputControl/OutputControlData.f90 @@ -7,34 +7,34 @@ !! !< module OutputControlDataModule - - use BaseDisModule, only: DisBaseType - use InputOutputModule, only: print_format - use KindModule, only: DP, I4B, LGP + + use BaseDisModule, only: DisBaseType + use InputOutputModule, only: print_format + use KindModule, only: DP, I4B, LGP use PrintSaveManagerModule, only: PrintSaveManagerType - + implicit none private public OutputControlDataType, ocd_cr - + !> @ brief OutputControlDataType !! !! Object for storing information and determining whether or !! not model data should be printed to a list file or saved to disk. !< type OutputControlDataType - character(len=16), pointer :: cname => null() !< name of variable, such as HEAD - character(len=60), pointer :: cdatafmp => null() !< fortran format for printing - integer(I4B), pointer :: idataun => null() !< fortran unit number for binary output - character(len=1), pointer :: editdesc => null() !< fortran format type (I, G, F, S, E) - integer(I4B), pointer :: nvaluesp => null() !< number of values per line for printing - integer(I4B), pointer :: nwidthp => null() !< width of the number for printing - real(DP), pointer :: dnodata => null() !< no data value - integer(I4B), pointer :: inodata => null() !< integer no data value - real(DP), dimension(:), pointer, contiguous :: dblvec => null() !< pointer to double precision data array - integer(I4B), dimension(:), pointer, contiguous :: intvec => null() !< pointer to integer data array - class(DisBaseType), pointer :: dis => null() !< pointer to discretization package - type(PrintSaveManagerType), pointer :: psmobj => null() !< print/save manager object + character(len=16), pointer :: cname => null() !< name of variable, such as HEAD + character(len=60), pointer :: cdatafmp => null() !< fortran format for printing + integer(I4B), pointer :: idataun => null() !< fortran unit number for binary output + character(len=1), pointer :: editdesc => null() !< fortran format type (I, G, F, S, E) + integer(I4B), pointer :: nvaluesp => null() !< number of values per line for printing + integer(I4B), pointer :: nwidthp => null() !< width of the number for printing + real(DP), pointer :: dnodata => null() !< no data value + integer(I4B), pointer :: inodata => null() !< integer no data value + real(DP), dimension(:), pointer, contiguous :: dblvec => null() !< pointer to double precision data array + integer(I4B), dimension(:), pointer, contiguous :: intvec => null() !< pointer to integer data array + class(DisBaseType), pointer :: dis => null() !< pointer to discretization package + type(PrintSaveManagerType), pointer :: psmobj => null() !< print/save manager object contains procedure :: allocate_scalars procedure :: init_int @@ -44,9 +44,9 @@ module OutputControlDataModule procedure :: ocd_ot procedure :: ocd_da end type OutputControlDataType - - contains - + +contains + !> @ brief Create OutputControlDataType !! !! Create by allocating a new OutputControlDataType object @@ -54,10 +54,10 @@ module OutputControlDataModule !< subroutine ocd_cr(ocdobj) ! -- dummy - type(OutputControlDataType), pointer :: ocdobj !< OutputControlDataType object + type(OutputControlDataType), pointer :: ocdobj !< OutputControlDataType object ! ! -- Create the object - allocate(ocdobj) + allocate (ocdobj) ! ! -- Allocate scalars call ocdobj%allocate_scalars() @@ -65,7 +65,7 @@ subroutine ocd_cr(ocdobj) ! -- Return return end subroutine ocd_cr - + !> @ brief Check OutputControlDataType object !! !! Perform a consistency check @@ -76,28 +76,28 @@ subroutine ocd_rp_check(this, inunit) use ConstantsModule, only: LINELENGTH use SimModule, only: store_error, count_errors, store_error_unit ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object - integer(I4B), intent(in) :: inunit !< Unit number for input + class(OutputControlDataType) :: this !< OutputControlDataType object + integer(I4B), intent(in) :: inunit !< Unit number for input ! -- locals character(len=LINELENGTH) :: errmsg ! -- formats - character(len=*), parameter :: fmtocsaveerr = & - "(1X,'REQUESTING TO SAVE ',A,' BUT ',A,' SAVE FILE NOT SPECIFIED. ', & + character(len=*), parameter :: fmtocsaveerr = & + "(1X,'REQUESTING TO SAVE ',A,' BUT ',A,' SAVE FILE NOT SPECIFIED. ', & &A,' SAVE FILE MUST BE SPECIFIED IN OUTPUT CONTROL OPTIONS.')" ! ! -- Check to make sure save file was specified - if(this%psmobj%save_detected) then - if(this%idataun == 0) then - write(errmsg, fmtocsaveerr) trim(adjustl(this%cname)), & - trim(adjustl(this%cname)), & - trim(adjustl(this%cname)) + if (this%psmobj%save_detected) then + if (this%idataun == 0) then + write (errmsg, fmtocsaveerr) trim(adjustl(this%cname)), & + trim(adjustl(this%cname)), & + trim(adjustl(this%cname)) call store_error(errmsg) - endif - endif + end if + end if ! - if(count_errors() > 0) then + if (count_errors() > 0) then call store_error_unit(inunit) - endif + end if ! ! -- return return @@ -111,13 +111,13 @@ end subroutine ocd_rp_check !< subroutine ocd_ot(this, ipflg, kstp, endofperiod, iout, iprint_opt, isav_opt) ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object - integer(I4B), intent(inout) :: ipflg !< Flag indicating if something was printed - integer(I4B), intent(in) :: kstp !< Current time step - logical(LGP), intent(in) :: endofperiod !< End of period logical flag - integer(I4B), intent(in) :: iout !< Unit number for output - integer(I4B), optional, intent(in) :: iprint_opt !< Optional print flag override - integer(I4B), optional, intent(in) :: isav_opt !< Optional save flag override + class(OutputControlDataType) :: this !< OutputControlDataType object + integer(I4B), intent(inout) :: ipflg !< Flag indicating if something was printed + integer(I4B), intent(in) :: kstp !< Current time step + logical(LGP), intent(in) :: endofperiod !< End of period logical flag + integer(I4B), intent(in) :: iout !< Unit number for output + integer(I4B), optional, intent(in) :: iprint_opt !< Optional print flag override + integer(I4B), optional, intent(in) :: isav_opt !< Optional save flag override ! -- local integer(I4B) :: iprint integer(I4B) :: idataun @@ -133,39 +133,39 @@ subroutine ocd_ot(this, ipflg, kstp, endofperiod, iout, iprint_opt, isav_opt) if (iprint_opt /= 0) then iprint = 1 ipflg = 1 - endif + end if else - if(this%psmobj%kstp_to_print(kstp, endofperiod)) then + if (this%psmobj%kstp_to_print(kstp, endofperiod)) then iprint = 1 ipflg = 1 - endif - endif + end if + end if ! ! -- determine whether or not to save the array to a file if (present(isav_opt)) then if (isav_opt /= 0) then idataun = this%idataun - endif + end if else - if(this%psmobj%kstp_to_save(kstp, endofperiod)) idataun = this%idataun - endif + if (this%psmobj%kstp_to_save(kstp, endofperiod)) idataun = this%idataun + end if ! ! -- Record double precision array - if(associated(this%dblvec)) & - call this%dis%record_array(this%dblvec, iout, iprint, idataun, & - this%cname, this%cdatafmp, this%nvaluesp, & - this%nwidthp, this%editdesc, this%dnodata) + if (associated(this%dblvec)) & + call this%dis%record_array(this%dblvec, iout, iprint, idataun, & + this%cname, this%cdatafmp, this%nvaluesp, & + this%nwidthp, this%editdesc, this%dnodata) ! ! -- Record integer array (not supported yet) - !if(associated(this%intvec)) & - !call this%dis%record_array(this%intvec, iout, iprint, idataun, & - ! this%cname, this%cdatafmp, this%nvaluesp, & + !if(associated(this%intvec)) & + !call this%dis%record_array(this%intvec, iout, iprint, idataun, & + ! this%cname, this%cdatafmp, this%nvaluesp, & ! this%nwidthp, this%editdesc, this%inodata) ! ! -- Return return end subroutine ocd_ot - + !> @ brief Deallocate OutputControlDataType !! !! Deallocate members of this type @@ -177,37 +177,37 @@ subroutine ocd_da(this) ! -- dummy class(OutputControlDataType) :: this ! - ! -- deallocate - deallocate(this%cname) - deallocate(this%cdatafmp) - deallocate(this%idataun) - deallocate(this%editdesc) - deallocate(this%nvaluesp) - deallocate(this%nwidthp) - deallocate(this%dnodata) - deallocate(this%inodata) - deallocate(this%psmobj) + ! -- deallocate + deallocate (this%cname) + deallocate (this%cdatafmp) + deallocate (this%idataun) + deallocate (this%editdesc) + deallocate (this%nvaluesp) + deallocate (this%nwidthp) + deallocate (this%dnodata) + deallocate (this%inodata) + deallocate (this%psmobj) ! ! -- return return - end subroutine ocd_da - + end subroutine ocd_da + !> @ brief Initialize this OutputControlDataType as double precision data !! !! Initialize this object as a double precision data type !! !< - subroutine init_dbl(this, cname, dblvec, dis, cdefpsm, cdeffmp, iout, & + subroutine init_dbl(this, cname, dblvec, dis, cdefpsm, cdeffmp, iout, & dnodata) ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object - character(len=*), intent(in) :: cname !< Name of variable - real(DP), dimension(:), pointer, contiguous, intent(in) :: dblvec !< Data array that will be managed by this object - class(DisBaseType), pointer, intent(in) :: dis !< Discretization package - character(len=*), intent(in) :: cdefpsm !< String for defining the print/save manager - character(len=*), intent(in) :: cdeffmp !< String for print format - integer(I4B), intent(in) :: iout !< Unit number for output - real(DP), intent(in) :: dnodata !< No data value + class(OutputControlDataType) :: this !< OutputControlDataType object + character(len=*), intent(in) :: cname !< Name of variable + real(DP), dimension(:), pointer, contiguous, intent(in) :: dblvec !< Data array that will be managed by this object + class(DisBaseType), pointer, intent(in) :: dis !< Discretization package + character(len=*), intent(in) :: cdefpsm !< String for defining the print/save manager + character(len=*), intent(in) :: cdeffmp !< String for print format + integer(I4B), intent(in) :: iout !< Unit number for output + real(DP), intent(in) :: dnodata !< No data value ! this%cname = cname this%dblvec => dblvec @@ -215,29 +215,29 @@ subroutine init_dbl(this, cname, dblvec, dis, cdefpsm, cdeffmp, iout, & this%dnodata = dnodata call this%psmobj%init() if (cdefpsm /= '') call this%psmobj%rp(cdefpsm, iout) - call print_format(cdeffmp, this%cdatafmp, & + call print_format(cdeffmp, this%cdatafmp, & this%editdesc, this%nvaluesp, this%nwidthp, 0) ! ! -- return return end subroutine init_dbl - + !> @ brief Initialize this OutputControlDataType as integer data !! !! Initialize this object as an integer data type !! !< - subroutine init_int(this, cname, intvec, dis, cdefpsm, cdeffmp, iout, & + subroutine init_int(this, cname, intvec, dis, cdefpsm, cdeffmp, iout, & inodata) ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object - character(len=*), intent(in) :: cname !< Name of variable - integer(I4B), dimension(:), pointer, contiguous, intent(in) :: intvec !< Data array that will be managed by this object - class(DisBaseType), pointer, intent(in) :: dis !< Discretization package - character(len=*), intent(in) :: cdefpsm !< String for defining the print/save manager - character(len=*), intent(in) :: cdeffmp !< String for print format - integer(I4B), intent(in) :: iout !< Unit number for output - integer(I4B), intent(in) :: inodata !< No data value + class(OutputControlDataType) :: this !< OutputControlDataType object + character(len=*), intent(in) :: cname !< Name of variable + integer(I4B), dimension(:), pointer, contiguous, intent(in) :: intvec !< Data array that will be managed by this object + class(DisBaseType), pointer, intent(in) :: dis !< Discretization package + character(len=*), intent(in) :: cdefpsm !< String for defining the print/save manager + character(len=*), intent(in) :: cdeffmp !< String for print format + integer(I4B), intent(in) :: iout !< Unit number for output + integer(I4B), intent(in) :: inodata !< No data value ! this%cname = cname this%intvec => intvec @@ -246,13 +246,13 @@ subroutine init_int(this, cname, intvec, dis, cdefpsm, cdeffmp, iout, & this%editdesc = 'I' call this%psmobj%init() if (cdefpsm /= '') call this%psmobj%rp(cdefpsm, iout) - call print_format(cdeffmp, this%cdatafmp, this%editdesc, this%nvaluesp, & + call print_format(cdeffmp, this%cdatafmp, this%editdesc, this%nvaluesp, & this%nwidthp, 0) ! ! -- return return - end subroutine init_int - + end subroutine init_int + !> @ brief Allocate OutputControlDataType members !! !! Allocate and initialize member variables @@ -262,17 +262,17 @@ subroutine allocate_scalars(this) ! -- modules use ConstantsModule, only: DZERO ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object + class(OutputControlDataType) :: this !< OutputControlDataType object ! - allocate(this%cname) - allocate(this%cdatafmp) - allocate(this%idataun) - allocate(this%editdesc) - allocate(this%nvaluesp) - allocate(this%nwidthp) - allocate(this%dnodata) - allocate(this%inodata) - allocate(this%psmobj) + allocate (this%cname) + allocate (this%cdatafmp) + allocate (this%idataun) + allocate (this%editdesc) + allocate (this%nvaluesp) + allocate (this%nwidthp) + allocate (this%dnodata) + allocate (this%inodata) + allocate (this%psmobj) ! this%cname = '' this%cdatafmp = '' @@ -285,8 +285,8 @@ subroutine allocate_scalars(this) ! ! -- return return - end subroutine allocate_scalars - + end subroutine allocate_scalars + !> @ brief Set options for this object based on an input string !! !! Set FILEOUT and PRINT_FORMAT options for this object. @@ -294,47 +294,47 @@ end subroutine allocate_scalars !< subroutine set_option(this, linein, inunit, iout) ! -- modules - use ConstantsModule, only: MNORMAL + use ConstantsModule, only: MNORMAL use OpenSpecModule, only: access, form use InputOutputModule, only: urword, getunit, openfile use SimModule, only: store_error, store_error_unit, count_errors ! -- dummy - class(OutputControlDataType) :: this !< OutputControlDataType object - character(len=*), intent(in) :: linein !< Character string with options - integer(I4B), intent(in) :: inunit !< Unit number for input - integer(I4B), intent(in) :: iout !< Unit number for output + class(OutputControlDataType) :: this !< OutputControlDataType object + character(len=*), intent(in) :: linein !< Character string with options + integer(I4B), intent(in) :: inunit !< Unit number for input + integer(I4B), intent(in) :: iout !< Unit number for output ! -- local character(len=len(linein)) :: line integer(I4B) :: lloc, istart, istop, ival real(DP) :: rval ! -- format - character(len=*),parameter :: fmtocsave = & - "(4X,A,' INFORMATION WILL BE WRITTEN TO:', & - &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)" + character(len=*), parameter :: fmtocsave = & + "(4X,A,' INFORMATION WILL BE WRITTEN TO:', & + &/,6X,'UNIT NUMBER: ', I0,/,6X, 'FILE NAME: ', A)" ! line(:) = linein(:) lloc = 1 call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) - select case(line(istart:istop)) - case('FILEOUT') + select case (line(istart:istop)) + case ('FILEOUT') call urword(line, lloc, istart, istop, 0, ival, rval, 0, 0) this%idataun = getunit() - write(iout, fmtocsave) trim(adjustl(this%cname)), this%idataun, & - line(istart:istop) - call openfile(this%idataun, iout, line(istart:istop), 'DATA(BINARY)', & + write (iout, fmtocsave) trim(adjustl(this%cname)), this%idataun, & + line(istart:istop) + call openfile(this%idataun, iout, line(istart:istop), 'DATA(BINARY)', & form, access, 'REPLACE', MNORMAL) - case('PRINT_FORMAT') + case ('PRINT_FORMAT') call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) - call print_format(line(istart:), this%cdatafmp, this%editdesc, & + call print_format(line(istart:), this%cdatafmp, this%editdesc, & this%nvaluesp, this%nwidthp, inunit) case default - call store_error('Looking for FILEOUT or PRINT_FORMAT. Found:') - call store_error(trim(adjustl(line))) - call store_error_unit(inunit) + call store_error('Looking for FILEOUT or PRINT_FORMAT. Found:') + call store_error(trim(adjustl(line))) + call store_error_unit(inunit) end select ! ! -- return return - end subroutine set_option - + end subroutine set_option + end module OutputControlDataModule diff --git a/src/Utilities/OutputControl/PrintSaveManager.f90 b/src/Utilities/OutputControl/PrintSaveManager.f90 index 064a3585766..2aa1fcc811f 100644 --- a/src/Utilities/OutputControl/PrintSaveManager.f90 +++ b/src/Utilities/OutputControl/PrintSaveManager.f90 @@ -28,17 +28,17 @@ !! !< module PrintSaveManagerModule - + use KindModule, only: DP, I4B, LGP use ArrayHandlersModule, only: expandarray use SimVariablesModule, only: errmsg - use SimModule, only: store_error - use InputOutputModule, only: urword - + use SimModule, only: store_error + use InputOutputModule, only: urword + implicit none private public :: PrintSaveManagerType - + !> @ brief PrintSaveManagerType !! !! Object for storing information and determining whether or @@ -47,25 +47,25 @@ module PrintSaveManagerModule type :: PrintSaveManagerType integer(I4B), allocatable, dimension(:) :: kstp_list_print integer(I4B), allocatable, dimension(:) :: kstp_list_save - integer(I4B) :: ifreq_print - integer(I4B) :: ifreq_save - logical :: print_first - logical :: save_first - logical :: print_last - logical :: save_last - logical :: print_all - logical :: save_all - logical :: save_detected - logical :: print_detected + integer(I4B) :: ifreq_print + integer(I4B) :: ifreq_save + logical :: print_first + logical :: save_first + logical :: print_last + logical :: save_last + logical :: print_all + logical :: save_all + logical :: save_detected + logical :: print_detected contains procedure :: init procedure :: rp procedure :: kstp_to_print procedure :: kstp_to_save end type PrintSaveManagerType - - contains - + +contains + !> @ brief Initialize PrintSaveManager !! !! Initializes variables of a PrintSaveManagerType @@ -73,13 +73,13 @@ module PrintSaveManagerModule !< subroutine init(this) ! -- dummy - class(PrintSaveManagerType) :: this !< psm object to initialize + class(PrintSaveManagerType) :: this !< psm object to initialize ! ! -- Initialize members to their defaults - if(allocated(this%kstp_list_print)) deallocate(this%kstp_list_print) - if(allocated(this%kstp_list_save)) deallocate(this%kstp_list_save) - allocate(this%kstp_list_print(0)) - allocate(this%kstp_list_save(0)) + if (allocated(this%kstp_list_print)) deallocate (this%kstp_list_print) + if (allocated(this%kstp_list_save)) deallocate (this%kstp_list_save) + allocate (this%kstp_list_print(0)) + allocate (this%kstp_list_save(0)) this%ifreq_print = 0 this%ifreq_save = 0 this%save_first = .false. @@ -94,18 +94,18 @@ subroutine init(this) ! -- return return end subroutine init - + !> @ brief Read and prepare for PrintSaveManager !! - !! Parse information in the line and assign settings for the + !! Parse information in the line and assign settings for the !! PrintSaveManagerType. !! !< subroutine rp(this, linein, iout) ! -- dummy - class(PrintSaveManagerType) :: this !< psm object - character(len=*), intent(in) :: linein !< character line of information - integer(I4B), intent(in) :: iout !< unit number of output file + class(PrintSaveManagerType) :: this !< psm object + character(len=*), intent(in) :: linein !< character line of information + integer(I4B), intent(in) :: iout !< unit number of output file ! -- local character(len=len(linein)) :: line logical lp, ls @@ -114,9 +114,9 @@ subroutine rp(this, linein, iout) real(DP) :: rval ! -- formats character(len=*), parameter :: fmt_steps = & - "(6x,'THE FOLLOWING STEPS WILL BE ',A,': ',50(I0,' '))" + &"(6x,'THE FOLLOWING STEPS WILL BE ',A,': ',50(I0,' '))" character(len=*), parameter :: fmt_freq = & - "(6x,'THE FOLLOWING FREQUENCY WILL BE ',A,': ',I0)" + &"(6x,'THE FOLLOWING FREQUENCY WILL BE ',A,': ',I0)" ! ! -- Set the values based on line ! -- Get keyword to use in assignment @@ -127,15 +127,15 @@ subroutine rp(this, linein, iout) ! -- set dimension for print or save lp = .false. ls = .false. - select case(line(istart:istop)) - case('PRINT') + select case (line(istart:istop)) + case ('PRINT') lp = .true. - case('SAVE') + case ('SAVE') ls = .true. case default - write(errmsg, '(2a)') & - 'Looking for PRINT or SAVE. Found:', trim(adjustl(line)) - call store_error(errmsg, terminate=.TRUE.) + write (errmsg, '(2a)') & + 'Looking for PRINT or SAVE. Found:', trim(adjustl(line)) + call store_error(errmsg, terminate=.TRUE.) end select ! ! -- set member variables @@ -144,64 +144,64 @@ subroutine rp(this, linein, iout) ! ! -- set the steps to print or save call urword(line, lloc, istart, istop, 1, ival, rval, 0, 0) - select case(line(istart:istop)) - case('ALL') - if(lp) then + select case (line(istart:istop)) + case ('ALL') + if (lp) then this%print_all = .true. - if(iout > 0) write(iout,"(6x,a)") 'ALL TIME STEPS WILL BE PRINTED' - endif - if(ls) then + if (iout > 0) write (iout, "(6x,a)") 'ALL TIME STEPS WILL BE PRINTED' + end if + if (ls) then this%save_all = .true. - if(iout > 0) write(iout,"(6x,a)") 'ALL TIME STEPS WILL BE SAVED' - endif - case('STEPS') + if (iout > 0) write (iout, "(6x,a)") 'ALL TIME STEPS WILL BE SAVED' + end if + case ('STEPS') listsearch: do call urword(line, lloc, istart, istop, 2, ival, rval, -1, 0) - if(ival > 0) then - if(lp) then + if (ival > 0) then + if (lp) then n = size(this%kstp_list_print) call expandarray(this%kstp_list_print) this%kstp_list_print(n + 1) = ival - endif - if(ls) then + end if + if (ls) then n = size(this%kstp_list_save) call expandarray(this%kstp_list_save) this%kstp_list_save(n + 1) = ival - endif + end if cycle listsearch - endif + end if exit listsearch - enddo listsearch - if(iout > 0) then - if(lp) write(iout, fmt_steps) 'PRINTED', this%kstp_list_print - if(ls) write(iout, fmt_steps) 'SAVED', this%kstp_list_save - endif - case('FREQUENCY') + end do listsearch + if (iout > 0) then + if (lp) write (iout, fmt_steps) 'PRINTED', this%kstp_list_print + if (ls) write (iout, fmt_steps) 'SAVED', this%kstp_list_save + end if + case ('FREQUENCY') call urword(line, lloc, istart, istop, 2, ival, rval, -1, 0) - if(lp) this%ifreq_print = ival - if(ls) this%ifreq_save = ival - if(iout > 0) then - if(lp) write(iout, fmt_freq) 'PRINTED', this%ifreq_print - if(ls) write(iout, fmt_freq) 'SAVED', this%ifreq_save - endif - case('FIRST') - if(lp) then + if (lp) this%ifreq_print = ival + if (ls) this%ifreq_save = ival + if (iout > 0) then + if (lp) write (iout, fmt_freq) 'PRINTED', this%ifreq_print + if (ls) write (iout, fmt_freq) 'SAVED', this%ifreq_save + end if + case ('FIRST') + if (lp) then this%print_first = .true. - if(iout > 0) write(iout,"(6x,a)") 'THE FIRST TIME STEP WILL BE PRINTED' - endif - if(ls) then + if (iout > 0) write (iout, "(6x,a)") 'THE FIRST TIME STEP WILL BE PRINTED' + end if + if (ls) then this%save_first = .true. - if(iout > 0) write(iout,"(6x,a)") 'THE FIRST TIME STEP WILL BE SAVED' - endif - case('LAST') - if(lp) then + if (iout > 0) write (iout, "(6x,a)") 'THE FIRST TIME STEP WILL BE SAVED' + end if + case ('LAST') + if (lp) then this%print_last = .true. - if(iout > 0) write(iout,"(6x,a)") 'THE LAST TIME STEP WILL BE PRINTED' - endif - if(ls) then + if (iout > 0) write (iout, "(6x,a)") 'THE LAST TIME STEP WILL BE PRINTED' + end if + if (ls) then this%save_last = .true. - if(iout > 0) write(iout,"(6x,a)") 'THE LAST TIME STEP WILL BE SAVED' - endif + if (iout > 0) write (iout, "(6x,a)") 'THE LAST TIME STEP WILL BE SAVED' + end if case default write (errmsg, '(2a)') & 'Looking for ALL, STEPS, FIRST, LAST, OR FREQUENCY. Found: ', & @@ -212,73 +212,73 @@ subroutine rp(this, linein, iout) ! -- return return end subroutine rp - + !> @ brief Determine if it is time to print the data !! - !! Determine if data should be printed based on kstp and endofperiod + !! Determine if data should be printed based on kstp and endofperiod !! !< logical function kstp_to_print(this, kstp, endofperiod) ! -- dummy - class(PrintSaveManagerType) :: this !< psm object - integer(I4B), intent(in) :: kstp !< current time step - logical(LGP), intent(in) :: endofperiod !< flag indicating end of stress period + class(PrintSaveManagerType) :: this !< psm object + integer(I4B), intent(in) :: kstp !< current time step + logical(LGP), intent(in) :: endofperiod !< flag indicating end of stress period ! -- local integer(I4B) :: i, n ! kstp_to_print = .false. - if(this%print_all) kstp_to_print = .true. - if(kstp == 1 .and. this%print_first) kstp_to_print = .true. - if(endofperiod .and. this%print_last) kstp_to_print = .true. - if(this%ifreq_print > 0) then - if(mod(kstp, this%ifreq_print) == 0) kstp_to_print = .true. - endif + if (this%print_all) kstp_to_print = .true. + if (kstp == 1 .and. this%print_first) kstp_to_print = .true. + if (endofperiod .and. this%print_last) kstp_to_print = .true. + if (this%ifreq_print > 0) then + if (mod(kstp, this%ifreq_print) == 0) kstp_to_print = .true. + end if n = size(this%kstp_list_print) - if(n > 0) then + if (n > 0) then do i = 1, n - if(kstp == this%kstp_list_print(i)) then + if (kstp == this%kstp_list_print(i)) then kstp_to_print = .true. exit - endif - enddo - endif + end if + end do + end if ! ! -- Return return end function kstp_to_print - + !> @ brief Determine if it is time to save the data !! - !! Determine if data should be saved based on kstp and endofperiod + !! Determine if data should be saved based on kstp and endofperiod !! !< logical function kstp_to_save(this, kstp, endofperiod) ! -- dummy - class(PrintSaveManagerType) :: this !< psm object - integer(I4B), intent(in) :: kstp !< current time step - logical(LGP), intent(in) :: endofperiod !< flag indicating end of stress period + class(PrintSaveManagerType) :: this !< psm object + integer(I4B), intent(in) :: kstp !< current time step + logical(LGP), intent(in) :: endofperiod !< flag indicating end of stress period ! -- local integer(I4B) :: i, n ! kstp_to_save = .false. - if(this%save_all) kstp_to_save = .true. - if(kstp == 1 .and. this%save_first) kstp_to_save = .true. - if(endofperiod .and. this%save_last) kstp_to_save = .true. - if(this%ifreq_save > 0) then - if(mod(kstp, this%ifreq_save) == 0) kstp_to_save = .true. - endif + if (this%save_all) kstp_to_save = .true. + if (kstp == 1 .and. this%save_first) kstp_to_save = .true. + if (endofperiod .and. this%save_last) kstp_to_save = .true. + if (this%ifreq_save > 0) then + if (mod(kstp, this%ifreq_save) == 0) kstp_to_save = .true. + end if n = size(this%kstp_list_save) - if(n > 0) then + if (n > 0) then do i = 1, n - if(kstp == this%kstp_list_save(i)) then + if (kstp == this%kstp_list_save(i)) then kstp_to_save = .true. exit - endif - enddo - endif + end if + end do + end if ! ! -- Return return end function kstp_to_save - -end module PrintSaveManagerModule \ No newline at end of file + +end module PrintSaveManagerModule diff --git a/src/Utilities/PackageBudget.f90 b/src/Utilities/PackageBudget.f90 index e1c37a63a57..93f1f5b2c6b 100644 --- a/src/Utilities/PackageBudget.f90 +++ b/src/Utilities/PackageBudget.f90 @@ -1,44 +1,44 @@ -!> @brief This module contains the PackageBudgetModule Module +!> @brief This module contains the PackageBudgetModule Module !! !! The PackageBudgetType object defined here provides flows to the GWT !! model. The PackageBudgetType can be filled with flows from a budget -!! object that was written from a previous GWF simulation, or its +!! object that was written from a previous GWF simulation, or its !! individual members can be pointed to flows that are being calculated !! by a GWF model that is running as part of this simulation. !< module PackageBudgetModule - + use KindModule use ConstantsModule, only: LENPACKAGENAME, LENAUXNAME, LENMEMPATH - use MemoryManagerModule, only: mem_allocate, mem_reassignptr, & + use MemoryManagerModule, only: mem_allocate, mem_reassignptr, & mem_reallocate, mem_deallocate implicit none - + private public :: PackageBudgetType - - !> @brief Derived type for storing flows + + !> @brief Derived type for storing flows !! !! This derived type stores flows and provides them through the FMI - !! package to other parts of GWT. + !! package to other parts of GWT. !! !< type :: PackageBudgetType - - character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored - character(len=LENPACKAGENAME), pointer :: name => null() !< name of the package - character(len=LENPACKAGENAME), pointer :: budtxt => null() !< type of flow (CHD, RCH, RCHA, ...) - character(len=LENAUXNAME), dimension(:), pointer, & - contiguous :: auxname => null() !< vector of auxname - integer(I4B), pointer :: naux => null() !< number of auxiliary variables - integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period - integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() !< vector of reduced node numbers - real(DP), dimension(:), pointer, contiguous :: flow => null() !< calculated flow - real(DP), dimension(:,:), pointer, contiguous :: auxvar => null() !< auxiliary variable array - + + character(len=LENMEMPATH) :: memoryPath = '' !< the location in the memory manager where the variables are stored + character(len=LENPACKAGENAME), pointer :: name => null() !< name of the package + character(len=LENPACKAGENAME), pointer :: budtxt => null() !< type of flow (CHD, RCH, RCHA, ...) + character(len=LENAUXNAME), dimension(:), pointer, & + contiguous :: auxname => null() !< vector of auxname + integer(I4B), pointer :: naux => null() !< number of auxiliary variables + integer(I4B), pointer :: nbound => null() !< number of boundaries for current stress period + integer(I4B), dimension(:), pointer, contiguous :: nodelist => null() !< vector of reduced node numbers + real(DP), dimension(:), pointer, contiguous :: flow => null() !< calculated flow + real(DP), dimension(:, :), pointer, contiguous :: auxvar => null() !< auxiliary variable array + contains - + procedure :: initialize procedure :: set_name procedure :: set_auxname @@ -46,19 +46,19 @@ module PackageBudgetModule procedure :: copy_values procedure :: get_flow procedure :: da - - end type PackageBudgetType - - contains - + + end type PackageBudgetType + +contains + !> @ brief Initialize a PackageBudgetType object !! - !! Establish the memory path and allocate and initialize member variables. + !! Establish the memory path and allocate and initialize member variables. !! !< subroutine initialize(this, mempath) - class(PackageBudgetType) :: this !< PackageBudgetType object - character(len=*), intent(in) :: mempath !< memory path in memory manager + class(PackageBudgetType) :: this !< PackageBudgetType object + character(len=*), intent(in) :: mempath !< memory path in memory manager this%memoryPath = mempath ! ! -- allocate member variables in memory manager @@ -78,50 +78,51 @@ subroutine initialize(this, mempath) this%nbound = 0 return end subroutine initialize - + !> @ brief Set names for this PackageBudgetType object !! - !! Set the name of the package and the name of the of budget text + !! Set the name of the package and the name of the of budget text !! !< subroutine set_name(this, name, budtxt) - class(PackageBudgetType) :: this !< PackageBudgetType object - character(len=LENPACKAGENAME) :: name !< name of the package (WEL-1, DRN-4, etc.) - character(len=LENPACKAGENAME) :: budtxt !< name of budget term (CHD, RCH, EVT, DRN-TO-MVR, etc.) + class(PackageBudgetType) :: this !< PackageBudgetType object + character(len=LENPACKAGENAME) :: name !< name of the package (WEL-1, DRN-4, etc.) + character(len=LENPACKAGENAME) :: budtxt !< name of budget term (CHD, RCH, EVT, DRN-TO-MVR, etc.) this%name = name this%budtxt = budtxt return end subroutine set_name - + !> @ brief Set aux names for this PackageBudgetType object !! - !! Set the number of auxiliary variables and the names of the + !! Set the number of auxiliary variables and the names of the !! auxiliary variables !! !< subroutine set_auxname(this, naux, auxname) - class(PackageBudgetType) :: this !< PackageBudgetType object - integer(I4B), intent(in) :: naux !< number of auxiliary variables + class(PackageBudgetType) :: this !< PackageBudgetType object + integer(I4B), intent(in) :: naux !< number of auxiliary variables character(len=LENAUXNAME), contiguous, & - dimension(:), intent(in) :: auxname !< array of names for auxiliary variables + dimension(:), intent(in) :: auxname !< array of names for auxiliary variables this%naux = naux - call mem_reallocate(this%auxname, LENAUXNAME, naux, 'AUXNAME', this%memoryPath) + call mem_reallocate(this%auxname, LENAUXNAME, naux, 'AUXNAME', & + this%memoryPath) this%auxname(:) = auxname(:) return end subroutine set_auxname - + !> @ brief Point members of this class to data stored in GWF packages !! - !! The routine is called when a GWF model is being run concurrently with + !! The routine is called when a GWF model is being run concurrently with !! a GWT model. In this situation, the member variables NBOUND, NODELIST, !! FLOW, and AUXVAR are pointed into member variables of the individual !! GWF Package members stored in BndType. !! !< subroutine set_pointers(this, flowvarname, mem_path_target) - class(PackageBudgetType) :: this !< PackageBudgetType object - character(len=*), intent(in) :: flowvarname !< name of variable storing flow (SIMVALS, SIMTOMVR) - character(len=*), intent(in) :: mem_path_target !< path where target variable is stored + class(PackageBudgetType) :: this !< PackageBudgetType object + character(len=*), intent(in) :: flowvarname !< name of variable storing flow (SIMVALS, SIMTOMVR) + character(len=*), intent(in) :: mem_path_target !< path where target variable is stored ! ! -- Reassign pointers to variables in the flow model call mem_reassignptr(this%nbound, 'NBOUND', this%memoryPath, & @@ -132,7 +133,7 @@ subroutine set_pointers(this, flowvarname, mem_path_target) flowvarname, mem_path_target) call mem_reassignptr(this%auxvar, 'AUXVAR', this%memoryPath, & 'AUXVAR', mem_path_target) - return + return end subroutine set_pointers !> @ brief Copy data read from a budget file into this object @@ -144,11 +145,11 @@ end subroutine set_pointers !! !< subroutine copy_values(this, nbound, nodelist, flow, auxvar) - class(PackageBudgetType) :: this !< PackageBudgetType object - integer(I4B), intent(in) :: nbound !< number of entries - integer(I4B), dimension(:), contiguous, intent(in) :: nodelist !< array of GWT node numbers - real(DP), dimension(:), contiguous, intent(in) :: flow !< array of flow rates - real(DP), dimension(:,:), contiguous, intent(in) :: auxvar !< array of auxiliary variables + class(PackageBudgetType) :: this !< PackageBudgetType object + integer(I4B), intent(in) :: nbound !< number of entries + integer(I4B), dimension(:), contiguous, intent(in) :: nodelist !< array of GWT node numbers + real(DP), dimension(:), contiguous, intent(in) :: flow !< array of flow rates + real(DP), dimension(:, :), contiguous, intent(in) :: auxvar !< array of auxiliary variables integer(I4B) :: i ! ! -- Assign variables @@ -159,8 +160,9 @@ subroutine copy_values(this, nbound, nodelist, flow, auxvar) if (size(this%nodelist) < nbound) then call mem_reallocate(this%nodelist, nbound, 'NODELIST', this%memoryPath) call mem_reallocate(this%flow, nbound, 'FLOW', this%memoryPath) - call mem_reallocate(this%auxvar, this%naux, nbound, 'AUXVAR', this%memoryPath) - endif + call mem_reallocate(this%auxvar, this%naux, nbound, 'AUXVAR', & + this%memoryPath) + end if ! ! -- Copy values into member variables do i = 1, nbound @@ -169,20 +171,20 @@ subroutine copy_values(this, nbound, nodelist, flow, auxvar) this%auxvar(:, i) = auxvar(:, i) end do end subroutine copy_values - + !> @ brief Get flow rate for specified entry !! !! Return the flow rate for the specified entry !! !< function get_flow(this, i) result(flow) - class(PackageBudgetType) :: this !< PackageBudgetType object - integer(I4B), intent(in) :: i !< entry number + class(PackageBudgetType) :: this !< PackageBudgetType object + integer(I4B), intent(in) :: i !< entry number real(DP) :: flow flow = this%flow(i) return end function get_flow - + !> @ brief Deallocate !! !! Free any memory associated with this object @@ -200,5 +202,5 @@ subroutine da(this) call mem_deallocate(this%auxvar, 'AUXVAR', this%memoryPath) return end subroutine da - -end module PackageBudgetModule \ No newline at end of file + +end module PackageBudgetModule diff --git a/src/Utilities/Sim.f90 b/src/Utilities/Sim.f90 index 7a344ec2983..50fdfe1340a 100644 --- a/src/Utilities/Sim.f90 +++ b/src/Utilities/Sim.f90 @@ -2,25 +2,25 @@ !! !! This module contains simulation methods for storing warning and error !! messages and notes. This module also has methods for counting warnings, -!! errors, and notes in addition to stopping the simulation. The module does -!! not have any dependencies on models, exchanges, or solutions in a +!! errors, and notes in addition to stopping the simulation. The module does +!! not have any dependencies on models, exchanges, or solutions in a !! simulation. !! !< module SimModule - - use KindModule, only: DP, I4B - use DefinedMacros, only: get_os - use ConstantsModule, only: MAXCHARLEN, LINELENGTH, & - DONE, & - IUSTART, IULAST, & - VSUMMARY, VALL, VDEBUG, & - OSWIN, OSUNDEF - use SimVariablesModule, only: istdout, iout, isim_level, ireturnerr, & - iforcestop, iunext, & - warnmsg + + use KindModule, only: DP, I4B + use DefinedMacros, only: get_os + use ConstantsModule, only: MAXCHARLEN, LINELENGTH, & + DONE, & + IUSTART, IULAST, & + VSUMMARY, VALL, VDEBUG, & + OSWIN, OSUNDEF + use SimVariablesModule, only: istdout, iout, isim_level, ireturnerr, & + iforcestop, iunext, & + warnmsg use GenericUtilitiesModule, only: sim_message, stop_with_error - use MessageModule, only: MessageType + use MessageModule, only: MessageType implicit none @@ -40,572 +40,567 @@ module SimModule public :: store_error_unit public :: store_error_filename public :: MaxErrors - + type(MessageType) :: sim_errors type(MessageType) :: sim_uniterrors type(MessageType) :: sim_warnings type(MessageType) :: sim_notes - contains +contains - !> @brief Return number of errors + !> @brief Return number of errors !! !! Function to return the number of errors messages that have been stored. !! !! @return ncount number of error messages stored !! - !< - function count_errors() result(ncount) - ! -- return variable - integer(I4B) :: ncount - ! - ! -- set ncount - ncount = sim_errors%count_message() - ! - ! -- return - return - end function count_errors + !< + function count_errors() result(ncount) + ! -- return variable + integer(I4B) :: ncount + ! + ! -- set ncount + ncount = sim_errors%count_message() + ! + ! -- return + return + end function count_errors - !> @brief Return number of warnings + !> @brief Return number of warnings !! !! Function to return the number of warning messages that have been stored. !! !! @return ncount number of warning messages stored !! - !< - function count_warnings() result(ncount) - ! -- return variable - integer(I4B) :: ncount - ! - ! -- set ncount - ncount = sim_warnings%count_message() - ! - ! -- return - return - end function count_warnings + !< + function count_warnings() result(ncount) + ! -- return variable + integer(I4B) :: ncount + ! + ! -- set ncount + ncount = sim_warnings%count_message() + ! + ! -- return + return + end function count_warnings - !> @brief Return number of notes + !> @brief Return number of notes !! !! Function to return the number of notes that have been stored. !! !! @return ncount number of notes stored !! - !< - function count_notes() result(ncount) - ! -- return variable - integer(I4B) :: ncount - ! - ! -- set ncount - ncount = sim_notes%count_message() - ! - ! -- return - return - end function count_notes + !< + function count_notes() result(ncount) + ! -- return variable + integer(I4B) :: ncount + ! + ! -- set ncount + ncount = sim_notes%count_message() + ! + ! -- return + return + end function count_notes - !> @brief Set the maximum number of errors stored + !> @brief Set the maximum number of errors stored !! !! Subroutine to set the maximum number of error messages that will be stored !! in a simulation. !! - !< - subroutine MaxErrors(imax) - ! -- dummy variables - integer(I4B), intent(in) :: imax !< maximum number of error messages that will be stored - ! - ! -- set the maximum number of error messages that will be saved - call sim_errors%set_max_message(imax) - ! - ! -- return - return - end subroutine MaxErrors + !< + subroutine MaxErrors(imax) + ! -- dummy variables + integer(I4B), intent(in) :: imax !< maximum number of error messages that will be stored + ! + ! -- set the maximum number of error messages that will be saved + call sim_errors%set_max_message(imax) + ! + ! -- return + return + end subroutine MaxErrors - !> @brief Store error message + !> @brief Store error message !! !! Subroutine to store a error message for printing at the end of !! the simulation. !! - !< - subroutine store_error(msg, terminate) - ! -- dummy variable - character(len=*), intent(in) :: msg !< error message - logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated - ! -- local variables - logical :: lterminate - ! - ! -- process optional variables - if (present(terminate)) then - lterminate = terminate - else - lterminate = .FALSE. - end if - ! - ! -- store error - call sim_errors%store_message(msg) - ! - ! -- terminate the simulation - if (lterminate) then - call ustop() - end if - ! - ! -- return - return - end subroutine store_error + !< + subroutine store_error(msg, terminate) + ! -- dummy variable + character(len=*), intent(in) :: msg !< error message + logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated + ! -- local variables + logical :: lterminate + ! + ! -- process optional variables + if (present(terminate)) then + lterminate = terminate + else + lterminate = .FALSE. + end if + ! + ! -- store error + call sim_errors%store_message(msg) + ! + ! -- terminate the simulation + if (lterminate) then + call ustop() + end if + ! + ! -- return + return + end subroutine store_error - !> @brief Get the file name + !> @brief Get the file name !! !! Subroutine to get the file name from the unit number for a open file. - !! If the INQUIRE function returns the full path (for example, the INTEL - !! compiler) then the returned file name (fname) is limited to the filename + !! If the INQUIRE function returns the full path (for example, the INTEL + !! compiler) then the returned file name (fname) is limited to the filename !! without the path. !! - !< - subroutine get_filename(iunit, fname) - ! -- dummy variables - integer(I4B), intent(in) :: iunit !< open file unit number - character(len=*), intent(inout) :: fname !< file name attached to the open file unit number - ! -- local variables - integer(I4B) :: ipos - integer(I4B) :: ios - integer(I4B) :: ilen - ! - ! -- get file name from unit number - inquire(unit=iunit, name=fname) - ! - ! -- determine the operating system - ios = get_os() - ! - ! -- extract filename from full path, if present - ! forward slash on linux, unix, and osx - if (ios /= OSWIN) then - ipos = index(fname, '/', back=.TRUE.) - end if - ! - ! -- check for backslash on windows or undefined os and - ! forward slashes were not found - if (ios == OSWIN .or. ios == OSUNDEF) then - if (ipos < 1) then - ipos = index(fname, '\', back=.TRUE.) - end if - end if - ! - ! -- exclude the path from the file name - if (ipos > 0) then - ilen = len_trim(fname) - write(fname, '(a)') fname(ipos+1:ilen) // ' ' + !< + subroutine get_filename(iunit, fname) + ! -- dummy variables + integer(I4B), intent(in) :: iunit !< open file unit number + character(len=*), intent(inout) :: fname !< file name attached to the open file unit number + ! -- local variables + integer(I4B) :: ipos + integer(I4B) :: ios + integer(I4B) :: ilen + ! + ! -- get file name from unit number + inquire (unit=iunit, name=fname) + ! + ! -- determine the operating system + ios = get_os() + ! + ! -- extract filename from full path, if present + ! forward slash on linux, unix, and osx + if (ios /= OSWIN) then + ipos = index(fname, '/', back=.TRUE.) + end if + ! + ! -- check for backslash on windows or undefined os and + ! forward slashes were not found + if (ios == OSWIN .or. ios == OSUNDEF) then + if (ipos < 1) then + ipos = index(fname, '\', back=.TRUE.) end if - ! - ! -- return - return - end subroutine get_filename + end if + ! + ! -- exclude the path from the file name + if (ipos > 0) then + ilen = len_trim(fname) + write (fname, '(a)') fname(ipos + 1:ilen)//' ' + end if + ! + ! -- return + return + end subroutine get_filename - !> @brief Store the file unit number + !> @brief Store the file unit number !! !! Subroutine to convert the unit number for a open file to a file name !! and indicate that there is an error reading from the file. By default, !! the simulation is terminated when this subroutine is called. !! - !< - subroutine store_error_unit(iunit, terminate) - ! -- dummy variables - integer(I4B), intent(in) :: iunit !< open file unit number - logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated - ! -- local variables - logical :: lterminate - character(len=LINELENGTH) :: fname - character(len=LINELENGTH) :: errmsg - ! - ! -- process optional variables - if (present(terminate)) then - lterminate = terminate - else - lterminate = .TRUE. - end if - ! - ! -- store error unit - inquire(unit=iunit, name=fname) - write(errmsg,'(3a)') & - "ERROR OCCURRED WHILE READING FILE '", trim(adjustl(fname)), "'" - call sim_uniterrors%store_message(errmsg) - ! - ! -- terminate the simulation - if (lterminate) then - call ustop() - end if - ! - ! -- return - return - end subroutine store_error_unit + !< + subroutine store_error_unit(iunit, terminate) + ! -- dummy variables + integer(I4B), intent(in) :: iunit !< open file unit number + logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated + ! -- local variables + logical :: lterminate + character(len=LINELENGTH) :: fname + character(len=LINELENGTH) :: errmsg + ! + ! -- process optional variables + if (present(terminate)) then + lterminate = terminate + else + lterminate = .TRUE. + end if + ! + ! -- store error unit + inquire (unit=iunit, name=fname) + write (errmsg, '(3a)') & + "ERROR OCCURRED WHILE READING FILE '", trim(adjustl(fname)), "'" + call sim_uniterrors%store_message(errmsg) + ! + ! -- terminate the simulation + if (lterminate) then + call ustop() + end if + ! + ! -- return + return + end subroutine store_error_unit - !> @brief Store the erroring file name + !> @brief Store the erroring file name !! !! Subroutine to store the file name issuing an error. By default, !! the simulation is terminated when this subroutine is called !! - !< - subroutine store_error_filename(filename, terminate) - ! -- dummy variables - character(len=*), intent(in) :: filename !< erroring file name - logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated - ! -- local variables - logical :: lterminate - character(len=LINELENGTH) :: errmsg - ! - ! -- process optional variables - if (present(terminate)) then - lterminate = terminate - else - lterminate = .TRUE. - end if - ! - ! -- store error unit - write(errmsg,'(3a)') & - "ERROR OCCURRED WHILE READING FILE '", trim(adjustl(filename)), "'" - call sim_uniterrors%store_message(errmsg) - ! - ! -- terminate the simulation - if (lterminate) then - call ustop() - end if - ! - ! -- return - return - end subroutine store_error_filename + !< + subroutine store_error_filename(filename, terminate) + ! -- dummy variables + character(len=*), intent(in) :: filename !< erroring file name + logical, optional, intent(in) :: terminate !< boolean indicating if the simulation should be terminated + ! -- local variables + logical :: lterminate + character(len=LINELENGTH) :: errmsg + ! + ! -- process optional variables + if (present(terminate)) then + lterminate = terminate + else + lterminate = .TRUE. + end if + ! + ! -- store error unit + write (errmsg, '(3a)') & + "ERROR OCCURRED WHILE READING FILE '", trim(adjustl(filename)), "'" + call sim_uniterrors%store_message(errmsg) + ! + ! -- terminate the simulation + if (lterminate) then + call ustop() + end if + ! + ! -- return + return + end subroutine store_error_filename - !> @brief Store warning message + !> @brief Store warning message !! !! Subroutine to store a warning message for printing at the end of !! the simulation. !! - !< - subroutine store_warning(msg, substring) - ! -- dummy variables - character(len=*), intent(in) :: msg !< warning message - character(len=*), intent(in), optional :: substring !< optional string that can be used - !! to prevent storing duplicate messages - ! - ! -- store warning - if (present(substring)) then - call sim_warnings%store_message(msg, substring) - else - call sim_warnings%store_message(msg) - end if - ! - ! -- return - return - end subroutine store_warning + !< + subroutine store_warning(msg, substring) + ! -- dummy variables + character(len=*), intent(in) :: msg !< warning message + character(len=*), intent(in), optional :: substring !< optional string that can be used + !! to prevent storing duplicate messages + ! + ! -- store warning + if (present(substring)) then + call sim_warnings%store_message(msg, substring) + else + call sim_warnings%store_message(msg) + end if + ! + ! -- return + return + end subroutine store_warning - !> @brief Store deprecation warning message + !> @brief Store deprecation warning message !! - !! Subroutine to store a warning message for deprecated variables + !! Subroutine to store a warning message for deprecated variables !! and printing at the end of simulation. !! - !< - subroutine deprecation_warning(cblock, cvar, cver, endmsg, iunit) - ! -- modules - use ArrayHandlersModule, only: ExpandArray - ! -- dummy variables - character(len=*), intent(in) :: cblock !< block name - character(len=*), intent(in) :: cvar !< variable name - character(len=*), intent(in) :: cver !< version when variable was deprecated - character(len=*), intent(in), optional :: endmsg !< optional user defined message to append - !! at the end of the deprecation warning - integer(I4B), intent(in), optional :: iunit !< optional input file unit number with - !! the deprecated variable - ! -- local variables - character(len=MAXCHARLEN) :: message - character(len=LINELENGTH) :: fname - ! - ! -- build message - write(message,'(a)') & - trim(cblock) // " BLOCK VARIABLE '" // trim(cvar) // "'" - if (present(iunit)) then - call get_filename(iunit, fname) - write(message,'(a,1x,3a)') & - trim(message), "IN FILE '", trim(fname), "'" - end if - write(message,'(a)') & - trim(message) // ' WAS DEPRECATED IN VERSION ' // trim(cver) // '.' - if (present(endmsg)) then - write(message,'(a,1x,2a)') trim(message), trim(endmsg), '.' - end if - ! - ! -- store warning - call sim_warnings%store_message(message) - ! - ! -- return - return - end subroutine deprecation_warning + !< + subroutine deprecation_warning(cblock, cvar, cver, endmsg, iunit) + ! -- modules + use ArrayHandlersModule, only: ExpandArray + ! -- dummy variables + character(len=*), intent(in) :: cblock !< block name + character(len=*), intent(in) :: cvar !< variable name + character(len=*), intent(in) :: cver !< version when variable was deprecated + character(len=*), intent(in), optional :: endmsg !< optional user defined message to append + !! at the end of the deprecation warning + integer(I4B), intent(in), optional :: iunit !< optional input file unit number with + !! the deprecated variable + ! -- local variables + character(len=MAXCHARLEN) :: message + character(len=LINELENGTH) :: fname + ! + ! -- build message + write (message, '(a)') & + trim(cblock)//" BLOCK VARIABLE '"//trim(cvar)//"'" + if (present(iunit)) then + call get_filename(iunit, fname) + write (message, '(a,1x,3a)') & + trim(message), "IN FILE '", trim(fname), "'" + end if + write (message, '(a)') & + trim(message)//' WAS DEPRECATED IN VERSION '//trim(cver)//'.' + if (present(endmsg)) then + write (message, '(a,1x,2a)') trim(message), trim(endmsg), '.' + end if + ! + ! -- store warning + call sim_warnings%store_message(message) + ! + ! -- return + return + end subroutine deprecation_warning - !> @brief Store note + !> @brief Store note !! !! Subroutine to store a note for printing at the end of the simulation. !! - !< - subroutine store_note(note) - ! -- modules - use ArrayHandlersModule, only: ExpandArray - ! -- dummy variables - character(len=*), intent(in) :: note !< note - ! - ! -- store note - call sim_notes%store_message(note) - ! - ! -- return - return - end subroutine store_note + !< + subroutine store_note(note) + ! -- modules + use ArrayHandlersModule, only: ExpandArray + ! -- dummy variables + character(len=*), intent(in) :: note !< note + ! + ! -- store note + call sim_notes%store_message(note) + ! + ! -- return + return + end subroutine store_note - !> @brief Stop the simulation. + !> @brief Stop the simulation. !! - !! Subroutine to stop the simulations with option to print message + !! Subroutine to stop the simulations with option to print message !! before stopping with the active error code. !! - !< - subroutine ustop(stopmess, ioutlocal) - ! -- dummy variables - character, optional, intent(in) :: stopmess*(*) !< optional message to print before - !! stopping the simulation - integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to - !! final message to - ! - ! -- print the final message - call print_final_message(stopmess, ioutlocal) - ! - ! -- return appropriate error codes when terminating the program - call stop_with_error(ireturnerr) - - end subroutine ustop + !< + subroutine ustop(stopmess, ioutlocal) + ! -- dummy variables + character, optional, intent(in) :: stopmess * (*) !< optional message to print before + !! stopping the simulation + integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to + !! final message to + ! + ! -- print the final message + call print_final_message(stopmess, ioutlocal) + ! + ! -- return appropriate error codes when terminating the program + call stop_with_error(ireturnerr) - !> @brief Print the final messages + end subroutine ustop + + !> @brief Print the final messages !! - !! Subroutine to print the notes, warnings, errors and the final message (if passed). + !! Subroutine to print the notes, warnings, errors and the final message (if passed). !! The subroutine also closes all open files. !! - !< - subroutine print_final_message(stopmess, ioutlocal) - ! -- dummy variables - character, optional, intent(in) :: stopmess*(*) !< optional message to print before - !! stopping the simulation - integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to - !! final message to - ! -- local variables - character(len=*), parameter :: fmt = '(1x,a)' - character(len=*), parameter :: msg = 'Stopping due to error(s)' - ! - ! -- print the accumulated messages - call sim_notes%print_message('NOTES:', 'note(s)', & - iunit=iout, level=VALL) - call sim_warnings%print_message('WARNING REPORT:', 'warning(s)', & - iunit=iout, level=VALL) - call sim_errors%print_message('ERROR REPORT:', 'error(s)', iunit=iout) - call sim_uniterrors%print_message('UNIT ERROR REPORT:', & - 'file unit error(s)', iunit=iout) - ! - ! -- write a stop message, if one is passed - if (present(stopmess)) then - if (stopmess.ne.' ') then - call sim_message(stopmess, fmt=fmt, iunit=iout) - call sim_message(stopmess, fmt=fmt) - if (present(ioutlocal)) then - if (ioutlocal > 0 .and. ioutlocal /= iout) then - write(ioutlocal,fmt) trim(stopmess) - close (ioutlocal) - endif - endif - endif - endif - ! - ! -- determine if an error condition has occurred - if (sim_errors%count_message() > 0) then - ireturnerr = 2 - if (iout > 0) then - call sim_message(stopmess, fmt=fmt, iunit=iout) - end if + !< + subroutine print_final_message(stopmess, ioutlocal) + ! -- dummy variables + character, optional, intent(in) :: stopmess * (*) !< optional message to print before + !! stopping the simulation + integer(I4B), optional, intent(in) :: ioutlocal !< optional output file to + !! final message to + ! -- local variables + character(len=*), parameter :: fmt = '(1x,a)' + character(len=*), parameter :: msg = 'Stopping due to error(s)' + ! + ! -- print the accumulated messages + call sim_notes%print_message('NOTES:', 'note(s)', & + iunit=iout, level=VALL) + call sim_warnings%print_message('WARNING REPORT:', 'warning(s)', & + iunit=iout, level=VALL) + call sim_errors%print_message('ERROR REPORT:', 'error(s)', iunit=iout) + call sim_uniterrors%print_message('UNIT ERROR REPORT:', & + 'file unit error(s)', iunit=iout) + ! + ! -- write a stop message, if one is passed + if (present(stopmess)) then + if (stopmess .ne. ' ') then + call sim_message(stopmess, fmt=fmt, iunit=iout) call sim_message(stopmess, fmt=fmt) - if (present(ioutlocal)) then - if (ioutlocal > 0 .and. ioutlocal /= iout) write(ioutlocal,fmt) msg - endif - endif - ! - ! -- close all open files - call sim_closefiles() - ! - ! -- return - return - end subroutine print_final_message + if (ioutlocal > 0 .and. ioutlocal /= iout) then + write (ioutlocal, fmt) trim(stopmess) + close (ioutlocal) + end if + end if + end if + end if + ! + ! -- determine if an error condition has occurred + if (sim_errors%count_message() > 0) then + ireturnerr = 2 + if (present(ioutlocal)) then + if (ioutlocal > 0 .and. ioutlocal /= iout) write (ioutlocal, fmt) msg + end if + end if + ! + ! -- close all open files + call sim_closefiles() + ! + ! -- return + return + end subroutine print_final_message - !> @brief Reset the simulation convergence flag + !> @brief Reset the simulation convergence flag !! !! Subroutine to reset the simulation convergence flag. !! - !< - subroutine converge_reset() - ! -- modules - use SimVariablesModule, only: isimcnvg - ! - ! -- reset simulation convergence flag - isimcnvg = 1 - ! - ! -- return - return - end subroutine converge_reset + !< + subroutine converge_reset() + ! -- modules + use SimVariablesModule, only: isimcnvg + ! + ! -- reset simulation convergence flag + isimcnvg = 1 + ! + ! -- return + return + end subroutine converge_reset - !> @brief Simulation convergence check + !> @brief Simulation convergence check !! !! Subroutine to check simulation convergence. If the continue option is !! set the simulation convergence flag is set to True if the simulation !! did not actually converge for a time step and the non-convergence counter !! is incremented. !! - !< - subroutine converge_check(hasConverged) - ! -- modules - use SimVariablesModule, only: isimcnvg, numnoconverge, isimcontinue - ! -- dummy variables - logical, intent(inout) :: hasConverged !< boolean indicting if the - !! simulation is considered converged - ! -- format - character(len=*), parameter :: fmtfail = & - "(1x, 'Simulation convergence failure.', & - &' Simulation will terminate after output and deallocation.')" - ! - ! -- Initialize hasConverged to True - hasConverged = .true. - ! - ! -- Count number of failures - if(isimcnvg == 0) then - numnoconverge = numnoconverge + 1 + !< + subroutine converge_check(hasConverged) + ! -- modules + use SimVariablesModule, only: isimcnvg, numnoconverge, isimcontinue + ! -- dummy variables + logical, intent(inout) :: hasConverged !< boolean indicting if the + !! simulation is considered converged + ! -- format + character(len=*), parameter :: fmtfail = & + "(1x, 'Simulation convergence failure.', & + &' Simulation will terminate after output and deallocation.')" + ! + ! -- Initialize hasConverged to True + hasConverged = .true. + ! + ! -- Count number of failures + if (isimcnvg == 0) then + numnoconverge = numnoconverge + 1 + end if + ! + ! -- Continue if 'CONTINUE' specified in simulation control file + if (isimcontinue == 1) then + if (isimcnvg == 0) then + isimcnvg = 1 end if - ! - ! -- Continue if 'CONTINUE' specified in simulation control file - if(isimcontinue == 1) then - if(isimcnvg == 0) then - isimcnvg = 1 - endif - endif - ! - ! -- save simulation failure message - if(isimcnvg == 0) then - call sim_message('', fmt=fmtfail, iunit=iout) - hasConverged = .false. - endif - ! - ! -- return - return - end subroutine converge_check + end if + ! + ! -- save simulation failure message + if (isimcnvg == 0) then + call sim_message('', fmt=fmtfail, iunit=iout) + hasConverged = .false. + end if + ! + ! -- return + return + end subroutine converge_check - !> @brief Print the header and initializes messaging - !! - !! Subroutine that prints the initial message and initializes the notes, - !! warning messages, unit errors, and error messages. - !! - !< - subroutine initial_message() - ! -- modules - use VersionModule, only: write_listfile_header - ! - ! -- initialize message lists - call sim_errors%init_message() - call sim_uniterrors%init_message() - call sim_warnings%init_message() - call sim_notes%init_message() - ! - ! -- Write banner to screen (unit stdout) - call write_listfile_header(istdout, write_kind_info=.false., & - write_sys_command=.false.) - ! - end subroutine initial_message + !> @brief Print the header and initializes messaging + !! + !! Subroutine that prints the initial message and initializes the notes, + !! warning messages, unit errors, and error messages. + !! + !< + subroutine initial_message() + ! -- modules + use VersionModule, only: write_listfile_header + ! + ! -- initialize message lists + call sim_errors%init_message() + call sim_uniterrors%init_message() + call sim_warnings%init_message() + call sim_notes%init_message() + ! + ! -- Write banner to screen (unit stdout) + call write_listfile_header(istdout, write_kind_info=.false., & + write_sys_command=.false.) + ! + end subroutine initial_message - !> @brief Create final message - !! - !! Subroutine that creates the appropriate final message and - !! terminates the program with an error message, if necessary. - !! - !< - subroutine final_message() - ! -- modules - use SimVariablesModule, only: isimcnvg, numnoconverge, ireturnerr, & - isimcontinue - ! -- formats - character(len=*), parameter :: fmtnocnvg = & - "(1x, 'Simulation convergence failure occurred ', i0, ' time(s).')" - ! - ! -- Write message if nonconvergence occured in at least one timestep - if(numnoconverge > 0) then - write(warnmsg, fmtnocnvg) numnoconverge - if (isimcontinue == 0) then - call sim_errors%store_message(warnmsg) - else - call sim_warnings%store_message(warnmsg) - end if - endif - ! - ! -- write final message - if(isimcnvg == 0) then - call print_final_message('Premature termination of simulation.', iout) + !> @brief Create final message + !! + !! Subroutine that creates the appropriate final message and + !! terminates the program with an error message, if necessary. + !! + !< + subroutine final_message() + ! -- modules + use SimVariablesModule, only: isimcnvg, numnoconverge, ireturnerr, & + isimcontinue + ! -- formats + character(len=*), parameter :: fmtnocnvg = & + &"(1x, 'Simulation convergence failure occurred ', i0, ' time(s).')" + ! + ! -- Write message if nonconvergence occured in at least one timestep + if (numnoconverge > 0) then + write (warnmsg, fmtnocnvg) numnoconverge + if (isimcontinue == 0) then + call sim_errors%store_message(warnmsg) else - call print_final_message('Normal termination of simulation.', iout) - endif - ! - ! -- If the simulation did not converge and the continue - ! option was not set, then set the return code to 1. The - ! purpose of setting the returncode this way is that the - ! program will terminate without a stop code if the simulation - ! reached the end and the continue flag was set, even if the - ! the simulation did not converge. - if (isimcnvg == 0 .and. isimcontinue == 0) then - ireturnerr = 1 + call sim_warnings%store_message(warnmsg) end if - ! - ! -- destroy messages - call sim_errors%deallocate_message() - call sim_uniterrors%deallocate_message() - call sim_warnings%deallocate_message() - call sim_notes%deallocate_message() - ! - ! -- return or halt - if (iforcestop == 1) then - call stop_with_error(ireturnerr) + end if + ! + ! -- write final message + if (isimcnvg == 0) then + call print_final_message('Premature termination of simulation.', iout) + else + call print_final_message('Normal termination of simulation.', iout) + end if + ! + ! -- If the simulation did not converge and the continue + ! option was not set, then set the return code to 1. The + ! purpose of setting the returncode this way is that the + ! program will terminate without a stop code if the simulation + ! reached the end and the continue flag was set, even if the + ! the simulation did not converge. + if (isimcnvg == 0 .and. isimcontinue == 0) then + ireturnerr = 1 + end if + ! + ! -- destroy messages + call sim_errors%deallocate_message() + call sim_uniterrors%deallocate_message() + call sim_warnings%deallocate_message() + call sim_notes%deallocate_message() + ! + ! -- return or halt + if (iforcestop == 1) then + call stop_with_error(ireturnerr) + end if + + end subroutine final_message + + !> @brief Close all open files + !! + !! Subroutine that closes all open files at the end of the simulation. + !! + !< + subroutine sim_closefiles() + ! -- modules + ! -- dummy + ! -- local variables + integer(I4B) :: i + logical :: opened + character(len=7) :: output_file + ! + ! -- close all open file units + do i = iustart, iunext - 1 + ! + ! -- determine if file unit i is open + inquire (unit=i, opened=opened) + ! + ! -- skip file units that are no longer open + if (.not. opened) then + cycle end if - - end subroutine final_message - - !> @brief Close all open files - !! - !! Subroutine that closes all open files at the end of the simulation. - !! - !< - subroutine sim_closefiles() - ! -- modules - ! -- dummy - ! -- local variables - integer(I4B) :: i - logical :: opened - character(len=7) :: output_file ! - ! -- close all open file units - do i = iustart, iunext - 1 - ! - ! -- determine if file unit i is open - inquire(unit=i, opened=opened) - ! - ! -- skip file units that are no longer open - if(.not. opened) then - cycle - end if - ! - ! -- flush the file if it can be written to - inquire(unit=i, write=output_file) - if (trim(adjustl(output_file)) == 'YES') then - flush(i) - end if - ! - ! -- close file unit i - close(i) - end do + ! -- flush the file if it can be written to + inquire (unit=i, write=output_file) + if (trim(adjustl(output_file)) == 'YES') then + flush (i) + end if ! - ! -- return - return - end subroutine sim_closefiles - + ! -- close file unit i + close (i) + end do + ! + ! -- return + return + end subroutine sim_closefiles + end module SimModule diff --git a/src/Utilities/SimVariables.f90 b/src/Utilities/SimVariables.f90 index 82b4f55a8bc..6847d8376c1 100644 --- a/src/Utilities/SimVariables.f90 +++ b/src/Utilities/SimVariables.f90 @@ -11,22 +11,23 @@ module SimVariablesModule use KindModule, only: DP, I4B use ConstantsModule, only: LINELENGTH, MAXCHARLEN, IUSTART, VALL, MNORMAL public - character(len=LINELENGTH) :: simfile = 'mfsim.nam' !< simulation name file - character(len=LINELENGTH) :: simlstfile = 'mfsim.lst' !< simulation listing file name - character(len=LINELENGTH) :: simstdout = 'mfsim.stdout' !< name of standard out file if screen output is piped to a file - character(len=MAXCHARLEN) :: errmsg !< error message string - character(len=MAXCHARLEN) :: warnmsg !< warning message string - integer(I4B) :: istdout = output_unit !< unit number for stdout - integer(I4B) :: isim_level = VALL !< simulation output level - integer(I4B) :: isim_mode = MNORMAL !< simulation mode - integer(I4B) :: iout !< file unit number for simulation output - integer(I4B) :: isimcnvg !< simulation convergence flag (1) if all objects have converged, (0) otherwise - integer(I4B) :: isimcontinue = 0 !< simulation continue flag (1) to continue if isimcnvg = 0, (0) to terminate - integer(I4B) :: isimcheck = 1 !< simulation input check flag (1) to check input, (0) to ignore checks - integer(I4B) :: numnoconverge = 0 !< number of times the simulation did not converge - integer(I4B) :: ireturnerr = 0 !< return code for program (0) successful, (1) non-convergence, (2) error - integer(I4B) :: iforcestop = 1 !< forced stop flag (1) forces a call to ustop(..) when the simulation has ended, (0) doesn't - integer(I4B) :: iunext = IUSTART !< next file unit number to assign - integer(I4B) :: lastStepFailed = 0 !< flag indicating if the last step failed (1) if last step failed; (0) otherwise (set in converge_check) - integer(I4B) :: iFailedStepRetry = 0 !< current retry for this time step + character(len=LINELENGTH) :: simfile = 'mfsim.nam' !< simulation name file + character(len=LINELENGTH) :: simlstfile = 'mfsim.lst' !< simulation listing file name + character(len=LINELENGTH) :: simstdout = 'mfsim.stdout' !< name of standard out file if screen output is piped to a file + character(len=LINELENGTH) :: idm_context = '__INPUT__' + character(len=MAXCHARLEN) :: errmsg !< error message string + character(len=MAXCHARLEN) :: warnmsg !< warning message string + integer(I4B) :: istdout = output_unit !< unit number for stdout + integer(I4B) :: isim_level = VALL !< simulation output level + integer(I4B) :: isim_mode = MNORMAL !< simulation mode + integer(I4B) :: iout !< file unit number for simulation output + integer(I4B) :: isimcnvg !< simulation convergence flag (1) if all objects have converged, (0) otherwise + integer(I4B) :: isimcontinue = 0 !< simulation continue flag (1) to continue if isimcnvg = 0, (0) to terminate + integer(I4B) :: isimcheck = 1 !< simulation input check flag (1) to check input, (0) to ignore checks + integer(I4B) :: numnoconverge = 0 !< number of times the simulation did not converge + integer(I4B) :: ireturnerr = 0 !< return code for program (0) successful, (1) non-convergence, (2) error + integer(I4B) :: iforcestop = 1 !< forced stop flag (1) forces a call to ustop(..) when the simulation has ended, (0) doesn't + integer(I4B) :: iunext = IUSTART !< next file unit number to assign + integer(I4B) :: lastStepFailed = 0 !< flag indicating if the last step failed (1) if last step failed; (0) otherwise (set in converge_check) + integer(I4B) :: iFailedStepRetry = 0 !< current retry for this time step end module SimVariablesModule diff --git a/src/Utilities/SmoothingFunctions.f90 b/src/Utilities/SmoothingFunctions.f90 index 12ae5ad60f4..c821e14c67d 100644 --- a/src/Utilities/SmoothingFunctions.f90 +++ b/src/Utilities/SmoothingFunctions.f90 @@ -1,17 +1,17 @@ module SmoothingModule use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, DHALF, DONE, DTWO, DTHREE, DFOUR, & - & DSIX, DPREC, DEM2, DEM4, DEM5, DEM6, DEM8, DEM14 + use ConstantsModule, only: DZERO, DHALF, DONE, DTWO, DTHREE, DFOUR, & + DSIX, DPREC, DEM2, DEM4, DEM5, DEM6, DEM8, DEM14 implicit none - - contains - - subroutine sSCurve(x,range,dydx,y) + +contains + + subroutine sSCurve(x, range, dydx, y) ! ****************************************************************************** ! COMPUTES THE S CURVE FOR SMOOTH DERIVATIVES BETWEEN X=0 AND X=1 ! FROM mfusg smooth SUBROUTINE in gwf2wel7u1.f ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(in) :: x @@ -25,28 +25,28 @@ subroutine sSCurve(x,range,dydx,y) ! code ! s = range - if ( s < DPREC ) s = DPREC + if (s < DPREC) s = DPREC xs = x / s if (xs < DZERO) xs = DZERO if (xs <= DZERO) then y = DZERO dydx = DZERO - elseif(xs < DONE)then + elseif (xs < DONE) then y = -DTWO * xs**DTHREE + DTHREE * xs**DTWO dydx = -DSIX * xs**DTWO + DSIX * xs else y = DONE dydx = DZERO - endif + end if return end subroutine sSCurve - - subroutine sCubicLinear(x,range,dydx,y) + + subroutine sCubicLinear(x, range, dydx, y) ! ****************************************************************************** ! COMPUTES THE S CURVE WHERE DY/DX = 0 at X=0; AND DY/DX = 1 AT X=1. ! Smooths from zero to a slope of 1. ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(in) :: x @@ -60,27 +60,27 @@ subroutine sCubicLinear(x,range,dydx,y) ! code ! s = range - if ( s < DPREC ) s = DPREC + if (s < DPREC) s = DPREC xs = x / s if (xs < DZERO) xs = DZERO if (xs <= DZERO) then y = DZERO dydx = DZERO - elseif(xs < DONE)then + elseif (xs < DONE) then y = -DONE * xs**DTHREE + DTWO * xs**DTWO dydx = -DTHREE * xs**DTWO + DFOUR * xs else y = DONE dydx = DZERO - endif + end if return end subroutine sCubicLinear - subroutine sCubic(x,range,dydx,y) + subroutine sCubic(x, range, dydx, y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; cubic function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(inout) :: x @@ -95,31 +95,31 @@ subroutine sCubic(x,range,dydx,y) ! dydx = DZERO y = DZERO - if ( range < DPREC ) range = DPREC - if ( x < DPREC ) x = DPREC + if (range < DPREC) range = DPREC + if (x < DPREC) x = DPREC s = range - aa = -DSIX/(s**DTHREE) - bb = -DSIX/(s**DTWO) + aa = -DSIX / (s**DTHREE) + bb = -DSIX / (s**DTWO) cof1 = x**DTWO - cof2 = -(DTWO*x)/(s**DTHREE) - cof3 = DTHREE/(s**DTWO) + cof2 = -(DTWO * x) / (s**DTHREE) + cof3 = DTHREE / (s**DTWO) y = cof1 * (cof2 + cof3) - dydx = (aa*x**DTWO - bb*x) - if ( x <= DZERO ) then + dydx = (aa * x**DTWO - bb * x) + if (x <= DZERO) then y = DZERO dydx = DZERO - else if ( (x - s) > -DPREC ) then + else if ((x - s) > -DPREC) then y = DONE dydx = DZERO end if return end subroutine sCubic - - subroutine sLinear(x,range,dydx,y) + + subroutine sLinear(x, range, dydx, y) ! ****************************************************************************** ! Linear smoothing function returns value between 0-1 ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(inout) :: x @@ -133,23 +133,23 @@ subroutine sLinear(x,range,dydx,y) ! dydx = DZERO y = DZERO - if ( range < DPREC ) range = DPREC - if ( x < DPREC ) x = DPREC + if (range < DPREC) range = DPREC + if (x < DPREC) x = DPREC s = range - y = DONE - (s - x)/s - dydx = DONE/s - if ( y > DONE ) then + y = DONE - (s - x) / s + dydx = DONE / s + if (y > DONE) then y = DONE dydx = DZERO end if return end subroutine sLinear - - subroutine sQuadratic(x,range,dydx,y) + + subroutine sQuadratic(x, range, dydx, y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; quadratic function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(inout) :: x @@ -163,12 +163,12 @@ subroutine sQuadratic(x,range,dydx,y) ! dydx = DZERO y = DZERO - if ( range < DPREC ) range = DPREC - if ( x < DPREC ) x = DPREC + if (range < DPREC) range = DPREC + if (x < DPREC) x = DPREC s = range y = (x**DTWO) / (s**DTWO) - dydx = DTWO*x/(s**DTWO) - if ( y > DONE ) then + dydx = DTWO * x / (s**DTWO) + if (y > DONE) then y = DONE dydx = DZERO end if @@ -179,7 +179,7 @@ subroutine sChSmooth(d, smooth, dwdh) ! ****************************************************************************** ! Function to smooth channel variables during channel drying ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ real(DP), intent(in) :: d @@ -196,38 +196,38 @@ subroutine sChSmooth(d, smooth, dwdh) real(DP) :: y ! ------------------------------------------------------------------------------ ! code -! +! smooth = DZERO s = DEM5 x = d diff = x - s - if ( diff > DZERO ) then + if (diff > DZERO) then smooth = DONE dwdh = DZERO else aa = -DONE / (s**DTWO) ad = -DTWO / (s**DTWO) b = DTWO / s - y = aa * x**DTWO + b*x - dwdh = (ad*x + b) - if ( x <= DZERO ) then + y = aa * x**DTWO + b * x + dwdh = (ad * x + b) + if (x <= DZERO) then y = DZERO dwdh = DZERO - else if ( diff > -DEM14 ) then + else if (diff > -DEM14) then y = DONE dwdh = DZERO end if smooth = y end if return -end subroutine sChSmooth - + end subroutine sChSmooth + function sLinearSaturation(top, bot, x) result(y) ! ****************************************************************************** ! Linear smoothing function returns value between 0-1; ! Linear saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -252,13 +252,12 @@ function sLinearSaturation(top, bot, x) result(y) return end function sLinearSaturation - function sCubicSaturation(top, bot, x, eps) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; ! Quadratic saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -292,24 +291,23 @@ function sCubicSaturation(top, bot, x, eps) result(y) y = DZERO else if (w < s) then y = -cof1 * (w**DTHREE) + cof2 * (w**DTWO) - else if (w < (b-s)) then + else if (w < (b - s)) then y = w / b else if (w < b) then y = DONE + cof1 * ((b - w)**DTHREE) - cof2 * ((b - w)**DTWO) else y = DONE end if - + return end function sCubicSaturation - function sQuadraticSaturation(top, bot, x, eps, bmin) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; ! Quadratic saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -349,14 +347,14 @@ function sQuadraticSaturation(top, bot, x, eps, bmin) result(y) else br = (x - bot) / b end if - av = DONE / (DONE - teps) + av = DONE / (DONE - teps) bri = DONE - br if (br < tbmin) then br = tbmin end if if (br < teps) then - y = av * DHALF * (br*br) / teps - elseif (br < (DONE-teps)) then + y = av * DHALF * (br * br) / teps + elseif (br < (DONE - teps)) then y = av * br + DHALF * (DONE - av) elseif (br < DONE) then y = DONE - ((av * DHALF * (bri * bri)) / teps) @@ -370,16 +368,16 @@ function sQuadraticSaturation(top, bot, x, eps, bmin) result(y) y = DONE end if end if - + return end function sQuadraticSaturation - + function svanGenuchtenSaturation(top, bot, x, alpha, beta, sr) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; ! van Genuchten saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -412,14 +410,13 @@ function svanGenuchtenSaturation(top, bot, x, alpha, beta, sr) result(y) return end function svanGenuchtenSaturation - - + function sQuadraticSaturationDerivative(top, bot, x, eps, bmin) result(y) ! ****************************************************************************** ! Derivative of nonlinear smoothing function returns value between 0-1; ! Derivative of the quadratic saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -458,14 +455,14 @@ function sQuadraticSaturationDerivative(top, bot, x, eps, bmin) result(y) else br = (x - bot) / b end if - av = DONE / (DONE - teps) + av = DONE / (DONE - teps) bri = DONE - br if (br < tbmin) then br = tbmin end if if (br < teps) then y = av * br / teps - elseif (br < (DONE-teps)) then + elseif (br < (DONE - teps)) then y = av elseif (br < DONE) then y = av * bri / teps @@ -473,18 +470,16 @@ function sQuadraticSaturationDerivative(top, bot, x, eps, bmin) result(y) y = DZERO end if y = y / b - + return end function sQuadraticSaturationDerivative - - function sQSaturation(top, bot, x, c1, c2) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; ! Cubic saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -531,7 +526,7 @@ function sQSaturation(top, bot, x, c1, c2) result(y) ! -- calculate fraction if (s < DZERO) then y = DZERO - else if(s < DONE) then + else if (s < DONE) then y = cof1 * w**DTHREE + cof2 * w**DTWO else y = DONE @@ -540,13 +535,13 @@ function sQSaturation(top, bot, x, c1, c2) result(y) ! -- return return end function sQSaturation - + function sQSaturationDerivative(top, bot, x, c1, c2) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns value between 0-1; ! Cubic saturation function ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -569,7 +564,7 @@ function sQSaturationDerivative(top, bot, x, c1, c2) result(y) ! ! -- process optional variables if (present(c1)) then - cof1 = c1 + cof1 = c1 else cof1 = -DTWO end if @@ -586,7 +581,7 @@ function sQSaturationDerivative(top, bot, x, c1, c2) result(y) b = top - bot s = w / b ! - ! -- multiply cof1 and cof2 by 3 and 2, respectively, and then + ! -- multiply cof1 and cof2 by 3 and 2, respectively, and then ! divide by range to the power 3 and 2, respectively cof1 = cof1 * DTHREE / b**DTHREE cof2 = cof2 * DTWO / b**DTWO @@ -594,7 +589,7 @@ function sQSaturationDerivative(top, bot, x, c1, c2) result(y) ! -- calculate derivative of fraction with respect to x if (s < DZERO) then y = DZERO - else if(s < DONE) then + else if (s < DONE) then y = cof1 * w**DTWO + cof2 * w else y = DZERO @@ -603,14 +598,14 @@ function sQSaturationDerivative(top, bot, x, c1, c2) result(y) ! -- return return end function sQSaturationDerivative - + function sSlope(x, xi, yi, sm, sp, ta) result(y) ! ****************************************************************************** ! Nonlinear smoothing function returns a smoothed value of y that has the value ! yi at xi and yi + (sm * dx) for x-values less than xi and yi + (sp * dx) for ! x-values greater than xi, where dx = x - xi. ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -654,15 +649,15 @@ function sSlope(x, xi, yi, sm, sp, ta) result(y) ! ! -- return return - end function sSlope - + end function sSlope + function sSlopeDerivative(x, xi, sm, sp, ta) result(y) ! ****************************************************************************** -! Derivative of nonlinear smoothing function that has the value yi at xi and -! yi + (sm * dx) for x-values less than xi and yi + (sp * dx) for x-values +! Derivative of nonlinear smoothing function that has the value yi at xi and +! yi + (sm * dx) for x-values less than xi and yi + (sp * dx) for x-values ! greater than xi, where dx = x - xi. ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -697,20 +692,20 @@ function sSlopeDerivative(x, xi, sm, sp, ta) result(y) rho = dx / mu ! ! -- calculate derivative from individual contributions - y = DHALF * (sm + sp) - DHALF * rho * (sm - sp) + y = DHALF * (sm + sp) - DHALF * rho * (sm - sp) ! ! -- return return - end function sSlopeDerivative - + end function sSlopeDerivative + function sQuadratic0sp(x, xi, tomega) result(y) ! ****************************************************************************** -! Nonlinear smoothing function returns a smoothed value of y that uses a +! Nonlinear smoothing function returns a smoothed value of y that uses a ! quadratic to smooth x over range of xi - epsilon to xi + epsilon. ! Simplification of sQuadraticSlope with sm = 0, sp = 1, and yi = 0. ! From Panday et al. (2013) - eq. 35 - https://dx.doi.org/10.5066/F7R20ZFJ ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -749,16 +744,16 @@ function sQuadratic0sp(x, xi, tomega) result(y) ! ! -- return return - end function sQuadratic0sp - + end function sQuadratic0sp + function sQuadratic0spDerivative(x, xi, tomega) result(y) ! ****************************************************************************** -! Derivative of nonlinear smoothing function returns a smoothed value of y +! Derivative of nonlinear smoothing function returns a smoothed value of y ! that uses a quadratic to smooth x over range of xi - epsilon to xi + epsilon. ! Simplification of sQuadraticSlope with sm = 0, sp = 1, and yi = 0. ! From Panday et al. (2013) - eq. 35 - https://dx.doi.org/10.5066/F7R20ZFJ ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -797,15 +792,15 @@ function sQuadratic0spDerivative(x, xi, tomega) result(y) ! ! -- return return - end function sQuadratic0spDerivative - + end function sQuadratic0spDerivative + function sQuadraticSlope(x, xi, yi, sm, sp, tomega) result(y) ! ****************************************************************************** ! Quadratic smoothing function returns a smoothed value of y that has the value ! yi at xi and yi + (sm * dx) for x-values less than xi and yi + (sp * dx) for ! x-values greater than xi, where dx = x - xi. ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -852,16 +847,15 @@ function sQuadraticSlope(x, xi, yi, sm, sp, tomega) result(y) ! ! -- return return - end function sQuadraticSlope - - + end function sQuadraticSlope + function sQuadraticSlopeDerivative(x, xi, sm, sp, tomega) result(y) ! ****************************************************************************** -! Derivative of quadratic smoothing function returns a smoothed value of y -! that has the value yi at xi and yi + (sm * dx) for x-values less than xi and +! Derivative of quadratic smoothing function returns a smoothed value of y +! that has the value yi at xi and yi + (sm * dx) for x-values less than xi and ! yi + (sp * dx) for x-values greater than xi, where dx = x - xi. ! ****************************************************************************** -! +! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- return @@ -904,6 +898,6 @@ function sQuadraticSlopeDerivative(x, xi, sm, sp, tomega) result(y) ! ! -- return return - end function sQuadraticSlopeDerivative - + end function sQuadraticSlopeDerivative + end module SmoothingModule diff --git a/src/Utilities/Sparse.f90 b/src/Utilities/Sparse.f90 index e942aed7af2..af01ef34d9a 100644 --- a/src/Utilities/Sparse.f90 +++ b/src/Utilities/Sparse.f90 @@ -3,275 +3,278 @@ module SparseModule !of a matrix. Module uses FORTRAN 2003 extensions to manage !the data structures in an object oriented fashion. - use KindModule, only: DP, I4B + use KindModule, only: DP, I4B + implicit none + + type rowtype + integer(I4B) :: nnz ! number of nonzero entries in the row + integer(I4B), allocatable, dimension(:) :: icolarray ! array of column numbers + end type rowtype + + type, public :: sparsematrix + integer(I4B) :: nrow ! number of rows in the matrix + integer(I4B) :: ncol ! number of columns in the matrix + integer(I4B) :: nnz ! number of nonzero matrix entries + type(rowtype), allocatable, dimension(:) :: row ! one rowtype for each matrix row + contains + generic :: init => initialize, initializefixed + procedure :: addconnection + procedure :: filliaja + procedure :: sort + procedure :: destroy + + procedure, private :: initializefixed + procedure, private :: initialize + end type sparsematrix + +contains + + subroutine destroy(this) + class(sparsematrix), intent(inout) :: this + deallocate (this%row) + end subroutine destroy + + subroutine initialize(this, nrow, ncol, rowmaxnnz) + !initial the sparse matrix. This subroutine + !acts a method for a sparse matrix by initializing + !the row data. It presently requires one maximum + !value for all rows, however, this can be changed + !to a vector of maximum values with one value for + !each row. + ! -- dummy + class(sparsematrix), intent(inout) :: this + integer(I4B), intent(in) :: nrow, ncol + integer(I4B), intent(in), dimension(nrow) :: rowmaxnnz + ! -- local + integer(I4B) :: i + ! -- code + this%nrow = nrow + this%ncol = ncol + this%nnz = 0 + allocate (this%row(nrow)) + do i = 1, nrow + allocate (this%row(i)%icolarray(rowmaxnnz(i))) + this%row(i)%icolarray = 0 + this%row(i)%nnz = 0 + end do + ! + ! -- return + return + end subroutine initialize + + ! overload + subroutine initializefixed(this, nrow, ncol, maxnnz) implicit none - - type rowtype - integer(I4B) :: nnz ! number of nonzero entries in the row - integer(I4B), allocatable, dimension(:) :: icolarray ! array of column numbers - end type rowtype + class(sparsematrix), intent(inout) :: this + integer(I4B), intent(in) :: nrow, ncol + integer(I4B), intent(in) :: maxnnz + ! local + integer(I4B), dimension(:), allocatable :: rowmaxnnz + integer(I4B) :: i - type, public :: sparsematrix - integer(I4B) :: nrow ! number of rows in the matrix - integer(I4B) :: ncol ! number of columns in the matrix - integer(I4B) :: nnz ! number of nonzero matrix entries - type(rowtype), allocatable, dimension(:) :: row ! one rowtype for each matrix row - contains - generic :: init => initialize, initializefixed - procedure :: addconnection - procedure :: filliaja - procedure :: sort - procedure :: destroy + allocate (rowmaxnnz(nrow)) - procedure, private :: initializefixed - procedure, private :: initialize - end type sparsematrix - - contains + do i = 1, nrow + rowmaxnnz(i) = maxnnz + end do - subroutine destroy(this) - class(sparsematrix), intent(inout) :: this - deallocate(this%row) - end subroutine destroy + call this%initialize(nrow, ncol, rowmaxnnz) + deallocate (rowmaxnnz) - subroutine initialize(this,nrow,ncol,rowmaxnnz) - !initial the sparse matrix. This subroutine - !acts a method for a sparse matrix by initializing - !the row data. It presently requires one maximum - !value for all rows, however, this can be changed - !to a vector of maximum values with one value for - !each row. - ! -- dummy - class(sparsematrix), intent(inout) :: this - integer(I4B),intent(in) :: nrow,ncol - integer(I4B),intent(in),dimension(nrow) :: rowmaxnnz - ! -- local - integer(I4B) :: i - ! -- code - this%nrow = nrow - this%ncol = ncol - this%nnz = 0 - allocate(this%row(nrow)) - do i = 1, nrow - allocate(this%row(i)%icolarray(rowmaxnnz(i))) - this%row(i)%icolarray=0 - this%row(i)%nnz=0 - end do - ! - ! -- return - return - end subroutine initialize + end subroutine initializefixed - ! overload - subroutine initializefixed(this,nrow,ncol,maxnnz) - implicit none - class(sparsematrix), intent(inout) :: this - integer(I4B),intent(in) :: nrow,ncol - integer(I4B),intent(in) :: maxnnz - ! local - integer(I4B), dimension(nrow) :: rowmaxnnz - integer(I4B) :: i - - do i=1,nrow - rowmaxnnz(i) = maxnnz - enddo - - call this%initialize(nrow, ncol, rowmaxnnz) - - end subroutine initializefixed - - subroutine filliaja(this, ia, ja, ierror, sort) - !allocate and fill the ia and ja arrays using information - !from the sparsematrix. - !ierror is returned as: - ! 0 if no error - ! 1 if ia is not the correct size - ! 2 if ja is not the correct size - ! 3 if both ia and ja are not correct size - ! -- dummy - class(sparsematrix), intent(inout) :: this - integer(I4B),dimension(:),intent(inout) :: ia, ja - integer(I4B),intent(inout) :: ierror - logical, intent(in), optional :: sort - ! -- local - logical :: sortja - integer(I4B) :: i,j,ipos - ! -- code - ! - ! -- process optional dummy variables - if (present(sort)) then - sortja = sort - else - sortja = .FALSE. - end if - ! - ! -- initialize error variable - ierror = 0 - ! - ! -- check for error conditions - if (ubound(ia,dim=1) /= this%nrow+1) then - ierror = 1 - end if - if (ubound(ja,dim=1) /= this%nnz) then - ierror = ierror + 2 - end if - if (ierror/=0) then - return - end if - ! - ! -- sort this - if (sortja) then - call this%sort() - end if - ! - ! -- fill ia and ja - ipos = 1 - ia(1) = ipos - do i = 1, this%nrow - do j = 1, this%row(i)%nnz - ja(ipos) = this%row(i)%icolarray(j) - ipos = ipos + 1 - end do - ia(i+1) = ipos - end do - ! - ! -- return + subroutine filliaja(this, ia, ja, ierror, sort) + !allocate and fill the ia and ja arrays using information + !from the sparsematrix. + !ierror is returned as: + ! 0 if no error + ! 1 if ia is not the correct size + ! 2 if ja is not the correct size + ! 3 if both ia and ja are not correct size + ! -- dummy + class(sparsematrix), intent(inout) :: this + integer(I4B), dimension(:), intent(inout) :: ia, ja + integer(I4B), intent(inout) :: ierror + logical, intent(in), optional :: sort + ! -- local + logical :: sortja + integer(I4B) :: i, j, ipos + ! -- code + ! + ! -- process optional dummy variables + if (present(sort)) then + sortja = sort + else + sortja = .FALSE. + end if + ! + ! -- initialize error variable + ierror = 0 + ! + ! -- check for error conditions + if (ubound(ia, dim=1) /= this%nrow + 1) then + ierror = 1 + end if + if (ubound(ja, dim=1) /= this%nnz) then + ierror = ierror + 2 + end if + if (ierror /= 0) then return - end subroutine filliaja + end if + ! + ! -- sort this + if (sortja) then + call this%sort() + end if + ! + ! -- fill ia and ja + ipos = 1 + ia(1) = ipos + do i = 1, this%nrow + do j = 1, this%row(i)%nnz + ja(ipos) = this%row(i)%icolarray(j) + ipos = ipos + 1 + end do + ia(i + 1) = ipos + end do + ! + ! -- return + return + end subroutine filliaja - subroutine addconnection(this, i, j, inodup, iaddop) - !add a connection to the sparsematrix. if inodup - !(for no duplicates) is 1, then j is added only - !if it is unique. - ! -- dummy - class(sparsematrix), intent(inout) :: this - integer(I4B),intent(in) :: i, j, inodup - integer(I4B),optional,intent(inout) :: iaddop - ! -- local - integer(I4B) :: iadded - ! -- code - call insert(j, this%row(i), inodup, iadded) - this%nnz = this%nnz+iadded - if (present(iaddop)) iaddop = iadded - ! - ! -- return - return - end subroutine addconnection + subroutine addconnection(this, i, j, inodup, iaddop) + !add a connection to the sparsematrix. if inodup + !(for no duplicates) is 1, then j is added only + !if it is unique. + ! -- dummy + class(sparsematrix), intent(inout) :: this + integer(I4B), intent(in) :: i, j, inodup + integer(I4B), optional, intent(inout) :: iaddop + ! -- local + integer(I4B) :: iadded + ! -- code + call insert(j, this%row(i), inodup, iadded) + this%nnz = this%nnz + iadded + if (present(iaddop)) iaddop = iadded + ! + ! -- return + return + end subroutine addconnection - subroutine insert(j, thisrow, inodup, iadded) - !insert j into thisrow (for row i) - !inodup=1 means do not include duplicate connections - !iadded is 1 if a new entry was added (meaning that nnz for the row was increased) - !iadded is 0 if duplicate and not added. Used to track total number of connections - ! -- dummy - integer(I4B), intent(in) :: j, inodup - type(rowtype), intent(inout) :: thisrow - integer(I4B), allocatable,dimension(:) :: iwk - integer(I4B), intent(inout) :: iadded - ! -- local - integer(I4B) :: jj, maxnnz - ! -- code - iadded = 0 - maxnnz = ubound(thisrow%icolarray,dim=1) - if (thisrow%icolarray(1) == 0) then - thisrow%icolarray(1) = j - thisrow%nnz = thisrow%nnz + 1 - iadded = 1 - return - end if - if (thisrow%nnz == maxnnz) then - ! -- increase size of the row - allocate(iwk(thisrow%nnz)) - iwk = thisrow%icolarray - deallocate(thisrow%icolarray) - ! -- Specify how to increase the size of the icolarray. Adding 1 - ! will be most memory conservative, but may be a little slower - ! due to frequent allocate/deallocate. Another option would be - ! to double the size: maxnnz=maxnnz*2 - maxnnz = maxnnz + 1 - allocate(thisrow%icolarray(maxnnz)) - thisrow%icolarray(1:thisrow%nnz) = iwk(1:thisrow%nnz) - thisrow%icolarray(thisrow%nnz+1:maxnnz) = 0 - end if - if (inodup == 1) then - do jj = 1, thisrow%nnz - if (thisrow%icolarray(jj)==j) then - return - end if - end do - end if - ! - ! -- add the connection to end + subroutine insert(j, thisrow, inodup, iadded) + !insert j into thisrow (for row i) + !inodup=1 means do not include duplicate connections + !iadded is 1 if a new entry was added (meaning that nnz for the row was increased) + !iadded is 0 if duplicate and not added. Used to track total number of connections + ! -- dummy + integer(I4B), intent(in) :: j, inodup + type(rowtype), intent(inout) :: thisrow + integer(I4B), allocatable, dimension(:) :: iwk + integer(I4B), intent(inout) :: iadded + ! -- local + integer(I4B) :: jj, maxnnz + ! -- code + iadded = 0 + maxnnz = ubound(thisrow%icolarray, dim=1) + if (thisrow%icolarray(1) == 0) then + thisrow%icolarray(1) = j thisrow%nnz = thisrow%nnz + 1 - thisrow%icolarray(thisrow%nnz) = j iadded = 1 - ! - ! -- return return - end subroutine insert - - subroutine sort(this) - !sort the icolarray for each row, but do not include - !the diagonal position in the sort so that it stays in front - ! -- dummy - class(sparsematrix), intent(inout) :: this - ! -- local - integer(I4B) :: i, nval - ! -- code - do i = 1, this%nrow - nval = this%row(i)%nnz - call sortintarray(nval-1, & - this%row(i)%icolarray(2:nval)) + end if + if (thisrow%nnz == maxnnz) then + ! -- increase size of the row + allocate (iwk(thisrow%nnz)) + iwk = thisrow%icolarray + deallocate (thisrow%icolarray) + ! -- Specify how to increase the size of the icolarray. Adding 1 + ! will be most memory conservative, but may be a little slower + ! due to frequent allocate/deallocate. Another option would be + ! to double the size: maxnnz=maxnnz*2 + maxnnz = maxnnz + 1 + allocate (thisrow%icolarray(maxnnz)) + thisrow%icolarray(1:thisrow%nnz) = iwk(1:thisrow%nnz) + thisrow%icolarray(thisrow%nnz + 1:maxnnz) = 0 + end if + if (inodup == 1) then + do jj = 1, thisrow%nnz + if (thisrow%icolarray(jj) == j) then + return + end if end do - ! - ! -- return - return - end subroutine sort + end if + ! + ! -- add the connection to end + thisrow%nnz = thisrow%nnz + 1 + thisrow%icolarray(thisrow%nnz) = j + iadded = 1 + ! + ! -- return + return + end subroutine insert + + subroutine sort(this) + !sort the icolarray for each row, but do not include + !the diagonal position in the sort so that it stays in front + ! -- dummy + class(sparsematrix), intent(inout) :: this + ! -- local + integer(I4B) :: i, nval + ! -- code + do i = 1, this%nrow + nval = this%row(i)%nnz + call sortintarray(nval - 1, & + this%row(i)%icolarray(2:nval)) + end do + ! + ! -- return + return + end subroutine sort - subroutine sortintarray(nval,iarray) - !simple subroutine for sorting an array - !in place. It is not the fastest sort function - !but should suffice for relatively short nodelists. - ! -- dummy - integer(I4B),intent(in) :: nval - integer(I4B),intent(inout),dimension(nval) :: iarray - ! -- local - integer(I4B) :: i, j, itemp - ! -- code - do i = 1, nval-1 - do j = i+1, nval - if (iarray(i) > iarray(j)) then - itemp = iarray(j) - iarray(j) = iarray(i) - iarray(i) = itemp - end if - end do + subroutine sortintarray(nval, iarray) + !simple subroutine for sorting an array + !in place. It is not the fastest sort function + !but should suffice for relatively short nodelists. + ! -- dummy + integer(I4B), intent(in) :: nval + integer(I4B), intent(inout), dimension(nval) :: iarray + ! -- local + integer(I4B) :: i, j, itemp + ! -- code + do i = 1, nval - 1 + do j = i + 1, nval + if (iarray(i) > iarray(j)) then + itemp = iarray(j) + iarray(j) = iarray(i) + iarray(i) = itemp + end if end do - ! - ! -- return - return - end subroutine sortintarray + end do + ! + ! -- return + return + end subroutine sortintarray - subroutine csr_diagsum(ia, flowja) - !Add up the off diagonal terms and put the sum in the - !diagonal position - ! -- dummy - integer(I4B), dimension(:), contiguous :: ia - real(DP), dimension(:), contiguous :: flowja - ! -- local - integer(I4B) :: nodes - integer(I4B) :: n - integer(I4B) :: iposdiag - integer(I4B) :: ipos - ! -- code - nodes = size(ia) - 1 - do n = 1, nodes - iposdiag = ia(n) - do ipos = ia(n) + 1, ia(n + 1) - 1 - flowja(iposdiag) = flowja(iposdiag) + flowja(ipos) - end do + subroutine csr_diagsum(ia, flowja) + !Add up the off diagonal terms and put the sum in the + !diagonal position + ! -- dummy + integer(I4B), dimension(:), contiguous :: ia + real(DP), dimension(:), contiguous :: flowja + ! -- local + integer(I4B) :: nodes + integer(I4B) :: n + integer(I4B) :: iposdiag + integer(I4B) :: ipos + ! -- code + nodes = size(ia) - 1 + do n = 1, nodes + iposdiag = ia(n) + do ipos = ia(n) + 1, ia(n + 1) - 1 + flowja(iposdiag) = flowja(iposdiag) + flowja(ipos) end do - return - end subroutine csr_diagsum + end do + return + end subroutine csr_diagsum -end module SparseModule \ No newline at end of file +end module SparseModule diff --git a/src/Utilities/StringList.f90 b/src/Utilities/StringList.f90 index 1ee9cbdffe8..7d79fa69647 100644 --- a/src/Utilities/StringList.f90 +++ b/src/Utilities/StringList.f90 @@ -1,41 +1,38 @@ module StringListModule - + use KindModule, only: DP, I4B use ListModule, only: ListType + use CharacterStringModule, only: CharacterStringType private public :: AddStringToList, GetStringFromList - type :: CharacterContainerType - character(len=:), allocatable :: charstring - end type CharacterContainerType - contains - subroutine ConstructCharacterContainer (newCharCont, text) + subroutine ConstructCharacterContainer(newCharCont, text) implicit none - type(CharacterContainerType), pointer, intent(out) :: newCharCont + type(CharacterStringType), pointer, intent(out) :: newCharCont character(len=*), intent(in) :: text ! - allocate(newCharCont) - newCharCont%charstring = text + allocate (newCharCont) + newCharCont = text return end subroutine ConstructCharacterContainer - function CastAsCharacterContainerType(obj) result (res) + function CastAsCharacterStringType(obj) result(res) implicit none class(*), pointer, intent(inout) :: obj - type(CharacterContainerType), pointer :: res + type(CharacterStringType), pointer :: res ! res => null() if (.not. associated(obj)) return ! select type (obj) - type is (CharacterContainerType) + type is (CharacterStringType) res => obj end select return - end function CastAsCharacterContainerType + end function CastAsCharacterStringType subroutine AddStringToList(list, string) implicit none @@ -44,19 +41,19 @@ subroutine AddStringToList(list, string) character(len=*), intent(in) :: string ! -- local class(*), pointer :: obj - type(CharacterContainerType), pointer :: newCharacterContainer + type(CharacterStringType), pointer :: newCharacterContainer ! newCharacterContainer => null() call ConstructCharacterContainer(newCharacterContainer, string) if (associated(newCharacterContainer)) then obj => newCharacterContainer call list%Add(obj) - endif + end if ! return end subroutine AddStringToList - - function GetStringFromList(list, indx) result (string) + + function GetStringFromList(list, indx) result(string) implicit none ! -- dummy type(ListType), intent(inout) :: list @@ -64,14 +61,16 @@ function GetStringFromList(list, indx) result (string) character(len=:), allocatable :: string ! -- local class(*), pointer :: obj - type(CharacterContainerType), pointer :: charcont + type(CharacterStringType), pointer :: charcont ! - string = '' obj => list%GetItem(indx) - charcont => CastAsCharacterContainerType(obj) + charcont => CastAsCharacterStringType(obj) if (associated(charcont)) then - string = charcont%charstring - endif + allocate (character(len=charcont%strlen()) :: string) + string(:) = charcont + else + string = '' + end if ! return end function GetStringFromList diff --git a/src/Utilities/Table.f90 b/src/Utilities/Table.f90 index 7d46f215712..b7e119621eb 100644 --- a/src/Utilities/Table.f90 +++ b/src/Utilities/Table.f90 @@ -1,22 +1,22 @@ -! Comprehensive table object that stores all of the -! intercell flows, and the inflows and the outflows for +! Comprehensive table object that stores all of the +! intercell flows, and the inflows and the outflows for ! an advanced package. module TableModule - + use KindModule, only: I4B, I8B, DP - use ConstantsModule, only: LINELENGTH, LENBUDTXT, & - TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & + use ConstantsModule, only: LINELENGTH, LENBUDTXT, & + TABSTRING, TABUCSTRING, TABINTEGER, TABREAL, & TABCENTER use TableTermModule, only: TableTermType use InputOutputModule, only: UWWORD, parseline use SimModule, only: store_error use SimVariablesModule, only: errmsg - + implicit none - + public :: TableType public :: table_cr - + type :: TableType ! ! -- name, number of control volumes, and number of table terms @@ -45,18 +45,18 @@ module TableModule ! ! -- table table object, for writing the typical MODFLOW table type(TableType), pointer :: table => null() - + character(len=LINELENGTH), pointer :: linesep => null() character(len=LINELENGTH), pointer :: dataline => null() character(len=LINELENGTH), dimension(:), pointer :: header => null() - - contains - + + contains + procedure :: table_df procedure :: table_da procedure :: initialize_column procedure :: line_to_columns - procedure :: finalize_table + procedure :: finalize_table procedure :: set_maxbound procedure :: set_kstpkper procedure :: set_title @@ -65,20 +65,20 @@ module TableModule procedure :: print_separator procedure, private :: allocate_strings - procedure, private :: set_header - procedure, private :: write_header - procedure, private :: write_line + procedure, private :: set_header + procedure, private :: write_header + procedure, private :: write_line procedure, private :: finalize procedure, private :: add_error procedure, private :: reset - - generic, public :: add_term => add_integer, add_long_integer, & - add_real, add_string - procedure, private :: add_integer, add_long_integer, add_real, add_string + + generic, public :: add_term => add_integer, add_long_integer, & + add_real, add_string + procedure, private :: add_integer, add_long_integer, add_real, add_string end type TableType - - contains + +contains subroutine table_cr(this, name, title) ! ****************************************************************************** @@ -98,12 +98,12 @@ subroutine table_cr(this, name, title) ! -- check if table already associated and reset if necessary if (associated(this)) then call this%table_da() - deallocate(this) - nullify(this) + deallocate (this) + nullify (this) end if ! ! -- Create the object - allocate(this) + allocate (this) ! ! -- initialize variables this%name = name @@ -113,7 +113,7 @@ subroutine table_cr(this, name, title) return end subroutine table_cr - subroutine table_df(this, maxbound, ntableterm, iout, transient, & + subroutine table_df(this, maxbound, ntableterm, iout, transient, & lineseparator, separator, finalize) ! ****************************************************************************** ! table_df -- Define the new table object @@ -134,29 +134,29 @@ subroutine table_df(this, maxbound, ntableterm, iout, transient, & ! ------------------------------------------------------------------------------ ! ! -- allocate scalars - allocate(this%sep) - allocate(this%write_csv) - allocate(this%first_entry) - allocate(this%transient) - allocate(this%add_linesep) - allocate(this%allow_finalization) - allocate(this%iout) - allocate(this%maxbound) - allocate(this%nheaderlines) - allocate(this%nlinewidth) - allocate(this%ntableterm) - allocate(this%ientry) - allocate(this%iloc) - allocate(this%icount) + allocate (this%sep) + allocate (this%write_csv) + allocate (this%first_entry) + allocate (this%transient) + allocate (this%add_linesep) + allocate (this%allow_finalization) + allocate (this%iout) + allocate (this%maxbound) + allocate (this%nheaderlines) + allocate (this%nlinewidth) + allocate (this%ntableterm) + allocate (this%ientry) + allocate (this%iloc) + allocate (this%icount) ! ! -- allocate space for tableterm - allocate(this%tableterm(ntableterm)) + allocate (this%tableterm(ntableterm)) ! ! -- initialize values based on optional dummy variables if (present(transient)) then this%transient = transient - allocate(this%kstp) - allocate(this%kper) + allocate (this%kstp) + allocate (this%kper) else this%transient = .FALSE. end if @@ -193,7 +193,7 @@ subroutine table_df(this, maxbound, ntableterm, iout, transient, & ! -- return return end subroutine table_df - + subroutine initialize_column(this, text, width, alignment) ! ****************************************************************************** ! initialize_column -- Initialize data for a column @@ -225,16 +225,16 @@ subroutine initialize_column(this, text, width, alignment) ! ! -- check that ientry is in bounds if (this%ientry > this%ntableterm) then - write(errmsg,'(a,a,a,i0,a,1x,a,1x,a,a,a,1x,i0,1x,a)') & - 'Trying to add column "', trim(adjustl(text)), '" (', & - this%ientry, ') in the', trim(adjustl(this%name)), 'table ("', & - trim(adjustl(this%title)), '") that only has', this%ntableterm, & + write (errmsg, '(a,a,a,i0,a,1x,a,1x,a,a,a,1x,i0,1x,a)') & + 'Trying to add column "', trim(adjustl(text)), '" (', & + this%ientry, ') in the', trim(adjustl(this%name)), 'table ("', & + trim(adjustl(this%title)), '") that only has', this%ntableterm, & 'columns.' call store_error(errmsg, terminate=.TRUE.) end if ! ! -- initialize table term - call this%tableterm(idx)%initialize(text, width, alignment=ialign) + call this%tableterm(idx)%initialize(text, width, alignment=ialign) ! ! -- create header when all terms have been specified if (this%ientry == this%ntableterm) then @@ -247,7 +247,7 @@ subroutine initialize_column(this, text, width, alignment) ! -- return return end subroutine initialize_column - + subroutine set_header(this) ! ****************************************************************************** ! set_header -- Set the table object header @@ -306,19 +306,19 @@ subroutine set_header(this) alignment = this%tableterm(j)%get_alignment() call this%tableterm(j)%get_header(n, cval) if (this%write_csv) then - if ( j == 1) then - write(this%header(nn), '(a)') trim(adjustl(cval)) + if (j == 1) then + write (this%header(nn), '(a)') trim(adjustl(cval)) else - write(this%header(nn), '(a,",",G0)') & + write (this%header(nn), '(a,",",G0)') & trim(this%header(nn)), trim(adjustl(cval)) end if else if (j == this%ntableterm) then - call UWWORD(this%header(nn), iloc, width, TABUCSTRING, & - cval(1:width), ival, rval, ALIGNMENT=alignment) + call UWWORD(this%header(nn), iloc, width, TABUCSTRING, & + cval(1:width), ival, rval, ALIGNMENT=alignment) else - call UWWORD(this%header(nn), iloc, width, TABUCSTRING, & - cval(1:width), ival, rval, ALIGNMENT=alignment, & + call UWWORD(this%header(nn), iloc, width, TABUCSTRING, & + cval(1:width), ival, rval, ALIGNMENT=alignment, & SEP=this%sep) end if end if @@ -328,7 +328,7 @@ subroutine set_header(this) ! -- return return end subroutine set_header - + subroutine allocate_strings(this, width, nlines) ! ****************************************************************************** ! allocate_strings -- Allocate allocatable character arrays @@ -359,9 +359,9 @@ subroutine allocate_strings(this, width, nlines) this%nlinewidth = width ! ! -- allocate deferred length strings - allocate(this%header(this%nheaderlines)) - allocate(this%linesep) - allocate(this%dataline) + allocate (this%header(this%nheaderlines)) + allocate (this%linesep) + allocate (this%dataline) ! ! -- initialize lines this%linesep = linesep(1:width) @@ -374,12 +374,12 @@ subroutine allocate_strings(this, width, nlines) ! linesep if (this%add_linesep) then this%header(1) = linesep(1:width) - this%header(nlines+2) = linesep(1:width) + this%header(nlines + 2) = linesep(1:width) end if ! ! -- return return - end subroutine allocate_strings + end subroutine allocate_strings subroutine write_header(this) ! ****************************************************************************** @@ -405,16 +405,16 @@ subroutine write_header(this) ! -- write title title = this%title if (this%transient) then - write(title, '(a,a,i6)') trim(adjustl(title)), ' PERIOD ', this%kper - write(title, '(a,a,i8)') trim(adjustl(title)), ' STEP ', this%kstp + write (title, '(a,a,i6)') trim(adjustl(title)), ' PERIOD ', this%kper + write (title, '(a,a,i8)') trim(adjustl(title)), ' STEP ', this%kstp end if if (len_trim(title) > 0) then - write(this%iout, '(/,1x,a)') trim(adjustl(title)) + write (this%iout, '(/,1x,a)') trim(adjustl(title)) end if ! ! -- write header do n = 1, this%nheaderlines - write(this%iout, '(1x,a)') this%header(n)(1:width) + write (this%iout, '(1x,a)') this%header(n) (1:width) end do end if ! @@ -426,7 +426,7 @@ subroutine write_header(this) ! -- return return end subroutine write_header - + subroutine write_line(this) ! ****************************************************************************** ! write_line -- Write the data line @@ -445,7 +445,7 @@ subroutine write_line(this) width = this%nlinewidth ! ! -- write the dataline - write(this%iout, '(1x,a)') this%dataline(1:width) + write (this%iout, '(1x,a)') this%dataline(1:width) ! ! -- update column and line counters this%ientry = 0 @@ -455,11 +455,11 @@ subroutine write_line(this) ! -- return return end subroutine write_line - + subroutine finalize(this) ! ****************************************************************************** ! finalize -- Private method that test for last line. If last line the -! public finalize_table method is called +! public finalize_table method is called ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -478,7 +478,7 @@ subroutine finalize(this) ! -- return return end subroutine finalize - + subroutine finalize_table(this) ! ****************************************************************************** ! finalize -- Public method to finalize the table @@ -496,14 +496,14 @@ subroutine finalize_table(this) call this%print_separator(iextralines=1) ! ! -- flush file - flush(this%iout) + flush (this%iout) ! ! -- reinitialize variables call this%reset() ! ! -- return return - end subroutine finalize_table + end subroutine finalize_table subroutine table_da(this) ! ****************************************************************************** @@ -525,37 +525,37 @@ subroutine table_da(this) end do ! ! -- deallocate space for tableterm - deallocate(this%tableterm) + deallocate (this%tableterm) ! ! -- deallocate character scalars and arrays - deallocate(this%linesep) - deallocate(this%dataline) - deallocate(this%header) + deallocate (this%linesep) + deallocate (this%dataline) + deallocate (this%header) ! ! -- deallocate scalars if (this%transient) then - deallocate(this%kstp) - deallocate(this%kper) + deallocate (this%kstp) + deallocate (this%kper) end if - deallocate(this%sep) - deallocate(this%write_csv) - deallocate(this%first_entry) - deallocate(this%transient) - deallocate(this%add_linesep) - deallocate(this%allow_finalization) - deallocate(this%iout) - deallocate(this%maxbound) - deallocate(this%nheaderlines) - deallocate(this%nlinewidth) - deallocate(this%ntableterm) - deallocate(this%ientry) - deallocate(this%iloc) - deallocate(this%icount) + deallocate (this%sep) + deallocate (this%write_csv) + deallocate (this%first_entry) + deallocate (this%transient) + deallocate (this%add_linesep) + deallocate (this%allow_finalization) + deallocate (this%iout) + deallocate (this%maxbound) + deallocate (this%nheaderlines) + deallocate (this%nlinewidth) + deallocate (this%ntableterm) + deallocate (this%ientry) + deallocate (this%iloc) + deallocate (this%icount) ! ! -- Return return end subroutine table_da - + subroutine line_to_columns(this, line) ! ****************************************************************************** ! line_to_columns -- convert a line to the correct number of columns @@ -599,12 +599,12 @@ subroutine line_to_columns(this, line) end do ! ! -- clean up local allocatable array - deallocate(words) + deallocate (words) ! ! -- Return return - end subroutine line_to_columns - + end subroutine line_to_columns + subroutine add_error(this) ! ****************************************************************************** ! add_error -- evaluate if error condition occurs when adding data to dataline @@ -620,9 +620,9 @@ subroutine add_error(this) ! ! -- check that ientry is within bounds if (this%ientry > this%ntableterm) then - write(errmsg,'(a,1x,i0,5(1x,a),1x,i0,1x,a)') & - 'Trying to add data to column ', this%ientry, 'in the', & - trim(adjustl(this%name)), 'table (', trim(adjustl(this%title)), & + write (errmsg, '(a,1x,i0,5(1x,a),1x,i0,1x,a)') & + 'Trying to add data to column ', this%ientry, 'in the', & + trim(adjustl(this%name)), 'table (', trim(adjustl(this%title)), & ') that only has', this%ntableterm, 'columns.' call store_error(errmsg, terminate=.TRUE.) end if @@ -630,7 +630,7 @@ subroutine add_error(this) ! -- Return return end subroutine add_error - + subroutine add_integer(this, ival) ! ****************************************************************************** ! add_integer -- add integer value to the dataline @@ -674,16 +674,16 @@ subroutine add_integer(this, ival) ! -- add data to line if (this%write_csv) then if (j == 1) then - write(this%dataline, '(G0)') ival + write (this%dataline, '(G0)') ival else - write(this%dataline, '(a,",",G0)') trim(this%dataline), ival + write (this%dataline, '(a,",",G0)') trim(this%dataline), ival end if else if (j == this%ntableterm) then - call UWWORD(this%dataline, this%iloc, width, TABINTEGER, & + call UWWORD(this%dataline, this%iloc, width, TABINTEGER, & cval, ival, rval, ALIGNMENT=alignment) else - call UWWORD(this%dataline, this%iloc, width, TABINTEGER, & + call UWWORD(this%dataline, this%iloc, width, TABINTEGER, & cval, ival, rval, ALIGNMENT=alignment, SEP=this%sep) end if end if @@ -701,7 +701,7 @@ subroutine add_integer(this, ival) ! -- Return return end subroutine add_integer - + subroutine add_long_integer(this, long_ival) ! ****************************************************************************** ! add_long_integer -- add long integer value to the dataline @@ -746,17 +746,17 @@ subroutine add_long_integer(this, long_ival) ! -- add data to line if (this%write_csv) then if (j == 1) then - write(this%dataline, '(G0)') long_ival + write (this%dataline, '(G0)') long_ival else - write(this%dataline, '(a,",",G0)') trim(this%dataline), long_ival + write (this%dataline, '(a,",",G0)') trim(this%dataline), long_ival end if else - write(cval, '(i0)') long_ival + write (cval, '(i0)') long_ival if (j == this%ntableterm) then - call UWWORD(this%dataline, this%iloc, width, TABSTRING, & + call UWWORD(this%dataline, this%iloc, width, TABSTRING, & trim(cval), ival, rval, ALIGNMENT=alignment) else - call UWWORD(this%dataline, this%iloc, width, TABSTRING, & + call UWWORD(this%dataline, this%iloc, width, TABSTRING, & trim(cval), ival, rval, ALIGNMENT=alignment, SEP=this%sep) end if end if @@ -818,16 +818,16 @@ subroutine add_real(this, rval) ! -- add data to line if (this%write_csv) then if (j == 1) then - write(this%dataline, '(G0)') rval + write (this%dataline, '(G0)') rval else - write(this%dataline, '(a,",",G0)') trim(this%dataline), rval + write (this%dataline, '(a,",",G0)') trim(this%dataline), rval end if else if (j == this%ntableterm) then - call UWWORD(this%dataline, this%iloc, width, TABREAL, & + call UWWORD(this%dataline, this%iloc, width, TABREAL, & cval, ival, rval, ALIGNMENT=alignment) else - call UWWORD(this%dataline, this%iloc, width, TABREAL, & + call UWWORD(this%dataline, this%iloc, width, TABREAL, & cval, ival, rval, ALIGNMENT=alignment, SEP=this%sep) end if end if @@ -845,7 +845,7 @@ subroutine add_real(this, rval) ! -- Return return end subroutine add_real - + subroutine add_string(this, cval) ! ****************************************************************************** ! add_string -- add string value to the dataline @@ -889,17 +889,17 @@ subroutine add_string(this, cval) ! -- add data to line if (this%write_csv) then if (j == 1) then - write(this%dataline, '(a)') trim(adjustl(cval)) + write (this%dataline, '(a)') trim(adjustl(cval)) else - write(this%dataline, '(a,",",a)') & + write (this%dataline, '(a,",",a)') & trim(this%dataline), trim(adjustl(cval)) end if else if (j == this%ntableterm) then - call UWWORD(this%dataline, this%iloc, width, TABSTRING, & + call UWWORD(this%dataline, this%iloc, width, TABSTRING, & cval, ival, rval, ALIGNMENT=alignment) else - call UWWORD(this%dataline, this%iloc, width, TABSTRING, & + call UWWORD(this%dataline, this%iloc, width, TABSTRING, & cval, ival, rval, ALIGNMENT=alignment, SEP=this%sep) end if end if @@ -917,7 +917,7 @@ subroutine add_string(this, cval) ! -- Return return end subroutine add_string - + subroutine set_maxbound(this, maxbound) ! ****************************************************************************** ! set_maxbound -- reset maxbound @@ -940,8 +940,8 @@ subroutine set_maxbound(this, maxbound) ! ! -- return return - end subroutine set_maxbound - + end subroutine set_maxbound + subroutine set_kstpkper(this, kstp, kper) ! ****************************************************************************** ! set_kstpkper -- reset kstp and kper @@ -963,8 +963,8 @@ subroutine set_kstpkper(this, kstp, kper) ! ! -- return return - end subroutine set_kstpkper - + end subroutine set_kstpkper + subroutine set_title(this, title) ! ****************************************************************************** ! set_maxbound -- reset maxbound @@ -985,7 +985,7 @@ subroutine set_title(this, title) ! -- return return end subroutine set_title - + subroutine set_iout(this, iout) ! ****************************************************************************** ! set_iout -- reset iout @@ -1005,8 +1005,8 @@ subroutine set_iout(this, iout) ! ! -- return return - end subroutine set_iout - + end subroutine set_iout + subroutine print_list_entry(this, i, nodestr, q, bname) ! ****************************************************************************** ! print_list_entry -- write flow term table values @@ -1034,8 +1034,8 @@ subroutine print_list_entry(this, i, nodestr, q, bname) ! ! -- return return - end subroutine print_list_entry - + end subroutine print_list_entry + subroutine print_separator(this, iextralines) ! ****************************************************************************** ! print_separator -- print a line separator to the table @@ -1065,16 +1065,16 @@ subroutine print_separator(this, iextralines) ! ! -- print line separator if (this%add_linesep) then - write(this%iout, '(1x,a)') this%linesep(1:width) + write (this%iout, '(1x,a)') this%linesep(1:width) do i = 1, iextra - write(this%iout, '(/)') + write (this%iout, '(/)') end do end if ! ! -- return return end subroutine print_separator - + subroutine reset(this) ! ****************************************************************************** ! reset -- Private method to reset table counters @@ -1095,6 +1095,6 @@ subroutine reset(this) ! ! -- return return - end subroutine reset + end subroutine reset end module TableModule diff --git a/src/Utilities/TableTerm.f90 b/src/Utilities/TableTerm.f90 index f00d1cc7cd1..f7e5e3c9cc8 100644 --- a/src/Utilities/TableTerm.f90 +++ b/src/Utilities/TableTerm.f90 @@ -1,31 +1,30 @@ ! A table term is the information needed to describe flow. -! The table object contains an array of table terms. -! For an advanced package. The table object describes all of +! The table object contains an array of table terms. +! For an advanced package. The table object describes all of ! the flows. module TableTermModule use KindModule, only: I4B, DP - use ConstantsModule, only: LINELENGTH, LENBUDTXT, DZERO, & - TABLEFT, TABCENTER, TABRIGHT, & - TABSTRING, TABUCSTRING, TABINTEGER, TABREAL + use ConstantsModule, only: LINELENGTH, LENBUDTXT, DZERO, & + TABLEFT, TABCENTER, TABRIGHT, & + TABSTRING, TABUCSTRING, TABINTEGER, TABREAL use InputOutputModule, only: UPCASE, parseline implicit none public :: TableTermType - - + type :: TableTermType character(len=LINELENGTH), pointer :: tag => null() integer(I4B), pointer :: width => null() integer(I4B), pointer :: alignment => null() integer(I4B), pointer :: nheader_lines => null() - + character(len=LINELENGTH), dimension(:), pointer :: initial_lines => null() character(len=LINELENGTH), dimension(:), pointer :: header_lines => null() - + contains - + procedure :: initialize procedure, private :: allocate_scalars procedure :: get_width @@ -34,12 +33,11 @@ module TableTermModule procedure :: set_header procedure :: get_header procedure :: da - - + end type TableTermType - contains - +contains + subroutine initialize(this, tag, width, alignment) ! ****************************************************************************** ! initialize -- initialize the table term @@ -66,16 +64,16 @@ subroutine initialize(this, tag, width, alignment) ! ! -- allocate scalars call this%allocate_scalars() - + ! -- process dummy variables this%tag = tag - + if (present(alignment)) then this%alignment = alignment else this%alignment = TABCENTER end if - + this%width = width ! ! -- parse tag into words @@ -86,16 +84,16 @@ subroutine initialize(this, tag, width, alignment) do i = 1, nwords ilen = len(trim(words(i))) if (ilen > width) then - words(i)(width:width) = '.' + words(i) (width:width) = '.' do j = width + 1, ilen - words(i)(j:j) = ' ' + words(i) (j:j) = ' ' end do end if end do ! ! -- combine words that fit into width i = 0 - do + do i = i + 1 if (i > nwords) then exit @@ -104,7 +102,7 @@ subroutine initialize(this, tag, width, alignment) tstring = string do j = i + 1, nwords if (len(trim(adjustl(string))) > 0) then - tstring = trim(adjustl(tstring)) // ' ' // trim(adjustl(words(j))) + tstring = trim(adjustl(tstring))//' '//trim(adjustl(words(j))) else tstring = trim(adjustl(words(j))) end if @@ -130,22 +128,22 @@ subroutine initialize(this, tag, width, alignment) end do ! ! allocate initial_lines and fill with words - allocate(this%initial_lines(this%nheader_lines)) - do i = 1, this%nheader_lines - this%initial_lines(i) = words(i)(1:width) + allocate (this%initial_lines(this%nheader_lines)) + do i = 1, this%nheader_lines + this%initial_lines(i) = words(i) (1:width) end do ! ! -- deallocate words - deallocate(words) + deallocate (words) ! ! -- return return end subroutine initialize - + function get_width(this) ! ****************************************************************************** -! get_width -- get column width +! get_width -- get column width ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -162,10 +160,10 @@ function get_width(this) ! -- return return end function get_width - + function get_alignment(this) ! ****************************************************************************** -! get_width -- get column width +! get_width -- get column width ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -181,8 +179,8 @@ function get_alignment(this) ! ! -- return return - end function get_alignment - + end function get_alignment + function get_header_lines(this) ! ****************************************************************************** ! get_header_lines -- get the number of lines in initial_lines @@ -202,7 +200,7 @@ function get_header_lines(this) ! -- return return end function get_header_lines - + subroutine allocate_scalars(this) ! ****************************************************************************** ! allocate_scalars -- allocate table term scalars @@ -216,10 +214,10 @@ subroutine allocate_scalars(this) ! ------------------------------------------------------------------------------ ! ! -- allocate scalars - allocate(this%tag) - allocate(this%alignment) - allocate(this%width) - allocate(this%nheader_lines) + allocate (this%tag) + allocate (this%alignment) + allocate (this%width) + allocate (this%nheader_lines) ! ! -- initialize scalars this%nheader_lines = 0 @@ -227,7 +225,7 @@ subroutine allocate_scalars(this) ! -- return return end subroutine allocate_scalars - + subroutine da(this) ! ****************************************************************************** ! da -- deallocate table terms @@ -242,16 +240,16 @@ subroutine da(this) !integer(I4B) :: n ! ------------------------------------------------------------------------------ ! - ! -- deallocate scalars - deallocate(this%tag) - deallocate(this%alignment) - deallocate(this%width) - deallocate(this%nheader_lines) - deallocate(this%header_lines) + ! -- deallocate scalars + deallocate (this%tag) + deallocate (this%alignment) + deallocate (this%width) + deallocate (this%nheader_lines) + deallocate (this%header_lines) ! ! -- return end subroutine da - + subroutine set_header(this, nlines) ! ****************************************************************************** ! set_header -- set final header lines for table term @@ -274,8 +272,8 @@ subroutine set_header(this, nlines) ! -- initialize variables string = ' ' ! - ! allocate header_lines - allocate(this%header_lines(nlines)) + ! allocate header_lines + allocate (this%header_lines(nlines)) ! ! -- initialize header lines do i = 1, nlines @@ -286,20 +284,20 @@ subroutine set_header(this, nlines) ! bottom to top idiff = nlines - this%nheader_lines i0 = 1 - idiff - do i = this%nheader_lines, 1, -1 + do i = this%nheader_lines, 1, -1 j = i + idiff this%header_lines(j) = this%initial_lines(i) end do ! ! -- deallocate temporary header lines - deallocate(this%initial_lines) + deallocate (this%initial_lines) ! ! -- reinitialize nheader_lines this%nheader_lines = nlines ! ! -- return end subroutine set_header - + subroutine get_header(this, iline, cval) ! ****************************************************************************** ! get_header -- get header entry for table term iline @@ -317,9 +315,9 @@ subroutine get_header(this, iline, cval) ! ------------------------------------------------------------------------------ ! ! -- set return value - cval = this%header_lines(iline)(1:this%width) + cval = this%header_lines(iline) (1:this%width) ! ! -- return - end subroutine get_header - -end module TableTermModule \ No newline at end of file + end subroutine get_header + +end module TableTermModule diff --git a/src/Utilities/TimeSeries/TimeArray.f90 b/src/Utilities/TimeSeries/TimeArray.f90 index 15da0224f6e..49b7ee99e4c 100644 --- a/src/Utilities/TimeSeries/TimeArray.f90 +++ b/src/Utilities/TimeSeries/TimeArray.f90 @@ -1,10 +1,10 @@ module TimeArrayModule - use BaseDisModule, only: DisBaseType - use KindModule, only: DP, I4B - use ListModule, only: ListType + use BaseDisModule, only: DisBaseType + use KindModule, only: DP, I4B + use ListModule, only: ListType use SimVariablesModule, only: errmsg - use SimModule, only: store_error + use SimModule, only: store_error implicit none private @@ -37,7 +37,7 @@ subroutine ConstructTimeArray(newTa, dis) ! ------------------------------------------------------------------------------ ! -- dummy type(TimeArrayType), pointer, intent(out) :: newTa - class(DisBaseType), pointer, intent(in) :: dis + class(DisBaseType), pointer, intent(in) :: dis ! -- local integer(I4B) :: isize ! ------------------------------------------------------------------------------ @@ -48,9 +48,9 @@ subroutine ConstructTimeArray(newTa, dis) else errmsg = 'Time array series is not supported for discretization type' call store_error(errmsg, terminate=.TRUE.) - endif - allocate(newTa) - allocate(newTa%taArray(isize)) + end if + allocate (newTa) + allocate (newTa%taArray(isize)) return end subroutine ConstructTimeArray @@ -84,7 +84,7 @@ subroutine AddTimeArrayToList(list, timearray) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(TimeArrayType), pointer, intent(inout) :: timearray ! -- local class(*), pointer :: obj @@ -96,7 +96,7 @@ subroutine AddTimeArrayToList(list, timearray) return end subroutine AddTimeArrayToList - function GetTimeArrayFromList(list, indx) result (res) + function GetTimeArrayFromList(list, indx) result(res) ! ****************************************************************************** ! GetTimeArrayFromList -- get ta from list ! ****************************************************************************** @@ -105,8 +105,8 @@ function GetTimeArrayFromList(list, indx) result (res) ! ------------------------------------------------------------------------------ ! -- dummy type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: indx - type(TimeArrayType), pointer :: res + integer(I4B), intent(in) :: indx + type(TimeArrayType), pointer :: res ! -- local class(*), pointer :: obj ! ------------------------------------------------------------------------------ @@ -128,7 +128,7 @@ subroutine ta_da(this) class(TimeArrayType) :: this ! ------------------------------------------------------------------------------ ! - deallocate(this%taArray) + deallocate (this%taArray) this%taArray => null() ! return diff --git a/src/Utilities/TimeSeries/TimeArraySeries.f90 b/src/Utilities/TimeSeries/TimeArraySeries.f90 index 2aa13b54f4a..34119ffa65a 100644 --- a/src/Utilities/TimeSeries/TimeArraySeries.f90 +++ b/src/Utilities/TimeSeries/TimeArraySeries.f90 @@ -1,25 +1,25 @@ module TimeArraySeriesModule use ArrayReadersModule, only: ReadArray - use BlockParserModule, only: BlockParserType - use ConstantsModule, only: LINELENGTH, UNDEFINED, STEPWISE, LINEAR, & - LENTIMESERIESNAME, DZERO, DONE - use GenericUtilitiesModule, only: is_same - use InputOutputModule, only: GetUnit, openfile - use KindModule, only: DP, I4B - use ListModule, only: ListType, ListNodeType + use BlockParserModule, only: BlockParserType + use ConstantsModule, only: LINELENGTH, UNDEFINED, STEPWISE, LINEAR, & + LENTIMESERIESNAME, DZERO, DONE + use GenericUtilitiesModule, only: is_same + use InputOutputModule, only: GetUnit, openfile + use KindModule, only: DP, I4B + use ListModule, only: ListType, ListNodeType use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error, store_error_unit - use TimeArrayModule, only: TimeArrayType, ConstructTimeArray, & - AddTimeArrayToList, CastAsTimeArrayType, & - GetTimeArrayFromList - use BaseDisModule, only: DisBaseType + use SimModule, only: count_errors, store_error, store_error_unit + use TimeArrayModule, only: TimeArrayType, ConstructTimeArray, & + AddTimeArrayToList, CastAsTimeArrayType, & + GetTimeArrayFromList + use BaseDisModule, only: DisBaseType use, intrinsic :: iso_fortran_env, only: IOSTAT_END implicit none private - public :: TimeArraySeriesType, ConstructTimeArraySeries, & - CastAsTimeArraySeriesType, GetTimeArraySeriesFromList + public :: TimeArraySeriesType, ConstructTimeArraySeries, & + CastAsTimeArraySeriesType, GetTimeArraySeriesFromList type TimeArraySeriesType ! -- Public members @@ -67,18 +67,18 @@ subroutine ConstructTimeArraySeries(newTas, filename) logical :: lex ! ------------------------------------------------------------------------------ ! formats - 10 format('Error: Time-array-series file "',a,'" does not exist.') +10 format('Error: Time-array-series file "', a, '" does not exist.') ! ! -- Allocate a new object of type TimeArraySeriesType - allocate(newTas) - allocate(newTas%list) + allocate (newTas) + allocate (newTas%list) ! ! -- Ensure that input file exists - inquire(file=filename,exist=lex) + inquire (file=filename, exist=lex) if (.not. lex) then - write(errmsg,10)trim(filename) + write (errmsg, 10) trim(filename) call store_error(errmsg, terminate=.TRUE.) - endif + end if newTas%datafile = filename ! return @@ -99,7 +99,7 @@ subroutine tas_init(this, fname, dis, iout, tasname, autoDeallocate) class(DisBaseType), pointer, intent(inout) :: dis integer(I4B), intent(in) :: iout character(len=*), intent(inout) :: tasname - logical, optional, intent(in) :: autoDeallocate + logical, optional, intent(in) :: autoDeallocate ! -- local integer(I4B) :: istatus integer(I4B) :: ierr @@ -111,7 +111,7 @@ subroutine tas_init(this, fname, dis, iout, tasname, autoDeallocate) ! -- initialize some variables if (present(autoDeallocate)) this%autoDeallocate = autoDeallocate this%dataFile = fname - allocate(this%list) + allocate (this%list) ! ! -- assign members this%dis => dis @@ -131,13 +131,13 @@ subroutine tas_init(this, fname, dis, iout, tasname, autoDeallocate) ! ! -- get BEGIN line of ATTRIBUTES block call this%parser%GetBlock('ATTRIBUTES', found, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) if (.not. found) then - errmsg = 'Error: Attributes block not found in file: ' // & - trim(fname) + errmsg = 'Error: Attributes block not found in file: '// & + trim(fname) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- parse ATTRIBUTES entries do @@ -161,64 +161,64 @@ subroutine tas_init(this, fname, dis, iout, tasname, autoDeallocate) case ('LINEAR') this%iMethod = LINEAR case default - errmsg = 'Unknown interpolation method: "' // trim(keyvalue) // '"' + errmsg = 'Unknown interpolation method: "'//trim(keyvalue)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() end select case ('AUTODEALLOCATE') this%autoDeallocate = (keyvalue == 'TRUE') case ('SFAC') - read(keyvalue,*,iostat=istatus)this%sfac + read (keyvalue, *, iostat=istatus) this%sfac if (istatus /= 0) then - errmsg = 'Error reading numeric SFAC value from "' // trim(keyvalue) & - // '"' + errmsg = 'Error reading numeric SFAC value from "'//trim(keyvalue) & + //'"' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if case default - errmsg = 'Unknown option found in ATTRIBUTES block: "' // & - trim(keyword) // '"' + errmsg = 'Unknown option found in ATTRIBUTES block: "'// & + trim(keyword)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() end select - enddo + end do ! ! -- ensure that NAME and METHOD have been specified if (this%Name == '') then - errmsg = 'Name not specified for time array series in file: ' // & + errmsg = 'Name not specified for time array series in file: '// & trim(this%dataFile) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if if (this%iMethod == UNDEFINED) then - errmsg = 'Interpolation method not specified for time' // & - ' array series in file: ' // trim(this%dataFile) + errmsg = 'Interpolation method not specified for time'// & + ' array series in file: '//trim(this%dataFile) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- handle any errors encountered so far - if (count_errors()>0) then - errmsg = 'Error(s) encountered initializing time array series from file: ' // & - trim(this%dataFile) + if (count_errors() > 0) then + errmsg = 'Error(s) encountered initializing time array series from file: ' & + //trim(this%dataFile) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- try to read first time array into linked list if (.not. this%read_next_array()) then - errmsg = 'Error encountered reading time-array data from file: ' // & + errmsg = 'Error encountered reading time-array data from file: '// & trim(this%dataFile) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! return end subroutine tas_init subroutine GetAverageValues(this, nvals, values, time0, time1) ! ****************************************************************************** -! GetAverageValues -- populate an array time-weighted average value for a +! GetAverageValues -- populate an array time-weighted average value for a ! specified time span. ! ****************************************************************************** ! @@ -226,10 +226,10 @@ subroutine GetAverageValues(this, nvals, values, time0, time1) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeArraySeriesType), intent(inout) :: this - integer(I4B), intent(in) :: nvals + integer(I4B), intent(in) :: nvals real(DP), dimension(nvals), intent(inout) :: values - real(DP), intent(in) :: time0 - real(DP), intent(in) :: time1 + real(DP), intent(in) :: time0 + real(DP), intent(in) :: time1 ! -- local integer(I4B) :: i real(DP) :: timediff @@ -238,13 +238,13 @@ subroutine GetAverageValues(this, nvals, values, time0, time1) timediff = time1 - time0 if (timediff > 0) then call this%get_integrated_values(nvals, values, time0, time1) - do i=1,nvals + do i = 1, nvals values(i) = values(i) / timediff - enddo + end do else ! -- time0 and time1 are the same, so skip the integration step. call this%get_values_at_time(nvals, values, time0) - endif + end if ! return end subroutine GetAverageValues @@ -278,7 +278,7 @@ subroutine get_surrounding_records(this, time, taEarlier, taLater) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeArraySeriesType), intent(inout) :: this - real(DP), intent(in) :: time + real(DP), intent(in) :: time type(TimeArrayType), pointer, intent(inout) :: taEarlier type(TimeArrayType), pointer, intent(inout) :: taLater ! -- local @@ -295,7 +295,7 @@ subroutine get_surrounding_records(this, time, taEarlier, taLater) ! if (associated(this%list%firstNode)) then currNode => this%list%firstNode - endif + end if ! ! -- If the next node is earlier than time of interest, advance along ! linked list until the next node is later than time of interest. @@ -308,15 +308,15 @@ subroutine get_surrounding_records(this, time, taEarlier, taLater) currNode => currNode%nextNode else exit - endif + end if else ! -- read another array if (.not. this%read_next_array()) exit - endif + end if else exit - endif - enddo + end if + end do ! if (associated(currNode)) then ! @@ -333,8 +333,8 @@ subroutine get_surrounding_records(this, time, taEarlier, taLater) time0 = ta0%taTime else exit - endif - enddo + end if + end do ! ! -- find later record node1 => currNode @@ -352,11 +352,11 @@ subroutine get_surrounding_records(this, time, taEarlier, taLater) if (.not. this%read_next_array()) then ! -- end of file reached, so exit loop exit - endif - endif - enddo + end if + end if + end do ! - endif + end if ! if (time0 <= time) taEarlier => ta0 if (time1 >= time) taLater => ta1 @@ -376,7 +376,7 @@ logical function read_next_array(this) ! -- local integer(I4B) :: i, ierr, istart, istat, istop, lloc, nrow, ncol, nodesperlayer logical :: lopen, isFound - type(TimeArrayType), pointer :: ta => null() + type(TimeArrayType), pointer :: ta => null() ! ------------------------------------------------------------------------------ ! istart = 1 @@ -386,38 +386,39 @@ logical function read_next_array(this) ! Get dimensions for supported discretization type if (this%dis%supports_layers()) then nodesperlayer = this%dis%get_ncpl() - if(size(this%dis%mshape) == 3) then + if (size(this%dis%mshape) == 3) then nrow = this%dis%mshape(2) ncol = this%dis%mshape(3) else nrow = 1 ncol = this%dis%mshape(2) - endif + end if else - errmsg = 'Time array series is not supported for selected discretization type.' + errmsg = 'Time array series is not supported for selected & + &discretization type.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! read_next_array = .false. - inquire(unit=this%inunit,opened=lopen) + inquire (unit=this%inunit, opened=lopen) if (lopen) then call ConstructTimeArray(ta, this%dis) ! -- read a time and an array from the input file ! -- Get a TIME block and read the time call this%parser%GetBlock('TIME', isFound, ierr, & - supportOpenClose=.false.) + supportOpenClose=.false.) if (isFound) then ta%taTime = this%parser%GetDouble() ! -- Read the array call ReadArray(this%parser%iuactive, ta%taArray, this%Name, & - this%dis%ndim, ncol, nrow, 1, nodesperlayer, & - this%iout, 0, 0) + this%dis%ndim, ncol, nrow, 1, nodesperlayer, & + this%iout, 0, 0) ! ! -- multiply values by sfac do i = 1, nodesperlayer ta%taArray(i) = ta%taArray(i) * this%sfac - enddo + end do ! ! -- append the new time array to the list call AddTimeArrayToList(this%list, ta) @@ -425,8 +426,8 @@ logical function read_next_array(this) ! ! -- make sure block is closed call this%parser%terminateblock() - endif - endif + end if + end if return ! Normal return ! return @@ -434,7 +435,7 @@ end function read_next_array subroutine get_values_at_time(this, nvals, values, time) ! ****************************************************************************** -! get_values_at_time -- Return an array of values for a specified time, same +! get_values_at_time -- Return an array of values for a specified time, same ! units as time-series values. ! ****************************************************************************** ! @@ -448,44 +449,44 @@ subroutine get_values_at_time(this, nvals, values, time) ! -- local integer(I4B) :: i, ierr real(DP) :: ratio, time0, time1, timediff, timediffi, val0, val1, & - valdiff + valdiff type(TimeArrayType), pointer :: taEarlier => null() type(TimeArrayType), pointer :: taLater => null() ! formats - 10 format('Error getting array at time ',g10.3, & - ' for time-array series "',a,'"') +10 format('Error getting array at time ', g10.3, & + ' for time-array series "', a, '"') ! ------------------------------------------------------------------------------ ! ierr = 0 - call this%get_surrounding_records(time,taEarlier,taLater) + call this%get_surrounding_records(time, taEarlier, taLater) if (associated(taEarlier)) then if (associated(taLater)) then ! -- values are available for both earlier and later times if (this%iMethod == STEPWISE) then ! -- Just populate values from elements of earlier time array - values = taEarlier%taArray + values = taEarlier%taArray elseif (this%iMethod == LINEAR) then ! -- perform linear interpolation time0 = taEarlier%taTime time1 = taLater%tatime timediff = time1 - time0 timediffi = time - time0 - if (timediff>0) then - ratio = timediffi/timediff + if (timediff > 0) then + ratio = timediffi / timediff else ! -- should not happen if TS does not contain duplicate times ratio = 0.5d0 - endif + end if ! -- Iterate through all elements and perform interpolation. - do i=1,nvals + do i = 1, nvals val0 = taEarlier%taArray(i) val1 = taLater%taArray(i) valdiff = val1 - val0 - values(i) = val0 + (ratio*valdiff) - enddo + values(i) = val0 + (ratio * valdiff) + end do else ierr = 1 - endif + end if else if (is_same(taEarlier%taTime, time)) then values = taEarlier%taArray @@ -493,12 +494,12 @@ subroutine get_values_at_time(this, nvals, values, time) ! -- Only earlier time is available, and it is not time of interest; ! however, if method is STEPWISE, use value for earlier time. if (this%iMethod == STEPWISE) then - values = taEarlier%taArray + values = taEarlier%taArray else ierr = 1 - endif - endif - endif + end if + end if + end if else if (associated(taLater)) then if (is_same(taLater%taTime, time)) then @@ -506,26 +507,26 @@ subroutine get_values_at_time(this, nvals, values, time) else ! -- only later time is available, and it is not time of interest ierr = 1 - endif + end if else ! -- Neither earlier nor later time is available. ! This should never happen! ierr = 1 - endif - endif + end if + end if ! if (ierr > 0) then - write(errmsg,10)time,trim(this%Name) + write (errmsg, 10) time, trim(this%Name) call store_error(errmsg) call store_error_unit(this%inunit) - endif + end if ! return end subroutine get_values_at_time subroutine get_integrated_values(this, nvals, values, time0, time1) ! ****************************************************************************** -! get_integrated_values -- Populates an array with integrated values for a +! get_integrated_values -- Populates an array with integrated values for a ! specified time span. Units: (ts-value-unit)*time ! ****************************************************************************** ! @@ -533,14 +534,14 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeArraySeriesType), intent(inout) :: this - integer(I4B), intent(in) :: nvals + integer(I4B), intent(in) :: nvals real(DP), dimension(nvals), intent(inout) :: values - real(DP), intent(in) :: time0 - real(DP), intent(in) :: time1 + real(DP), intent(in) :: time0 + real(DP), intent(in) :: time1 ! -- local integer(I4B) :: i real(DP) :: area, currTime, nextTime, ratio0, ratio1, t0, & - t01, t1, timediff, value, value0, value1, valuediff + t01, t1, timediff, value, value0, value1, valuediff logical :: ldone type(ListNodeType), pointer :: precNode => null() type(ListNodeType), pointer :: currNode => null(), nextNode => null() @@ -548,8 +549,8 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) class(*), pointer :: currObj => null(), nextObj => null() ! -- formats 10 format('Error encountered while performing integration', & - ' for time-array series "',a,'" for time interval: ', & - g12.5,' to ',g12.5) + ' for time-array series "', a, '" for time interval: ', & + g12.5, ' to ', g12.5) ! ------------------------------------------------------------------------------ ! values = DZERO @@ -567,11 +568,11 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) if (.not. associated(currNode%nextNode)) then ! -- try to read the next array if (.not. this%read_next_array()) then - write(errmsg,10)trim(this%Name),time0,time1 + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg) call store_error_unit(this%inunit) - endif - endif + end if + end if if (associated(currNode%nextNode)) then nextNode => currNode%nextNode nextObj => nextNode%GetItem() @@ -583,26 +584,26 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) t0 = currTime else t0 = time0 - endif + end if if (nextTime <= time1) then t1 = nextTime else t1 = time1 - endif + end if ! -- For each element, find area of rectangle ! or trapezoid delimited by t0 and t1. t01 = t1 - t0 select case (this%iMethod) case (STEPWISE) - do i=1,nvals + do i = 1, nvals ! -- compute area of a rectangle value0 = currRecord%taArray(i) area = value0 * t01 ! -- add area to integrated value values(i) = values(i) + area - enddo + end do case (LINEAR) - do i=1,nvals + do i = 1, nvals ! -- compute area of a trapezoid timediff = nextTime - currTime ratio0 = (t0 - currTime) / timediff @@ -613,17 +614,17 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) area = 0.5d0 * t01 * (value0 + value1) ! -- add area to integrated value values(i) = values(i) + area - enddo + end do end select else - write(errmsg,10)trim(this%Name),time0,time1 + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg) call store_error('(Probable programming error)', terminate=.TRUE.) - endif + end if else ! Current node time = time1 so should be done ldone = .true. - endif + end if ! ! -- Are we done yet? if (t1 >= time1) then @@ -632,50 +633,50 @@ subroutine get_integrated_values(this, nvals, values, time0, time1) if (.not. associated(currNode%nextNode)) then ! -- try to read the next array if (.not. this%read_next_array()) then - write(errmsg,10)trim(this%Name),time0,time1 + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg) call this%parser%StoreErrorUnit() - endif - endif + end if + end if if (associated(currNode%nextNode)) then currNode => currNode%nextNode else - write(errmsg,10)trim(this%Name),time0,time1 + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg) call store_error('(Probable programming error)', terminate=.TRUE.) - endif - endif - enddo - endif + end if + end if + end do + end if ! if (this%autoDeallocate) then if (associated(precNode)) then - if (associated(precNode%prevNode))then + if (associated(precNode%prevNode)) then call this%DeallocateBackward(precNode%prevNode) - endif - endif - endif + end if + end if + end if ! return end subroutine get_integrated_values subroutine DeallocateBackward(this, fromNode) ! ****************************************************************************** -! DeallocateBackward -- Deallocate fromNode and all previous nodes in list; +! DeallocateBackward -- Deallocate fromNode and all previous nodes in list; ! reassign firstNode. ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeArraySeriesType), intent(inout) :: this + class(TimeArraySeriesType), intent(inout) :: this type(ListNodeType), pointer, intent(inout) :: fromNode ! ! -- local - type(ListNodeType), pointer :: current => null() - type(ListNodeType), pointer :: prev => null() + type(ListNodeType), pointer :: current => null() + type(ListNodeType), pointer :: prev => null() type(TimeArrayType), pointer :: ta => null() - class(*), pointer :: obj => null() + class(*), pointer :: obj => null() ! ------------------------------------------------------------------------------ ! if (associated(fromNode)) then @@ -684,7 +685,7 @@ subroutine DeallocateBackward(this, fromNode) this%list%firstNode => fromNode%nextNode else this%list%firstNode => null() - endif + end if ! -- deallocate fromNode and all previous nodes current => fromNode do while (associated(current)) @@ -696,41 +697,42 @@ subroutine DeallocateBackward(this, fromNode) call ta%da() call this%list%RemoveNode(current, .true.) current => prev - enddo + end do fromNode => null() - endif + end if ! return end subroutine DeallocateBackward subroutine get_latest_preceding_node(this, time, tslNode) ! ****************************************************************************** -! get_latest_preceding_node -- Return pointer to ListNodeType object for the +! get_latest_preceding_node -- Return pointer to ListNodeType object for the ! node representing the latest preceding time in the time series ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeArraySeriesType), intent(inout) :: this - real(DP), intent(in) :: time + class(TimeArraySeriesType), intent(inout) :: this + real(DP), intent(in) :: time type(ListNodeType), pointer, intent(inout) :: tslNode ! -- local real(DP) :: time0 - type(ListNodeType), pointer :: currNode => null() - type(ListNodeType), pointer :: node0 => null() + type(ListNodeType), pointer :: currNode => null() + type(ListNodeType), pointer :: node0 => null() type(TimeArrayType), pointer :: ta => null() type(TimeArrayType), pointer :: ta0 => null() - class(*), pointer :: obj => null() + class(*), pointer :: obj => null() ! ------------------------------------------------------------------------------ ! tslNode => null() if (associated(this%list%firstNode)) then currNode => this%list%firstNode else - call store_error('probable programming error in get_latest_preceding_node', & + call store_error('probable programming error in & + &get_latest_preceding_node', & terminate=.TRUE.) - endif + end if ! continue ! -- If the next node is earlier than time of interest, advance along @@ -740,19 +742,19 @@ subroutine get_latest_preceding_node(this, time, tslNode) if (associated(currNode%nextNode)) then obj => currNode%nextNode%GetItem() ta => CastAsTimeArrayType(obj) - if (ta%taTime < time .or. is_same(ta%taTime, time)) then + if (ta%taTime < time .or. is_same(ta%taTime, time)) then currNode => currNode%nextNode else exit - endif + end if else ! -- read another record if (.not. this%read_next_array()) exit - endif + end if else exit - endif - enddo + end if + end do ! if (associated(currNode)) then ! @@ -769,9 +771,9 @@ subroutine get_latest_preceding_node(this, time, tslNode) time0 = ta0%taTime else exit - endif - enddo - endif + end if + end do + end if ! if (time0 <= time) tslNode => node0 ! @@ -794,30 +796,30 @@ subroutine tas_da(this) ! ! -- Deallocate contents of each time array in list n = this%list%Count() - do i=1,n + do i = 1, n ta => GetTimeArrayFromList(this%list, i) call ta%da() - enddo + end do ! ! -- Deallocate the list of time arrays call this%list%Clear(.true.) - deallocate(this%list) + deallocate (this%list) ! return end subroutine tas_da ! -- Procedures not type-bound - function CastAsTimeArraySeriesType(obj) result (res) + function CastAsTimeArraySeriesType(obj) result(res) ! ****************************************************************************** -! CastAsTimeArraySeriesType -- Cast an unlimited polymorphic object as +! CastAsTimeArraySeriesType -- Cast an unlimited polymorphic object as ! class(TimeArraySeriesType) ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(*), pointer, intent(inout) :: obj + class(*), pointer, intent(inout) :: obj type(TimeArraySeriesType), pointer :: res ! ------------------------------------------------------------------------------ ! @@ -832,7 +834,7 @@ function CastAsTimeArraySeriesType(obj) result (res) return end function CastAsTimeArraySeriesType - function GetTimeArraySeriesFromList(list, indx) result (res) + function GetTimeArraySeriesFromList(list, indx) result(res) ! ****************************************************************************** ! GetTimeArraySeriesFromList -- get time array from list ! ****************************************************************************** @@ -840,8 +842,8 @@ function GetTimeArraySeriesFromList(list, indx) result (res) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list - integer, intent(in) :: indx + type(ListType), intent(inout) :: list + integer, intent(in) :: indx type(TimeArraySeriesType), pointer :: res ! -- local class(*), pointer :: obj diff --git a/src/Utilities/TimeSeries/TimeArraySeriesLink.f90 b/src/Utilities/TimeSeries/TimeArraySeriesLink.f90 index add7e0852bf..4e1bb7d7a01 100644 --- a/src/Utilities/TimeSeries/TimeArraySeriesLink.f90 +++ b/src/Utilities/TimeSeries/TimeArraySeriesLink.f90 @@ -1,9 +1,9 @@ module TimeArraySeriesLinkModule use KindModule, only: DP, I4B - use ConstantsModule, only: LENPACKAGENAME, LENTIMESERIESTEXT - use InputOutputModule, only: UPCASE - use ListModule, only: ListType + use ConstantsModule, only: LENPACKAGENAME, LENTIMESERIESTEXT + use InputOutputModule, only: UPCASE + use ListModule, only: ListType use TimeArraySeriesModule, only: TimeArraySeriesType implicit none @@ -53,7 +53,7 @@ subroutine tasl_da(this) end subroutine tasl_da subroutine ConstructTimeArraySeriesLink(newTasLink, timeArraySeries, & - pkgName, bndArray, iprpak, text) + pkgName, bndArray, iprpak, text) ! ****************************************************************************** ! ConstructTimeArraySeriesLink -- construct ! ****************************************************************************** @@ -61,17 +61,17 @@ subroutine ConstructTimeArraySeriesLink(newTasLink, timeArraySeries, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(TimeArraySeriesLinkType), pointer, intent(out) :: newTasLink - type(TimeArraySeriesType), pointer, intent(in) :: timeArraySeries - character(len=*), intent(in) :: pkgName - real(DP), dimension(:), pointer, intent(in) :: bndArray - integer(I4B), intent(in) :: iprpak - character(len=*), intent(in) :: text + type(TimeArraySeriesLinkType), pointer, intent(out) :: newTasLink + type(TimeArraySeriesType), pointer, intent(in) :: timeArraySeries + character(len=*), intent(in) :: pkgName + real(DP), dimension(:), pointer, intent(in) :: bndArray + integer(I4B), intent(in) :: iprpak + character(len=*), intent(in) :: text ! -- local character(len=LENPACKAGENAME) :: pkgNameTemp ! ------------------------------------------------------------------------------ ! - allocate(newTasLink) + allocate (newTasLink) ! Store package name as all caps pkgNameTemp = pkgName call UPCASE(pkgNameTemp) @@ -86,7 +86,7 @@ end subroutine ConstructTimeArraySeriesLink function CastAsTimeArraySeriesLinkType(obj) result(res) ! ****************************************************************************** -! CastAsTimeArraySeriesLinkType -- Cast an unlimited polymorphic object as +! CastAsTimeArraySeriesLinkType -- Cast an unlimited polymorphic object as ! TimeArraySeriesLinkType ! ****************************************************************************** ! @@ -115,7 +115,7 @@ subroutine AddTimeArraySeriesLinkToList(list, tasLink) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(TimeArraySeriesLinkType), pointer, intent(inout) :: tasLink ! -- local class(*), pointer :: obj @@ -127,7 +127,7 @@ subroutine AddTimeArraySeriesLinkToList(list, tasLink) return end subroutine AddTimeArraySeriesLinkToList - function GetTimeArraySeriesLinkFromList(list, idx) result (res) + function GetTimeArraySeriesLinkFromList(list, idx) result(res) ! ****************************************************************************** ! GetTimeArraySeriesLinkFromList -- get from list ! ****************************************************************************** @@ -135,9 +135,9 @@ function GetTimeArraySeriesLinkFromList(list, idx) result (res) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx - type(TimeArraySeriesLinkType), pointer :: res + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx + type(TimeArraySeriesLinkType), pointer :: res ! -- local class(*), pointer :: obj ! ------------------------------------------------------------------------------ diff --git a/src/Utilities/TimeSeries/TimeArraySeriesManager.f90 b/src/Utilities/TimeSeries/TimeArraySeriesManager.f90 index ebd11739f1c..46040ca4cde 100644 --- a/src/Utilities/TimeSeries/TimeArraySeriesManager.f90 +++ b/src/Utilities/TimeSeries/TimeArraySeriesManager.f90 @@ -1,18 +1,18 @@ module TimeArraySeriesManagerModule - use KindModule, only: DP, I4B - use SimVariablesModule, only: errmsg - use ConstantsModule, only: DZERO, LENTIMESERIESNAME, LINELENGTH, & - LENHUGELINE - use ListModule, only: ListType - use SimModule, only: store_error, store_error_unit - use TdisModule, only: delt, totimc, kper, kstp + use KindModule, only: DP, I4B + use SimVariablesModule, only: errmsg + use ConstantsModule, only: DZERO, LENTIMESERIESNAME, LINELENGTH, & + LENHUGELINE + use ListModule, only: ListType + use SimModule, only: store_error, store_error_unit + use TdisModule, only: delt, totimc, kper, kstp use TimeArraySeriesLinkModule, only: TimeArraySeriesLinkType, & ConstructTimeArraySeriesLink, & GetTimeArraySeriesLinkFromList, & AddTimeArraySeriesLinkToList - use TimeArraySeriesModule, only: TimeArraySeriesType - use BaseDisModule, only: DisBaseType + use TimeArraySeriesModule, only: TimeArraySeriesType + use BaseDisModule, only: DisBaseType implicit none @@ -21,13 +21,13 @@ module TimeArraySeriesManagerModule type TimeArraySeriesManagerType ! -- Public members - integer(I4B), public :: iout = 0 ! output unit num - class(DisBaseType), pointer, public :: dis => null() ! pointer to dis + integer(I4B), public :: iout = 0 ! output unit num + class(DisBaseType), pointer, public :: dis => null() ! pointer to dis ! -- Private members - type(ListType), pointer, private :: boundTasLinks => null() ! list of TAS links - character(len=LINELENGTH), allocatable, dimension(:) :: tasfiles ! list of TA file names - type(TimeArraySeriesType), dimension(:), pointer, contiguous :: taslist ! array of TA pointers - character(len=LENTIMESERIESNAME), allocatable, dimension(:) :: tasnames ! array of TA names + type(ListType), pointer, private :: boundTasLinks => null() ! list of TAS links + character(len=LINELENGTH), allocatable, dimension(:) :: tasfiles ! list of TA file names + type(TimeArraySeriesType), dimension(:), pointer, contiguous :: taslist ! array of TA pointers + character(len=LENTIMESERIESNAME), allocatable, dimension(:) :: tasnames ! array of TA names contains ! -- Public procedures procedure, public :: tasmanager_df @@ -64,12 +64,12 @@ subroutine tasmanager_cr(this, dis, iout) ! this%iout = iout this%dis => dis - allocate(this%boundTasLinks) - allocate(this%tasfiles(0)) + allocate (this%boundTasLinks) + allocate (this%tasfiles(0)) ! return end subroutine tasmanager_cr - + subroutine tasmanager_df(this) ! ****************************************************************************** ! tasmanager_df -- define @@ -88,19 +88,19 @@ subroutine tasmanager_df(this) ! -- determine how many tasfiles. This is the number of time array series ! so allocate arrays to store them nfiles = size(this%tasfiles) - allocate(this%taslist(nfiles)) - allocate(this%tasnames(nfiles)) + allocate (this%taslist(nfiles)) + allocate (this%tasnames(nfiles)) ! ! -- Setup a time array series for each file specified do i = 1, nfiles tasptr => this%taslist(i) - call tasptr%tas_init(this%tasfiles(i), this%dis, & - this%iout, this%tasnames(i)) - enddo + call tasptr%tas_init(this%tasfiles(i), this%dis, & + this%iout, this%tasnames(i)) + end do ! return end subroutine tasmanager_df - + subroutine tasmgr_ad(this) ! ****************************************************************************** ! tasmgr_ad -- time step (or subtime step) advance. @@ -117,10 +117,11 @@ subroutine tasmgr_ad(this) integer(I4B) :: i, j, nlinks, nvals, isize1, isize2, inunit real(DP) :: begintime, endtime ! formats - character(len=*),parameter :: fmt5 = & - "(/,'Time-array-series controlled arrays in stress period ', & + character(len=*), parameter :: fmt5 = & + "(/,'Time-array-series controlled arrays in stress period ', & &i0, ', time step ', i0, ':')" -10 format('"',a, '" package: ',a,' array obtained from time-array series "',a,'"') +10 format('"', a, '" package: ', a, ' array obtained from time-array series "', & + a, '"') ! ------------------------------------------------------------------------------ ! ! -- Initialize time variables @@ -134,9 +135,9 @@ subroutine tasmgr_ad(this) nlinks = this%boundTasLinks%Count() do i = 1, nlinks tasLink => GetTimeArraySeriesLinkFromList(this%boundTasLinks, i) - if (tasLink%Iprpak == 1 .and. i==1) then - write(this%iout, fmt5) kper, kstp - endif + if (tasLink%Iprpak == 1 .and. i == 1) then + write (this%iout, fmt5) kper, kstp + end if if (tasLink%UseDefaultProc) then timearrayseries => tasLink%timeArraySeries nvals = size(tasLink%BndArray) @@ -148,20 +149,20 @@ subroutine tasmgr_ad(this) ! -- If conversion from flux to flow is required, multiply by cell area if (tasLink%ConvertFlux) then call this%tasmgr_convert_flux(tasLink) - endif + end if ! ! -- If PRINT_INPUT is specified, write information ! regarding source of time-array series data if (tasLink%Iprpak == 1) then - write(this%iout,10) trim(tasLink%PackageName), & - trim(tasLink%Text), & - trim(tasLink%timeArraySeries%Name) - endif - endif + write (this%iout, 10) trim(tasLink%PackageName), & + trim(tasLink%Text), & + trim(tasLink%timeArraySeries%Name) + end if + end if if (i == nlinks) then - write(this%iout, '()') - endif - enddo + write (this%iout, '()') + end if + end do ! ! -- Now that all array values have been substituted, can now multiply ! an array by a multiplier array @@ -174,19 +175,19 @@ subroutine tasmgr_ad(this) if (isize1 == isize2 .and. isize1 == nvals) then do j = 1, nvals tasLink%BndArray(j) = tasLink%BndArray(j) * tasLink%RMultArray(j) - enddo + end do else - errmsg = 'Size mismatch between boundary and multiplier arrays' // & - ' using time-array series: ' // & + errmsg = 'Size mismatch between boundary and multiplier arrays'// & + ' using time-array series: '// & trim(tasLink%TimeArraySeries%Name) call store_error(errmsg) inunit = tasLink%TimeArraySeries%GetInunit() call store_error_unit(inunit) - endif - endif - endif - enddo - endif + end if + end if + end if + end do + end if ! return end subroutine tasmgr_ad @@ -208,10 +209,10 @@ subroutine tasmgr_da(this) ! -- Deallocate contents of each TimeArraySeriesType object in list ! of time-array series links. n = this%boundTasLinks%Count() - do i=1,n + do i = 1, n tasLink => GetTimeArraySeriesLinkFromList(this%boundTasLinks, i) call tasLink%da() - enddo + end do ! ! -- Go through and deallocate individual time array series do i = 1, size(this%taslist) @@ -220,12 +221,12 @@ subroutine tasmgr_da(this) ! ! -- Deallocate the list of time-array series links. call this%boundTasLinks%Clear(.true.) - deallocate(this%boundTasLinks) - deallocate(this%tasfiles) + deallocate (this%boundTasLinks) + deallocate (this%tasfiles) ! ! -- Deallocate the time array series - deallocate(this%taslist) - deallocate(this%tasnames) + deallocate (this%taslist) + deallocate (this%tasnames) ! ! -- nullify pointers this%dis => null() @@ -282,9 +283,9 @@ subroutine Reset(this, pkgName) if (associated(taslink)) then do j = 1, size(taslink%BndArray) taslink%BndArray(j) = DZERO - enddo - endif - enddo + end do + end if + end do ! ! -- Delete all existing time array links if (associated(this%boundTasLinks)) then @@ -295,14 +296,14 @@ subroutine Reset(this, pkgName) if (associated(taslink)) then call taslink%da() call this%boundTasLinks%RemoveNode(i, .true.) - endif - enddo - endif + end if + end do + end if ! return end subroutine Reset - subroutine MakeTasLink(this, pkgName, bndArray, iprpak, & + subroutine MakeTasLink(this, pkgName, bndArray, iprpak, & tasName, text, convertFlux, nodelist, inunit) ! ****************************************************************************** ! MakeTasLink -- Make link from TAS to package array @@ -324,7 +325,7 @@ subroutine MakeTasLink(this, pkgName, bndArray, iprpak, & integer(I4B) :: i, nfiles, iloc character(LINELENGTH) :: ermsg type(TimeArraySeriesLinkType), pointer :: newTasLink - type(TimeArraySeriesType), pointer :: tasptr => null() + type(TimeArraySeriesType), pointer :: tasptr => null() ! ------------------------------------------------------------------------------ ! ! -- Find the time array series @@ -334,13 +335,13 @@ subroutine MakeTasLink(this, pkgName, bndArray, iprpak, & if (this%tasnames(i) == tasname) then iloc = i exit - endif + end if end do if (iloc == 0) then - ermsg = 'Error: Time-array series "' // trim(tasName) // '" not found.' + ermsg = 'Error: Time-array series "'//trim(tasName)//'" not found.' call store_error(ermsg) call store_error_unit(inunit) - endif + end if tasptr => this%taslist(iloc) ! ! -- Construct a time-array series link @@ -375,7 +376,7 @@ function GetLink(this, indx) result(tasLink) ! if (associated(this%boundTasLinks)) then tasLink => GetTimeArraySeriesLinkFromList(this%boundTasLinks, indx) - endif + end if ! return end function GetLink @@ -397,7 +398,7 @@ function CountLinks(this) CountLinks = this%boundTasLinks%Count() else CountLinks = 0 - endif + end if ! return end function CountLinks @@ -421,13 +422,13 @@ subroutine tasmgr_convert_flux(this, tasLink) ! ------------------------------------------------------------------------------ ! n = size(tasLink%BndArray) - do i=1,n + do i = 1, n noder = tasLink%nodelist(i) if (noder > 0) then area = this%dis%get_area(noder) tasLink%BndArray(i) = tasLink%BndArray(i) * area - endif - enddo + end if + end do ! return end subroutine tasmgr_convert_flux @@ -440,7 +441,7 @@ subroutine tasmgr_add_link(this, tasLink) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeArraySeriesManagerType) :: this + class(TimeArraySeriesManagerType) :: this type(TimeArraySeriesLinkType), pointer :: tasLink ! -- local ! ------------------------------------------------------------------------------ diff --git a/src/Utilities/TimeSeries/TimeSeries.f90 b/src/Utilities/TimeSeries/TimeSeries.f90 index b6c687a84c6..fa9af784796 100644 --- a/src/Utilities/TimeSeries/TimeSeries.f90 +++ b/src/Utilities/TimeSeries/TimeSeries.f90 @@ -1,16 +1,16 @@ module TimeSeriesModule use KindModule, only: DP, I4B - use BlockParserModule, only: BlockParserType - use ConstantsModule, only: LINELENGTH, UNDEFINED, STEPWISE, LINEAR, & - LINEAREND, LENTIMESERIESNAME, LENHUGELINE, & - DZERO, DONE, DNODATA - use GenericUtilitiesModule, only: is_same - use InputOutputModule, only: GetUnit, openfile, ParseLine, upcase - use ListModule, only: ListType, ListNodeType + use BlockParserModule, only: BlockParserType + use ConstantsModule, only: LINELENGTH, UNDEFINED, STEPWISE, LINEAR, & + LINEAREND, LENTIMESERIESNAME, LENHUGELINE, & + DZERO, DONE, DNODATA + use GenericUtilitiesModule, only: is_same + use InputOutputModule, only: GetUnit, openfile, ParseLine, upcase + use ListModule, only: ListType, ListNodeType use SimVariablesModule, only: errmsg - use SimModule, only: count_errors, store_error, & - store_error_unit + use SimModule, only: count_errors, store_error, & + store_error_unit use TimeSeriesRecordModule, only: TimeSeriesRecordType, & ConstructTimeSeriesRecord, & CastAsTimeSeriesRecordType, & @@ -63,7 +63,8 @@ module TimeSeriesModule integer(I4B), public :: nTimeSeries = 0 logical, public :: finishedReading = .false. character(len=LINELENGTH), public :: datafile = '' - type(TimeSeriesType), dimension(:), pointer, contiguous, public :: timeSeries => null() + type(TimeSeriesType), dimension(:), & + pointer, contiguous, public :: timeSeries => null() type(BlockParserType), pointer, public :: parser contains ! -- Public procedures @@ -95,14 +96,14 @@ subroutine ConstructTimeSeriesFile(newTimeSeriesFile) type(TimeSeriesFileType), pointer, intent(inout) :: newTimeSeriesFile ! ------------------------------------------------------------------------------ ! - allocate(newTimeSeriesFile) - allocate(newTimeSeriesFile%parser) + allocate (newTimeSeriesFile) + allocate (newTimeSeriesFile%parser) return end subroutine ConstructTimeSeriesFile function CastAsTimeSeriesFileType(obj) result(res) ! ****************************************************************************** -! CastAsTimeSeriesFileType -- Cast an unlimited polymorphic object as +! CastAsTimeSeriesFileType -- Cast an unlimited polymorphic object as ! class(TimeSeriesFileType) ! ****************************************************************************** ! @@ -126,7 +127,7 @@ end function CastAsTimeSeriesFileType function CastAsTimeSeriesFileClass(obj) result(res) ! ****************************************************************************** -! CastAsTimeSeriesFileClass -- Cast an unlimited polymorphic object as +! CastAsTimeSeriesFileClass -- Cast an unlimited polymorphic object as ! class(TimeSeriesFileType) ! ****************************************************************************** ! @@ -156,7 +157,7 @@ subroutine AddTimeSeriesFileToList(list, tsfile) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list class(TimeSeriesFileType), pointer, intent(inout) :: tsfile ! -- local class(*), pointer :: obj => null() @@ -168,7 +169,7 @@ subroutine AddTimeSeriesFileToList(list, tsfile) return end subroutine AddTimeSeriesFileToList - function GetTimeSeriesFileFromList(list, idx) result (res) + function GetTimeSeriesFileFromList(list, idx) result(res) ! ****************************************************************************** ! GetTimeSeriesFileFromList -- get from list ! ****************************************************************************** @@ -176,8 +177,8 @@ function GetTimeSeriesFileFromList(list, idx) result (res) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - type(ListType), intent(inout) :: list - integer(I4B), intent(in) :: idx + type(ListType), intent(inout) :: list + integer(I4B), intent(in) :: idx type(TimeSeriesFileType), pointer :: res ! -- local class(*), pointer :: obj => null() @@ -188,12 +189,12 @@ function GetTimeSeriesFileFromList(list, idx) result (res) ! if (.not. associated(res)) then res => CastAsTimeSeriesFileClass(obj) - endif + end if ! return end function GetTimeSeriesFileFromList - function SameTimeSeries(ts1, ts2) result (same) + function SameTimeSeries(ts1, ts2) result(same) ! ****************************************************************************** ! SameTimeSeries -- Compare two time series; if they are identical, return true. ! ****************************************************************************** @@ -217,12 +218,12 @@ function SameTimeSeries(ts1, ts2) result (same) call ts1%Reset() call ts2%Reset() ! - do i=1,n1 + do i = 1, n1 tsr1 => ts1%GetNextTimeSeriesRecord() tsr2 => ts2%GetNextTimeSeriesRecord() if (tsr1%tsrTime /= tsr2%tsrTime) return if (tsr1%tsrValue /= tsr2%tsrValue) return - enddo + end do ! same = .true. ! @@ -247,24 +248,24 @@ function GetValue(this, time0, time1, extendToEndOfSimulation) real(DP) :: GetValue ! -- dummy class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time0 - real(DP), intent(in) :: time1 + real(DP), intent(in) :: time0 + real(DP), intent(in) :: time1 logical, intent(in), optional :: extendToEndOfSimulation ! logical :: extend ! ------------------------------------------------------------------------------ ! - if(present(extendToEndOfSimulation)) then + if (present(extendToEndOfSimulation)) then extend = extendToEndOfSimulation else extend = .false. - endif + end if ! select case (this%iMethod) case (STEPWISE, LINEAR) GetValue = this%get_average_value(time0, time1, extend) case (LINEAREND) - GetValue = this%get_value_at_time(time1, extend) + GetValue = this%get_value_at_time(time1, extend) end select ! return @@ -280,9 +281,9 @@ subroutine initialize_time_series(this, tsfile, name, autoDeallocate) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeSeriesType), intent(inout) :: this - class(TimeSeriesFileType), target :: tsfile - character(len=*), intent(in) :: name - logical, intent(in), optional :: autoDeallocate + class(TimeSeriesFileType), target :: tsfile + character(len=*), intent(in) :: name + logical, intent(in), optional :: autoDeallocate ! -- local character(len=LENTIMESERIESNAME) :: tsNameTemp ! ------------------------------------------------------------------------------ @@ -299,13 +300,13 @@ subroutine initialize_time_series(this, tsfile, name, autoDeallocate) if (present(autoDeallocate)) this%autoDeallocate = autoDeallocate ! ! -- allocate the list - allocate(this%list) + allocate (this%list) ! ! -- ensure that NAME has been specified if (this%Name == '') then errmsg = 'Name not specified for time series.' call store_error(errmsg, terminate=.TRUE.) - endif + end if ! return end subroutine initialize_time_series @@ -319,7 +320,7 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time + real(DP), intent(in) :: time type(TimeSeriesRecordType), pointer, intent(inout) :: tsrecEarlier type(TimeSeriesRecordType), pointer, intent(inout) :: tsrecLater ! -- local @@ -329,7 +330,7 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) type(ListNodeType), pointer :: tsNode1 => null() type(TimeSeriesRecordType), pointer :: tsr => null(), tsrec0 => null() type(TimeSeriesRecordType), pointer :: tsrec1 => null() - class(*), pointer :: obj => null() + class(*), pointer :: obj => null() ! ------------------------------------------------------------------------------ ! tsrecEarlier => null() @@ -337,7 +338,7 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) ! if (associated(this%list%firstNode)) then currNode => this%list%firstNode - endif + end if ! ! -- If the next node is earlier than time of interest, advance along ! linked list until the next node is later than time of interest. @@ -350,15 +351,15 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) currNode => currNode%nextNode else exit - endif + end if else ! -- read another record if (.not. this%read_next_record()) exit - endif + end if else exit - endif - enddo + end if + end do ! if (associated(currNode)) then ! @@ -375,8 +376,8 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) time0 = tsrec0%tsrTime else exit - endif - enddo + end if + end do ! ! -- find later record tsNode1 => currNode @@ -394,11 +395,11 @@ subroutine get_surrounding_records(this, time, tsrecEarlier, tsrecLater) if (.not. this%read_next_record()) then ! -- end of file reached, so exit loop exit - endif - endif - enddo + end if + end if + end do ! - endif + end if ! if (time0 < time .or. is_same(time0, time)) tsrecEarlier => tsrec0 if (time1 > time .or. is_same(time1, time)) tsrecLater => tsrec1 @@ -416,8 +417,8 @@ subroutine get_surrounding_nodes(this, time, nodeEarlier, nodeLater) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time + class(TimeSeriesType), intent(inout) :: this + real(DP), intent(in) :: time type(ListNodeType), pointer, intent(inout) :: nodeEarlier type(ListNodeType), pointer, intent(inout) :: nodeLater ! -- local @@ -429,17 +430,17 @@ subroutine get_surrounding_nodes(this, time, nodeEarlier, nodeLater) type(TimeSeriesRecordType), pointer :: tsrec1 => null() type(TimeSeriesRecordType), pointer :: tsrecEarlier type(TimeSeriesRecordType), pointer :: tsrecLater - class(*), pointer :: obj => null() + class(*), pointer :: obj => null() ! ------------------------------------------------------------------------------ ! tsrecEarlier => null() tsrecLater => null() nodeEarlier => null() - nodeLater => null() + nodeLater => null() ! if (associated(this%list%firstNode)) then currNode => this%list%firstNode - endif + end if ! ! -- If the next node is earlier than time of interest, advance along ! linked list until the next node is later than time of interest. @@ -452,14 +453,14 @@ subroutine get_surrounding_nodes(this, time, nodeEarlier, nodeLater) currNode => currNode%nextNode else exit - endif + end if else exit - endif + end if else exit - endif - enddo + end if + end do ! if (associated(currNode)) then ! @@ -476,8 +477,8 @@ subroutine get_surrounding_nodes(this, time, nodeEarlier, nodeLater) time0 = tsrec0%tsrTime else exit - endif - enddo + end if + end do ! ! -- find later record tsNode1 => currNode @@ -492,19 +493,19 @@ subroutine get_surrounding_nodes(this, time, nodeEarlier, nodeLater) time1 = tsrec1%tsrTime else exit - endif - enddo + end if + end do ! - endif + end if ! if (time0 < time .or. is_same(time0, time)) then tsrecEarlier => tsrec0 nodeEarlier => tsNode0 - endif + end if if (time1 > time .or. is_same(time1, time)) then tsrecLater => tsrec1 nodeLater => tsNode1 - endif + end if ! return end subroutine get_surrounding_nodes @@ -526,12 +527,12 @@ logical function read_next_record(this) if (this%tsfile%finishedReading) then read_next_record = .false. return - endif + end if ! read_next_record = this%tsfile%read_tsfile_line() if (.not. read_next_record) then this%tsfile%finishedReading = .true. - endif + end if return ! end function read_next_record @@ -548,25 +549,25 @@ function get_value_at_time(this, time, extendToEndOfSimulation) real(DP) :: get_value_at_time ! -- dummy class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time ! time of interest + real(DP), intent(in) :: time ! time of interest logical, intent(in) :: extendToEndOfSimulation ! -- local integer(I4B) :: ierr real(DP) :: ratio, time0, time1, timediff, timediffi, val0, val1, & - valdiff + valdiff type(TimeSeriesRecordType), pointer :: tsrEarlier => null() type(TimeSeriesRecordType), pointer :: tsrLater => null() ! -- formats - 10 format('Error getting value at time ',g10.3,' for time series "',a,'"') +10 format('Error getting value at time ', g10.3, ' for time series "', a, '"') ! ------------------------------------------------------------------------------ ! ierr = 0 - call this%get_surrounding_records(time,tsrEarlier,tsrLater) + call this%get_surrounding_records(time, tsrEarlier, tsrLater) if (associated(tsrEarlier)) then if (associated(tsrLater)) then ! -- values are available for both earlier and later times if (this%iMethod == STEPWISE) then - get_value_at_time = tsrEarlier%tsrValue + get_value_at_time = tsrEarlier%tsrValue elseif (this%iMethod == LINEAR .or. this%iMethod == LINEAREND) then ! -- For get_value_at_time, result is the same for either ! linear method. @@ -575,19 +576,19 @@ function get_value_at_time(this, time, extendToEndOfSimulation) time1 = tsrLater%tsrtime timediff = time1 - time0 timediffi = time - time0 - if (timediff>0) then - ratio = timediffi/timediff + if (timediff > 0) then + ratio = timediffi / timediff else ! -- should not happen if TS does not contain duplicate times ratio = 0.5d0 - endif + end if val0 = tsrEarlier%tsrValue val1 = tsrLater%tsrValue valdiff = val1 - val0 - get_value_at_time = val0 + (ratio*valdiff) + get_value_at_time = val0 + (ratio * valdiff) else ierr = 1 - endif + end if else if (extendToEndOfSimulation .or. is_same(tsrEarlier%tsrTime, time)) then get_value_at_time = tsrEarlier%tsrValue @@ -595,12 +596,12 @@ function get_value_at_time(this, time, extendToEndOfSimulation) ! -- Only earlier time is available, and it is not time of interest; ! however, if method is STEPWISE, use value for earlier time. if (this%iMethod == STEPWISE) then - get_value_at_time = tsrEarlier%tsrValue + get_value_at_time = tsrEarlier%tsrValue else ierr = 1 - endif - endif - endif + end if + end if + end if else if (associated(tsrLater)) then if (is_same(tsrLater%tsrTime, time)) then @@ -608,18 +609,18 @@ function get_value_at_time(this, time, extendToEndOfSimulation) else ! -- only later time is available, and it is not time of interest ierr = 1 - endif + end if else ! -- Neither earlier nor later time is available. ! This should never happen! ierr = 1 - endif - endif + end if + end if ! if (ierr > 0) then - write(errmsg,10) time, trim(this%Name) + write (errmsg, 10) time, trim(this%Name) call store_error(errmsg, terminate=.TRUE.) - endif + end if ! return end function get_value_at_time @@ -637,12 +638,12 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) real(DP) :: get_integrated_value ! -- dummy class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time0 - real(DP), intent(in) :: time1 + real(DP), intent(in) :: time0 + real(DP), intent(in) :: time1 logical, intent(in) :: extendToEndOfSimulation ! -- local real(DP) :: area, currTime, nextTime, ratio0, ratio1, t0, t01, t1, & - timediff, value, value0, value1, valuediff, currVal, nextVal + timediff, value, value0, value1, valuediff, currVal, nextVal logical :: ldone, lprocess type(ListNodeType), pointer :: tslNodePreceding => null() type(ListNodeType), pointer :: currNode => null(), nextNode => null() @@ -650,8 +651,8 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) type(TimeSeriesRecordType), pointer :: nextRecord => null() class(*), pointer :: currObj => null(), nextObj => null() ! -- formats - 10 format('Error encountered while performing integration', & - ' for time series "',a,'" for time interval: ',g12.5,' to ',g12.5) +10 format('Error encountered while performing integration', & + ' for time series "', a, '" for time interval: ', g12.5, ' to ', g12.5) ! ------------------------------------------------------------------------------ ! value = DZERO @@ -671,12 +672,12 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) if (.not. associated(currNode%nextNode)) then ! -- try to read the next record if (.not. this%read_next_record()) then - if(.not. extendToEndOfSimulation) then - write(errmsg,10)trim(this%Name),time0,time1 + if (.not. extendToEndOfSimulation) then + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg, terminate=.TRUE.) - endif - endif - endif + end if + end if + end if ! currVal = currRecord%tsrValue lprocess = .false. @@ -692,7 +693,7 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) nextTime = time1 nextVal = currVal lprocess = .true. - endif + end if ! if (lprocess) then ! -- determine lower and upper limits of time span of interest @@ -701,12 +702,12 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) t0 = currTime else t0 = time0 - endif + end if if (nextTime < time1 .or. is_same(nextTime, time1)) then t1 = nextTime else t1 = time1 - endif + end if ! -- find area of rectangle or trapezoid delimited by t0 and t1 t01 = t1 - t0 select case (this%iMethod) @@ -727,12 +728,12 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) elseif (this%iMethod == LINEAREND) then area = DZERO value = value1 - endif + end if end select ! -- add area to integrated value value = value + area - endif - endif + end if + end if ! ! -- Are we done yet? if (t1 > time1) then @@ -744,24 +745,24 @@ function get_integrated_value(this, time0, time1, extendToEndOfSimulation) if (.not. associated(currNode%nextNode)) then ! -- Not done and no more data, so try to read the next record if (.not. this%read_next_record()) then - write(errmsg,10)trim(this%Name),time0,time1 + write (errmsg, 10) trim(this%Name), time0, time1 call store_error(errmsg, terminate=.TRUE.) - endif + end if elseif (associated(currNode%nextNode)) then currNode => currNode%nextNode - endif - endif - enddo - endif + end if + end if + end do + end if ! get_integrated_value = value if (this%autoDeallocate) then if (associated(tslNodePreceding)) then - if (associated(tslNodePreceding%prevNode))then + if (associated(tslNodePreceding%prevNode)) then call this%list%DeallocateBackward(tslNodePreceding%prevNode) - endif - endif - endif + end if + end if + end if return end function get_integrated_value @@ -778,8 +779,8 @@ function get_average_value(this, time0, time1, extendToEndOfSimulation) real(DP) :: get_average_value ! -- dummy class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time0 - real(DP), intent(in) :: time1 + real(DP), intent(in) :: time0 + real(DP), intent(in) :: time1 logical, intent(in) :: extendToEndOfSimulation ! -- local real(DP) :: timediff, value, valueIntegrated @@ -787,16 +788,17 @@ function get_average_value(this, time0, time1, extendToEndOfSimulation) ! timediff = time1 - time0 if (timediff > 0) then - valueIntegrated = this%get_integrated_value(time0, time1, extendToEndOfSimulation) + valueIntegrated = this%get_integrated_value(time0, time1, & + extendToEndOfSimulation) if (this%iMethod == LINEAREND) then value = valueIntegrated else value = valueIntegrated / timediff - endif + end if else ! -- time0 and time1 are the same value = this%get_value_at_time(time0, extendToEndOfSimulation) - endif + end if get_average_value = value ! return @@ -812,8 +814,8 @@ subroutine get_latest_preceding_node(this, time, tslNode) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeSeriesType), intent(inout) :: this - real(DP), intent(in) :: time + class(TimeSeriesType), intent(inout) :: this + real(DP), intent(in) :: time type(ListNodeType), pointer, intent(inout) :: tslNode ! -- local real(DP) :: time0 @@ -821,16 +823,17 @@ subroutine get_latest_preceding_node(this, time, tslNode) type(ListNodeType), pointer :: tsNode0 => null() type(TimeSeriesRecordType), pointer :: tsr => null() type(TimeSeriesRecordType), pointer :: tsrec0 => null() - class(*), pointer :: obj => null() + class(*), pointer :: obj => null() ! ------------------------------------------------------------------------------ ! tslNode => null() if (associated(this%list%firstNode)) then currNode => this%list%firstNode else - call store_error('probable programming error in get_latest_preceding_node', & + call store_error('probable programming error in & + &get_latest_preceding_node', & terminate=.TRUE.) - endif + end if ! ! -- If the next node is earlier than time of interest, advance along ! linked list until the next node is later than time of interest. @@ -843,15 +846,15 @@ subroutine get_latest_preceding_node(this, time, tslNode) currNode => currNode%nextNode else exit - endif + end if else ! -- read another record if (.not. this%read_next_record()) exit - endif + end if else exit - endif - enddo + end if + end do ! if (associated(currNode)) then ! @@ -868,9 +871,9 @@ subroutine get_latest_preceding_node(this, time, tslNode) time0 = tsrec0%tsrTime else exit - endif - enddo - endif + end if + end do + end if ! if (time0 < time .or. is_same(time0, time)) tslNode => tsNode0 ! @@ -890,8 +893,8 @@ subroutine ts_da(this) ! if (associated(this%list)) then call this%list%Clear(.true.) - deallocate(this%list) - endif + deallocate (this%list) + end if ! return end subroutine ts_da @@ -916,7 +919,7 @@ subroutine AddTimeSeriesRecord(this, tsr) return end subroutine AddTimeSeriesRecord - function GetCurrentTimeSeriesRecord(this) result (res) + function GetCurrentTimeSeriesRecord(this) result(res) ! ****************************************************************************** ! GetCurrentTimeSeriesRecord -- get current ts record ! ****************************************************************************** @@ -936,12 +939,12 @@ function GetCurrentTimeSeriesRecord(this) result (res) obj => this%list%GetItem() if (associated(obj)) then res => CastAsTimeSeriesRecordType(obj) - endif + end if ! return end function GetCurrentTimeSeriesRecord - function GetPreviousTimeSeriesRecord(this) result (res) + function GetPreviousTimeSeriesRecord(this) result(res) ! ****************************************************************************** ! GetPreviousTimeSeriesRecord -- get previous ts record ! ****************************************************************************** @@ -961,12 +964,12 @@ function GetPreviousTimeSeriesRecord(this) result (res) obj => this%list%GetPreviousItem() if (associated(obj)) then res => CastAsTimeSeriesRecordType(obj) - endif + end if ! return end function GetPreviousTimeSeriesRecord - function GetNextTimeSeriesRecord(this) result (res) + function GetNextTimeSeriesRecord(this) result(res) ! ****************************************************************************** ! GetNextTimeSeriesRecord -- get next ts record ! ****************************************************************************** @@ -986,12 +989,12 @@ function GetNextTimeSeriesRecord(this) result (res) obj => this%list%GetNextItem() if (associated(obj)) then res => CastAsTimeSeriesRecordType(obj) - endif + end if ! return end function GetNextTimeSeriesRecord - function GetTimeSeriesRecord(this, time, epsi) result (res) + function GetTimeSeriesRecord(this, time, epsi) result(res) ! ****************************************************************************** ! GetTimeSeriesRecord -- get ts record ! ****************************************************************************** @@ -1016,12 +1019,12 @@ function GetTimeSeriesRecord(this, time, epsi) result (res) if (is_same(tsr%tsrTime, time)) then res => tsr exit - endif + end if if (tsr%tsrTime > time) exit else exit - endif - enddo + end if + end do ! return end function GetTimeSeriesRecord @@ -1050,7 +1053,7 @@ subroutine InsertTsr(this, tsr) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeSeriesType), intent(inout) :: this + class(TimeSeriesType), intent(inout) :: this type(TimeSeriesRecordType), pointer, intent(inout) :: tsr ! -- local double precision :: badtime, time, time0, time1 @@ -1070,16 +1073,16 @@ subroutine InsertTsr(this, tsr) tsrEarlier => CastAsTimeSeriesRecordType(obj) if (associated(tsrEarlier)) then time0 = tsrEarlier%tsrTime - endif - endif + end if + end if ! if (associated(nodeLater)) then obj => nodeLater%GetItem() tsrLater => CastAsTimeSeriesRecordType(obj) if (associated(tsrLater)) then time1 = tsrLater%tsrTime - endif - endif + end if + end if ! if (time0 > badtime) then ! Time0 is valid @@ -1093,17 +1096,17 @@ subroutine InsertTsr(this, tsr) ! No need to insert a time series record, but if existing record ! for time of interest has NODATA as tsrValue, replace tsrValue if (time == time0 .and. tsrEarlier%tsrValue == DNODATA .and. & - tsr%tsrValue /= DNODATA) then + tsr%tsrValue /= DNODATA) then tsrEarlier%tsrValue = tsr%tsrValue elseif (time == time1 .and. tsrLater%tsrValue == DNODATA .and. & tsr%tsrValue /= DNODATA) then tsrLater%tsrValue = tsr%tsrValue - endif - endif + end if + end if else ! Time0 is valid and time1 is invalid. Just add tsr to the list. call this%AddTimeSeriesRecord(tsr) - endif + end if else ! Time0 is invalid, so time1 must be for first node in list if (time1 > badtime) then @@ -1117,18 +1120,18 @@ subroutine InsertTsr(this, tsr) ! for time of interest has NODATA as tsrValue, replace tsrValue if (tsrLater%tsrValue == DNODATA .and. tsr%tsrValue /= DNODATA) then tsrLater%tsrValue = tsr%tsrValue - endif - endif + end if + end if else ! Both time0 and time1 are invalid. Just add tsr to the list. call this%AddTimeSeriesRecord(tsr) - endif - endif + end if + end if ! return end subroutine InsertTsr - function FindLatestTime(this, readToEnd) result (endtime) + function FindLatestTime(this, readToEnd) result(endtime) ! ****************************************************************************** ! FindLatestTime -- find latest time ! ****************************************************************************** @@ -1149,9 +1152,9 @@ function FindLatestTime(this, readToEnd) result (endtime) if (present(readToEnd)) then if (readToEnd) then do while (this%read_next_record()) - enddo - endif - endif + end do + end if + end if ! nrecords = this%list%Count() obj => this%list%GetItem(nrecords) @@ -1170,7 +1173,7 @@ subroutine Clear(this, destroy) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeSeriesType), intent(inout) :: this - logical, optional, intent(in) :: destroy + logical, optional, intent(in) :: destroy ! ------------------------------------------------------------------------------ ! call this%list%Clear(destroy) @@ -1197,11 +1200,11 @@ function Count(this) Count = size(this%timeSeries) else Count = 0 - endif + end if return end function Count - function GetTimeSeries(this, indx) result (res) + function GetTimeSeries(this, indx) result(res) ! ****************************************************************************** ! GetTimeSeries -- get ts ! ****************************************************************************** @@ -1218,13 +1221,13 @@ function GetTimeSeries(this, indx) result (res) res => null() if (indx > 0 .and. indx <= this%nTimeSeries) then res => this%timeSeries(indx) - endif + end if return end function GetTimeSeries subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! ****************************************************************************** -! Initializetsfile -- Open time-series tsfile file and read options and first +! Initializetsfile -- Open time-series tsfile file and read options and first ! record, which may contain data to define multiple time series. ! ****************************************************************************** ! @@ -1232,14 +1235,15 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! ------------------------------------------------------------------------------ ! -- dummy class(TimeSeriesFileType), target, intent(inout) :: this - character(len=*), intent(in) :: filename - integer(I4B), intent(in) :: iout - logical, optional, intent(in) :: autoDeallocate + character(len=*), intent(in) :: filename + integer(I4B), intent(in) :: iout + logical, optional, intent(in) :: autoDeallocate ! -- local integer(I4B) :: iMethod, istatus, j, nwords integer(I4B) :: ierr, inunit logical :: autoDeallocateLocal = .true. logical :: continueread, found, endOfBlock + logical :: methodWasSet real(DP) :: sfaclocal character(len=40) :: keyword, keyvalue character(len=:), allocatable :: line @@ -1249,6 +1253,7 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! -- Initialize some variables if (present(autoDeallocate)) autoDeallocateLocal = autoDeallocate iMethod = UNDEFINED + methodWasSet = .false. ! ! -- Assign members this%iout = iout @@ -1257,7 +1262,7 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! -- Open the time-series tsfile input file this%inunit = GetUnit() inunit = this%inunit - call openfile(inunit,0,filename,'TS6') + call openfile(inunit, 0, filename, 'TS6') ! ! -- Initialize block parser call this%parser%Initialize(this%inunit, this%iout) @@ -1268,20 +1273,20 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! ! -- get BEGIN line of ATTRIBUTES block call this%parser%GetBlock('ATTRIBUTES', found, ierr, & - supportOpenClose=.true.) + supportOpenClose=.true.) if (ierr /= 0) then ! end of file - errmsg = 'End-of-file encountered while searching for' // & - ' ATTRIBUTES in time-series ' // & - 'input file "' // trim(this%datafile) // '"' + errmsg = 'End-of-file encountered while searching for'// & + ' ATTRIBUTES in time-series '// & + 'input file "'//trim(this%datafile)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() elseif (.not. found) then - errmsg = 'ATTRIBUTES block not found in time-series ' // & - 'tsfile input file "' // trim(this%datafile) // '"' + errmsg = 'ATTRIBUTES block not found in time-series '// & + 'tsfile input file "'//trim(this%datafile)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if ! ! -- parse ATTRIBUTES entries do @@ -1293,12 +1298,13 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) call this%parser%GetStringCaps(keyword) ! ! support either NAME or NAMES as equivalent keywords - if (keyword=='NAMES') keyword = 'NAME' + if (keyword == 'NAMES') keyword = 'NAME' ! - if (keyword /= 'NAME' .and. keyword /= 'METHODS' .and. keyword /= 'SFACS') then + if (keyword /= 'NAME' .and. keyword /= 'METHODS' .and. & + keyword /= 'SFACS') then ! -- get the word following the keyword (the key value) call this%parser%GetStringCaps(keyvalue) - endif + end if ! select case (keyword) case ('NAME') @@ -1308,18 +1314,19 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) this%nTimeSeries = nwords ! -- Allocate the timeSeries array and initialize each ! time series. - allocate(this%timeSeries(this%nTimeSeries)) - do j=1,this%nTimeSeries + allocate (this%timeSeries(this%nTimeSeries)) + do j = 1, this%nTimeSeries call this%timeSeries(j)%initialize_time_series(this, words(j), & - autoDeallocateLocal) - enddo + autoDeallocateLocal) + end do case ('METHOD') + methodWasSet = .true. if (this%nTimeSeries == 0) then errmsg = 'Error: NAME attribute not provided before METHOD in file: ' & - // trim(filename) + //trim(filename) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if select case (keyvalue) case ('STEPWISE') iMethod = STEPWISE @@ -1328,28 +1335,29 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) case ('LINEAREND') iMethod = LINEAREND case default - errmsg = 'Unknown interpolation method: "' // trim(keyvalue) // '"' + errmsg = 'Unknown interpolation method: "'//trim(keyvalue)//'"' call store_error(errmsg) end select - do j=1,this%nTimeSeries + do j = 1, this%nTimeSeries this%timeSeries(j)%iMethod = iMethod - enddo + end do case ('METHODS') + methodWasSet = .true. if (this%nTimeSeries == 0) then errmsg = 'Error: NAME attribute not provided before METHODS in file: ' & - // trim(filename) + //trim(filename) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif + end if call this%parser%GetRemainingLine(line) call ParseLine(line, nwords, words, this%parser%iuactive) if (nwords < this%nTimeSeries) then - errmsg = 'METHODS attribute does not list a method for' // & - ' all time series.' + errmsg = 'METHODS attribute does not list a method for'// & + ' all time series.' call store_error(errmsg) call this%parser%StoreErrorUnit() - endif - do j=1,this%nTimeSeries + end if + do j = 1, this%nTimeSeries call upcase(words(j)) select case (words(j)) case ('STEPWISE') @@ -1359,48 +1367,48 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) case ('LINEAREND') iMethod = LINEAREND case default - errmsg = 'Unknown interpolation method: "' // trim(words(j)) // '"' + errmsg = 'Unknown interpolation method: "'//trim(words(j))//'"' call store_error(errmsg) end select this%timeSeries(j)%iMethod = iMethod - enddo + end do case ('SFAC') if (this%nTimeSeries == 0) then errmsg = 'NAME attribute not provided before SFAC in file: ' & - // trim(filename) + //trim(filename) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif - read(keyvalue,*,iostat=istatus)sfaclocal + end if + read (keyvalue, *, iostat=istatus) sfaclocal if (istatus /= 0) then - errmsg = 'Error reading numeric value from: "' // trim(keyvalue) // '"' + errmsg = 'Error reading numeric value from: "'//trim(keyvalue)//'"' call store_error(errmsg) - endif - do j=1,this%nTimeSeries + end if + do j = 1, this%nTimeSeries this%timeSeries(j)%sfac = sfaclocal - enddo + end do case ('SFACS') if (this%nTimeSeries == 0) then errmsg = 'NAME attribute not provided before SFACS in file: ' & - // trim(filename) + //trim(filename) call store_error(errmsg) call this%parser%StoreErrorUnit() - endif - do j=1,this%nTimeSeries + end if + do j = 1, this%nTimeSeries sfaclocal = this%parser%GetDouble() this%timeSeries(j)%sfac = sfaclocal - enddo + end do case ('AUTODEALLOCATE') - do j=1,this%nTimeSeries + do j = 1, this%nTimeSeries this%timeSeries(j)%autoDeallocate = (keyvalue == 'TRUE') - enddo + end do case default - errmsg = 'Unknown option found in ATTRIBUTES block: "' // & - trim(keyword) // '"' + errmsg = 'Unknown option found in ATTRIBUTES block: "'// & + trim(keyword)//'"' call store_error(errmsg) call this%parser%StoreErrorUnit() end select - enddo + end do ! ! -- Get TIMESERIES block call this%parser%GetBlock('TIMESERIES', found, ierr, & @@ -1408,17 +1416,24 @@ subroutine Initializetsfile(this, filename, iout, autoDeallocate) ! ! -- Read the first line of time-series data if (.not. this%read_tsfile_line()) then - errmsg = 'Error: No time-series data contained in file: ' // & - trim(this%datafile) + errmsg = 'Error: No time-series data contained in file: '// & + trim(this%datafile) + call store_error(errmsg) + end if + ! + ! -- Ensure method was set + if (.not. methodWasSet) then + errmsg = 'Interpolation method was not set. METHOD or METHODS & + &must be specified in the ATTRIBUTES block for this time series file.' call store_error(errmsg) - endif + end if ! ! -- Clean up and return - if (allocated(words)) deallocate(words) + if (allocated(words)) deallocate (words) ! if (count_errors() > 0) then call this%parser%StoreErrorUnit() - endif + end if ! return end subroutine Initializetsfile @@ -1448,20 +1463,20 @@ logical function read_tsfile_line(this) ! -- Check if we've reached the end of the TIMESERIES block if (endOfBlock) then return - endif + end if ! ! -- Get the time tsrTime = this%parser%GetDouble() ! ! -- Construct a new record and append a new node to each time series - tsloop: do i=1,this%nTimeSeries + tsloop: do i = 1, this%nTimeSeries tsrValue = this%parser%GetDouble() if (tsrValue == DNODATA) cycle tsloop ! -- multiply value by sfac tsrValue = tsrValue * this%timeSeries(i)%sfac call ConstructTimeSeriesRecord(tsRecord, tsrTime, tsrValue) call AddTimeSeriesRecordToList(this%timeSeries(i)%list, tsRecord) - enddo tsloop + end do tsloop read_tsfile_line = .true. ! return @@ -1482,16 +1497,16 @@ subroutine tsf_da(this) ! ------------------------------------------------------------------------------ ! n = this%Count() - do i=1,n + do i = 1, n ts => this%GetTimeSeries(i) if (associated(ts)) then call ts%da() ! deallocate(ts) - endif - enddo + end if + end do ! - deallocate(this%timeSeries) - deallocate(this%parser) + deallocate (this%timeSeries) + deallocate (this%parser) ! return end subroutine tsf_da diff --git a/src/Utilities/TimeSeries/TimeSeriesFileList.f90 b/src/Utilities/TimeSeries/TimeSeriesFileList.f90 index 06bcfd1e8ef..f0dbd3a8f42 100644 --- a/src/Utilities/TimeSeries/TimeSeriesFileList.f90 +++ b/src/Utilities/TimeSeries/TimeSeriesFileList.f90 @@ -1,8 +1,8 @@ module TimeSeriesFileListModule use KindModule, only: DP, I4B - use ConstantsModule, only: LINELENGTH - use ListModule, only: ListType + use ConstantsModule, only: LINELENGTH + use ListModule, only: ListType use TimeSeriesModule, only: TimeSeriesFileType, & ConstructTimeSeriesFile, & GetTimeSeriesFileFromList, & @@ -19,13 +19,13 @@ module TimeSeriesFileListModule type(ListType), public :: tsfileList contains ! -- Public procedures - procedure, public :: Add - procedure, public :: Counttsfiles - procedure, public :: CountTimeSeries - procedure, public :: Gettsfile - procedure, public :: Clear - procedure, public :: da => tsfl_da - procedure, public :: add_time_series_tsfile + procedure, public :: Add + procedure, public :: Counttsfiles + procedure, public :: CountTimeSeries + procedure, public :: Gettsfile + procedure, public :: Clear + procedure, public :: da => tsfl_da + procedure, public :: add_time_series_tsfile end type TimeSeriesFileListType contains @@ -87,17 +87,17 @@ function CountTimeSeries(this) ! numtsfiles = this%Counttsfiles() CountTimeSeries = 0 - do i=1,numtsfiles + do i = 1, numtsfiles tsfile => this%Gettsfile(i) if (associated(tsfile)) then CountTimeSeries = CountTimeSeries + tsfile%Count() - endif - enddo + end if + end do ! return end function CountTimeSeries - function Gettsfile(this, indx) result (res) + function Gettsfile(this, indx) result(res) implicit none ! -- dummy class(TimeSeriesFileListType) :: this @@ -115,7 +115,7 @@ end function Gettsfile subroutine add_time_series_tsfile(this, tsfile) implicit none ! -- dummy - class(TimeSeriesFileListType), intent(inout) :: this + class(TimeSeriesFileListType), intent(inout) :: this class(TimeSeriesFileType), pointer, intent(inout) :: tsfile ! -- local ! @@ -132,10 +132,10 @@ subroutine tsfl_da(this) type(TimeSeriesFileType), pointer :: tsf => null() ! n = this%Counttsfiles() - do i=1,n + do i = 1, n tsf => this%Gettsfile(i) call tsf%da() - enddo + end do ! call this%tsfileList%Clear(.true.) ! diff --git a/src/Utilities/TimeSeries/TimeSeriesLink.f90 b/src/Utilities/TimeSeries/TimeSeriesLink.f90 index f755903306f..6379be6daf6 100644 --- a/src/Utilities/TimeSeries/TimeSeriesLink.f90 +++ b/src/Utilities/TimeSeries/TimeSeriesLink.f90 @@ -1,23 +1,23 @@ module TimeSeriesLinkModule use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, LENBOUNDNAME, LENPACKAGENAME, & - LENTIMESERIESTEXT + use ConstantsModule, only: DZERO, LENBOUNDNAME, LENPACKAGENAME, & + LENTIMESERIESTEXT use InputOutputModule, only: UPCASE - use ListModule, only: ListType - use TimeSeriesModule, only: TimeSeriesType + use ListModule, only: ListType + use TimeSeriesModule, only: TimeSeriesType implicit none private - public :: TimeSeriesLinkType, ConstructTimeSeriesLink, & + public :: TimeSeriesLinkType, ConstructTimeSeriesLink, & GetTimeSeriesLinkFromList, AddTimeSeriesLinkToList private :: CastAsTimeSeriesLinkType type :: TimeSeriesLinkType ! -- Public members - integer(I4B), public :: IRow = 0 ! row index (2nd dim) in bound or auxval array - integer(I4B), public :: JCol = 0 ! column index (1st dim) in bound or auxval array + integer(I4B), public :: IRow = 0 ! row index (2nd dim) in bound or auxval array + integer(I4B), public :: JCol = 0 ! column index (1st dim) in bound or auxval array integer(I4B), public :: Iprpak = 1 ! BndElement can point to an element in either the bound or auxval ! array of BndType, or any other double precision variable or array @@ -53,7 +53,7 @@ subroutine ConstructTimeSeriesLink(newTsLink, timeSeries, pkgName, & ! -- local character(len=LENPACKAGENAME) :: pkgNameTemp ! - allocate(newTsLink) + allocate (newTsLink) ! ! Store package name as all caps pkgNameTemp = pkgName @@ -68,7 +68,7 @@ subroutine ConstructTimeSeriesLink(newTsLink, timeSeries, pkgName, & ! if (present(text)) then newTsLink%Text = text - endif + end if ! return end subroutine ConstructTimeSeriesLink @@ -110,7 +110,7 @@ end function GetTimeSeriesLinkFromList subroutine AddTimeSeriesLinkToList(list, tslink) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(TimeSeriesLinkType), pointer, intent(inout) :: tslink ! -- local class(*), pointer :: obj diff --git a/src/Utilities/TimeSeries/TimeSeriesManager.f90 b/src/Utilities/TimeSeries/TimeSeriesManager.f90 index 065831a4bf3..157564a863f 100644 --- a/src/Utilities/TimeSeries/TimeSeriesManager.f90 +++ b/src/Utilities/TimeSeries/TimeSeriesManager.f90 @@ -1,43 +1,43 @@ module TimeSeriesManagerModule - use KindModule, only: DP, I4B - use ConstantsModule, only: DZERO, LENPACKAGENAME, MAXCHARLEN, & - LINELENGTH, LENTIMESERIESNAME - use HashTableModule, only: HashTableType, hash_table_cr, & - hash_table_da - use InputOutputModule, only: same_word, UPCASE - use ListModule, only: ListType - use SimModule, only: store_error, store_error_unit - use TdisModule, only: delt, kper, kstp, totim, totimc, & - totimsav - use TimeSeriesFileListModule, only: TimeSeriesFileListType - use TimeSeriesLinkModule, only: TimeSeriesLinkType, & - ConstructTimeSeriesLink, & - GetTimeSeriesLinkFromList, & - AddTimeSeriesLinkToList - use TimeSeriesModule, only: TimeSeriesContainerType, & - TimeSeriesFileType, & - TimeSeriesType + use KindModule, only: DP, I4B + use ConstantsModule, only: DZERO, LENPACKAGENAME, MAXCHARLEN, & + LINELENGTH, LENTIMESERIESNAME + use HashTableModule, only: HashTableType, hash_table_cr, & + hash_table_da + use InputOutputModule, only: same_word, UPCASE + use ListModule, only: ListType + use SimModule, only: store_error, store_error_unit + use TdisModule, only: delt, kper, kstp, totim, totimc, & + totimsav + use TimeSeriesFileListModule, only: TimeSeriesFileListType + use TimeSeriesLinkModule, only: TimeSeriesLinkType, & + ConstructTimeSeriesLink, & + GetTimeSeriesLinkFromList, & + AddTimeSeriesLinkToList + use TimeSeriesModule, only: TimeSeriesContainerType, & + TimeSeriesFileType, & + TimeSeriesType implicit none private - public :: TimeSeriesManagerType, read_value_or_time_series, & - read_value_or_time_series_adv, & + public :: TimeSeriesManagerType, read_value_or_time_series, & + read_value_or_time_series_adv, & var_timeseries, tsmanager_cr type TimeSeriesManagerType - integer(I4B), public :: iout = 0 ! output unit number - type(TimeSeriesFileListType), pointer, public :: tsfileList => null() ! list of ts files objs - type(ListType), pointer, public :: boundTsLinks => null() ! links to bound and aux - integer(I4B) :: numtsfiles = 0 ! number of ts files - character(len=MAXCHARLEN), allocatable, dimension(:) :: tsfiles ! list of ts files - logical, private :: removeTsLinksOnCompletion = .false. ! flag indicating whether time series links should be removed in ad() once simulation time passes the end of the time series - logical, private :: extendTsToEndOfSimulation = .false. ! flag indicating whether time series should be extended to provide their final value for all times after the series end time - type(ListType), pointer, private :: auxvarTsLinks => null() ! list of aux links - type(HashTableType), pointer, private :: BndTsHashTable => null() ! hash of ts to tsobj - type(TimeSeriesContainerType), allocatable, dimension(:), & - private :: TsContainers + integer(I4B), public :: iout = 0 ! output unit number + type(TimeSeriesFileListType), pointer, public :: tsfileList => null() ! list of ts files objs + type(ListType), pointer, public :: boundTsLinks => null() ! links to bound and aux + integer(I4B) :: numtsfiles = 0 ! number of ts files + character(len=MAXCHARLEN), allocatable, dimension(:) :: tsfiles ! list of ts files + logical, private :: removeTsLinksOnCompletion = .false. ! flag indicating whether time series links should be removed in ad() once simulation time passes the end of the time series + logical, private :: extendTsToEndOfSimulation = .false. ! flag indicating whether time series should be extended to provide their final value for all times after the series end time + type(ListType), pointer, private :: auxvarTsLinks => null() ! list of aux links + type(HashTableType), pointer, private :: BndTsHashTable => null() ! hash of ts to tsobj + type(TimeSeriesContainerType), allocatable, dimension(:), & + private :: TsContainers contains ! -- Public procedures procedure, public :: tsmanager_df @@ -53,9 +53,10 @@ module TimeSeriesManagerModule procedure, private :: make_link end type TimeSeriesManagerType - contains - - subroutine tsmanager_cr(this, iout, removeTsLinksOnCompletion, extendTsToEndOfSimulation) +contains + + subroutine tsmanager_cr(this, iout, removeTsLinksOnCompletion, & + extendTsToEndOfSimulation) ! ****************************************************************************** ! tsmanager_cr -- create the tsmanager ! ****************************************************************************** @@ -70,20 +71,20 @@ subroutine tsmanager_cr(this, iout, removeTsLinksOnCompletion, extendTsToEndOfSi ! ------------------------------------------------------------------------------ ! this%iout = iout - if(present(removeTsLinksOnCompletion)) then + if (present(removeTsLinksOnCompletion)) then this%removeTsLinksOnCompletion = removeTsLinksOnCompletion - endif - if(present(extendTsToEndOfSimulation)) then + end if + if (present(extendTsToEndOfSimulation)) then this%extendTsToEndOfSimulation = extendTsToEndOfSimulation - endif - allocate(this%boundTsLinks) - allocate(this%auxvarTsLinks) - allocate(this%tsfileList) - allocate(this%tsfiles(1000)) + end if + allocate (this%boundTsLinks) + allocate (this%auxvarTsLinks) + allocate (this%tsfileList) + allocate (this%tsfiles(1000)) ! return end subroutine tsmanager_cr - + subroutine tsmanager_df(this) ! ****************************************************************************** ! tsmanager_df -- define @@ -98,12 +99,12 @@ subroutine tsmanager_df(this) ! if (this%numtsfiles > 0) then call this%HashBndTimeSeries() - endif + end if ! ! -- return return end subroutine tsmanager_df - + subroutine add_tsfile(this, fname, inunit) ! ****************************************************************************** ! add_tsfile -- add a time series file to this manager @@ -128,29 +129,29 @@ subroutine add_tsfile(this, fname, inunit) if (this%numtsfiles > 0) then do i = 1, this%numtsfiles if (this%tsfiles(i) == fname) then - call store_error('Found duplicate time-series file name: ' // trim(fname)) + call store_error('Found duplicate time-series file name: '//trim(fname)) call store_error_unit(inunit) - endif - enddo - endif + end if + end do + end if ! ! -- Save fname this%numtsfiles = this%numtsfiles + 1 isize = size(this%tsfiles) if (this%numtsfiles > isize) then call ExpandArray(this%tsfiles, 1000) - endif + end if this%tsfiles(this%numtsfiles) = fname ! - ! -- + ! -- call this%tsfileList%Add(fname, this%iout, tsfile) ! return end subroutine add_tsfile - + subroutine tsmgr_ad(this) ! ****************************************************************************** -! tsmgr_ad -- time step (or subtime step) advance. Call this each time step or +! tsmgr_ad -- time step (or subtime step) advance. Call this each time step or ! subtime step. ! ****************************************************************************** ! @@ -163,15 +164,19 @@ subroutine tsmgr_ad(this) type(TimeSeriesType), pointer :: timeseries => null() integer(I4B) :: i, nlinks, nauxlinks real(DP) :: begintime, endtime, tsendtime - character(len=LENPACKAGENAME+2) :: pkgID + character(len=LENPACKAGENAME + 2) :: pkgID ! formats - character(len=*),parameter :: fmt5 = & - &"(/,'Time-series controlled values in stress period: ', i0, & - &', time step ', i0, ':')" - 10 format(a,' package: Boundary ',i0,', entry ',i0, ' value from time series "',a,'" = ',g12.5) - 15 format(a,' package: Boundary ',i0,', entry ',i0,' value from time series "',a,'" = ',g12.5,' (',a,')') - 20 format(a,' package: Boundary ',i0,', ',a,' value from time series "',a,'" = ',g12.5) - 25 format(a,' package: Boundary ',i0,', ',a,' value from time series "',a,'" = ',g12.5,' (',a,')') + character(len=*), parameter :: fmt5 = & + "(/,'Time-series controlled values in stress period: ', i0, & + &', time step ', i0, ':')" +10 format(a, ' package: Boundary ', i0, ', entry ', i0, & + ' value from time series "', a, '" = ', g12.5) +15 format(a, ' package: Boundary ', i0, ', entry ', i0, & + ' value from time series "', a, '" = ', g12.5, ' (', a, ')') +20 format(a, ' package: Boundary ', i0, ', ', a, & + ' value from time series "', a, '" = ', g12.5) +25 format(a, ' package: Boundary ', i0, ', ', a, & + ' value from time series "', a, '" = ', g12.5, ' (', a, ')') ! ------------------------------------------------------------------------------ ! ! -- Initialize time variables @@ -187,7 +192,7 @@ subroutine tsmgr_ad(this) ! appropriate time series. Need to do auxvartslinks ! first because they may be a multiplier column i = 1 - do while(i <= nauxlinks) + do while (i <= nauxlinks) tsLink => GetTimeSeriesLinkFromList(this%auxvarTsLinks, i) timeseries => tsLink%timeSeries ! @@ -198,50 +203,51 @@ subroutine tsmgr_ad(this) call this%auxvarTsLinks%RemoveNode(i, .TRUE.) nauxlinks = this%auxvartslinks%Count() cycle - endif - endif + end if + end if ! if (i == 1) then if (tsLink%Iprpak == 1) then - write(this%iout, fmt5) kper, kstp - endif - endif - tsLink%BndElement = timeseries%GetValue(begintime, endtime, this%extendTsToEndOfSimulation) + write (this%iout, fmt5) kper, kstp + end if + end if + tsLink%BndElement = timeseries%GetValue(begintime, endtime, & + this%extendTsToEndOfSimulation) ! ! -- Write time series values to output file if (tsLink%Iprpak == 1) then - pkgID = '"' // trim(tsLink%PackageName) // '"' + pkgID = '"'//trim(tsLink%PackageName)//'"' if (tsLink%Text == '') then if (tsLink%BndName == '') then - write(this%iout,10)trim(pkgID), tsLink%IRow, tsLink%JCol, & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement + write (this%iout, 10) trim(pkgID), tsLink%IRow, tsLink%JCol, & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement else - write(this%iout,15)trim(pkgID), tsLink%IRow, tsLink%JCol, & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement, trim(tsLink%BndName) - endif + write (this%iout, 15) trim(pkgID), tsLink%IRow, tsLink%JCol, & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement, trim(tsLink%BndName) + end if else if (tsLink%BndName == '') then - write(this%iout,20)trim(pkgID), tsLink%IRow, trim(tsLink%Text), & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement + write (this%iout, 20) trim(pkgID), tsLink%IRow, trim(tsLink%Text), & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement else - write(this%iout,25)trim(pkgID), tsLink%IRow, trim(tsLink%Text), & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement, trim(tsLink%BndName) - endif - endif - endif + write (this%iout, 25) trim(pkgID), tsLink%IRow, trim(tsLink%Text), & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement, trim(tsLink%BndName) + end if + end if + end if ! i = i + 1 - enddo + end do ! ! -- Iterate through boundtslinks and replace specified ! elements of bound with average value obtained from ! appropriate time series. (For list-type packages) i = 1 - do while(i <= nlinks) + do while (i <= nlinks) tsLink => GetTimeSeriesLinkFromList(this%boundTsLinks, i) timeseries => tsLink%timeSeries ! @@ -252,68 +258,69 @@ subroutine tsmgr_ad(this) call this%boundTsLinks%RemoveNode(i, .TRUE.) nlinks = this%boundTsLinks%Count() cycle - endif - endif + end if + end if ! if (i == 1 .and. nauxlinks == 0) then if (tsLink%Iprpak == 1) then - write(this%iout, fmt5) kper, kstp - endif - endif + write (this%iout, fmt5) kper, kstp + end if + end if ! this part needs to be different for MAW because MAW does not use ! bound array for well rate (although rate is stored in ! this%bound(4,ibnd)), it uses this%mawwells(n)%rate%value if (tsLink%UseDefaultProc) then timeseries => tsLink%timeSeries - tsLink%BndElement = timeseries%GetValue(begintime, endtime, this%extendTsToEndOfSimulation) + tsLink%BndElement = timeseries%GetValue(begintime, endtime, & + this%extendTsToEndOfSimulation) ! - ! -- If multiplier is active and it applies to this element, + ! -- If multiplier is active and it applies to this element, ! do the multiplication. This must be done after the auxlinks ! have been calculated in case iauxmultcol is being used. if (associated(tsLink%RMultiplier)) then tsLink%BndElement = tsLink%BndElement * tsLink%RMultiplier - endif + end if ! ! -- Write time series values to output files if (tsLink%Iprpak == 1) then - pkgID = '"' // trim(tsLink%PackageName) // '"' + pkgID = '"'//trim(tsLink%PackageName)//'"' if (tsLink%Text == '') then if (tsLink%BndName == '') then - write(this%iout,10)trim(pkgID), tsLink%IRow, tsLink%JCol, & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement + write (this%iout, 10) trim(pkgID), tsLink%IRow, tsLink%JCol, & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement else - write(this%iout,15)trim(pkgID), tsLink%IRow, tsLink%JCol, & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement, trim(tsLink%BndName) - endif + write (this%iout, 15) trim(pkgID), tsLink%IRow, tsLink%JCol, & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement, trim(tsLink%BndName) + end if else if (tsLink%BndName == '') then - write(this%iout,20)trim(pkgID), tsLink%IRow, trim(tsLink%Text), & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement + write (this%iout, 20) trim(pkgID), tsLink%IRow, trim(tsLink%Text), & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement else - write(this%iout,25)trim(pkgID), tsLink%IRow, trim(tsLink%Text), & - trim(tsLink%timeSeries%Name), & - tsLink%BndElement, trim(tsLink%BndName) - endif - endif - endif + write (this%iout, 25) trim(pkgID), tsLink%IRow, trim(tsLink%Text), & + trim(tsLink%timeSeries%Name), & + tsLink%BndElement, trim(tsLink%BndName) + end if + end if + end if ! ! -- If conversion from flux to flow is required, multiply by cell area if (tsLink%ConvertFlux) then tsLink%BndElement = tsLink%BndElement * tsLink%CellArea - endif - endif + end if + end if ! i = i + 1 - enddo + end do ! ! -- Finish with ending line if (nlinks + nauxlinks > 0) then if (tsLink%Iprpak == 1) then - write(this%iout,'()') - endif + write (this%iout, '()') + end if end if ! return @@ -333,22 +340,22 @@ subroutine tsmgr_da(this) ! ! -- Deallocate time-series links in boundTsLinks call this%boundTsLinks%Clear(.true.) - deallocate(this%boundTsLinks) + deallocate (this%boundTsLinks) ! ! -- Deallocate time-series links in auxvarTsLinks call this%auxvarTsLinks%Clear(.true.) - deallocate(this%auxvarTsLinks) + deallocate (this%auxvarTsLinks) ! ! -- Deallocate tsfileList call this%tsfileList%da() - deallocate(this%tsfileList) + deallocate (this%tsfileList) ! ! -- Deallocate the hash table if (associated(this%BndTsHashTable)) then call hash_table_da(this%BndTsHashTable) end if ! - deallocate(this%tsfiles) + deallocate (this%tsfiles) ! return end subroutine tsmgr_da @@ -365,7 +372,7 @@ subroutine Reset(this, pkgName) class(TimeSeriesManagerType) :: this character(len=*), intent(in) :: pkgName ! -- local - integer(I4B) :: i, nlinks + integer(I4B) :: i, nlinks type(TimeSeriesLinkType), pointer :: tslink ! ------------------------------------------------------------------------------ ! Zero out values for time-series controlled stresses. @@ -376,34 +383,34 @@ subroutine Reset(this, pkgName) ! ! Reassign all linked elements to zero nlinks = this%boundTsLinks%Count() - do i=1,nlinks + do i = 1, nlinks tslink => GetTimeSeriesLinkFromList(this%boundTsLinks, i) if (associated(tslink)) then if (tslink%PackageName == pkgName) then tslink%BndElement = DZERO - endif - endif - enddo + end if + end if + end do ! ! Remove links belonging to calling package nlinks = this%boundTsLinks%Count() - do i=nlinks,1,-1 + do i = nlinks, 1, -1 tslink => GetTimeSeriesLinkFromList(this%boundTsLinks, i) if (associated(tslink)) then if (tslink%PackageName == pkgName) then call this%boundTsLinks%RemoveNode(i, .true.) - endif - endif - enddo + end if + end if + end do nlinks = this%auxvarTsLinks%Count() - do i=nlinks,1,-1 - tslink => GetTimeSeriesLinkFromList(this%auxvarTsLinks,i) + do i = nlinks, 1, -1 + tslink => GetTimeSeriesLinkFromList(this%auxvarTsLinks, i) if (associated(tslink)) then if (tslink%PackageName == pkgName) then call this%auxvarTsLinks%RemoveNode(i, .true.) - endif - endif - enddo + end if + end if + end do ! return end subroutine Reset @@ -411,22 +418,22 @@ end subroutine Reset subroutine make_link(this, timeSeries, pkgName, auxOrBnd, bndElem, & irow, jcol, iprpak, tsLink, text, bndName) ! ****************************************************************************** -! make_link -- +! make_link -- ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeSeriesManagerType), intent(inout) :: this - type(TimeSeriesType), pointer, intent(inout) :: timeSeries - character(len=*), intent(in) :: pkgName - character(len=3), intent(in) :: auxOrBnd - real(DP), pointer, intent(inout) :: bndElem - integer(I4B), intent(in) :: irow, jcol - integer(I4B), intent(in) :: iprpak + class(TimeSeriesManagerType), intent(inout) :: this + type(TimeSeriesType), pointer, intent(inout) :: timeSeries + character(len=*), intent(in) :: pkgName + character(len=3), intent(in) :: auxOrBnd + real(DP), pointer, intent(inout) :: bndElem + integer(I4B), intent(in) :: irow, jcol + integer(I4B), intent(in) :: iprpak type(TimeSeriesLinkType), pointer, intent(inout) :: tsLink - character(len=*), intent(in) :: text - character(len=*), intent(in) :: bndName + character(len=*), intent(in) :: text + character(len=*), intent(in) :: bndName ! -- local ! ------------------------------------------------------------------------------ ! @@ -440,17 +447,17 @@ subroutine make_link(this, timeSeries, pkgName, auxOrBnd, bndElem, & call AddTimeSeriesLinkToList(this%auxvarTsLinks, tsLink) else call store_error('programmer error in make_link', terminate=.TRUE.) - endif + end if tsLink%Text = text tsLink%BndName = bndName - endif + end if ! return end subroutine make_link function GetLink(this, auxOrBnd, indx) result(tsLink) ! ****************************************************************************** -! GetLink -- +! GetLink -- ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -458,7 +465,7 @@ function GetLink(this, auxOrBnd, indx) result(tsLink) ! -- dummy class(TimeSeriesManagerType) :: this character(len=3), intent(in) :: auxOrBnd - integer(I4B), intent(in) :: indx + integer(I4B), intent(in) :: indx type(TimeSeriesLinkType), pointer :: tsLink ! -- local type(ListType), pointer :: list @@ -476,14 +483,14 @@ function GetLink(this, auxOrBnd, indx) result(tsLink) ! if (associated(list)) then tsLink => GetTimeSeriesLinkFromList(list, indx) - endif + end if ! return end function GetLink function CountLinks(this, auxOrBnd) ! ****************************************************************************** -! CountLinks -- +! CountLinks -- ! ****************************************************************************** ! ! SPECIFICATIONS: @@ -500,21 +507,21 @@ function CountLinks(this, auxOrBnd) CountLinks = this%boundTsLinks%Count() elseif (auxOrBnd == 'AUX') then CountLinks = this%auxvarTsLinks%count() - endif + end if ! return end function CountLinks - function get_time_series(this, name) result (res) + function get_time_series(this, name) result(res) ! ****************************************************************************** -! get_time_series -- +! get_time_series -- ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class(TimeSeriesManagerType) :: this - character(len=*), intent(in) :: name + class(TimeSeriesManagerType) :: this + character(len=*), intent(in) :: name ! -- result type(TimeSeriesType), pointer :: res ! -- local @@ -527,14 +534,14 @@ function get_time_series(this, name) result (res) indx = this%BndTsHashTable%get_index(name) if (indx > 0) then res => this%TsContainers(indx)%timeSeries - endif + end if ! return end function get_time_series subroutine HashBndTimeSeries(this) ! ****************************************************************************** -! HashBndTimeSeries -- +! HashBndTimeSeries -- ! Store all boundary (stress) time series links in ! TsContainers and construct hash table BndTsHashTable. ! ****************************************************************************** @@ -542,7 +549,7 @@ subroutine HashBndTimeSeries(this) ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - class (TimeSeriesManagerType), intent(inout) :: this + class(TimeSeriesManagerType), intent(inout) :: this ! -- local integer(I4B) :: i, j, k, numtsfiles, numts character(len=LENTIMESERIESNAME) :: name @@ -554,7 +561,7 @@ subroutine HashBndTimeSeries(this) ! ! Allocate the TsContainers array to accommodate all time-series links. numts = this%tsfileList%CountTimeSeries() - allocate(this%TsContainers(numts)) + allocate (this%TsContainers(numts)) ! ! Store a pointer to each time series in the TsContainers array ! and put its key (time-series name) and index in the hash table. @@ -563,51 +570,51 @@ subroutine HashBndTimeSeries(this) do i = 1, numtsfiles tsfile => this%tsfileList%Gettsfile(i) numts = tsfile%Count() - do j=1,numts + do j = 1, numts k = k + 1 this%TsContainers(k)%timeSeries => tsfile%GetTimeSeries(j) if (associated(this%TsContainers(k)%timeSeries)) then name = this%TsContainers(k)%timeSeries%Name call this%BndTsHashTable%add_entry(name, k) - endif - enddo - enddo + end if + end do + end do ! return end subroutine HashBndTimeSeries ! -- Non-type-bound procedures - subroutine read_value_or_time_series(textInput, ii, jj, bndElem, & - pkgName, auxOrBnd, tsManager, iprpak, tsLink) + subroutine read_value_or_time_series(textInput, ii, jj, bndElem, pkgName, & + auxOrBnd, tsManager, iprpak, tsLink) ! ****************************************************************************** -! read_value_or_time_series -- +! read_value_or_time_series -- ! Call this subroutine if the time-series link is available or needed. ! ****************************************************************************** ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - character(len=*), intent(in) :: textInput - integer(I4B), intent(in) :: ii - integer(I4B), intent(in) :: jj - real(DP), pointer, intent(inout) :: bndElem - character(len=*), intent(in) :: pkgName - character(len=3), intent(in) :: auxOrBnd - type(TimeSeriesManagerType), intent(inout) :: tsManager - integer(I4B), intent(in) :: iprpak + character(len=*), intent(in) :: textInput + integer(I4B), intent(in) :: ii + integer(I4B), intent(in) :: jj + real(DP), pointer, intent(inout) :: bndElem + character(len=*), intent(in) :: pkgName + character(len=3), intent(in) :: auxOrBnd + type(TimeSeriesManagerType), intent(inout) :: tsManager + integer(I4B), intent(in) :: iprpak type(TimeSeriesLinkType), pointer, intent(inout) :: tsLink ! -- local - type(TimeSeriesType), pointer :: timeseries => null() + type(TimeSeriesType), pointer :: timeseries => null() type(TimeSeriesLinkType), pointer :: tslTemp => null() - integer(I4B) :: i, istat, nlinks - real(DP) :: r + integer(I4B) :: i, istat, nlinks + real(DP) :: r character(len=LINELENGTH) :: errmsg character(len=LENTIMESERIESNAME) :: tsNameTemp logical :: found ! ------------------------------------------------------------------------------ ! - read (textInput,*,iostat=istat) r + read (textInput, *, iostat=istat) r if (istat == 0) then bndElem = r else @@ -621,53 +628,54 @@ subroutine read_value_or_time_series(textInput, ii, jj, bndElem, & if (associated(timeseries)) then ! -- Assign value from time series to current ! array element - r = timeseries%GetValue(totimsav, totim, tsManager%extendTsToEndOfSimulation) + r = timeseries%GetValue(totimsav, totim, & + tsManager%extendTsToEndOfSimulation) bndElem = r ! Look to see if this array element already has a time series ! linked to it. If not, make a link to it. nlinks = tsManager%CountLinks(auxOrBnd) found = .false. - searchlinks: do i=1,nlinks + searchlinks: do i = 1, nlinks tslTemp => tsManager%GetLink(auxOrBnd, i) if (tslTemp%PackageName == pkgName) then - ! -- Check ii, jj against iRow, jCol stored in link - if (tslTemp%IRow==ii .and. tslTemp%JCol==jj) then - ! -- This array element is already linked to a time series. - tsLink => tslTemp - found = .true. - exit searchlinks - endif - endif - enddo searchlinks + ! -- Check ii, jj against iRow, jCol stored in link + if (tslTemp%IRow == ii .and. tslTemp%JCol == jj) then + ! -- This array element is already linked to a time series. + tsLink => tslTemp + found = .true. + exit searchlinks + end if + end if + end do searchlinks if (.not. found) then ! -- Link was not found. Make one and add it to the list. - call tsManager%make_link(timeseries, pkgName, auxOrBnd, bndElem, & + call tsManager%make_link(timeseries, pkgName, auxOrBnd, bndElem, & ii, jj, iprpak, tsLink, '', '') - endif + end if else - errmsg = 'Error in list input. Expected numeric value or ' // & - "time-series name, but found '" // trim(textInput) // "'." + errmsg = 'Error in list input. Expected numeric value or '// & + "time-series name, but found '"//trim(textInput)//"'." call store_error(errmsg) - endif - endif + end if + end if end subroutine read_value_or_time_series - subroutine read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, & + subroutine read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, & auxOrBnd, tsManager, iprpak, varName) ! ****************************************************************************** -! read_value_or_time_series_adv -- Call this subroutine from advanced +! read_value_or_time_series_adv -- Call this subroutine from advanced ! packages to define timeseries link for a variable (varName). ! ! -- Arguments are as follows: ! textInput : string that is either a float or a string name -! ii : column number -! jj : row number -! bndElem : pointer to a position in an array in package pkgName +! ii : column number +! jj : row number +! bndElem : pointer to a position in an array in package pkgName ! pkgName : package name ! auxOrBnd : 'AUX' or 'BND' keyword ! tsManager : timeseries manager object for package ! iprpak : integer flag indicating if interpolated timeseries values -! should be printed to package iout during TsManager%ad() +! should be printed to package iout during TsManager%ad() ! varName : variable name ! ! ****************************************************************************** @@ -675,22 +683,22 @@ subroutine read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, & ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! -- dummy - character(len=*), intent(in) :: textInput - integer(I4B), intent(in) :: ii - integer(I4B), intent(in) :: jj - real(DP), pointer, intent(inout) :: bndElem - character(len=*), intent(in) :: pkgName - character(len=3), intent(in) :: auxOrBnd + character(len=*), intent(in) :: textInput + integer(I4B), intent(in) :: ii + integer(I4B), intent(in) :: jj + real(DP), pointer, intent(inout) :: bndElem + character(len=*), intent(in) :: pkgName + character(len=3), intent(in) :: auxOrBnd type(TimeSeriesManagerType), intent(inout) :: tsManager - integer(I4B), intent(in) :: iprpak - character(len=*), intent(in) :: varName + integer(I4B), intent(in) :: iprpak + character(len=*), intent(in) :: varName ! -- local integer(I4B) :: istat real(DP) :: v character(len=LINELENGTH) :: errmsg character(len=LENTIMESERIESNAME) :: tsNameTemp logical :: found - type(TimeSeriesType), pointer :: timeseries => null() + type(TimeSeriesType), pointer :: timeseries => null() type(TimeSeriesLinkType), pointer :: tsLink => null() ! ------------------------------------------------------------------------------ ! @@ -704,10 +712,10 @@ subroutine read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, & bndElem = v ! ! -- remove existing link if it exists for this boundary element - found = remove_existing_link(tsManager, ii, jj, pkgName, & + found = remove_existing_link(tsManager, ii, jj, pkgName, & auxOrBnd, varName) - ! - ! -- timeseries + ! + ! -- timeseries else ! ! -- attempt to read numeric value from textInput failed. @@ -724,37 +732,38 @@ subroutine read_value_or_time_series_adv(textInput, ii, jj, bndElem, pkgName, & if (associated(timeseries)) then ! ! -- Assign average value from time series to current array element - v = timeseries%GetValue(totimsav, totim, tsManager%extendTsToEndOfSimulation) + v = timeseries%GetValue(totimsav, totim, & + tsManager%extendTsToEndOfSimulation) bndElem = v ! ! -- remove existing link if it exists for this boundary element - found = remove_existing_link(tsManager, ii, jj, & + found = remove_existing_link(tsManager, ii, jj, & pkgName, auxOrBnd, varName) ! ! -- Add link to the list. - call tsManager%make_link(timeseries, pkgName, auxOrBnd, bndElem, & + call tsManager%make_link(timeseries, pkgName, auxOrBnd, bndElem, & ii, jj, iprpak, tsLink, varName, '') - ! - ! -- not a valid timeseries name + ! + ! -- not a valid timeseries name else - errmsg = 'Error in list input. Expected numeric value or ' // & - "time-series name, but found '" // trim(textInput) // "'." + errmsg = 'Error in list input. Expected numeric value or '// & + "time-series name, but found '"//trim(textInput)//"'." call store_error(errmsg) end if end if return end subroutine read_value_or_time_series_adv -! +! ! -- private subroutines - function remove_existing_link(tsManager, ii, jj, & + function remove_existing_link(tsManager, ii, jj, & pkgName, auxOrBnd, varName) result(found) ! ****************************************************************************** ! remove_existing_link -- remove an existing timeseries link if it is defined. ! ! -- Arguments are as follows: ! tsManager : timeseries manager object for package -! ii : column number -! jj : row number +! ii : column number +! jj : row number ! pkgName : package name ! auxOrBnd : 'AUX' or 'BND' keyword ! varName : variable name @@ -767,11 +776,11 @@ function remove_existing_link(tsManager, ii, jj, & logical :: found ! -- dummy type(TimeSeriesManagerType), intent(inout) :: tsManager - integer(I4B), intent(in) :: ii - integer(I4B), intent(in) :: jj - character(len=*), intent(in) :: pkgName - character(len=3), intent(in) :: auxOrBnd - character(len=*), intent(in) :: varName + integer(I4B), intent(in) :: ii + integer(I4B), intent(in) :: jj + character(len=*), intent(in) :: pkgName + character(len=3), intent(in) :: auxOrBnd + character(len=*), intent(in) :: varName ! -- local integer(I4B) :: i integer(I4B) :: nlinks @@ -786,12 +795,12 @@ function remove_existing_link(tsManager, ii, jj, & csearchlinks: do i = 1, nlinks tslTemp => tsManager%GetLink(auxOrBnd, i) ! - ! -- Check ii against iRow, jj against jCol, and varName + ! -- Check ii against iRow, jj against jCol, and varName ! against Text member of link if (tslTemp%PackageName == pkgName) then ! ! -- This array element is already linked to a time series. - if (tslTemp%IRow == ii .and. tslTemp%JCol == jj .and. & + if (tslTemp%IRow == ii .and. tslTemp%JCol == jj .and. & same_word(tslTemp%Text, varName)) then found = .TRUE. removeLink = i diff --git a/src/Utilities/TimeSeries/TimeSeriesRecord.f90 b/src/Utilities/TimeSeries/TimeSeriesRecord.f90 index b161f70d267..8bfb1bc735c 100644 --- a/src/Utilities/TimeSeries/TimeSeriesRecord.f90 +++ b/src/Utilities/TimeSeries/TimeSeriesRecord.f90 @@ -1,5 +1,5 @@ module TimeSeriesRecordModule - + use KindModule, only: DP, I4B use ListModule, only: ListType @@ -21,7 +21,7 @@ subroutine ConstructTimeSeriesRecord(newTsRecord, time, value) type(TimeSeriesRecordType), pointer, intent(out) :: newTsRecord real(DP), intent(in) :: time, value ! - allocate(newTsRecord) + allocate (newTsRecord) newTsRecord%tsrTime = time newTsRecord%tsrValue = value return @@ -46,7 +46,7 @@ end function CastAsTimeSeriesRecordType subroutine AddTimeSeriesRecordToList(list, tsrecord) implicit none ! -- dummy - type(ListType), intent(inout) :: list + type(ListType), intent(inout) :: list type(TimeSeriesRecordType), pointer, intent(inout) :: tsrecord ! -- local class(*), pointer :: obj => null() diff --git a/src/Utilities/Timer.f90 b/src/Utilities/Timer.f90 index 01b73632c8d..14358101ac4 100644 --- a/src/Utilities/Timer.f90 +++ b/src/Utilities/Timer.f90 @@ -1,5 +1,5 @@ module TimerModule - + use KindModule, only: DP, I4B use ConstantsModule, only: LINELENGTH, DZERO use GenericUtilitiesModule, only: sim_message @@ -9,9 +9,9 @@ module TimerModule public :: elapsed_time public :: code_timer integer(I4B), dimension(8) :: ibdt - - contains - + +contains + subroutine start_time() ! ****************************************************************************** ! Start simulation timer @@ -24,20 +24,20 @@ subroutine start_time() character(len=LINELENGTH) :: line integer(I4B) :: i ! -- format - character(len=*), parameter :: fmtdt = & - "(1X,'Run start date and time (yyyy/mm/dd hh:mm:ss): ', & + character(len=*), parameter :: fmtdt = & + "(1X,'Run start date and time (yyyy/mm/dd hh:mm:ss): ', & &I4,'/',I2.2,'/',I2.2,1X,I2,':',I2.2,':',I2.2)" ! ------------------------------------------------------------------------------ - ! + ! ! -- Get current date and time, assign to IBDT, and write to screen call date_and_time(values=ibdt) - write(line, fmtdt) (ibdt(i), i = 1, 3), (ibdt(i), i = 5, 7) + write (line, fmtdt) (ibdt(i), i=1, 3), (ibdt(i), i=5, 7) call sim_message(line, skipafter=1) ! ! -- return return end subroutine start_time - + SUBROUTINE elapsed_time(iout, iprtim) ! ****************************************************************************** ! Get end time and calculate elapsed time @@ -56,111 +56,111 @@ SUBROUTINE elapsed_time(iout, iprtim) integer(I4B) :: ndays, leap, ibd, ied, mb, me, nm, mc, m integer(I4B) :: nhours, nmins, nsecs, msecs, nrsecs real(DP) :: elsec, rsecs - DATA IDPM/31,28,31,30,31,30,31,31,30,31,30,31/ ! Days per month - DATA NSPD/86400/ ! Seconds per day + DATA IDPM/31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31/ ! Days per month + DATA NSPD/86400/ ! Seconds per day ! -- format - character(len=*), parameter :: fmtdt = & - "(1X,'Run end date and time (yyyy/mm/dd hh:mm:ss): ', & + character(len=*), parameter :: fmtdt = & + "(1X,'Run end date and time (yyyy/mm/dd hh:mm:ss): ', & &I4,'/',I2.2,'/',I2.2,1X,I2,':',I2.2,':',I2.2)" ! ------------------------------------------------------------------------------ ! ! Get current date and time, assign to IEDT, and write. - CALL DATE_AND_TIME(VALUES=IEDT) - ! - ! -- write elapsed time to stdout - write(line,fmtdt) (IEDT(I),I=1,3),(IEDT(I),I=5,7) - call sim_message(line, skipbefore=1) - ! - ! -- write elapsted time to iout - IF(IPRTIM.GT.0) THEN - call sim_message(line, iunit=iout, skipbefore=1) - END IF + CALL DATE_AND_TIME(VALUES=IEDT) + ! + ! -- write elapsed time to stdout + write (line, fmtdt) (IEDT(I), I=1, 3), (IEDT(I), I=5, 7) + call sim_message(line, skipbefore=1) + ! + ! -- write elapsted time to iout + IF (IPRTIM .GT. 0) THEN + call sim_message(line, iunit=iout, skipbefore=1) + END IF ! ! Calculate elapsed time in days and seconds - NDAYS=0 - LEAP=0 - IF (MOD(IEDT(1),4).EQ.0) LEAP = 1 - IBD = IBDT(3) ! BEGIN DAY - IED = IEDT(3) ! END DAY + NDAYS = 0 + LEAP = 0 + IF (MOD(IEDT(1), 4) .EQ. 0) LEAP = 1 + IBD = IBDT(3) ! BEGIN DAY + IED = IEDT(3) ! END DAY ! FIND DAYS - IF (IBDT(2).NE.IEDT(2)) THEN + IF (IBDT(2) .NE. IEDT(2)) THEN ! MONTHS DIFFER - MB = IBDT(2) ! BEGIN MONTH - ME = IEDT(2) ! END MONTH - NM = ME-MB+1 ! NUMBER OF MONTHS TO LOOK AT - IF (MB.GT.ME) NM = NM+12 - MC=MB-1 - DO M=1,NM - MC=MC+1 ! MC IS CURRENT MONTH - IF (MC.EQ.13) MC = 1 - IF (MC.EQ.MB) THEN - NDAYS = NDAYS+IDPM(MC)-IBD - IF (MC.EQ.2) NDAYS = NDAYS + LEAP - ELSEIF (MC.EQ.ME) THEN - NDAYS = NDAYS+IED - ELSE - NDAYS = NDAYS+IDPM(MC) - IF (MC.EQ.2) NDAYS = NDAYS + LEAP - ENDIF - ENDDO - ELSEIF (IBD.LT.IED) THEN + MB = IBDT(2) ! BEGIN MONTH + ME = IEDT(2) ! END MONTH + NM = ME - MB + 1 ! NUMBER OF MONTHS TO LOOK AT + IF (MB .GT. ME) NM = NM + 12 + MC = MB - 1 + DO M = 1, NM + MC = MC + 1 ! MC IS CURRENT MONTH + IF (MC .EQ. 13) MC = 1 + IF (MC .EQ. MB) THEN + NDAYS = NDAYS + IDPM(MC) - IBD + IF (MC .EQ. 2) NDAYS = NDAYS + LEAP + ELSEIF (MC .EQ. ME) THEN + NDAYS = NDAYS + IED + ELSE + NDAYS = NDAYS + IDPM(MC) + IF (MC .EQ. 2) NDAYS = NDAYS + LEAP + END IF + END DO + ELSEIF (IBD .LT. IED) THEN ! START AND END IN SAME MONTH, ONLY ACCOUNT FOR DAYS - NDAYS = IED-IBD - ENDIF - ELSEC=NDAYS*NSPD + NDAYS = IED - IBD + END IF + ELSEC = NDAYS * NSPD ! ! ADD OR SUBTRACT SECONDS - ELSEC = ELSEC+(IEDT(5)-IBDT(5))*3600.0 - ELSEC = ELSEC+(IEDT(6)-IBDT(6))*60.0 - ELSEC = ELSEC+(IEDT(7)-IBDT(7)) - ELSEC = ELSEC+(IEDT(8)-IBDT(8))*0.001 + ELSEC = ELSEC + (IEDT(5) - IBDT(5)) * 3600.0 + ELSEC = ELSEC + (IEDT(6) - IBDT(6)) * 60.0 + ELSEC = ELSEC + (IEDT(7) - IBDT(7)) + ELSEC = ELSEC + (IEDT(8) - IBDT(8)) * 0.001 ! ! CONVERT SECONDS TO DAYS, HOURS, MINUTES, AND SECONDS - NDAYS = INT(ELSEC/NSPD) - RSECS = MOD(ELSEC, 86400.0_DP) - NHOURS = INT(RSECS/3600.0) - RSECS = MOD(RSECS,3600.0_DP) - NMINS = INT(RSECS/60.0) - RSECS = MOD(RSECS,60.0_DP) - NSECS = INT(RSECS) - RSECS = MOD(RSECS,1.0_DP) - MSECS = NINT(RSECS*1000.0) - NRSECS = NSECS - IF (RSECS.GE.0.5) NRSECS=NRSECS+1 + NDAYS = INT(ELSEC / NSPD) + RSECS = MOD(ELSEC, 86400.0_DP) + NHOURS = INT(RSECS / 3600.0) + RSECS = MOD(RSECS, 3600.0_DP) + NMINS = INT(RSECS / 60.0) + RSECS = MOD(RSECS, 60.0_DP) + NSECS = INT(RSECS) + RSECS = MOD(RSECS, 1.0_DP) + MSECS = NINT(RSECS * 1000.0) + NRSECS = NSECS + IF (RSECS .GE. 0.5) NRSECS = NRSECS + 1 ! ! Write elapsed time to screen - IF (NDAYS.GT.0) THEN - WRITE(line, 1010) NDAYS,NHOURS,NMINS,NRSECS - 1010 FORMAT(1X,'Elapsed run time: ',I3,' Days, ',I2,' Hours, ',I2, & - ' Minutes, ',I2,' Seconds') - ELSEIF (NHOURS.GT.0) THEN - WRITE(line, 1020) NHOURS,NMINS,NRSECS - 1020 FORMAT(1X,'Elapsed run time: ',I2,' Hours, ',I2, & - ' Minutes, ',I2,' Seconds') - ELSEIF (NMINS.GT.0) THEN - WRITE(line, 1030) NMINS,NSECS,MSECS - 1030 FORMAT(1X,'Elapsed run time: ',I2,' Minutes, ', & - I2,'.',I3.3,' Seconds') - ELSE - WRITE(line, 1040) NSECS,MSECS - 1040 FORMAT(1X,'Elapsed run time: ',I2,'.',I3.3,' Seconds') - ENDIF - call sim_message(line, skipafter=1) + IF (NDAYS .GT. 0) THEN + WRITE (line, 1010) NDAYS, NHOURS, NMINS, NRSECS +1010 FORMAT(1X, 'Elapsed run time: ', I3, ' Days, ', I2, ' Hours, ', I2, & + ' Minutes, ', I2, ' Seconds') + ELSEIF (NHOURS .GT. 0) THEN + WRITE (line, 1020) NHOURS, NMINS, NRSECS +1020 FORMAT(1X, 'Elapsed run time: ', I2, ' Hours, ', I2, & + ' Minutes, ', I2, ' Seconds') + ELSEIF (NMINS .GT. 0) THEN + WRITE (line, 1030) NMINS, NSECS, MSECS +1030 FORMAT(1X, 'Elapsed run time: ', I2, ' Minutes, ', & + I2, '.', I3.3, ' Seconds') + ELSE + WRITE (line, 1040) NSECS, MSECS +1040 FORMAT(1X, 'Elapsed run time: ', I2, '.', I3.3, ' Seconds') + END IF + call sim_message(line, skipafter=1) ! ! Write times to file if requested - IF(IPRTIM.GT.0) THEN - IF (NDAYS.GT.0) THEN - WRITE(IOUT,1010) NDAYS,NHOURS,NMINS,NRSECS - ELSEIF (NHOURS.GT.0) THEN - WRITE(IOUT,1020) NHOURS,NMINS,NRSECS - ELSEIF (NMINS.GT.0) THEN - WRITE(IOUT,1030) NMINS,NSECS,MSECS - ELSE - WRITE(IOUT,1040) NSECS,MSECS - ENDIF - ENDIF + IF (IPRTIM .GT. 0) THEN + IF (NDAYS .GT. 0) THEN + WRITE (IOUT, 1010) NDAYS, NHOURS, NMINS, NRSECS + ELSEIF (NHOURS .GT. 0) THEN + WRITE (IOUT, 1020) NHOURS, NMINS, NRSECS + ELSEIF (NMINS .GT. 0) THEN + WRITE (IOUT, 1030) NMINS, NSECS, MSECS + ELSE + WRITE (IOUT, 1040) NSECS, MSECS + END IF + END IF ! - RETURN + RETURN END SUBROUTINE elapsed_time ! @@ -190,5 +190,5 @@ SUBROUTINE code_timer(it, t1, ts) ! -- RETURN RETURN END SUBROUTINE code_timer - + end module TimerModule diff --git a/src/Utilities/VectorInt.f90 b/src/Utilities/VectorInt.f90 index 91fbc060880..589c9771875 100644 --- a/src/Utilities/VectorInt.f90 +++ b/src/Utilities/VectorInt.f90 @@ -1,47 +1,48 @@ module VectorIntModule - use KindModule, only: I4B + use KindModule, only: I4B, LGP use SimModule, only: ustop use ArrayHandlersModule, only: ExpandArray implicit none private - public :: VectorInt - + public :: VectorInt + integer(I4B), parameter :: defaultInitialCapacity = 4 - + ! This is a dynamic vector type for integers type :: VectorInt integer(I4B), private, allocatable :: values(:) ! the internal array for storage - integer(I4B) :: size ! the number of elements (technically this stuff should be unsigned) - integer(I4B) :: capacity ! the reserved storage + integer(I4B) :: size ! the number of elements (technically this stuff should be unsigned) + integer(I4B) :: capacity ! the reserved storage contains - procedure, pass(this) :: init ! allocate memory, init size and capacity - procedure, pass(this) :: push_back ! adds an element at the end of the vector - procedure, pass(this) :: at ! random access, unsafe, no bounds checking - procedure, pass(this) :: at_safe ! random access with bounds checking - procedure, pass(this) :: clear ! empties the vector, leaves memory unchanged - procedure, pass(this) :: shrink_to_fit ! reduces the allocated memory to fit the actual vector size - procedure, pass(this) :: destroy ! deletes the memory + procedure, pass(this) :: init ! allocate memory, init size and capacity + procedure, pass(this) :: push_back ! adds an element at the end of the vector + procedure, pass(this) :: at ! random access, unsafe, no bounds checking + procedure, pass(this) :: at_safe ! random access with bounds checking + procedure, pass(this) :: clear ! empties the vector, leaves memory unchanged + procedure, pass(this) :: shrink_to_fit ! reduces the allocated memory to fit the actual vector size + procedure, pass(this) :: destroy ! deletes the memory + procedure, pass(this) :: contains ! true when element already present ! private procedure, private, pass(this) :: expand end type VectorInt contains ! module routines - + subroutine init(this, capacity) class(VectorInt), intent(inout) :: this integer(I4B), intent(in), optional :: capacity ! the initial capacity, when given - + if (present(capacity)) then this%capacity = capacity else this%capacity = defaultInitialCapacity - end if - - allocate(this%values(this%capacity)) + end if + + allocate (this%values(this%capacity)) this%size = 0 - + end subroutine init - + subroutine push_back(this, newValue) class(VectorInt), intent(inout) :: this integer(I4B) :: newValue @@ -49,95 +50,114 @@ subroutine push_back(this, newValue) if (this%size + 1 > this%capacity) then call this%expand() end if - + this%size = this%size + 1 this%values(this%size) = newValue - + end subroutine push_back - + function at(this, idx) result(value) class(VectorInt), intent(inout) :: this - integer(I4B), intent(in) :: idx - integer(I4B) :: value - + integer(I4B), intent(in) :: idx + integer(I4B) :: value + value = this%values(idx) - + end function at - + function at_safe(this, idx) result(value) class(VectorInt), intent(inout) :: this - integer(I4B), intent(in) :: idx - integer(I4B) :: value - + integer(I4B), intent(in) :: idx + integer(I4B) :: value + if (idx > this%size) then - write(*,*) 'VectorInt exception: access out of bounds, index ', idx, ' exceeds actual size (', this%size, ')' + write (*, *) 'VectorInt exception: access out of bounds, index ', idx, & + ' exceeds actual size (', this%size, ')' call ustop() end if value = this%at(idx) - + end function at_safe - + subroutine clear(this) class(VectorInt), intent(inout) :: this - + ! really, this is all there is to it... this%size = 0 - + end subroutine clear - + subroutine shrink_to_fit(this) class(VectorInt), intent(inout) :: this ! local integer(I4B), allocatable :: tempValues(:) integer(I4B) :: i, newSize - + if (this%size == this%capacity) then - return + return end if - + ! store temp newSize = this%size - allocate(tempValues(newSize)) + allocate (tempValues(newSize)) do i = 1, newSize - tempValues(i) = this%values(i) + tempValues(i) = this%values(i) end do - + ! reinit call this%destroy() call this%init(newSize) - + ! copy back do i = 1, newSize - call this%push_back(tempValues(i)) + call this%push_back(tempValues(i)) end do - + end subroutine shrink_to_fit - + subroutine destroy(this) class(VectorInt), intent(inout) :: this - + if (allocated(this%values)) then - deallocate(this%values) + deallocate (this%values) this%size = 0 this%capacity = 0 else - write(*,*) 'VectorInt exception: cannot delete an unallocated array' + write (*, *) 'VectorInt exception: cannot delete an unallocated array' call ustop() end if - + end subroutine destroy - + ! expand the array with the given strategy, at ! least by 1 subroutine expand(this) class(VectorInt), intent(inout) :: this integer(I4B) :: increment - + ! expansion strategy - increment = this%capacity/2 + 1 + increment = this%capacity / 2 + 1 call ExpandArray(this%values, increment) this%capacity = this%capacity + increment - + end subroutine expand - + + ! check if the element is already present + function contains(this, val) result(res) + class(VectorInt), intent(inout) :: this + integer(I4B) :: val + logical(LGP) :: res + ! local + integer(I4B) :: i + + res = .false. + do i = 1, this%size + if (this%at(i) == val) then + res = .true. + return + end if + end do + + end function contains + end module VectorIntModule diff --git a/src/Utilities/comarg.f90 b/src/Utilities/comarg.f90 index 9eae7118541..f9d328dee06 100644 --- a/src/Utilities/comarg.f90 +++ b/src/Utilities/comarg.f90 @@ -1,14 +1,14 @@ module CommandArguments use KindModule - use ConstantsModule, only: LINELENGTH, LENBIGLINE, LENHUGELINE, & - VSUMMARY, VALL, VDEBUG, & + use ConstantsModule, only: LINELENGTH, LENBIGLINE, LENHUGELINE, & + VSUMMARY, VALL, VDEBUG, & MVALIDATE - use VersionModule, only: VERSION, MFVNAM, IDEVELOPMODE, & - FMTDISCLAIMER, FMTLICENSE + use VersionModule, only: VERSION, MFVNAM, IDEVELOPMODE, & + FMTDISCLAIMER, FMTLICENSE use CompilerVersion - use SimVariablesModule, only: istdout, isim_level, & - simfile, simlstfile, simstdout, & - isim_mode + use SimVariablesModule, only: istdout, isim_level, & + simfile, simlstfile, simstdout, & + isim_mode use GenericUtilitiesModule, only: sim_message, write_message use SimModule, only: store_error, ustop use InputOutputModule, only: upcase, getunit @@ -18,8 +18,8 @@ module CommandArguments private public :: GetCommandLineArguments ! - contains - +contains + !> @brief Get command line arguments !! !! Subroutine to get and write information on command line arguments. @@ -56,7 +56,7 @@ subroutine GetCommandLineArguments() call get_command_argument(0, cexe) cexe = adjustl(cexe) ! - ! -- find the program basename, not including the path (this should be + ! -- find the program basename, not including the path (this should be ! mf6.exe, mf6d.exe, etc.) ipos = index(cexe, '/', back=.TRUE.) if (ipos == 0) then @@ -71,8 +71,8 @@ subroutine GetCommandLineArguments() ! ! -- write header call get_compile_date(cdate) - write(header, '(a,4(1x,a),a)') & - trim(adjustl(cexe)), '- MODFLOW', & + write (header, '(a,4(1x,a),a)') & + trim(adjustl(cexe)), '- MODFLOW', & trim(adjustl(VERSION)), '(compiled', trim(adjustl(cdate)), ')' ! ! -- set ctyp @@ -88,12 +88,12 @@ subroutine GetCommandLineArguments() do iarg = 1, icountcmd call get_command_argument(iarg, uctag) call upcase(uctag) - if (trim(adjustl(uctag)) == '-S' .or. & - trim(adjustl(uctag)) == '--SILENT') then + if (trim(adjustl(uctag)) == '-S' .or. & + trim(adjustl(uctag)) == '--SILENT') then ! ! -- get file unit and open mfsim.stdout istdout = getunit() - open(unit=istdout, file=trim(adjustl(simstdout))) + open (unit=istdout, file=trim(adjustl(simstdout))) ! ! -- exit loop exit @@ -127,9 +127,9 @@ subroutine GetCommandLineArguments() if (ipos > 0) then ipos = index(tag, '=') ilen = len_trim(tag) - clevel = tag(ipos+1:ilen) + clevel = tag(ipos + 1:ilen) call upcase(clevel) - uctag = tag(1:ipos-1) + uctag = tag(1:ipos - 1) call upcase(uctag) end if ! @@ -139,110 +139,110 @@ subroutine GetCommandLineArguments() if (ipos > 0) then ipos = index(tag, '=') ilen = len_trim(tag) - cmode = tag(ipos+1:ilen) + cmode = tag(ipos + 1:ilen) call upcase(cmode) - uctag = tag(1:ipos-1) + uctag = tag(1:ipos - 1) call upcase(uctag) end if ! ! -- evaluate the command line argument (uctag) - select case(trim(adjustl(uctag))) - case('-H', '-?', '--HELP') - lstop = .TRUE. + select case (trim(adjustl(uctag))) + case ('-H', '-?', '--HELP') + lstop = .TRUE. + call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) + case ('-V', '--VERSION') + lstop = .TRUE. + write (line, '(2a,2(1x,a))') & + trim(adjustl(cexe)), ':', trim(adjustl(VERSION)), ctyp + call write_message(line, skipbefore=1, skipafter=1) + case ('-DEV', '--DEVELOP') + lstop = .TRUE. + write (line, '(2a,g0)') & + trim(adjustl(cexe)), ': develop version ', ltyp + call write_message(line, skipbefore=1, skipafter=1) + case ('-C', '--COMPILER') + lstop = .TRUE. + call get_compiler(compiler) + write (line, '(2a,1x,a)') & + trim(adjustl(cexe)), ':', trim(adjustl(compiler)) + call write_message(line, skipbefore=1, skipafter=1) + case ('-S', '--SILENT') + write (line, '(2a,1x,a)') & + trim(adjustl(cexe)), ':', 'all screen output sent to mfsim.stdout' + call write_message(line, skipbefore=1, skipafter=1) + case ('-D', '--DISCLAIMER') + lstop = .TRUE. + call sim_message('', fmt=FMTDISCLAIMER) + case ('-LIC', '--LICENSE') + lstop = .TRUE. + call sim_message('', fmt=FMTLICENSE) + case ('-CO', '--COMPILER-OPT') + lstop = .TRUE. + call get_compile_options(coptions) + call write_message(coptions, skipbefore=1, skipafter=1) + case ('-L', '--LEVEL') + if (len_trim(clevel) < 1) then + iarg = iarg + 1 + call get_command_argument(iarg, clevel) + call upcase(clevel) + end if + select case (trim(adjustl(clevel))) + case ('SUMMARY') + isim_level = VSUMMARY + case ('DEBUG') + isim_level = VDEBUG + case default call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) - case('-V', '--VERSION') - lstop = .TRUE. - write(line, '(2a,2(1x,a))') & - trim(adjustl(cexe)), ':', trim(adjustl(VERSION)), ctyp - call write_message(line, skipbefore=1, skipafter=1) - case('-DEV', '--DEVELOP') - lstop = .TRUE. - write(line, '(2a,g0)') & - trim(adjustl(cexe)), ': develop version ', ltyp - call write_message(line, skipbefore=1, skipafter=1) - case('-C', '--COMPILER') - lstop = .TRUE. - call get_compiler(compiler) - write(line, '(2a,1x,a)') & - trim(adjustl(cexe)), ':', trim(adjustl(compiler)) - call write_message(line, skipbefore=1, skipafter=1) - case('-S', '--SILENT') - write(line, '(2a,1x,a)') & - trim(adjustl(cexe)), ':', 'all screen output sent to mfsim.stdout' - call write_message(line, skipbefore=1, skipafter=1) - case('-D', '--DISCLAIMER') - lstop = .TRUE. - call sim_message('', fmt=FMTDISCLAIMER) - case('-LIC', '--LICENSE') - lstop = .TRUE. - call sim_message('', fmt=FMTLICENSE) - case('-CO', '--COMPILER-OPT') - lstop = .TRUE. - call get_compile_options(coptions) - call write_message(coptions, skipbefore=1, skipafter=1) - case('-L', '--LEVEL') - if (len_trim(clevel) < 1) then - iarg = iarg + 1 - call get_command_argument(iarg, clevel) - call upcase(clevel) - end if - select case(trim(adjustl(clevel))) - case('SUMMARY') - isim_level = VSUMMARY - case('DEBUG') - isim_level = VDEBUG - case default - call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) - write(errmsg, '(2a,1x,a)') & - trim(adjustl(cexe)), ': illegal STDOUT level option -', & - trim(adjustl(clevel)) - call store_error(errmsg) - end select - ! - ! -- write message to stdout - write(line, '(2a,2(1x,a))') & - trim(adjustl(cexe)), ':', 'stdout output level', & + write (errmsg, '(2a,1x,a)') & + trim(adjustl(cexe)), ': illegal STDOUT level option -', & trim(adjustl(clevel)) - call write_message(line, skipbefore=1, skipafter=1) - case('-M', '--MODE') - if (len_trim(cmode) < 1) then - iarg = iarg + 1 - call get_command_argument(iarg, cmode) - call upcase(cmode) - end if - select case(trim(adjustl(cmode))) - case('VALIDATE') - isim_mode = MVALIDATE - case default - call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) - errmsg = trim(adjustl(cexe)) // ': illegal MODFLOW 6 ' // & - 'simulation mode option - ' // trim(adjustl(cmode)) - call store_error(errmsg, terminate=.TRUE.) - end select - ! - ! -- write message to stdout - line = trim(adjustl(cexe)) // ': MODFLOW 6 simulation mode ' // & - trim(adjustl(cmode)) // '. Model input will be checked for all ' // & - 'stress periods but the matrix equations will not be ' // & - 'assembled or solved.' - call write_message(line, skipbefore=1, skipafter=1) + call store_error(errmsg) + end select + ! + ! -- write message to stdout + write (line, '(2a,2(1x,a))') & + trim(adjustl(cexe)), ':', 'stdout output level', & + trim(adjustl(clevel)) + call write_message(line, skipbefore=1, skipafter=1) + case ('-M', '--MODE') + if (len_trim(cmode) < 1) then + iarg = iarg + 1 + call get_command_argument(iarg, cmode) + call upcase(cmode) + end if + select case (trim(adjustl(cmode))) + case ('VALIDATE') + isim_mode = MVALIDATE case default - lstop = .TRUE. call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) - write(errmsg, '(2a,1x,a)') & - trim(adjustl(cexe)), ': illegal option -', trim(adjustl(tag)) + errmsg = trim(adjustl(cexe))//': illegal MODFLOW 6 '// & + 'simulation mode option - '//trim(adjustl(cmode)) call store_error(errmsg, terminate=.TRUE.) + end select + ! + ! -- write message to stdout + line = trim(adjustl(cexe))//': MODFLOW 6 simulation mode '// & + trim(adjustl(cmode))//'. Model input will be checked for all '// & + 'stress periods but the matrix equations will not be '// & + 'assembled or solved.' + call write_message(line, skipbefore=1, skipafter=1) + case default + lstop = .TRUE. + call write_usage(trim(adjustl(header)), trim(adjustl(cexe))) + write (errmsg, '(2a,1x,a)') & + trim(adjustl(cexe)), ': illegal option -', trim(adjustl(tag)) + call store_error(errmsg, terminate=.TRUE.) end select end do ! ! -- check if simfile exists, only if the model should be run if (.not. lstop) then - inquire(file=trim(adjustl(simfile)), exist=lexist) + inquire (file=trim(adjustl(simfile)), exist=lexist) if (.NOT. lexist) then lstop = .TRUE. - write(errmsg, '(2a,2(1x,a))') & - trim(adjustl(cexe)), ':', trim(adjustl(simfile)), & - 'is not present in working directory.' + write (errmsg, '(2a,2(1x,a))') & + trim(adjustl(cexe)), ':', trim(adjustl(simfile)), & + 'is not present in working directory.' call store_error(errmsg, terminate=.TRUE.) end if end if @@ -260,7 +260,7 @@ subroutine GetCommandLineArguments() ! -- return return end subroutine GetCommandLineArguments - + !> @brief Write command line argument usage !! !! Subroutine to write usage information for command line arguments. @@ -268,48 +268,48 @@ end subroutine GetCommandLineArguments !< subroutine write_usage(header, cexe) ! -- dummy variables - character(len=*), intent(in) :: header !< header for usage - character(len=*), intent(in) :: cexe !< executable name + character(len=*), intent(in) :: header !< header for usage + character(len=*), intent(in) :: cexe !< executable name ! -- local variables character(len=LINELENGTH) :: line ! -- format - character(len=*), parameter :: OPTIONSFMT = & - "(/, & - &'Options GNU long option Meaning ',/, & - &' -h, -? --help Show this message',/, & - &' -v --version Display program version information.',/, & - &' -dev --develop Display program develop option mode.',/, & - &' -d --disclaimer Display program disclaimer.',/, & - &' -lic --license Display program license information.',/, & - &' -c --compiler Display compiler information.',/, & - &' -co --compiler-opt Display compiler options.',/, & - &' -s --silent All STDOUT to mfsim.stdout.',/, & - &' -l --level STDOUT output to screen based on .',/, & - &' =summary Limited output to STDOUT.',/, & - &' =debug Enhanced output to STDOUT.',/, & + character(len=*), parameter :: OPTIONSFMT = & + "(/,& + &'Options GNU long option Meaning ',/,& + &' -h, -? --help Show this message',/,& + &' -v --version Display program version information.',/,& + &' -dev --develop Display program develop option mode.',/,& + &' -d --disclaimer Display program disclaimer.',/,& + &' -lic --license Display program license information.',/,& + &' -c --compiler Display compiler information.',/,& + &' -co --compiler-opt Display compiler options.',/,& + &' -s --silent All STDOUT to mfsim.stdout.',/,"// & + "' -l --level STDOUT output to screen based on .',/,& + &' =summary Limited output to STDOUT.',/,& + &' =debug Enhanced output to STDOUT.',/,& &' -m --mode MODFLOW 6 simulation mode based on .',/,& - &' =validate Check model input for',/, & - &' errors but do not ',/, & - &' assemble or solve matrix ',/, & - &' equations or write ',/, & - &' solution output.',/, & - &' ',/, & - &'Bug reporting and contributions are welcome from the community. ',/, & - &'Questions can be asked on the issues page[1]. Before creating a new',/, & - &'issue, please take a moment to search and make sure a similar issue',/, & - &'does not already exist. If one does exist, you can comment (most',/, & - &'simply even with just :+1:) to show your support for that issue.',/, & - &' ',/, & + &' =validate Check model input for',/,& + &' errors but do not ',/,& + &' assemble or solve matrix ',/,& + &' equations or write ',/,& + &' solution output.',/,"// & + "' ',/,& + &'Bug reporting and contributions are welcome from the community. ',/,& + &'Questions can be asked on the issues page[1]. Before creating a new',/,& + &'issue, please take a moment to search and make sure a similar issue',/,& + &'does not already exist. If one does exist, you can comment (most',/,& + &'simply even with just :+1:) to show your support for that issue.',/,& + &' ',/,& &'[1] https://github.com/MODFLOW-USGS/modflow6/issues',/)" ! ! -- write command line usage information to the screen call sim_message(header) - write(line, '(a,1x,a,15x,a,2(1x,a),2a)') & - 'usage:', cexe, 'run MODFLOW', trim(adjustl(MFVNAM)), & + write (line, '(a,1x,a,15x,a,2(1x,a),2a)') & + 'usage:', cexe, 'run MODFLOW', trim(adjustl(MFVNAM)), & 'using "', trim(adjustl(simfile)), '"' call sim_message(line) - write(line, '(a,1x,a,1x,a,5x,a)') & - ' or:', cexe, '[options]', & + write (line, '(a,1x,a,1x,a,5x,a)') & + ' or:', cexe, '[options]', & 'retrieve program information' call sim_message(line) call sim_message('', fmt=OPTIONSFMT) @@ -317,5 +317,5 @@ subroutine write_usage(header, cexe) ! -- return return end subroutine write_usage - -end module CommandArguments \ No newline at end of file + +end module CommandArguments diff --git a/src/Utilities/compilerversion.F90 b/src/Utilities/compilerversion.F90 index 4f701dad114..e9801e8b12d 100644 --- a/src/Utilities/compilerversion.F90 +++ b/src/Utilities/compilerversion.F90 @@ -7,10 +7,10 @@ module CompilerVersion implicit none private ! -- compiler version - character(len=10) :: ccompiler !< compiler string - character(len=10) :: cversion !< compiler version string - character(len=20) :: cdate !< compilation date - integer(I4B) :: icompiler = CUNKNOWN !< compiler enum + character(len=10) :: ccompiler !< compiler string + character(len=10) :: cversion !< compiler version string + character(len=20) :: cdate !< compilation date + integer(I4B) :: icompiler = CUNKNOWN !< compiler enum public :: get_compiler, get_compile_date, get_compile_options contains @@ -34,7 +34,7 @@ subroutine get_compiler(txt) #endif #ifdef _CRAYFTN icompiler = CCRAYFTN - cdate = __DATE__ // ' ' // __TIME__ + cdate = __DATE__//' '//__TIME__ #endif ! ! -- set compiler strings @@ -45,7 +45,7 @@ subroutine get_compiler(txt) end if ! ! -- write string with compiler information - write (txt, '(a,4(1x,a))') & + write (txt, '(a,3(1x,a))') & 'MODFLOW 6 compiled', trim(adjustl(cdate)), & 'with', trim(adjustl(compiler_version())) ! @@ -60,7 +60,7 @@ end subroutine get_compiler !< subroutine get_compile_date(txt) ! -- dummy variables - character(len=20), intent(inout) :: txt !< compilation date + character(len=20), intent(inout) :: txt !< compilation date ! -- set variables #ifdef __GFORTRAN__ cdate = __DATE__//' '//__TIME__ @@ -69,7 +69,7 @@ subroutine get_compile_date(txt) cdate = __DATE__//' '//__TIME__ #endif #ifdef _CRAYFTN - cdate = __DATE__ // ' ' // __TIME__ + cdate = __DATE__//' '//__TIME__ #endif ! ! -- write compilation date string @@ -86,7 +86,7 @@ end subroutine get_compile_date !< subroutine get_compile_options(txt) ! -- dummy variables - character(len=LENBIGLINE), intent(inout) :: txt !< compilation options + character(len=LENBIGLINE), intent(inout) :: txt !< compilation options ! -- set variables ! ! -- set txt string diff --git a/src/Utilities/genericutils.f90 b/src/Utilities/genericutils.f90 index 188fc721614..549e3476d17 100644 --- a/src/Utilities/genericutils.f90 +++ b/src/Utilities/genericutils.f90 @@ -1,6 +1,6 @@ !> @brief This module contains generic utilties !! -!! This module contains generic utilities that have +!! This module contains generic utilities that have !! limited dependencies. !! !< @@ -11,33 +11,33 @@ module GenericUtilitiesModule LINELENGTH, LENHUGELINE, VSUMMARY use SimVariablesModule, only: istdout, isim_level ! - implicit none - + implicit none + private - + public :: sim_message public :: write_message public :: write_centered public :: is_same public :: stop_with_error - contains +contains !> @brief Write simulation message !! !! Subroutine to print message to user specified iunit or STDOUT based on level. !! !< - subroutine sim_message(message, iunit, fmt, level, & + subroutine sim_message(message, iunit, fmt, level, & skipbefore, skipafter, advance) ! -- dummy variables - character(len=*), intent(in) :: message !< message to write to iunit - integer(I4B), intent(in), optional :: iunit !< optional file unit to write the message to (default=stdout) - character(len=*), intent(in), optional :: fmt !< optional format to write the message (default='(a)') - integer(I4B), intent(in), optional :: level !< optional level for the message (default=summary) - integer(I4B), intent(in), optional :: skipbefore !< optional number of empty lines before message (default=0) - integer(I4B), intent(in), optional :: skipafter !< optional number of empty lines after message (default=0) - logical(LGP), intent(in), optional :: advance !< optional boolean indicating if advancing output (default is .TRUE.) + character(len=*), intent(in) :: message !< message to write to iunit + integer(I4B), intent(in), optional :: iunit !< optional file unit to write the message to (default=stdout) + character(len=*), intent(in), optional :: fmt !< optional format to write the message (default='(a)') + integer(I4B), intent(in), optional :: level !< optional level for the message (default=summary) + integer(I4B), intent(in), optional :: skipbefore !< optional number of empty lines before message (default=0) + integer(I4B), intent(in), optional :: skipafter !< optional number of empty lines after message (default=0) + logical(LGP), intent(in), optional :: advance !< optional boolean indicating if advancing output (default is .TRUE.) ! -- local variables character(len=3) :: cadvance integer(I4B) :: i @@ -84,7 +84,7 @@ subroutine sim_message(message, iunit, fmt, level, & ! -- write empty line before message if (present(skipbefore)) then do i = 1, skipbefore - write(iu, *) + write (iu, *) end do end if ! @@ -92,16 +92,16 @@ subroutine sim_message(message, iunit, fmt, level, & ! or equal the isim_level for the simulation if (ilevel <= isim_level) then if (ilen > 0) then - write(iu, trim(simfmt), advance=cadvance) message(1:ilen) + write (iu, trim(simfmt), advance=cadvance) message(1:ilen) else - write(iu, trim(simfmt), advance=cadvance) + write (iu, trim(simfmt), advance=cadvance) end if end if ! ! -- write empty line after message if (present(skipafter)) then do i = 1, skipafter - write(iu, *) + write (iu, *) end do end if ! @@ -111,7 +111,7 @@ end subroutine sim_message !> @brief Write messages !! - !! Subroutine that formats and writes a single message that + !! Subroutine that formats and writes a single message that !! may exceeed 78 characters in length. Messages longer than !! 78 characters are written across multiple lines. When a !! counter is passed in subsequent lines are indented. @@ -120,32 +120,32 @@ end subroutine sim_message subroutine write_message(message, icount, iwidth, iunit, level, & skipbefore, skipafter) ! -- dummy variables - character (len=*), intent(in) :: message !< message to be written - integer(I4B), intent(in), optional :: icount !< counter to prepended to the message - integer(I4B), intent(in), optional :: iwidth !< maximum width of the prepended counter - integer(I4B), intent(in), optional :: iunit !< the unit number to which the message is written - integer(I4B), intent(in), optional :: level !< level of message (VSUMMARY, VALL, VDEBUG) - integer(I4B), intent(in), optional :: skipbefore !< optional number of empty lines before message (default=0) - integer(I4B), intent(in), optional :: skipafter !< optional number of empty lines after message (default=0) + character(len=*), intent(in) :: message !< message to be written + integer(I4B), intent(in), optional :: icount !< counter to prepended to the message + integer(I4B), intent(in), optional :: iwidth !< maximum width of the prepended counter + integer(I4B), intent(in), optional :: iunit !< the unit number to which the message is written + integer(I4B), intent(in), optional :: level !< level of message (VSUMMARY, VALL, VDEBUG) + integer(I4B), intent(in), optional :: skipbefore !< optional number of empty lines before message (default=0) + integer(I4B), intent(in), optional :: skipafter !< optional number of empty lines after message (default=0) ! -- local variables - integer(I4B), parameter :: len_line=78 + integer(I4B), parameter :: len_line = 78 character(len=LENHUGELINE) :: amessage - character(len=len_line) :: line - character(len=16) :: cfmt - character(len=10) :: counter - character(len=5) :: fmt_first - character(len=20) :: fmt_cont - logical(LGP) :: include_counter - integer(I4B) :: isb - integer(I4B) :: isa - integer(I4B) :: jend - integer(I4B) :: len_str1 - integer(I4B) :: len_str2 - integer(I4B) :: len_message - integer(I4B) :: junit - integer(I4B) :: ilevel - integer(I4B) :: i - integer(I4B) :: j + character(len=len_line) :: line + character(len=16) :: cfmt + character(len=10) :: counter + character(len=5) :: fmt_first + character(len=20) :: fmt_cont + logical(LGP) :: include_counter + integer(I4B) :: isb + integer(I4B) :: isa + integer(I4B) :: jend + integer(I4B) :: len_str1 + integer(I4B) :: len_str2 + integer(I4B) :: len_message + integer(I4B) :: junit + integer(I4B) :: ilevel + integer(I4B) :: i + integer(I4B) :: j ! ! -- return if no message is passed if (len_trim(message) < 1) then @@ -162,10 +162,10 @@ subroutine write_message(message, icount, iwidth, iunit, level, & include_counter = .FALSE. junit = istdout j = 0 - ! + ! ! -- process optional dummy variables ! -- set the unit number - if(present(iunit))then + if (present(iunit)) then if (iunit > 0) then junit = iunit end if @@ -193,18 +193,18 @@ subroutine write_message(message, icount, iwidth, iunit, level, & end if ! ! -- create the counter to prepend to the start of the message, - ! formats, and variables used to create strings + ! formats, and variables used to create strings if (present(iwidth) .and. present(icount)) then include_counter = .TRUE. ! -- write counter - write(cfmt, '(A,I0,A)') '(1x,i', iwidth, ',".",1x)' - write(counter, cfmt) icount + write (cfmt, '(A,I0,A)') '(1x,i', iwidth, ',".",1x)' + write (counter, cfmt) icount ! -- calculate the length of the first and second string on a line len_str1 = len(trim(counter)) + 1 len_str2 = len_line - len_str1 ! -- write format for the continuation lines - write(fmt_cont, '(a,i0,a)') & - '(',len(trim(counter)) + 1, 'x,a)' + write (fmt_cont, '(a,i0,a)') & + '(', len(trim(counter)) + 1, 'x,a)' end if ! ! -- calculate the length of the message @@ -214,19 +214,19 @@ subroutine write_message(message, icount, iwidth, iunit, level, & 5 continue jend = j + len_str2 if (jend >= len_message) go to 100 - do i = jend, j+1, -1 - if (amessage(i:i).eq.' ') then + do i = jend, j + 1, -1 + if (amessage(i:i) .eq. ' ') then if (j == 0) then if (include_counter) then - line = counter(1:len_str1)//amessage(j+1:i) + line = counter(1:len_str1)//amessage(j + 1:i) else - line = amessage(j+1:i) + line = amessage(j + 1:i) end if call sim_message(line, iunit=junit, & fmt=fmt_first, level=ilevel, & skipbefore=isb) else - line = adjustl(amessage(j+1:i)) + line = adjustl(amessage(j + 1:i)) call sim_message(line, iunit=junit, & fmt=fmt_cont, level=ilevel) end if @@ -236,15 +236,15 @@ subroutine write_message(message, icount, iwidth, iunit, level, & end do if (j == 0) then if (include_counter) then - line = counter(1:len_str1)//amessage(j+1:jend) + line = counter(1:len_str1)//amessage(j + 1:jend) else - line = amessage(j+1:jend) + line = amessage(j + 1:jend) end if call sim_message(line, iunit=junit, & fmt=fmt_first, level=ilevel, & skipbefore=isb) else - line = amessage(j+1:jend) + line = amessage(j + 1:jend) call sim_message(line, iunit=junit, & fmt=fmt_cont, level=ilevel) end if @@ -256,15 +256,15 @@ subroutine write_message(message, icount, iwidth, iunit, level, & jend = len_message if (j == 0) then if (include_counter) then - line = counter(1:len_str1)//amessage(j+1:jend) + line = counter(1:len_str1)//amessage(j + 1:jend) else - line = amessage(j+1:jend) + line = amessage(j + 1:jend) end if call sim_message(line, iunit=junit, & fmt=fmt_first, level=ilevel, & skipbefore=isb, skipafter=isa) else - line = amessage(j+1:jend) + line = amessage(j + 1:jend) call sim_message(line, iunit=junit, fmt=fmt_cont, & level=ilevel, & skipafter=isa) @@ -276,15 +276,15 @@ end subroutine write_message !> @brief Write centered text !! - !! Subroutine to write text to unit iunit centered in width defined by linelen. + !! Subroutine to write text to unit iunit centered in width defined by linelen. !! Left-pad with blanks as needed. !! !< subroutine write_centered(text, linelen, iunit) ! -- dummy variables - character(len=*), intent(in) :: text !< message to write to iunit - integer(I4B), intent(in) :: linelen !< length of line to center text in - integer(I4B), intent(in), optional :: iunit !< optional file unit to write text (default=stdout) + character(len=*), intent(in) :: text !< message to write to iunit + integer(I4B), intent(in) :: linelen !< length of line to center text in + integer(I4B), intent(in), optional :: iunit !< optional file unit to write text (default=stdout) ! -- local variables character(len=linelen) :: line character(len=linelen) :: blank @@ -314,17 +314,17 @@ subroutine write_centered(text, linelen, iunit) 5 continue jend = j + linelen if (jend >= len_message) go to 100 - do i = jend, j+1, -1 - if (text(i:i).eq.' ') then - line = text(j+1:i) - ipad = ((linelen - len_trim(line)) / 2) + do i = jend, j + 1, -1 + if (text(i:i) .eq. ' ') then + line = text(j + 1:i) + ipad = ((linelen - len_trim(line)) / 2) call sim_message(blank(1:ipad)//line, iunit=iu) j = i go to 5 end if end do - line = text(j+1:jend) - ipad = ((linelen - len_trim(line)) / 2) + line = text(j + 1:jend) + ipad = ((linelen - len_trim(line)) / 2) call sim_message(blank(1:ipad)//line, iunit=iu) j = jend go to 5 @@ -332,28 +332,28 @@ subroutine write_centered(text, linelen, iunit) ! -- last piece of amessage to write to a line 100 continue jend = len_message - line = text(j+1:jend) - ipad = ((linelen - len_trim(line)) / 2) + line = text(j + 1:jend) + ipad = ((linelen - len_trim(line)) / 2) call sim_message(blank(1:ipad)//line, iunit=iu) end if ! ! -- return return end subroutine write_centered - + !> @brief Function to determine if two reals are the same !! - !! Function to evaluate if the difference between a and b are less than eps + !! Function to evaluate if the difference between a and b are less than eps !! (i.e. a and b are the same). !! !< function is_same(a, b, eps) result(lvalue) ! -- return variable - logical(LGP) :: lvalue !< boolean indicating if a and b are the same + logical(LGP) :: lvalue !< boolean indicating if a and b are the same ! -- dummy variables - real(DP), intent(in) :: a !< first number to evaluate - real(DP), intent(in) :: b !< second number to evaluate - real(DP), intent(in), optional :: eps !< optional maximum difference between a abd b (default=DSAME) + real(DP), intent(in) :: a !< first number to evaluate + real(DP), intent(in) :: b !< second number to evaluate + real(DP), intent(in), optional :: eps !< optional maximum difference between a abd b (default=DSAME) ! -- local variables real(DP) :: epsloc real(DP) :: denom @@ -364,7 +364,7 @@ function is_same(a, b, eps) result(lvalue) epsloc = eps else epsloc = DSAME - endif + end if lvalue = .FALSE. if (a == b) then lvalue = .TRUE. @@ -377,7 +377,7 @@ function is_same(a, b, eps) result(lvalue) denom = DPREC end if end if - rdiff = abs( (a - b) / denom ) + rdiff = abs((a - b) / denom) if (rdiff <= epsloc) then lvalue = .TRUE. end if @@ -394,7 +394,7 @@ end function is_same !< subroutine stop_with_error(ierr) ! -- dummy variables - integer(I4B), intent(in), optional :: ierr !< optional error code to return (default=0) + integer(I4B), intent(in), optional :: ierr !< optional error code to return (default=0) ! -- local variables integer(I4B) :: ireturn_err ! @@ -404,10 +404,10 @@ subroutine stop_with_error(ierr) else ireturn_err = 0 end if - + ! -- return the correct return code call exit(ireturn_err) - - end subroutine stop_with_error - end module GenericUtilitiesModule \ No newline at end of file + end subroutine stop_with_error + +end module GenericUtilitiesModule diff --git a/src/Utilities/kind.f90 b/src/Utilities/kind.f90 index e258a239389..42d2da55f92 100644 --- a/src/Utilities/kind.f90 +++ b/src/Utilities/kind.f90 @@ -6,57 +6,58 @@ !! !< module KindModule - use, intrinsic:: iso_fortran_env, only: I4B => int32, & - I8B => int64, & - LGP => int32, & - DP => real64 - + use, intrinsic :: iso_fortran_env, only: I4B => int32, & + &I8B => int64, & + &LGP => int32, & + &DP => real64 + implicit none - public:: I4B, I8B, LGP, DP, write_kindinfo + public :: I4B, I8B, LGP, DP, write_kindinfo + +contains - contains - - !> @brief Write variable data types + !> @brief Write variable data types !! !! This subroutine writes the precision of logical, integer, long integer, !! and real data types used in MODFLOW 6. !! - !< - subroutine write_kindinfo(iout) - ! -- dummy variables - integer(I4B), intent(in) :: iout !< file unit to output kind variables - ! -- local variables - integer(LGP) :: ldum = 0 - integer(I4B) :: idum = 0 - integer(I8B) :: long_idum = 0 - integer(DP) :: irdum = 0 ! for bit size of real variables - real(DP) :: rdum = 0._DP - ! - ! -- write kind information - write(iout, '(/a)') 'Real Variables' - write(iout, '(2x,a,i0)') 'KIND: ', DP - write(iout, '(2x,a,1pg15.6)') 'TINY (smallest non-zero value): ', tiny(rdum) - write(iout, '(2x,a,1pg15.6)') 'HUGE (largest value): ', huge(rdum) - write(iout, '(2x,a,i0)') 'PRECISION: ', precision(rdum) - write(iout, '(2x,a,i0)') 'BIT SIZE: ', bit_size(irdum) - - write(iout, '(/a)') 'Integer Variables' - write(iout, '(2x,a,i0)') 'KIND: ', I4B - write(iout, '(2x,a,i0)') 'HUGE (largest value): ', huge(idum) - write(iout, '(2x,a,i0)') 'BIT SIZE: ', bit_size(idum) - - write(iout, '(/a)') 'Long Integer Variables' - write(iout, '(2x,a,i0)') 'KIND: ', I8B - write(iout, '(2x,a,i0)') 'HUGE (largest value): ', huge(long_idum) - write(iout, '(2x,a,i0)') 'BIT SIZE: ', bit_size(long_idum) - - write(iout, '(/a)') 'Logical Variables' - write(iout, '(2x,a,i0)') 'KIND: ', LGP - write(iout, '(2x,a,i0)') 'BIT SIZE: ', bit_size(ldum) - ! - ! -- Return - return - end subroutine write_kindinfo - + !< + subroutine write_kindinfo(iout) + ! -- dummy variables + integer(I4B), intent(in) :: iout !< file unit to output kind variables + ! -- local variables + integer(LGP) :: ldum = 0 + integer(I4B) :: idum = 0 + integer(I8B) :: long_idum = 0 + integer(DP) :: irdum = 0 ! for bit size of real variables + real(DP) :: rdum = 0._DP + ! + ! -- write kind information + write (iout, '(/a)') 'Real Variables' + write (iout, '(2x,a,i0)') 'KIND: ', DP + write (iout, '(2x,a,1pg15.6)') 'TINY (smallest non-zero value): ', & + tiny(rdum) + write (iout, '(2x,a,1pg15.6)') 'HUGE (largest value): ', huge(rdum) + write (iout, '(2x,a,i0)') 'PRECISION: ', precision(rdum) + write (iout, '(2x,a,i0)') 'SIZE IN BITS: ', bit_size(irdum) + + write (iout, '(/a)') 'Integer Variables' + write (iout, '(2x,a,i0)') 'KIND: ', I4B + write (iout, '(2x,a,i0)') 'HUGE (largest value): ', huge(idum) + write (iout, '(2x,a,i0)') 'SIZE IN BITS: ', bit_size(idum) + + write (iout, '(/a)') 'Long Integer Variables' + write (iout, '(2x,a,i0)') 'KIND: ', I8B + write (iout, '(2x,a,i0)') 'HUGE (largest value): ', huge(long_idum) + write (iout, '(2x,a,i0)') 'SIZE IN BITS: ', bit_size(long_idum) + + write (iout, '(/a)') 'Logical Variables' + write (iout, '(2x,a,i0)') 'KIND: ', LGP + write (iout, '(2x,a,i0)') 'SIZE IN BITS: ', bit_size(ldum) + ! + ! -- Return + return + end subroutine write_kindinfo + end module KindModule diff --git a/src/Utilities/sort.f90 b/src/Utilities/sort.f90 index 7fdc63e7292..4cc637a3511 100644 --- a/src/Utilities/sort.f90 +++ b/src/Utilities/sort.f90 @@ -11,514 +11,511 @@ module SortModule interface qsort module procedure qsort_int1d, qsort_dbl1d end interface - + interface unique_values module procedure unique_values_int1d, unique_values_dbl1d end interface - - contains - subroutine qsort_int1d(indx, v, reverse) +contains + subroutine qsort_int1d(indx, v, reverse) ! ************************************************************************** ! qsort -- quick sort that also includes an index number ! ************************************************************************** ! ! SPECIFICATIONS: ! -------------------------------------------------------------------------- - ! -- dummy arguments - integer(I4B), dimension(:), intent(inout) :: indx - integer(I4B), dimension(:), intent(inout) :: v - logical, intent(in), optional :: reverse - ! -- local variables - logical :: lrev - integer(I4B), parameter :: nn=15 - integer(I4B), parameter :: nstack=50 - integer(I4B) :: nsize - integer(I4B) :: k - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: jstack - integer(I4B) :: ileft - integer(I4B) :: iright - integer(I4B), dimension(nstack) :: istack - integer(I4B) :: iidx - integer(I4B) :: ia - integer(I4B) :: a - ! -- functions - ! -- code - ! - ! -- process optional dummy variables - if (present(reverse)) then - lrev = reverse + ! -- dummy arguments + integer(I4B), dimension(:), intent(inout) :: indx + integer(I4B), dimension(:), intent(inout) :: v + logical, intent(in), optional :: reverse + ! -- local variables + logical :: lrev + integer(I4B), parameter :: nn = 15 + integer(I4B), parameter :: nstack = 50 + integer(I4B) :: nsize + integer(I4B) :: k + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: jstack + integer(I4B) :: ileft + integer(I4B) :: iright + integer(I4B), dimension(nstack) :: istack + integer(I4B) :: iidx + integer(I4B) :: ia + integer(I4B) :: a + ! -- functions + ! -- code + ! + ! -- process optional dummy variables + if (present(reverse)) then + lrev = reverse + else + lrev = .FALSE. + end if + ! + ! -- initialize variables + nsize = size(v) + jstack = 0 + ileft = 1 + iright = nsize + ! + ! -- perform quicksort + do + if (iright - ileft < nn) then + do j = (ileft + 1), iright + a = v(j) + iidx = indx(j) + do i = (j - 1), ileft, -1 + if (v(i) <= a) exit + v(i + 1) = v(i) + indx(i + 1) = indx(i) + end do + v(i + 1) = a + indx(i + 1) = iidx + end do + if (jstack == 0) return + iright = istack(jstack) + ileft = istack(jstack - 1) + jstack = jstack - 2 else - lrev = .FALSE. - endif - ! - ! -- initialize variables - nsize = size(v) - jstack = 0 - ileft = 1 - iright = nsize - ! - ! -- perform quicksort - do - if (iright - ileft < nn) then - do j = (ileft + 1), iright - a = v(j) - iidx = indx(j) - do i = (j - 1), ileft, -1 - if (v(i) <= a) exit - v(i+ 1) = v(i) - indx(i+ 1) = indx(i) - end do - v(i + 1) = a - indx(i + 1) = iidx + k = (ileft + iright) / 2 + call iswap(v(k), v(ileft + 1)) + call iswap(indx(k), indx(ileft + 1)) + if (v(ileft) > v(iright)) then + call iswap(v(ileft), v(iright)) + call iswap(indx(ileft), indx(iright)) + end if + if (v(ileft + 1) > v(iright)) then + call iswap(v(ileft + 1), v(iright)) + call iswap(indx(ileft + 1), indx(iright)) + end if + if (v(ileft) > v(ileft + 1)) then + call iswap(v(ileft), v(ileft + 1)) + call iswap(indx(ileft), indx(ileft + 1)) + end if + i = ileft + 1 + j = iright + a = v(ileft + 1) + ia = indx(ileft + 1) + do + do + i = i + 1 + if (v(i) >= a) then + exit + end if end do - if (jstack == 0) return - iright = istack(jstack) - ileft = istack(jstack - 1) - jstack = jstack - 2 - else - k = (ileft + iright)/2 - call iswap(v(k), v(ileft + 1)) - call iswap(indx(k), indx(ileft + 1)) - if (v(ileft) > v(iright)) then - call iswap(v(ileft), v(iright)) - call iswap(indx(ileft), indx(iright)) - end if - if (v(ileft + 1) > v(iright)) then - call iswap(v(ileft + 1), v(iright)) - call iswap(indx(ileft + 1), indx(iright)) - end if - if (v(ileft) > v(ileft + 1)) then - call iswap(v(ileft), v(ileft + 1)) - call iswap(indx(ileft), indx(ileft + 1)) - end if - i = ileft + 1 - j = iright - a = v(ileft + 1) - ia = indx(ileft + 1) do - do - i = i + 1 - if (v(i) >= a) then - exit - end if - end do - do - j = j - 1 - if (v(j) <= a) then - exit - end if - end do - if (j < i) then + j = j - 1 + if (v(j) <= a) then exit end if - call iswap(v(i), v(j)) - call iswap(indx(i), indx(j)) end do - v(ileft + 1) = v(j) - indx(ileft + 1) = indx(j) - v(j) = a - indx(j) = ia - jstack = jstack + 2 - if (jstack > nstack) then - write(errmsg,'(4x,a,3(1x,a))') & - 'JSTACK > NSTACK IN SortModule::qsort' - call store_error(errmsg, terminate=.TRUE.) - end if - if ((iright - i + 1) >= (j - 1)) then - istack(jstack) = iright - istack(jstack - 1) = i - iright = j - 1 - else - istack(jstack) = j - 1 - istack(jstack - 1) = ileft - ileft = i + if (j < i) then + exit end if - end if - end do - ! - ! -- reverse order of the heap index - if (lrev) then - j = nsize - do i = 1, nsize / 2 call iswap(v(i), v(j)) call iswap(indx(i), indx(j)) - j = j - 1 end do + v(ileft + 1) = v(j) + indx(ileft + 1) = indx(j) + v(j) = a + indx(j) = ia + jstack = jstack + 2 + if (jstack > nstack) then + write (errmsg, '(4x,a,3(1x,a))') & + 'JSTACK > NSTACK IN SortModule::qsort' + call store_error(errmsg, terminate=.TRUE.) + end if + if ((iright - i + 1) >= (j - 1)) then + istack(jstack) = iright + istack(jstack - 1) = i + iright = j - 1 + else + istack(jstack) = j - 1 + istack(jstack - 1) = ileft + ileft = i + end if end if - ! - ! -- return - return - end subroutine qsort_int1d + end do + ! + ! -- reverse order of the heap index + if (lrev) then + j = nsize + do i = 1, nsize / 2 + call iswap(v(i), v(j)) + call iswap(indx(i), indx(j)) + j = j - 1 + end do + end if + ! + ! -- return + return + end subroutine qsort_int1d - subroutine qsort_dbl1d(indx, v, reverse) + subroutine qsort_dbl1d(indx, v, reverse) ! ************************************************************************** ! qsort -- quick sort that also includes an index number ! ************************************************************************** ! ! SPECIFICATIONS: ! -------------------------------------------------------------------------- - ! -- dummy arguments - integer(I4B), dimension(:), intent(inout) :: indx - real(DP), dimension(:), intent(inout) :: v - logical, intent(in), optional :: reverse - ! -- local variables - logical :: lrev - integer(I4B), parameter :: nn=15 - integer(I4B), parameter :: nstack=50 - integer(I4B) :: nsize - integer(I4B) :: k - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: jstack - integer(I4B) :: ileft - integer(I4B) :: iright - integer(I4B), dimension(nstack) :: istack - integer(I4B) :: iidx - integer(I4B) :: ia - real(DP) :: a - ! -- functions - ! -- code - ! - ! -- process optional dummy variables - if (present(reverse)) then - lrev = reverse + ! -- dummy arguments + integer(I4B), dimension(:), intent(inout) :: indx + real(DP), dimension(:), intent(inout) :: v + logical, intent(in), optional :: reverse + ! -- local variables + logical :: lrev + integer(I4B), parameter :: nn = 15 + integer(I4B), parameter :: nstack = 50 + integer(I4B) :: nsize + integer(I4B) :: k + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: jstack + integer(I4B) :: ileft + integer(I4B) :: iright + integer(I4B), dimension(nstack) :: istack + integer(I4B) :: iidx + integer(I4B) :: ia + real(DP) :: a + ! -- functions + ! -- code + ! + ! -- process optional dummy variables + if (present(reverse)) then + lrev = reverse + else + lrev = .FALSE. + end if + ! + ! -- initialize variables + nsize = size(v) + jstack = 0 + ileft = 1 + iright = nsize + ! + ! -- perform quicksort + do + if (iright - ileft < nn) then + do j = (ileft + 1), iright + a = v(j) + iidx = indx(j) + do i = (j - 1), ileft, -1 + if (v(i) <= a) exit + v(i + 1) = v(i) + indx(i + 1) = indx(i) + end do + v(i + 1) = a + indx(i + 1) = iidx + end do + if (jstack == 0) return + iright = istack(jstack) + ileft = istack(jstack - 1) + jstack = jstack - 2 else - lrev = .FALSE. - endif - ! - ! -- initialize variables - nsize = size(v) - jstack = 0 - ileft = 1 - iright = nsize - ! - ! -- perform quicksort - do - if (iright - ileft < nn) then - do j = (ileft + 1), iright - a = v(j) - iidx = indx(j) - do i = (j - 1), ileft, -1 - if (v(i) <= a) exit - v(i+ 1) = v(i) - indx(i+ 1) = indx(i) - end do - v(i + 1) = a - indx(i + 1) = iidx + k = (ileft + iright) / 2 + call rswap(v(k), v(ileft + 1)) + call iswap(indx(k), indx(ileft + 1)) + if (v(ileft) > v(iright)) then + call rswap(v(ileft), v(iright)) + call iswap(indx(ileft), indx(iright)) + end if + if (v(ileft + 1) > v(iright)) then + call rswap(v(ileft + 1), v(iright)) + call iswap(indx(ileft + 1), indx(iright)) + end if + if (v(ileft) > v(ileft + 1)) then + call rswap(v(ileft), v(ileft + 1)) + call iswap(indx(ileft), indx(ileft + 1)) + end if + i = ileft + 1 + j = iright + a = v(ileft + 1) + ia = indx(ileft + 1) + do + do + i = i + 1 + if (v(i) >= a) then + exit + end if end do - if (jstack == 0) return - iright = istack(jstack) - ileft = istack(jstack - 1) - jstack = jstack - 2 - else - k = (ileft + iright)/2 - call rswap(v(k), v(ileft + 1)) - call iswap(indx(k), indx(ileft + 1)) - if (v(ileft) > v(iright)) then - call rswap(v(ileft), v(iright)) - call iswap(indx(ileft), indx(iright)) - end if - if (v(ileft + 1) > v(iright)) then - call rswap(v(ileft + 1), v(iright)) - call iswap(indx(ileft + 1), indx(iright)) - end if - if (v(ileft) > v(ileft + 1)) then - call rswap(v(ileft), v(ileft + 1)) - call iswap(indx(ileft), indx(ileft + 1)) - end if - i = ileft + 1 - j = iright - a = v(ileft + 1) - ia = indx(ileft + 1) do - do - i = i + 1 - if (v(i) >= a) then - exit - end if - end do - do - j = j - 1 - if (v(j) <= a) then - exit - end if - end do - if (j < i) then + j = j - 1 + if (v(j) <= a) then exit end if - call rswap(v(i), v(j)) - call iswap(indx(i), indx(j)) end do - v(ileft + 1) = v(j) - indx(ileft + 1) = indx(j) - v(j) = a - indx(j) = ia - jstack = jstack + 2 - if (jstack > nstack) then - write(errmsg,'(4x,a,3(1x,a))') & - 'JSTACK > NSTACK IN SortModule::qsort' - call store_error(errmsg, terminate=.TRUE.) - end if - if ((iright - i + 1) >= (j - 1)) then - istack(jstack) = iright - istack(jstack - 1) = i - iright = j - 1 - else - istack(jstack) = j - 1 - istack(jstack - 1) = ileft - ileft = i + if (j < i) then + exit end if - end if - end do - ! - ! -- reverse order of the heap index - if (lrev) then - j = nsize - do i = 1, nsize / 2 call rswap(v(i), v(j)) call iswap(indx(i), indx(j)) - j = j - 1 end do + v(ileft + 1) = v(j) + indx(ileft + 1) = indx(j) + v(j) = a + indx(j) = ia + jstack = jstack + 2 + if (jstack > nstack) then + write (errmsg, '(4x,a,3(1x,a))') & + 'JSTACK > NSTACK IN SortModule::qsort' + call store_error(errmsg, terminate=.TRUE.) + end if + if ((iright - i + 1) >= (j - 1)) then + istack(jstack) = iright + istack(jstack - 1) = i + iright = j - 1 + else + istack(jstack) = j - 1 + istack(jstack - 1) = ileft + ileft = i + end if end if - ! - ! -- return - return - end subroutine qsort_dbl1d - - subroutine unique_values_int1d(a, b) - ! - dummy arguments - integer(I4B), dimension(:), allocatable, intent(in) :: a - integer(I4B), dimension(:), allocatable, intent(inout) :: b - ! -- local variables - integer(I4B) :: count - integer(I4B) :: n - integer(I4B), dimension(:), allocatable :: indxarr - integer(I4B), dimension(:), allocatable :: tarr - ! -- functions - ! -- code - ! - ! -- allocate tarr and create idxarr - allocate(tarr(size(a))) - allocate(indxarr(size(a))) - ! - ! -- fill tarr with a and create index - do n = 1, size(a) - tarr(n) = a(n) - indxarr(n) = n + end do + ! + ! -- reverse order of the heap index + if (lrev) then + j = nsize + do i = 1, nsize / 2 + call rswap(v(i), v(j)) + call iswap(indx(i), indx(j)) + j = j - 1 end do - ! - ! -- sort a in increasing order - call qsort(indxarr, tarr, reverse=.TRUE.) - ! - ! -- determine the number of unique values - count = 1 - do n = 2, size(tarr) - if (tarr(n) > tarr(n-1)) count = count + 1 - end do - ! - ! -- allocate b for unique values - if (allocated(b)) then - deallocate(b) + end if + ! + ! -- return + return + end subroutine qsort_dbl1d + + subroutine unique_values_int1d(a, b) + ! - dummy arguments + integer(I4B), dimension(:), allocatable, intent(in) :: a + integer(I4B), dimension(:), allocatable, intent(inout) :: b + ! -- local variables + integer(I4B) :: count + integer(I4B) :: n + integer(I4B), dimension(:), allocatable :: indxarr + integer(I4B), dimension(:), allocatable :: tarr + ! -- functions + ! -- code + ! + ! -- allocate tarr and create idxarr + allocate (tarr(size(a))) + allocate (indxarr(size(a))) + ! + ! -- fill tarr with a and create index + do n = 1, size(a) + tarr(n) = a(n) + indxarr(n) = n + end do + ! + ! -- sort a in increasing order + call qsort(indxarr, tarr, reverse=.TRUE.) + ! + ! -- determine the number of unique values + count = 1 + do n = 2, size(tarr) + if (tarr(n) > tarr(n - 1)) count = count + 1 + end do + ! + ! -- allocate b for unique values + if (allocated(b)) then + deallocate (b) + end if + allocate (b(count)) + ! + ! -- fill b with unique values + b(1) = tarr(1) + count = 1 + do n = 2, size(a) + if (tarr(n) > b(count)) then + count = count + 1 + b(count) = tarr(n) end if - allocate(b(count)) - ! - ! -- fill b with unique values - b(1) = tarr(1) - count = 1 - do n = 2, size(a) - if (tarr(n) > b(count)) then - count = count + 1 - b(count) = tarr(n) - end if - end do - ! - ! -- allocate tarr and create idxarr - deallocate(tarr) - deallocate(indxarr) - ! - ! -- return - return - end subroutine unique_values_int1d - - subroutine unique_values_dbl1d(a, b) - ! - dummy arguments - real(DP), dimension(:), allocatable, intent(in) :: a - real(DP), dimension(:), allocatable, intent(inout) :: b - ! -- local variables - integer(I4B) :: count - integer(I4B) :: n - integer(I4B), dimension(:), allocatable :: indxarr - real(DP), dimension(:), allocatable :: tarr - ! -- functions - ! -- code - ! - ! -- allocate tarr and create idxarr - allocate(tarr(size(a))) - allocate(indxarr(size(a))) - ! - ! -- fill tarr with a and create index - do n = 1, size(a) - tarr(n) = a(n) - indxarr(n) = n - end do - ! - ! -- sort a in increasing order - call qsort(indxarr, tarr, reverse=.TRUE.) - ! - ! -- determine the number of unique values - count = 1 - do n = 2, size(tarr) - if (tarr(n) > tarr(n-1)) count = count + 1 - end do - ! - ! -- allocate b for unique values - if (allocated(b)) then - deallocate(b) + end do + ! + ! -- allocate tarr and create idxarr + deallocate (tarr) + deallocate (indxarr) + ! + ! -- return + return + end subroutine unique_values_int1d + + subroutine unique_values_dbl1d(a, b) + ! - dummy arguments + real(DP), dimension(:), allocatable, intent(in) :: a + real(DP), dimension(:), allocatable, intent(inout) :: b + ! -- local variables + integer(I4B) :: count + integer(I4B) :: n + integer(I4B), dimension(:), allocatable :: indxarr + real(DP), dimension(:), allocatable :: tarr + ! -- functions + ! -- code + ! + ! -- allocate tarr and create idxarr + allocate (tarr(size(a))) + allocate (indxarr(size(a))) + ! + ! -- fill tarr with a and create index + do n = 1, size(a) + tarr(n) = a(n) + indxarr(n) = n + end do + ! + ! -- sort a in increasing order + call qsort(indxarr, tarr, reverse=.TRUE.) + ! + ! -- determine the number of unique values + count = 1 + do n = 2, size(tarr) + if (tarr(n) > tarr(n - 1)) count = count + 1 + end do + ! + ! -- allocate b for unique values + if (allocated(b)) then + deallocate (b) + end if + allocate (b(count)) + ! + ! -- fill b with unique values + b(1) = tarr(1) + count = 1 + do n = 2, size(a) + if (tarr(n) > b(count)) then + count = count + 1 + b(count) = tarr(n) end if - allocate(b(count)) - ! - ! -- fill b with unique values - b(1) = tarr(1) - count = 1 - do n = 2, size(a) - if (tarr(n) > b(count)) then - count = count + 1 - b(count) = tarr(n) - end if - end do - ! - ! -- allocate tarr and create idxarr - deallocate(tarr) - deallocate(indxarr) - ! - ! -- return - return - end subroutine unique_values_dbl1d - - subroutine selectn(indx, v, reverse) + end do + ! + ! -- allocate tarr and create idxarr + deallocate (tarr) + deallocate (indxarr) + ! + ! -- return + return + end subroutine unique_values_dbl1d + + subroutine selectn(indx, v, reverse) ! ************************************************************************** ! selectn -- heap selection ! ************************************************************************** ! ! SPECIFICATIONS: ! -------------------------------------------------------------------------- - ! -- dummy arguments - integer(I4B), dimension(:), intent(inout) :: indx - real(DP), dimension(:), intent(inout) :: v - logical, intent(in), optional :: reverse - ! -- local variables - logical :: lrev - integer(I4B) :: nsizei - integer(I4B) :: nsizev - integer(I4B) :: i - integer(I4B) :: j - integer(I4B) :: k - integer(I4B) :: n - !integer(I4B) :: iidx - real(DP), dimension(:), allocatable :: vv - ! -- functions - ! -- code - ! - ! -- process optional dummy variables - if (present(reverse)) then - lrev = reverse - else - lrev = .FALSE. - endif - ! - ! -- initialize heap - nsizev = size(v) - nsizei = min(nsizev, size(indx)) - allocate(vv(nsizei)) - ! - ! -- initialize heap index (indx) and heap (vv) - do n = 1, nsizei - vv(n) = v(n) - indx(n) = n - end do - ! - ! -- initial sort - call qsort(indx, vv) - ! - ! -- evaluate the remaining elements in v - do i = nsizei+1, nsizev - ! - ! -- put the current value on the heap - if (v(i) > vv(1)) then - vv(1) = v(i) - indx(1) = i - j = 1 - do - k = 2 * j - if (k > nsizei) then - exit - end if - if (k /= nsizei) then - if (vv(k) > vv(k+1)) then - k = k + 1 - end if - end if - if (vv(j) <= vv(k)) then - exit + ! -- dummy arguments + integer(I4B), dimension(:), intent(inout) :: indx + real(DP), dimension(:), intent(inout) :: v + logical, intent(in), optional :: reverse + ! -- local variables + logical :: lrev + integer(I4B) :: nsizei + integer(I4B) :: nsizev + integer(I4B) :: i + integer(I4B) :: j + integer(I4B) :: k + integer(I4B) :: n + !integer(I4B) :: iidx + real(DP), dimension(:), allocatable :: vv + ! -- functions + ! -- code + ! + ! -- process optional dummy variables + if (present(reverse)) then + lrev = reverse + else + lrev = .FALSE. + end if + ! + ! -- initialize heap + nsizev = size(v) + nsizei = min(nsizev, size(indx)) + allocate (vv(nsizei)) + ! + ! -- initialize heap index (indx) and heap (vv) + do n = 1, nsizei + vv(n) = v(n) + indx(n) = n + end do + ! + ! -- initial sort + call qsort(indx, vv) + ! + ! -- evaluate the remaining elements in v + do i = nsizei + 1, nsizev + ! + ! -- put the current value on the heap + if (v(i) > vv(1)) then + vv(1) = v(i) + indx(1) = i + j = 1 + do + k = 2 * j + if (k > nsizei) then + exit + end if + if (k /= nsizei) then + if (vv(k) > vv(k + 1)) then + k = k + 1 end if - call rswap(vv(k), vv(j)) - call iswap(indx(k), indx(j)) - j = k - end do - end if - end do - ! - ! -- final sort - call qsort(indx, vv) - ! - ! -- reverse order of the heap index - if (lrev) then - j = nsizei - do i = 1, nsizei / 2 - call iswap(indx(i), indx(j)) - j = j - 1 + end if + if (vv(j) <= vv(k)) then + exit + end if + call rswap(vv(k), vv(j)) + call iswap(indx(k), indx(j)) + j = k end do end if - ! - ! -- return - return - end subroutine selectn + end do + ! + ! -- final sort + call qsort(indx, vv) + ! + ! -- reverse order of the heap index + if (lrev) then + j = nsizei + do i = 1, nsizei / 2 + call iswap(indx(i), indx(j)) + j = j - 1 + end do + end if + ! + ! -- return + return + end subroutine selectn - subroutine rswap(a, b) - ! -- dummy arguments - real(DP), intent(inout) :: a - real(DP), intent(inout) :: b - ! -- local variables - real(DP) :: d - ! -- functions - ! -- code - d = a - a = b - b = d - ! - ! -- return - return - end subroutine rswap + subroutine rswap(a, b) + ! -- dummy arguments + real(DP), intent(inout) :: a + real(DP), intent(inout) :: b + ! -- local variables + real(DP) :: d + ! -- functions + ! -- code + d = a + a = b + b = d + ! + ! -- return + return + end subroutine rswap + + subroutine iswap(ia, ib) + ! -- dummy arguments + integer(I4B), intent(inout) :: ia + integer(I4B), intent(inout) :: ib + ! -- local variables + integer(I4B) :: id + ! -- functions + ! -- code + id = ia + ia = ib + ib = id + ! + ! -- return + return + end subroutine iswap - subroutine iswap(ia, ib) - ! -- dummy arguments - integer(I4B), intent(inout) :: ia - integer(I4B), intent(inout) :: ib - ! -- local variables - integer(I4B) :: id - ! -- functions - ! -- code - id = ia - ia = ib - ib = id - ! - ! -- return - return - end subroutine iswap - - - end module SortModule diff --git a/src/Utilities/version.f90 b/src/Utilities/version.f90 index 22946380c96..9255f504523 100644 --- a/src/Utilities/version.f90 +++ b/src/Utilities/version.f90 @@ -13,48 +13,50 @@ module VersionModule use CompilerVersion, only: get_compiler, get_compile_options implicit none public - ! -- modflow 6 version + ! -- modflow 6 version integer(I4B), parameter :: IDEVELOPMODE = 0 - character(len=40), parameter :: VERSION = '6.3.0 03/04/2022' - character(len=10), parameter :: MFVNAM = ' 6' - character(len=*), parameter :: MFTITLE = & - 'U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL' - character(len=*), parameter :: FMTTITLE = & - "(/,34X,'MODFLOW',A,/, & - &16X,'U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL', & - &/,23X,'Version ',A/)" - ! -- license for MODFLOW and libraries - character(len=*), parameter :: FMTLICENSE = & - "(/, & - &'As a work of the United States Government, this USGS product is ',/, & - &'in the public domain within the United States. You can copy, ',/, & - &'modify, distribute, and perform the work, even for commercial ',/, & - &'purposes, all without asking permission. Additionally, USGS ',/, & - &'waives copyright and related rights in the work worldwide ',/, & - &'through CC0 1.0 Universal Public Domain Dedication ',/, & - &'(https://creativecommons.org/publicdomain/zero/1.0/).',//, & - &'The following GNU Lesser General Public License (LGPL) libraries',/, & - &'are used in this USGS product:',//, & - &' SPARSKIT version 2.0',/, & - &' ilut, luson, and qsplit ',/, & - &' (https://www-users.cse.umn.edu/~saad/software/SPARSKIT/)',//, & - &' RCM - Reverse Cuthill McKee Ordering',/, & - &' (https://people.math.sc.edu/Burkardt/f_src/rcm/rcm.html)',//, & - &' BLAS - Basic Linear Algebra Subprograms Level 1',/, & - &' (https://people.math.sc.edu/Burkardt/f_src/blas1_d/', & - &'blas1_d.html)',//, & - &' SPARSEKIT - Sparse Matrix Utility Package',/, & - &' amux, dperm, dvperm, rperm, and cperm',/, & - &' (https://people.sc.fsu.edu/~jburkardt/f77_src/sparsekit/', & - &'sparsekit.html)',//, & - &'The following BSD-3 License libraries are used in this USGS product:',//, & - &' Modern Fortran DAG Library',/, & - &' Copyright (c) 2018, Jacob Williams',/, & - &' All rights reserved.',/, & - &' (https://github.com/jacobwilliams/daglib)',/ & - &)" - ! -- disclaimer must be appropriate for version (release or release candidate) - character(len=*), parameter :: FMTDISCLAIMER = & + character(len=*), parameter :: VERSIONNUMBER = '6.4.0' + character(len=*), parameter :: VERSIONTAG = ' release candidate 11/30/2022' + character(len=40), parameter :: VERSION = '6.4.0 11/30/2022' + character(len=10), parameter :: MFVNAM = ' 6' + character(len=*), parameter :: MFTITLE = & + &'U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL' + character(len=*), parameter :: FMTTITLE = & + "(/,34X,'MODFLOW',A,/,& + &16X,'U.S. GEOLOGICAL SURVEY MODULAR HYDROLOGIC MODEL',& + &/,23X,'Version ',A/)" + ! -- license for MODFLOW and libraries + character(len=*), parameter :: FMTLICENSE = & + "(/,& + &'As a work of the United States Government, this USGS product is ',/,& + &'in the public domain within the United States. You can copy, ',/,& + &'modify, distribute, and perform the work, even for commercial ',/,& + &'purposes, all without asking permission. Additionally, USGS ',/,& + &'waives copyright and related rights in the work worldwide ',/,& + &'through CC0 1.0 Universal Public Domain Dedication ',/,& + &'(https://creativecommons.org/publicdomain/zero/1.0/).',//,& + &'The following GNU Lesser General Public License (LGPL) libraries',/,& + &'are used in this USGS product:',//,"// & + "' SPARSKIT version 2.0',/,& + &' ilut, luson, and qsplit ',/,& + &' (https://www-users.cse.umn.edu/~saad/software/SPARSKIT/)',//,& + &' RCM - Reverse Cuthill McKee Ordering',/,& + &' (https://people.math.sc.edu/Burkardt/f_src/rcm/rcm.html)',//,& + &' BLAS - Basic Linear Algebra Subprograms Level 1',/,& + &' (https://people.math.sc.edu/Burkardt/f_src/blas1_d/',& + &'blas1_d.html)',//,"// & + "' SPARSEKIT - Sparse Matrix Utility Package',/,& + &' amux, dperm, dvperm, rperm, and cperm',/,& + &' (https://people.sc.fsu.edu/~jburkardt/f77_src/sparsekit/',& + &'sparsekit.html)',//,& + &'The following BSD-3 License libraries are used in this USGS product:',//,& + &' Modern Fortran DAG Library',/,& + &' Copyright (c) 2018, Jacob Williams',/,& + &' All rights reserved.',/,& + &' (https://github.com/jacobwilliams/daglib)',/& + &)" + ! -- disclaimer must be appropriate for version (release or release candidate) + character(len=*), parameter :: FMTDISCLAIMER = & "(/, & &'This software has been approved for release by the U.S. Geological ',/, & &'Survey (USGS). Although the software has been subjected to rigorous ',/, & @@ -69,85 +71,85 @@ module VersionModule &'Resources Software User Rights Notice for complete use, copyright, ',/, & &'and distribution information.',/)" - contains +contains - !> @ brief Write program header + !> @ brief Write program header !! !! Write header for program to the program listing file. !! - !< - subroutine write_listfile_header(iout, cmodel_type, write_sys_command, & - write_kind_info) - ! -- dummy variables - integer(I4B), intent(in) :: iout !< program listing file - character(len=*), intent(in), optional :: cmodel_type !< optional model type string - logical(LGP), intent(in), optional :: write_sys_command !< boolean indicating if the system command should be written - logical(LGP), intent(in), optional :: write_kind_info !< boolean indicating in program data types should be written - ! -- local variables - character(len=LENBIGLINE) :: syscmd - character(len=LENBIGLINE) :: compiler - character(len=LENBIGLINE) :: compiler_options - integer(I4B) :: iheader_width = 80 - logical(LGP) :: wki - logical(LGP) :: wsc - ! - ! -- Write title to list file - call write_centered('MODFLOW'//MFVNAM, iheader_width, iunit=iout) - call write_centered(MFTITLE, iheader_width, iunit=iout) - ! - ! -- Write model type to list file - if (present(cmodel_type)) then - call write_centered(cmodel_type, iheader_width, iunit=iout) - end if - ! - ! -- Write version - call write_centered('VERSION '//VERSION, iheader_width, iunit=iout) - ! - ! -- Write if develop mode - if (IDEVELOPMODE == 1) then - call write_centered('***DEVELOP MODE***', iheader_width, iunit=iout) - end if - ! - ! -- Write compiler version - call get_compiler(compiler) - call write_centered(' ', iheader_width, iunit=iout) - call write_centered(trim(adjustl(compiler)), iheader_width, iunit=iout) - ! - ! -- Write disclaimer - write(iout, FMTDISCLAIMER) - ! - ! -- Write license information - if (iout /= istdout) then - write(iout, FMTLICENSE) - end if - ! - ! -- write compiler options - if (iout /= istdout) then - call get_compile_options(compiler_options) - call write_message(compiler_options, iunit=iout) - end if - ! - ! -- Write the system command used to initiate simulation - wsc = .true. - if (present(write_sys_command)) wsc = write_sys_command - if (wsc) then - call GET_COMMAND(syscmd) - write(iout, '(/,a,/,a)') 'System command used to initiate simulation:', & - trim(syscmd) - end if - ! - ! -- Write precision of real variables - wki = .true. - if (present(write_kind_info)) wki = write_kind_info - if (wki) then - write(iout, '(/,a)') 'MODFLOW was compiled using uniform precision.' - call write_kindinfo(iout) - end if - write(iout, *) - ! - ! -- return - return - end subroutine write_listfile_header + !< + subroutine write_listfile_header(iout, cmodel_type, write_sys_command, & + write_kind_info) + ! -- dummy variables + integer(I4B), intent(in) :: iout !< program listing file + character(len=*), intent(in), optional :: cmodel_type !< optional model type string + logical(LGP), intent(in), optional :: write_sys_command !< boolean indicating if the system command should be written + logical(LGP), intent(in), optional :: write_kind_info !< boolean indicating in program data types should be written + ! -- local variables + character(len=LENBIGLINE) :: syscmd + character(len=LENBIGLINE) :: compiler + character(len=LENBIGLINE) :: compiler_options + integer(I4B) :: iheader_width = 80 + logical(LGP) :: wki + logical(LGP) :: wsc + ! + ! -- Write title to list file + call write_centered('MODFLOW'//MFVNAM, iheader_width, iunit=iout) + call write_centered(MFTITLE, iheader_width, iunit=iout) + ! + ! -- Write model type to list file + if (present(cmodel_type)) then + call write_centered(cmodel_type, iheader_width, iunit=iout) + end if + ! + ! -- Write version + call write_centered('VERSION '//VERSION, iheader_width, iunit=iout) + ! + ! -- Write if develop mode + if (IDEVELOPMODE == 1) then + call write_centered('***DEVELOP MODE***', iheader_width, iunit=iout) + end if + ! + ! -- Write compiler version + call get_compiler(compiler) + call write_centered(' ', iheader_width, iunit=iout) + call write_centered(trim(adjustl(compiler)), iheader_width, iunit=iout) + ! + ! -- Write disclaimer + write (iout, FMTDISCLAIMER) + ! + ! -- Write license information + if (iout /= istdout) then + write (iout, FMTLICENSE) + end if + ! + ! -- write compiler options + if (iout /= istdout) then + call get_compile_options(compiler_options) + call write_message(compiler_options, iunit=iout) + end if + ! + ! -- Write the system command used to initiate simulation + wsc = .true. + if (present(write_sys_command)) wsc = write_sys_command + if (wsc) then + call GET_COMMAND(syscmd) + write (iout, '(/,a,/,a)') & + 'System command used to initiate simulation:', trim(syscmd) + end if + ! + ! -- Write precision of real variables + wki = .true. + if (present(write_kind_info)) wki = write_kind_info + if (wki) then + write (iout, '(/,a)') 'MODFLOW was compiled using uniform precision.' + call write_kindinfo(iout) + end if + write (iout, *) + ! + ! -- return + return + end subroutine write_listfile_header end module VersionModule diff --git a/src/meson.build b/src/meson.build index 1fe13c8ca73..301b07c431f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,6 +24,10 @@ modflow_sources = files( 'Model' / 'Connection' / 'GwfInterfaceModel.f90', 'Model' / 'Connection' / 'GwtInterfaceModel.f90', 'Model' / 'Connection' / 'SpatialModelConnection.f90', + 'Model' / 'Connection' / 'MappedVariable.f90', + 'Model' / 'Connection' / 'DistributedData.f90', + 'Model' / 'Connection' / 'DistributedModel.f90', + 'Model' / 'Connection' / 'InterfaceMap.f90', 'Model' / 'Geometry' / 'BaseGeometry.f90', 'Model' / 'Geometry' / 'CircularGeometry.f90', 'Model' / 'Geometry' / 'RectangularGeometry.f90', @@ -33,8 +37,11 @@ modflow_sources = files( 'Model' / 'GroundWaterFlow' / 'gwf3chd8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3csub8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3dis8.f90', + 'Model' / 'GroundWaterFlow' / 'gwf3dis8idm.f90', 'Model' / 'GroundWaterFlow' / 'gwf3disu8.f90', + 'Model' / 'GroundWaterFlow' / 'gwf3disu8idm.f90', 'Model' / 'GroundWaterFlow' / 'gwf3disv8.f90', + 'Model' / 'GroundWaterFlow' / 'gwf3disv8idm.f90', 'Model' / 'GroundWaterFlow' / 'gwf3drn8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3evt8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3ghb8.f90', @@ -44,6 +51,7 @@ modflow_sources = files( 'Model' / 'GroundWaterFlow' / 'gwf3maw8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3mvr8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3npf8.f90', + 'Model' / 'GroundWaterFlow' / 'gwf3npf8idm.f90', 'Model' / 'GroundWaterFlow' / 'gwf3obs8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3oc8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3rch8.f90', @@ -54,12 +62,14 @@ modflow_sources = files( 'Model' / 'GroundWaterFlow' / 'gwf3tvk8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3tvs8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3uzf8.f90', + 'Model' / 'GroundWaterFlow' / 'gwf3vsc8.f90', 'Model' / 'GroundWaterFlow' / 'gwf3wel8.f90', 'Model' / 'GroundWaterTransport' / 'gwt1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1adv1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1apt1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1cnc1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1dsp.f90', + 'Model' / 'GroundWaterTransport' / 'gwt1dspidm.f90', 'Model' / 'GroundWaterTransport' / 'gwt1fmi1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1ic1.f90', 'Model' / 'GroundWaterTransport' / 'gwt1ist1.f90', @@ -78,12 +88,12 @@ modflow_sources = files( 'Model' / 'ModelUtilities' / 'DiscretizationBase.f90', 'Model' / 'ModelUtilities' / 'DisvGeom.f90', 'Model' / 'ModelUtilities' / 'GwfBuyInputData.f90', - 'Model' / 'ModelUtilities' / 'GwfNpfGridData.f90', + 'Model' / 'ModelUtilities' / 'GwfMvrPeriodData.f90', 'Model' / 'ModelUtilities' / 'GwfNpfOptions.f90', 'Model' / 'ModelUtilities' / 'GwfStorageUtils.f90', + 'Model' / 'ModelUtilities' / 'GwfVscInputData.f90', 'Model' / 'ModelUtilities' / 'GwtAdvOptions.f90', 'Model' / 'ModelUtilities' / 'GwtDspOptions.f90', - 'Model' / 'ModelUtilities' / 'GwtDspGridData.f90', 'Model' / 'ModelUtilities' / 'GwtSpc.f90', 'Model' / 'ModelUtilities' / 'Mover.f90', 'Model' / 'ModelUtilities' / 'PackageMover.f90', @@ -95,18 +105,35 @@ modflow_sources = files( 'Model' / 'BaseModel.f90', 'Model' / 'NumericalModel.f90', 'Model' / 'NumericalPackage.f90', - 'Solution' / 'SparseMatrixSolver' / 'ims8base.f90', - 'Solution' / 'SparseMatrixSolver' / 'ims8linear.f90', - 'Solution' / 'SparseMatrixSolver' / 'ims8reordering.f90', + 'Model' / 'TransportModel.f90', + 'Solution' / 'LinearMethods' / 'ims8base.f90', + 'Solution' / 'LinearMethods' / 'ims8linear.f90', + 'Solution' / 'LinearMethods' / 'ims8reordering.f90', + 'Solution' / 'LinearMethods' / 'ims8misc.f90', 'Solution' / 'BaseSolution.f90', 'Solution' / 'NumericalSolution.f90', 'Solution' / 'SolutionGroup.f90', 'Timing' / 'ats.f90', 'Timing' / 'tdis.f90', + 'Utilities' / 'ArrayRead' / 'ArrayReaderBase.f90', + 'Utilities' / 'ArrayRead' / 'Double1dReader.f90', + 'Utilities' / 'ArrayRead' / 'Double2dReader.f90', + 'Utilities' / 'ArrayRead' / 'Integer1dReader.f90', + 'Utilities' / 'ArrayRead' / 'Integer2dReader.f90', + 'Utilities' / 'ArrayRead' / 'LayeredArrayReader.f90', + 'Utilities' / 'Idm' / 'IdmLogger.f90', + 'Utilities' / 'Idm' / 'IdmMf6FileLoader.f90', + 'Utilities' / 'Idm' / 'ModflowInput.f90', + 'Utilities' / 'Idm' / 'InputDefinition.f90', + 'Utilities' / 'Idm' / 'InputDefinitionSelector.f90', + 'Utilities' / 'Idm' / 'LoadMf6FileType.f90', + 'Utilities' / 'Idm' / 'StructArray.f90', + 'Utilities' / 'Idm' / 'StructVector.f90', 'Utilities' / 'Memory' / 'Memory.f90', 'Utilities' / 'Memory' / 'MemoryHelper.f90', 'Utilities' / 'Memory' / 'MemoryList.f90', 'Utilities' / 'Memory' / 'MemoryManager.f90', + 'Utilities' / 'Memory' / 'MemoryManagerExt.f90', 'Utilities' / 'Memory' / 'MemorySetHandler.f90', 'Utilities' / 'Observation' / 'Obs3.f90', 'Utilities' / 'Observation' / 'ObsContainer.f90', @@ -133,6 +160,7 @@ modflow_sources = files( 'Utilities' / 'BudgetFileReader.f90', 'Utilities' / 'BudgetObject.f90', 'Utilities' / 'BudgetTerm.f90', + 'Utilities' / 'CharString.f90', 'Utilities' / 'comarg.f90', 'Utilities' / 'compilerversion.F90', 'Utilities' / 'Constants.f90', @@ -158,6 +186,7 @@ modflow_sources = files( 'Utilities' / 'Table.f90', 'Utilities' / 'TableTerm.f90', 'Utilities' / 'Timer.f90', + 'Utilities' / 'VectorInt.f90', 'Utilities' / 'version.f90', 'mf6core.f90', 'mf6lists.f90', @@ -168,4 +197,4 @@ mf6_external = static_library('mf6_external', external_libraries) mf6core = static_library('mf6core', modflow_sources, link_with: [mf6_external]) -executable('mf6', 'mf6.f90', link_with: [mf6core], install: true) +mf6exe = executable('mf6', 'mf6.f90', link_with: [mf6core], install: true) diff --git a/src/mf6.f90 b/src/mf6.f90 index 2b705c96ed5..94a2818ac87 100644 --- a/src/mf6.f90 +++ b/src/mf6.f90 @@ -9,6 +9,5 @@ program mf6 ! ! -- run call Mf6Run() - + end program - \ No newline at end of file diff --git a/src/mf6core.f90 b/src/mf6core.f90 index 5343beda4f1..1f3545f7a9a 100644 --- a/src/mf6core.f90 +++ b/src/mf6core.f90 @@ -5,344 +5,353 @@ !! of MODFLOW 6. !! !< -module Mf6CoreModule - use KindModule, only: I4B, LGP - use ListsModule, only: basesolutionlist, solutiongrouplist, & - basemodellist, baseexchangelist, & - baseconnectionlist - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList - use SpatialModelConnectionModule, only: SpatialModelConnectionType, & +module Mf6CoreModule + use KindModule, only: I4B, LGP + use ListsModule, only: basesolutionlist, solutiongrouplist, & + basemodellist, baseexchangelist, & + baseconnectionlist + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList + use SpatialModelConnectionModule, only: SpatialModelConnectionType, & GetSpatialModelConnectionFromList - use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList - use SolutionGroupModule, only: SolutionGroupType, GetSolutionGroupFromList - implicit none + use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList + use SolutionGroupModule, only: SolutionGroupType, GetSolutionGroupFromList + use DistributedDataModule + implicit none - contains - - !> @brief Main controller +contains + + !> @brief Main controller !! !! This subroutine is the main controller for MODFLOW 6. !! - !< - subroutine Mf6Run - ! -- modules - use CommandArguments, only: GetCommandLineArguments - use TdisModule, only: totim, totalsimtime - use KindModule, only: DP - ! -- local - logical(LGP) :: hasConverged - ! - ! -- parse any command line arguments - call GetCommandLineArguments() - ! - ! initialize simulation - call Mf6Initialize() - ! - ! -- time loop - tsloop: do while (totim < totalsimtime) - - ! perform a time step - hasConverged = Mf6Update() - - ! if not converged, break - if(.not. hasConverged) exit tsloop - - enddo tsloop - ! - ! -- finalize simulation - call Mf6Finalize() - - end subroutine Mf6Run - - !> @brief Initialize a simulation + !< + subroutine Mf6Run + ! -- modules + use CommandArguments, only: GetCommandLineArguments + use TdisModule, only: totim, totalsimtime + use KindModule, only: DP + ! -- local + logical(LGP) :: hasConverged + ! + ! -- parse any command line arguments + call GetCommandLineArguments() + ! + ! initialize simulation + call Mf6Initialize() + ! + ! -- time loop + do while (totim < totalsimtime) + + ! perform a time step + hasConverged = Mf6Update() + + ! if not converged, break + if (.not. hasConverged) exit + + end do + ! + ! -- finalize simulation + call Mf6Finalize() + + end subroutine Mf6Run + + !> @brief Initialize a simulation !! !! This subroutine initializes a MODFLOW 6 simulation. The subroutine: !! - creates the simulation !! - defines !! - allocates and reads static data !! - !< - subroutine Mf6Initialize() - ! -- modules - use SimulationCreateModule, only: simulation_cr - ! - ! -- print banner and info to screen - call printInfo() - - ! -- create - call simulation_cr() - - ! -- define - call simulation_df() - - ! -- allocate and read - call simulation_ar() - - end subroutine Mf6Initialize - - !> @brief Run a time step + !< + subroutine Mf6Initialize() + ! -- modules + use SimulationCreateModule, only: simulation_cr + ! + ! -- print banner and info to screen + call printInfo() + + ! -- create + call simulation_cr() + + ! -- define + call simulation_df() + + ! -- allocate and read + call simulation_ar() + + end subroutine Mf6Initialize + + !> @brief Run a time step !! !! This function runs a single time step to completion. !! !! @return hasConverged boolean indicating if convergence was achieved for the time step !! - !< - function Mf6Update() result(hasConverged) - ! -- return variable - logical(LGP) :: hasConverged - ! - ! -- prepare timestep - call Mf6PrepareTimestep() - ! - ! -- do timestep - call Mf6DoTimestep() - ! - ! -- after timestep - hasConverged = Mf6FinalizeTimestep() - ! - end function Mf6Update - - !> @brief Finalize the simulation + !< + function Mf6Update() result(hasConverged) + ! -- return variable + logical(LGP) :: hasConverged + ! + ! -- prepare timestep + call Mf6PrepareTimestep() + ! + ! -- do timestep + call Mf6DoTimestep() + ! + ! -- after timestep + hasConverged = Mf6FinalizeTimestep() + ! + end function Mf6Update + + !> @brief Finalize the simulation !! !! This subroutine finalizes a simulation. Steps include: !! - final processing !! - deallocate memory !! - !< - subroutine Mf6Finalize() - ! -- modules - use, intrinsic :: iso_fortran_env, only: output_unit - use ListsModule, only: lists_da - use MemoryManagerModule, only: mem_write_usage, mem_da - use TimerModule, only: elapsed_time - use SimVariablesModule, only: iout - use SimulationCreateModule, only: simulation_da - use TdisModule, only: tdis_da - use SimModule, only: final_message - ! -- local variables - integer(I4B) :: im - integer(I4B) :: ic - integer(I4B) :: is - integer(I4B) :: isg - class(SolutionGroupType), pointer :: sgp => null() - class(BaseSolutionType), pointer :: sp => null() - class(BaseModelType), pointer :: mp => null() - class(BaseExchangeType), pointer :: ep => null() - class(SpatialModelConnectionType), pointer :: mc => null() - ! - ! -- FINAL PROCESSING (FP) - ! -- Final processing for each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_fp() - enddo - ! - ! -- Final processing for each exchange - do ic = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ic) - call ep%exg_fp() - enddo - ! - ! -- Final processing for each solution - do is=1,basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_fp() - enddo - ! - ! -- DEALLOCATE (DA) - ! -- Deallocate tdis - call tdis_da() - ! - ! -- Deallocate for each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_da() - deallocate(mp) - enddo - ! - ! -- Deallocate for each exchange - do ic = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ic) - call ep%exg_da() - deallocate(ep) - enddo - ! - ! -- Deallocate for each connection - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_da() - deallocate(mc) - enddo - ! - ! -- Deallocate for each solution - do is=1,basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_da() - deallocate(sp) - enddo - ! - ! -- Deallocate solution group and simulation variables - do isg = 1, solutiongrouplist%Count() - sgp => GetSolutionGroupFromList(solutiongrouplist, isg) - call sgp%sgp_da() - deallocate(sgp) - enddo - call simulation_da() - call lists_da() - ! - ! -- Write memory usage, elapsed time and terminate - call mem_write_usage(iout) - call mem_da() - call elapsed_time(iout, 1) - call final_message() - ! - end subroutine Mf6Finalize - - !> @brief Print info to screen + !< + subroutine Mf6Finalize() + ! -- modules + use, intrinsic :: iso_fortran_env, only: output_unit + use ListsModule, only: lists_da + use MemoryManagerModule, only: mem_write_usage, mem_da + use TimerModule, only: elapsed_time + use SimVariablesModule, only: iout + use SimulationCreateModule, only: simulation_da + use TdisModule, only: tdis_da + use SimModule, only: final_message + ! -- local variables + integer(I4B) :: im + integer(I4B) :: ic + integer(I4B) :: is + integer(I4B) :: isg + class(SolutionGroupType), pointer :: sgp => null() + class(BaseSolutionType), pointer :: sp => null() + class(BaseModelType), pointer :: mp => null() + class(BaseExchangeType), pointer :: ep => null() + class(SpatialModelConnectionType), pointer :: mc => null() + ! + ! -- FINAL PROCESSING (FP) + ! -- Final processing for each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_fp() + end do + ! + ! -- Final processing for each exchange + do ic = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ic) + call ep%exg_fp() + end do + ! + ! -- Final processing for each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_fp() + end do + ! + ! -- DEALLOCATE (DA) + ! -- Deallocate tdis + call tdis_da() + ! + ! -- Deallocate for each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_da() + deallocate (mp) + end do + ! + ! -- Deallocate for each exchange + do ic = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ic) + call ep%exg_da() + deallocate (ep) + end do + ! + ! -- Deallocate for each connection + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_da() + deallocate (mc) + end do + ! + ! -- Deallocate for each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_da() + deallocate (sp) + end do + ! + ! -- Deallocate solution group and simulation variables + do isg = 1, solutiongrouplist%Count() + sgp => GetSolutionGroupFromList(solutiongrouplist, isg) + call sgp%sgp_da() + deallocate (sgp) + end do + call simulation_da() + call lists_da() + call distributed_data%destroy() + ! + ! -- Write memory usage, elapsed time and terminate + call mem_write_usage(iout) + call mem_da() + call elapsed_time(iout, 1) + call final_message() + ! + end subroutine Mf6Finalize + + !> @brief Print info to screen !! !! This subroutine prints the banner to the screen. !! - !< - subroutine printInfo() - use SimModule, only: initial_message - use TimerModule, only: start_time - ! - ! -- print initial message - call initial_message() - ! - ! -- get start time - call start_time() - return - end subroutine printInfo - - !> @brief Define the simulation + !< + subroutine printInfo() + use SimModule, only: initial_message + use TimerModule, only: start_time + ! + ! -- print initial message + call initial_message() + ! + ! -- get start time + call start_time() + return + end subroutine printInfo + + !> @brief Define the simulation !! !! This subroutine defined the simulation. Steps include: !! - define each model !! - define each solution !! - !< - subroutine simulation_df() - ! -- local variables - integer(I4B) :: im - integer(I4B) :: ic - integer(I4B) :: is - class(BaseSolutionType), pointer :: sp => null() - class(BaseModelType), pointer :: mp => null() - class(BaseExchangeType), pointer :: ep => null() - class(SpatialModelConnectionType), pointer :: mc => null() - - ! -- Define each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_df() - enddo - ! - ! -- Define each exchange - do ic = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ic) - call ep%exg_df() - enddo - ! - ! -- when needed, this is were the interface models are - ! created and added to the numerical solutions - call connections_cr() - ! - ! -- Define each connection - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_df() - enddo - ! - ! -- Define each solution - do is = 1, basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_df() - enddo - - end subroutine simulation_df - - !> @brief Simulation allocate and read + !< + subroutine simulation_df() + ! -- local variables + integer(I4B) :: im + integer(I4B) :: ic + integer(I4B) :: is + class(BaseSolutionType), pointer :: sp => null() + class(BaseModelType), pointer :: mp => null() + class(BaseExchangeType), pointer :: ep => null() + class(SpatialModelConnectionType), pointer :: mc => null() + + ! -- Define each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_df() + end do + ! + ! -- Define each exchange + do ic = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ic) + call ep%exg_df() + end do + ! + ! -- when needed, this is were the interface models are + ! created and added to the numerical solutions + call connections_cr() + ! + ! -- Define each connection + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_df() + end do + ! + ! -- Define each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_df() + end do + + end subroutine simulation_df + + !> @brief Simulation allocate and read !! - !! This subroutine allocates and read static data for the simulation. + !! This subroutine allocates and read static data for the simulation. !! Steps include: !! - allocate and read for each model !! - allocate and read for each exchange !! - allocate and read for each solution !! - !< - subroutine simulation_ar() - ! -- local variables - integer(I4B) :: im - integer(I4B) :: ic - integer(I4B) :: is - class(BaseSolutionType), pointer :: sp => null() - class(BaseModelType), pointer :: mp => null() - class(BaseExchangeType), pointer :: ep => null() - class(SpatialModelConnectionType), pointer :: mc => null() - - ! -- Allocate and read each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_ar() - enddo - ! - ! -- Allocate and read each exchange - do ic = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ic) - call ep%exg_ar() - enddo - ! - ! -- Allocate and read all model connections - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_ar() - enddo - ! - ! -- Allocate and read each solution - do is=1,basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_ar() - enddo - ! - end subroutine simulation_ar + !< + subroutine simulation_ar() + use DistributedDataModule + ! -- local variables + integer(I4B) :: im + integer(I4B) :: ic + integer(I4B) :: is + class(BaseSolutionType), pointer :: sp => null() + class(BaseModelType), pointer :: mp => null() + class(BaseExchangeType), pointer :: ep => null() + class(SpatialModelConnectionType), pointer :: mc => null() + + ! -- Allocate and read each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_ar() + end do + ! + ! -- Allocate and read each exchange + do ic = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ic) + call ep%exg_ar() + end do + ! + ! -- Synchronize + call distributed_data%synchronize(0, BEFORE_AR) + ! + ! -- Allocate and read all model connections + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_ar() + end do + ! + ! -- Synchronize + call distributed_data%synchronize(0, AFTER_AR) + ! + ! -- Allocate and read each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_ar() + end do + ! + end subroutine simulation_ar - !> @brief Create the model connections from the exchanges + !> @brief Create the model connections from the exchanges !! !! This will upgrade the numerical exchanges in the solution, - !! whenever the configuration requires this, to Connection + !! whenever the configuration requires this, to Connection !! objects. Currently we anticipate: !! !! GWF-GWF => GwfGwfConnection !! GWT-GWT => GwtGwtConecction - !< - subroutine connections_cr() - use ConnectionBuilderModule - use SimVariablesModule, only: iout - integer(I4B) :: isol - type(ConnectionBuilderType) :: connectionBuilder - class(BaseSolutionType), pointer :: sol => null() - - write(iout,'(/a)') 'PROCESSING MODEL CONNECTIONS' - - if (baseexchangelist%Count() == 0) then - ! if this is not a coupled simulation in any way, - ! then we will not need model connections - return - end if - - do isol = 1, basesolutionlist%Count() - sol => GetBaseSolutionFromList(basesolutionlist, isol) - call connectionBuilder%processSolution(sol) - end do + !< + subroutine connections_cr() + use ConnectionBuilderModule + use SimVariablesModule, only: iout + integer(I4B) :: isol + type(ConnectionBuilderType) :: connectionBuilder + class(BaseSolutionType), pointer :: sol => null() + + write (iout, '(/a)') 'PROCESSING MODEL CONNECTIONS' + + if (baseexchangelist%Count() == 0) then + ! if this is not a coupled simulation in any way, + ! then we will not need model connections + return + end if + + do isol = 1, basesolutionlist%Count() + sol => GetBaseSolutionFromList(basesolutionlist, isol) + call connectionBuilder%processSolution(sol) + end do - write(iout,'(a)') 'END OF MODEL CONNECTIONS' - end subroutine connections_cr - - !> @brief Read and prepare time step + write (iout, '(a)') 'END OF MODEL CONNECTIONS' + end subroutine connections_cr + + !> @brief Read and prepare time step !! - !! This subroutine reads and prepares period data for the simulation. + !! This subroutine reads and prepares period data for the simulation. !! Steps include: !! - read and prepare for each model !! - read and prepare for each exchange @@ -352,179 +361,179 @@ end subroutine connections_cr !! - calculate maximum time step for each solution !! - set time discretization timestep using smallest maximum timestep !! - !< - subroutine Mf6PrepareTimestep() - ! -- modules - use KindModule, only: I4B - use ConstantsModule, only: LINELENGTH, MNORMAL, MVALIDATE - use TdisModule, only: tdis_set_counters, tdis_set_timestep, & - kstp, kper - use ListsModule, only: basemodellist, baseexchangelist - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList - use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList - use SimModule, only: converge_reset - use SimVariablesModule, only: isim_mode - ! -- local variables - class(BaseModelType), pointer :: mp => null() - class(BaseExchangeType), pointer :: ep => null() - class(SpatialModelConnectionType), pointer :: mc => null() - class(BaseSolutionType), pointer :: sp => null() - character(len=LINELENGTH) :: line - character(len=LINELENGTH) :: fmt - integer(I4B) :: im - integer(I4B) :: ie - integer(I4B) :: ic - integer(I4B) :: is - ! - ! -- initialize fmt - fmt = "(/,a,/)" - ! - ! -- period update - call tdis_set_counters() - ! - ! -- set base line - write(line, '(a,i0,a,i0,a)') & - 'start timestep kper="', kper, '" kstp="', kstp, '" mode="' - ! - ! -- evaluate simulation mode - select case (isim_mode) - case (MVALIDATE) - line = trim(line) // 'validate"' - case(MNORMAL) - line = trim(line) // 'normal"' - end select - - ! -- Read and prepare each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_message(line, fmt=fmt) - call mp%model_rp() - enddo - ! - ! -- Read and prepare each exchange - do ie = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ie) - call ep%exg_rp() - enddo - ! - ! -- Read and prepare each connection - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_rp() - enddo - ! - ! -- reset simulation convergence flag - call converge_reset() - ! - ! -- time update for each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_calculate_delt() - enddo - ! - ! -- time update for each exchange - do ie = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ie) - call ep%exg_calculate_delt() - enddo - ! - ! -- time update for each connection - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_calculate_delt() - enddo - ! - ! -- time update for each solution - do is=1,basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_calculate_delt() - enddo - ! - ! -- set time step - call tdis_set_timestep() - - end subroutine Mf6PrepareTimestep - - !> @brief Run time step + !< + subroutine Mf6PrepareTimestep() + ! -- modules + use KindModule, only: I4B + use ConstantsModule, only: LINELENGTH, MNORMAL, MVALIDATE + use TdisModule, only: tdis_set_counters, tdis_set_timestep, & + kstp, kper + use ListsModule, only: basemodellist, baseexchangelist + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList + use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList + use SimModule, only: converge_reset + use SimVariablesModule, only: isim_mode + ! -- local variables + class(BaseModelType), pointer :: mp => null() + class(BaseExchangeType), pointer :: ep => null() + class(SpatialModelConnectionType), pointer :: mc => null() + class(BaseSolutionType), pointer :: sp => null() + character(len=LINELENGTH) :: line + character(len=LINELENGTH) :: fmt + integer(I4B) :: im + integer(I4B) :: ie + integer(I4B) :: ic + integer(I4B) :: is + ! + ! -- initialize fmt + fmt = "(/,a,/)" + ! + ! -- period update + call tdis_set_counters() + ! + ! -- set base line + write (line, '(a,i0,a,i0,a)') & + 'start timestep kper="', kper, '" kstp="', kstp, '" mode="' + ! + ! -- evaluate simulation mode + select case (isim_mode) + case (MVALIDATE) + line = trim(line)//'validate"' + case (MNORMAL) + line = trim(line)//'normal"' + end select + + ! -- Read and prepare each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_message(line, fmt=fmt) + call mp%model_rp() + end do + ! + ! -- Read and prepare each exchange + do ie = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ie) + call ep%exg_rp() + end do + ! + ! -- Read and prepare each connection + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_rp() + end do + ! + ! -- reset simulation convergence flag + call converge_reset() + ! + ! -- time update for each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_calculate_delt() + end do + ! + ! -- time update for each exchange + do ie = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ie) + call ep%exg_calculate_delt() + end do + ! + ! -- time update for each connection + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_calculate_delt() + end do + ! + ! -- time update for each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_calculate_delt() + end do + ! + ! -- set time step + call tdis_set_timestep() + + end subroutine Mf6PrepareTimestep + + !> @brief Run time step !! - !! This subroutine runs a single time step for the simulation. + !! This subroutine runs a single time step for the simulation. !! Steps include: !! - formulate the system of equations for each model and exchange !! - solve each solution !! - !< - subroutine Mf6DoTimestep() - ! -- modules - use KindModule, only: I4B - use ListsModule, only: solutiongrouplist - use SimVariablesModule, only: iFailedStepRetry - use SolutionGroupModule, only: SolutionGroupType, GetSolutionGroupFromList - ! -- local variables - class(SolutionGroupType), pointer :: sgp => null() - integer(I4B) :: isg - logical :: finishedTrying - - ! -- By default, the solution groups will be solved once, and - ! may fail. But if adaptive stepping is active, then - ! the solution groups may be solved over and over with - ! progressively smaller time steps to see if convergence - ! can be obtained. - iFailedStepRetry = 0 - retryloop: do - - do isg = 1, solutiongrouplist%Count() - sgp => GetSolutionGroupFromList(solutiongrouplist, isg) - call sgp%sgp_ca() - enddo - - call sim_step_retry(finishedTrying) - if (finishedTrying) exit retryloop - iFailedStepRetry = iFailedStepRetry + 1 - - end do retryloop - - end subroutine Mf6DoTimestep - - !> @brief Rerun time step + !< + subroutine Mf6DoTimestep() + ! -- modules + use KindModule, only: I4B + use ListsModule, only: solutiongrouplist + use SimVariablesModule, only: iFailedStepRetry + use SolutionGroupModule, only: SolutionGroupType, GetSolutionGroupFromList + ! -- local variables + class(SolutionGroupType), pointer :: sgp => null() + integer(I4B) :: isg + logical :: finishedTrying + + ! -- By default, the solution groups will be solved once, and + ! may fail. But if adaptive stepping is active, then + ! the solution groups may be solved over and over with + ! progressively smaller time steps to see if convergence + ! can be obtained. + iFailedStepRetry = 0 + retryloop: do + + do isg = 1, solutiongrouplist%Count() + sgp => GetSolutionGroupFromList(solutiongrouplist, isg) + call sgp%sgp_ca() + end do + + call sim_step_retry(finishedTrying) + if (finishedTrying) exit retryloop + iFailedStepRetry = iFailedStepRetry + 1 + + end do retryloop + + end subroutine Mf6DoTimestep + + !> @brief Rerun time step !! !! This subroutine reruns a single time step for the simulation when - !! the adaptive time step option is used. + !! the adaptive time step option is used. !! - !< - subroutine sim_step_retry(finishedTrying) - ! -- modules - use KindModule, only: DP - use SimVariablesModule, only: lastStepFailed - use SimModule, only: converge_reset - use TdisModule, only: kstp, kper, delt, tdis_delt_reset - use AdaptiveTimeStepModule, only: ats_reset_delt - ! -- dummy variables - logical, intent(out) :: finishedTrying !< boolean that indicates if no - ! additional reruns of the time step are required - ! - ! -- Check with ats to reset delt and keep trying - finishedTrying = .true. - call ats_reset_delt(kstp, kper, lastStepFailed, delt, finishedTrying) - ! - if (.not. finishedTrying) then - ! - ! -- Reset delt, which requires updating pertim, totim - ! and end of period and simulation indicators - call tdis_delt_reset(delt) - ! - ! -- Reset state of the simulation convergence flag - call converge_reset() - - end if - ! - ! -- return - return - end subroutine sim_step_retry - - !> @brief Finalize time step + !< + subroutine sim_step_retry(finishedTrying) + ! -- modules + use KindModule, only: DP + use SimVariablesModule, only: lastStepFailed + use SimModule, only: converge_reset + use TdisModule, only: kstp, kper, delt, tdis_delt_reset + use AdaptiveTimeStepModule, only: ats_reset_delt + ! -- dummy variables + logical, intent(out) :: finishedTrying !< boolean that indicates if no + ! additional reruns of the time step are required + ! + ! -- Check with ats to reset delt and keep trying + finishedTrying = .true. + call ats_reset_delt(kstp, kper, lastStepFailed, delt, finishedTrying) + ! + if (.not. finishedTrying) then + ! + ! -- Reset delt, which requires updating pertim, totim + ! and end of period and simulation indicators + call tdis_delt_reset(delt) + ! + ! -- Reset state of the simulation convergence flag + call converge_reset() + + end if + ! + ! -- return + return + end subroutine sim_step_retry + + !> @brief Finalize time step !! - !! This function finalizes a single time step for the simulation + !! This function finalizes a single time step for the simulation !! and writes output for the time step. Steps include: !! - write output for each model !! - write output for each exchange @@ -534,78 +543,78 @@ end subroutine sim_step_retry !! !! @return hasConverged boolean indicating if convergence was achieved for the time step !! - !< - function Mf6FinalizeTimestep() result(hasConverged) - ! -- modules - use KindModule, only: I4B - use ConstantsModule, only: LINELENGTH, MNORMAL, MVALIDATE - use ListsModule, only: basesolutionlist, basemodellist, baseexchangelist - use BaseModelModule, only: BaseModelType, GetBaseModelFromList - use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList - use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList - use SimModule, only: converge_check - use SimVariablesModule, only: isim_mode - ! -- return variable - logical(LGP) :: hasConverged - ! -- local variables - class(BaseSolutionType), pointer :: sp => null() - class(BaseModelType), pointer :: mp => null() - class(BaseExchangeType), pointer :: ep => null() - class(SpatialModelConnectionType), pointer :: mc => null() - character(len=LINELENGTH) :: line - character(len=LINELENGTH) :: fmt - integer(I4B) :: im - integer(I4B) :: ix - integer(I4B) :: ic - integer(I4B) :: is + !< + function Mf6FinalizeTimestep() result(hasConverged) + ! -- modules + use KindModule, only: I4B + use ConstantsModule, only: LINELENGTH, MNORMAL, MVALIDATE + use ListsModule, only: basesolutionlist, basemodellist, baseexchangelist + use BaseModelModule, only: BaseModelType, GetBaseModelFromList + use BaseExchangeModule, only: BaseExchangeType, GetBaseExchangeFromList + use BaseSolutionModule, only: BaseSolutionType, GetBaseSolutionFromList + use SimModule, only: converge_check + use SimVariablesModule, only: isim_mode + ! -- return variable + logical(LGP) :: hasConverged + ! -- local variables + class(BaseSolutionType), pointer :: sp => null() + class(BaseModelType), pointer :: mp => null() + class(BaseExchangeType), pointer :: ep => null() + class(SpatialModelConnectionType), pointer :: mc => null() + character(len=LINELENGTH) :: line + character(len=LINELENGTH) :: fmt + integer(I4B) :: im + integer(I4B) :: ix + integer(I4B) :: ic + integer(I4B) :: is + ! + ! -- initialize format and line + fmt = "(/,a,/)" + line = 'end timestep' + ! + ! -- evaluate simulation mode + select case (isim_mode) + case (MVALIDATE) + ! + ! -- Write final message for timestep for each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_message(line, fmt=fmt) + end do + case (MNORMAL) ! - ! -- initialize format and line - fmt = "(/,a,/)" - line = 'end timestep' + ! -- Write output and final message for timestep for each model + do im = 1, basemodellist%Count() + mp => GetBaseModelFromList(basemodellist, im) + call mp%model_ot() + call mp%model_message(line, fmt=fmt) + end do ! - ! -- evaluate simulation mode - select case (isim_mode) - case(MVALIDATE) - ! - ! -- Write final message for timestep for each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_message(line, fmt=fmt) - end do - case(MNORMAL) - ! - ! -- Write output and final message for timestep for each model - do im = 1, basemodellist%Count() - mp => GetBaseModelFromList(basemodellist, im) - call mp%model_ot() - call mp%model_message(line, fmt=fmt) - enddo - ! - ! -- Write output for each exchange - do ix = 1, baseexchangelist%Count() - ep => GetBaseExchangeFromList(baseexchangelist, ix) - call ep%exg_ot() - enddo - ! - ! -- Write output for each connection - do ic = 1, baseconnectionlist%Count() - mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) - call mc%exg_ot() - end do - ! - ! -- Write output for each solution - do is=1,basesolutionlist%Count() - sp => GetBaseSolutionFromList(basesolutionlist, is) - call sp%sln_ot() - enddo - end select + ! -- Write output for each exchange + do ix = 1, baseexchangelist%Count() + ep => GetBaseExchangeFromList(baseexchangelist, ix) + call ep%exg_ot() + end do ! - ! -- Check if we're done - call converge_check(hasConverged) + ! -- Write output for each connection + do ic = 1, baseconnectionlist%Count() + mc => GetSpatialModelConnectionFromList(baseconnectionlist, ic) + call mc%exg_ot() + end do ! - ! -- return - return - - end function Mf6FinalizeTimestep - + ! -- Write output for each solution + do is = 1, basesolutionlist%Count() + sp => GetBaseSolutionFromList(basesolutionlist, is) + call sp%sln_ot() + end do + end select + ! + ! -- Check if we're done + call converge_check(hasConverged) + ! + ! -- return + return + + end function Mf6FinalizeTimestep + end module Mf6CoreModule diff --git a/src/mf6lists.f90 b/src/mf6lists.f90 index 2d3ee1f2a9a..f567dcc8d46 100644 --- a/src/mf6lists.f90 +++ b/src/mf6lists.f90 @@ -9,7 +9,7 @@ module ListsModule implicit none private public :: basemodellist, basesolutionlist, solutiongrouplist, & - baseexchangelist, baseconnectionlist + baseexchangelist, baseconnectionlist, distmodellist public :: lists_da ! -- list of all models in simulation @@ -23,12 +23,15 @@ module ListsModule ! -- list of all exchanges in simulation type(ListType) :: baseexchangelist - + ! -- list of all connections in simulation type(ListType) :: baseconnectionlist - - contains - + + ! -- list of all distributed models + type(ListType) :: distmodellist + +contains + subroutine lists_da() ! ****************************************************************************** ! Deallocate the lists @@ -43,7 +46,8 @@ subroutine lists_da() call solutiongrouplist%Clear() call baseexchangelist%Clear() call baseconnectionlist%Clear() - + call distmodellist%Clear(destroy=.true.) + return end subroutine lists_da diff --git a/srcbmi/mf6bmi.f90 b/srcbmi/mf6bmi.f90 index 2b128cdf21d..e963f96cc4a 100644 --- a/srcbmi/mf6bmi.f90 +++ b/srcbmi/mf6bmi.f90 @@ -24,6 +24,7 @@ module mf6bmi c_f_pointer use KindModule, only: DP, I4B, LGP use ConstantsModule, only: LENMEMPATH, LENVARNAME + use CharacterStringModule use MemoryManagerModule, only: mem_setptr, get_mem_elem_size, get_isize, & get_mem_rank, get_mem_shape, get_mem_type, & memorylist, get_from_memorylist @@ -33,12 +34,13 @@ module mf6bmi use InputOutputModule, only: getunit implicit none - integer(c_int), bind(C, name="ISTDOUTTOFILE") :: istdout_to_file = 1 !< output control: =0 to screen, >0 to file + integer(c_int), bind(C, name="ISTDOUTTOFILE") :: istdout_to_file = 1 !< output control: =0 to screen, >0 to file !DIR$ ATTRIBUTES DLLEXPORT :: istdout_to_file contains - function bmi_get_component_name(name) result(bmi_status) bind(C, name="get_component_name") + function bmi_get_component_name(name) result(bmi_status) & + bind(C, name="get_component_name") !DIR$ ATTRIBUTES DLLEXPORT :: bmi_get_component_name ! -- dummy variables character(kind=c_char), intent(out) :: name(BMI_LENCOMPONENTNAME) @@ -126,11 +128,12 @@ end function bmi_finalize !! As MODFLOW currently does not have internal time, this will be !! returning 0.0 for now. New version... !< - function get_start_time(start_time) result(bmi_status) bind(C, name="get_start_time") + function get_start_time(start_time) result(bmi_status) & + bind(C, name="get_start_time") !DIR$ ATTRIBUTES DLLEXPORT :: get_start_time ! -- dummy variables real(kind=c_double), intent(out) :: start_time !< start time - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code start_time = 0.0_DP bmi_status = BMI_SUCCESS @@ -148,7 +151,7 @@ function get_end_time(end_time) result(bmi_status) bind(C, name="get_end_time") use TdisModule, only: totalsimtime ! -- dummy variables real(kind=c_double), intent(out) :: end_time !< end time - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code end_time = totalsimtime bmi_status = BMI_SUCCESS @@ -160,13 +163,14 @@ end function get_end_time !! As MODFLOW currently does not have internal time, this will be !! equal to the time passed w.r.t. the start time of the simulation. !< - function get_current_time(current_time) result(bmi_status) bind(C, name="get_current_time") + function get_current_time(current_time) result(bmi_status) & + bind(C, name="get_current_time") !DIR$ ATTRIBUTES DLLEXPORT :: get_current_time ! -- modules use TdisModule, only: totim ! -- dummy variables real(kind=c_double), intent(out) :: current_time !< current time - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code current_time = totim bmi_status = BMI_SUCCESS @@ -178,13 +182,14 @@ end function get_current_time !! Note that the returned value may vary between and within stress periods, !! depending on your time discretization settings in the TDIS package. !< - function get_time_step(time_step) result(bmi_status) bind(C, name="get_time_step") + function get_time_step(time_step) result(bmi_status) & + bind(C, name="get_time_step") !DIR$ ATTRIBUTES DLLEXPORT :: get_time_step ! -- modules use TdisModule, only: delt ! -- dummy variables - real(kind=c_double), intent(out) :: time_step !< current time step - integer(kind=c_int) :: bmi_status !< BMI status code + real(kind=c_double), intent(out) :: time_step !< current time step + integer(kind=c_int) :: bmi_status !< BMI status code time_step = delt bmi_status = BMI_SUCCESS @@ -195,11 +200,12 @@ end function get_time_step !! !! This concerns all variables stored in the memory manager !< - function get_input_item_count(count) result(bmi_status) bind(C, name="get_input_item_count") + function get_input_item_count(count) result(bmi_status) & + bind(C, name="get_input_item_count") !DIR$ ATTRIBUTES DLLEXPORT :: get_input_item_count ! -- dummy variables integer(kind=c_int), intent(out) :: count !< the number of input variables - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code count = memorylist%count() @@ -211,11 +217,12 @@ end function get_input_item_count !! !! This concerns all variables stored in the memory manager !< - function get_output_item_count(count) result(bmi_status) bind(C, name="get_output_item_count") + function get_output_item_count(count) result(bmi_status) & + bind(C, name="get_output_item_count") !DIR$ ATTRIBUTES DLLEXPORT :: get_output_item_count ! -- dummy variables integer(kind=c_int), intent(out) :: count !< the number of output variables - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code count = memorylist%count() @@ -237,11 +244,12 @@ end function get_output_item_count !! !! c_names = 'variable_address_1\x00 ... variable_address_2\x00 ... ' etc. !< - function get_input_var_names(c_names) result(bmi_status) bind(C, name="get_input_var_names") + function get_input_var_names(c_names) result(bmi_status) & + bind(C, name="get_input_var_names") !DIR$ ATTRIBUTES DLLEXPORT :: get_input_var_names ! -- dummy variables character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for input variables - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables integer(I4B) :: imem, start, i type(MemoryType), pointer :: mt => null() @@ -268,11 +276,12 @@ end function get_input_var_names !! and currently returns the same set of memory variables, !! which is all of them! !< - function get_output_var_names(c_names) result(bmi_status) bind(C, name="get_output_var_names") + function get_output_var_names(c_names) result(bmi_status) & + bind(C, name="get_output_var_names") !DIR$ ATTRIBUTES DLLEXPORT :: get_output_var_names ! -- dummy variables character(kind=c_char, len=1), intent(inout) :: c_names(*) !< array with memory paths for output variables - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables integer(I4B) :: imem, start, i type(MemoryType), pointer :: mt => null() @@ -295,12 +304,13 @@ end function get_output_var_names !> @brief Get the size (in bytes) of a single element of a variable !< - function get_var_itemsize(c_var_address, var_size) result(bmi_status) bind(C, name="get_var_itemsize") + function get_var_itemsize(c_var_address, var_size) result(bmi_status) & + bind(C, name="get_var_itemsize") !DIR$ ATTRIBUTES DLLEXPORT :: get_var_itemsize ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - integer(kind=c_int), intent(out) :: var_size !< size of the element in bytes - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int), intent(out) :: var_size !< size of the element in bytes + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -321,12 +331,13 @@ end function get_var_itemsize !> @brief Get size of the variable, in bytes !< - function get_var_nbytes(c_var_address, var_nbytes) result(bmi_status) bind(C, name="get_var_nbytes") + function get_var_nbytes(c_var_address, var_nbytes) result(bmi_status) & + bind(C, name="get_var_nbytes") !DIR$ ATTRIBUTES DLLEXPORT :: get_var_nbytes ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - integer(kind=c_int), intent(out) :: var_nbytes !< size in bytes - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int), intent(out) :: var_nbytes !< size in bytes + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables integer(I4B) :: var_size, isize character(len=LENMEMPATH) :: mem_path @@ -346,7 +357,7 @@ function get_var_nbytes(c_var_address, var_nbytes) result(bmi_status) bind(C, na call get_isize(var_name, mem_path, isize) if (isize == -1) bmi_status = BMI_FAILURE - var_nbytes = var_size*isize + var_nbytes = var_size * isize end function get_var_nbytes @@ -357,14 +368,15 @@ end function get_var_nbytes !! BMI function get_var_shape() can be used to create it). Multi-dimensional !! arrays are supported. !< - function get_value_double(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="get_value_double") + function get_value_double(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="get_value_double") !DIR$ ATTRIBUTES DLLEXPORT :: get_value_double ! -- modules use MemorySetHandlerModule, only: on_memory_set ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -428,19 +440,20 @@ end function get_value_double !> @brief Copy the integer values of a variable into the array !! - !! The copied variable us located at @p c_var_address. The caller should + !! The copied variable is located at @p c_var_address. The caller should !! provide @p c_arr_ptr pointing to an array of the proper shape (the !! BMI function get_var_shape() can be used to create it). Multi-dimensional !! arrays are supported. !< - function get_value_int(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="get_value_int") + function get_value_int(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="get_value_int") !DIR$ ATTRIBUTES DLLEXPORT :: get_value_int ! -- modules use MemorySetHandlerModule, only: on_memory_set ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -502,6 +515,84 @@ function get_value_int(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name end function get_value_int + !> @brief Copy the string(s) of a variable into the array + !! + !! The copied variable is located at @p c_var_address. The caller should + !! provide @p c_arr_ptr pointing to an array of the proper shape (the + !! BMI function get_var_shape() can be used to create it). For strings + !! currently scalars and 1d arrays (of CharacterStringType) are + !< supported + function get_value_string(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="get_value_string") + !DIR$ ATTRIBUTES DLLEXPORT :: get_value_string + ! -- modules + ! -- dummy variables + character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable + type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the string array + integer(kind=c_int) :: bmi_status !< BMI status code + ! -- local variables + character(len=LENMEMPATH) :: mem_path + character(len=LENVARNAME) :: var_name + logical(LGP) :: valid + integer(I4B) :: rank + character(len=:), pointer :: srcstr + character(kind=c_char), pointer :: tgtstr(:) + type(CharacterStringType), dimension(:), pointer, contiguous :: srccharstr1d + character(kind=c_char), pointer :: tgtstr1d(:, :) + character(:), allocatable :: tempstr + integer(I4B) :: i, ilen, isize + + bmi_status = BMI_SUCCESS + + call split_address(c_var_address, mem_path, var_name, valid) + if (.not. valid) then + bmi_status = BMI_FAILURE + return + end if + + ! single string, or array of strings (CharacterStringType) + rank = -1 + call get_mem_rank(var_name, mem_path, rank) + + if (rank == 0) then + ! a string scalar + call mem_setptr(srcstr, var_name, mem_path) + call get_mem_elem_size(var_name, mem_path, ilen) + call c_f_pointer(c_arr_ptr, tgtstr, shape=[ilen + 1]) + tgtstr(1:len(srcstr) + 1) = string_to_char_array(srcstr, len(srcstr)) + + else if (rank == 1) then + ! an array of strings + call mem_setptr(srccharstr1d, var_name, mem_path) + if (.not. associated(srccharstr1d)) then + write (bmi_last_error, fmt_general_err) 'string type not supported in API' + call report_bmi_error(bmi_last_error) + bmi_status = BMI_FAILURE + return + end if + + ! create fortran pointer to C data array + call get_isize(var_name, mem_path, isize) + call get_mem_elem_size(var_name, mem_path, ilen) + call c_f_pointer(c_arr_ptr, tgtstr1d, shape=[ilen + 1, isize]) + + ! allocate work array to handle CharacterStringType, + ! and copy the strings + allocate (character(ilen) :: tempstr) + do i = 1, isize + tempstr = srccharstr1d(i) + tgtstr1d(1:ilen + 1, i) = string_to_char_array(tempstr, ilen) + end do + deallocate (tempstr) + else + write (bmi_last_error, fmt_unsupported_rank) trim(var_name) + call report_bmi_error(bmi_last_error) + bmi_status = BMI_FAILURE + return + end if + + end function get_value_string + !> @brief Get a pointer to the array of double precision numbers !! !! The array is located at @p c_var_address. There is no copying of data involved. @@ -509,12 +600,13 @@ end function get_value_int !! can be used to get the variable's dimensionality, and get_var_shape() for !! its shape. !< - function get_value_ptr_double(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="get_value_ptr_double") + function get_value_ptr_double(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="get_value_ptr_double") !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_double ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -562,12 +654,13 @@ end function get_value_ptr_double !! Multi-dimensional arrays are supported and the get_var_rank() function !! can be used to get the variable's dimensionality. !< - function get_value_ptr_int(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="get_value_ptr_int") + function get_value_ptr_int(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="get_value_ptr_int") !DIR$ ATTRIBUTES DLLEXPORT :: get_value_ptr_int ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(inout) :: c_arr_ptr !< pointer to the array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -616,14 +709,15 @@ end function get_value_ptr_int !! and should have a C-style layout, which is particularly important for !! rank > 1. !< - function set_value_double(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="set_value_double") + function set_value_double(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="set_value_double") !DIR$ ATTRIBUTES DLLEXPORT :: set_value_double ! -- modules use MemorySetHandlerModule, only: on_memory_set ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the double precision array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -688,14 +782,15 @@ end function set_value_double !! !! The array pointed to by @p c_arr_ptr can have rank equal to 0, 1, or 2. !< - function set_value_int(c_var_address, c_arr_ptr) result(bmi_status) bind(C, name="set_value_int") + function set_value_int(c_var_address, c_arr_ptr) result(bmi_status) & + bind(C, name="set_value_int") !DIR$ ATTRIBUTES DLLEXPORT :: set_value_int ! -- modules use MemorySetHandlerModule, only: on_memory_set ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array - integer(kind=c_int) :: bmi_status !< BMI status code + type(c_ptr), intent(in) :: c_arr_ptr !< pointer to the integer array + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -758,18 +853,18 @@ end function set_value_int !> @brief Get the variable type as a string !! - !! The type returned is that of a single element. Currently we - !! support 'INTEGER' and 'DOUBLE'. When the variable cannot - !! be found, the string 'UNKNOWN' is assigned. - !< - function get_var_type(c_var_address, c_var_type) result(bmi_status) bind(C, name="get_var_type") -!DIR$ ATTRIBUTES DLLEXPORT :: get_var_type + !! The type returned is that of a single element. + !! When the variable cannot be found, the string + !< 'UNKNOWN' is assigned. + function get_var_type(c_var_address, c_var_type) result(bmi_status) & + bind(C, name="get_var_type") + !DIR$ ATTRIBUTES DLLEXPORT :: get_var_type ! -- modules use ConstantsModule, only: LENMEMTYPE ! -- dummy variables - character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - character(kind=c_char), intent(out) :: c_var_type(BMI_LENVARTYPE) !< variable type as a string - integer(kind=c_int) :: bmi_status !< BMI status code + character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable + character(kind=c_char), intent(out) :: c_var_type(BMI_LENVARTYPE) !< variable type as a string + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -785,7 +880,8 @@ function get_var_type(c_var_address, c_var_type) result(bmi_status) bind(C, name end if call get_mem_type(var_name, mem_path, mem_type) - c_var_type(1:len(trim(mem_type)) + 1) = string_to_char_array(trim(mem_type), len(trim(mem_type))) + c_var_type(1:len(trim(mem_type)) + 1) = & + string_to_char_array(trim(mem_type), len(trim(mem_type))) if (mem_type == 'UNKNOWN') then write (bmi_last_error, fmt_general_err) 'unknown memory type' @@ -800,12 +896,13 @@ end function get_var_type !! In order to support multi-dimensional arrays, this function gives !! access to the rank of the array. !< - function get_var_rank(c_var_address, c_var_rank) result(bmi_status) bind(C, name="get_var_rank") + function get_var_rank(c_var_address, c_var_rank) result(bmi_status) & + bind(C, name="get_var_rank") !DIR$ ATTRIBUTES DLLEXPORT :: get_var_rank ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - integer(kind=c_int), intent(out) :: c_var_rank !< variable rank - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int), intent(out) :: c_var_rank !< variable rank + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENMEMPATH) :: mem_path character(len=LENVARNAME) :: var_name @@ -837,14 +934,15 @@ end function get_var_rank !! Note that the returned shape representation will has been converted !! to C-style. !< - function get_var_shape(c_var_address, c_var_shape) result(bmi_status) bind(C, name="get_var_shape") + function get_var_shape(c_var_address, c_var_shape) result(bmi_status) & + bind(C, name="get_var_shape") !DIR$ ATTRIBUTES DLLEXPORT :: get_var_shape ! -- modules use ConstantsModule, only: MAXMEMRANK ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< memory address string of the variable - integer(c_int), intent(inout) :: c_var_shape(*) !< 1D array with the variable's shape - integer(kind=c_int) :: bmi_status !< BMI status code + integer(c_int), intent(inout) :: c_var_shape(*) !< 1D array with the variable's shape + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables integer(I4B), dimension(MAXMEMRANK) :: var_shape integer(I4B) :: var_rank diff --git a/srcbmi/mf6bmiError.f90 b/srcbmi/mf6bmiError.f90 index fa2c5942ea9..c337b68f2e7 100644 --- a/srcbmi/mf6bmiError.f90 +++ b/srcbmi/mf6bmiError.f90 @@ -13,23 +13,27 @@ module mf6bmiError integer, parameter :: BMI_SUCCESS = 0 !< BMI status code for success (taken from bmi.f90, CSDMS) integer(I4B), parameter :: LENERRMESSAGE = 1024 !< max length for the error message - integer(c_int), bind(C, name="BMI_LENERRMESSAGE") :: BMI_LENERRMESSAGE = LENERRMESSAGE + 1 !< max. length for the (exported) C-style error message + integer(c_int), bind(C, name="BMI_LENERRMESSAGE") :: BMI_LENERRMESSAGE = & + LENERRMESSAGE + 1 !< max. length for the (exported) C-style error message !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENERRMESSAGE character(len=LENERRMESSAGE) :: bmi_last_error = 'No BMI error reported' !< module variable containing the last error as a Fortran string - character(len=*), parameter :: fmt_general_err = & !< General bmi error, args: context/detail + character(len=*), parameter :: fmt_general_err = & !< General bmi error, args: context/detail "('BMI Error, ', a)" - character(len=*), parameter :: fmt_unknown_var = & !< Variable unknown, args: variable name, memory path + character(len=*), parameter :: fmt_unknown_var = & !< Variable unknown, args: variable name, memory path "('BMI Error, unknown variable: ', a, ' at ', a)" - character(len=*), parameter :: fmt_invalid_var = & !< Invalid variable address, args: variable address + character(len=*), parameter :: fmt_invalid_var = & !< Invalid variable address, args: variable address "('BMI Error, invalid address string: ', a)" - character(len=*), parameter :: fmt_unsupported_rank = & !< Unsupported rank, args: variable name - "('BMI Error, unsupported rank for variable: ', a)" + character(len=*), parameter :: fmt_unsupported_rank = & !< Unsupported rank, args: variable name + "('BMI Error, unsupported rank for variable: & + &', a)" character(len=*), parameter :: fmt_invalid_mem_access = & !< Invalid memory access, args: variable name - "('Fatal BMI Error, invalid access of memory for variable: ', a)" - character(len=*), parameter :: fmt_fail_cvg_sol = & !< Solution failed to converge, args: detail - "('BMI Error, Numerical Solution ', i3, ' failed to converge')" + "('Fatal BMI Error, invalid access of memory & + &for variable: ', a)" + character(len=*), parameter :: fmt_fail_cvg_sol = & !< Solution failed to converge, args: detail + "('BMI Error, Numerical Solution ', i3, & + &' failed to converge')" contains @@ -46,10 +50,11 @@ end subroutine report_bmi_error !> @brief Get the last error in the BMI as a character array !! with size BMI_LENERRMESSAGE !< - function get_last_bmi_error(c_error) result(bmi_status) bind(C, name="get_last_bmi_error") + function get_last_bmi_error(c_error) result(bmi_status) & + bind(C, name="get_last_bmi_error") !DIR$ ATTRIBUTES DLLEXPORT :: get_last_bmi_error ! -- dummy variables - character(kind=c_char, len=1), intent(out) :: c_error(BMI_LENERRMESSAGE) !< C style char array with error + character(kind=c_char, len=1), intent(out) :: c_error(BMI_LENERRMESSAGE) !< C style char array with error integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables integer(I4B) :: i, length diff --git a/srcbmi/mf6bmiGrid.f90 b/srcbmi/mf6bmiGrid.f90 index 48055b7666a..4af4d122e28 100644 --- a/srcbmi/mf6bmiGrid.f90 +++ b/srcbmi/mf6bmiGrid.f90 @@ -18,7 +18,8 @@ module mf6bmiGrid contains ! Get the grid identifier for the given variable. - function get_var_grid(c_var_address, var_grid) result(bmi_status) bind(C, name="get_var_grid") + function get_var_grid(c_var_address, var_grid) result(bmi_status) & + bind(C, name="get_var_grid") !DIR$ ATTRIBUTES DLLEXPORT :: get_var_grid ! -- modules use ListsModule, only: basemodellist @@ -37,7 +38,8 @@ function get_var_grid(c_var_address, var_grid) result(bmi_status) bind(C, name=" var_grid = -1 bmi_status = BMI_FAILURE - var_address = char_array_to_string(c_var_address, strlen(c_var_address)) + var_address = char_array_to_string(c_var_address, & + strlen(c_var_address, LENMEMADDRESS + 1)) model_name = extract_model_name(var_address, success) if (.not. success) then ! we failed @@ -55,7 +57,8 @@ function get_var_grid(c_var_address, var_grid) result(bmi_status) bind(C, name=" end function get_var_grid ! Get the grid type as a string. - function get_grid_type(grid_id, grid_type) result(bmi_status) bind(C, name="get_grid_type") + function get_grid_type(grid_id, grid_type) result(bmi_status) & + bind(C, name="get_grid_type") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_type ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -83,7 +86,8 @@ function get_grid_type(grid_id, grid_type) result(bmi_status) bind(C, name="get_ end function get_grid_type ! Get number of dimensions of the computational grid. - function get_grid_rank(grid_id, grid_rank) result(bmi_status) bind(C, name="get_grid_rank") + function get_grid_rank(grid_id, grid_rank) result(bmi_status) & + bind(C, name="get_grid_rank") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_rank ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -110,7 +114,8 @@ function get_grid_rank(grid_id, grid_rank) result(bmi_status) bind(C, name="get_ end function get_grid_rank ! Get the total number of elements in the computational grid. - function get_grid_size(grid_id, grid_size) result(bmi_status) bind(C, name="get_grid_size") + function get_grid_size(grid_id, grid_size) result(bmi_status) & + bind(C, name="get_grid_size") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_size ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -126,12 +131,13 @@ function get_grid_size(grid_id, grid_size) result(bmi_status) bind(C, name="get_ bmi_status = BMI_FAILURE if (get_grid_type(grid_id, grid_type) /= BMI_SUCCESS) return - grid_type_f = char_array_to_string(grid_type, strlen(grid_type)) + grid_type_f = char_array_to_string(grid_type, & + strlen(grid_type, LENGRIDTYPE + 1)) model_name = get_model_name(grid_id) if (grid_type_f == "rectilinear") then call mem_setptr(grid_shape, "MSHAPE", create_mem_path(model_name, 'DIS')) - grid_size = grid_shape(1)*grid_shape(2)*grid_shape(3) + grid_size = grid_shape(1) * grid_shape(2) * grid_shape(3) bmi_status = BMI_SUCCESS return else if (grid_type_f == "unstructured") then @@ -142,7 +148,8 @@ function get_grid_size(grid_id, grid_size) result(bmi_status) bind(C, name="get_ end function get_grid_size ! Get the dimensions of the computational grid. - function get_grid_shape(grid_id, grid_shape) result(bmi_status) bind(C, name="get_grid_shape") + function get_grid_shape(grid_id, grid_shape) result(bmi_status) & + bind(C, name="get_grid_shape") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_shape ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -162,15 +169,16 @@ function get_grid_shape(grid_id, grid_shape) result(bmi_status) bind(C, name="ge call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS')) if (grid_shape_ptr(1) == 1) then - grid_shape(1:2) = grid_shape_ptr(2:3) ! 2D + grid_shape(1:2) = grid_shape_ptr(2:3) ! 2D else - grid_shape(1:3) = grid_shape_ptr ! 3D + grid_shape(1:3) = grid_shape_ptr ! 3D end if bmi_status = BMI_SUCCESS end function get_grid_shape ! Provides an array (whose length is the number of rows) that gives the x-coordinate for each row. - function get_grid_x(grid_id, grid_x) result(bmi_status) bind(C, name="get_grid_x") + function get_grid_x(grid_id, grid_x) result(bmi_status) & + bind(C, name="get_grid_x") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_x ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -188,17 +196,20 @@ function get_grid_x(grid_id, grid_x) result(bmi_status) bind(C, name="get_grid_x bmi_status = BMI_FAILURE ! make sure function is only used for implemented grid_types if (get_grid_type(grid_id, grid_type) /= BMI_SUCCESS) return - grid_type_f = char_array_to_string(grid_type, strlen(grid_type)) + grid_type_f = char_array_to_string(grid_type, & + strlen(grid_type, LENGRIDTYPE + 1)) model_name = get_model_name(grid_id) if (grid_type_f == "rectilinear") then - call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS')) + call mem_setptr(grid_shape_ptr, "MSHAPE", & + create_mem_path(model_name, 'DIS')) ! The dimension of x is in the last element of the shape array. ! + 1 because we count corners, not centers. x_size = grid_shape_ptr(size(grid_shape_ptr)) + 1 grid_x(1:x_size) = [(i, i=0, x_size - 1)] else if (grid_type_f == "unstructured") then - call mem_setptr(vertices_ptr, "VERTICES", create_mem_path(model_name, 'DIS')) + call mem_setptr(vertices_ptr, "VERTICES", & + create_mem_path(model_name, 'DIS')) ! x-coordinates are in the 1st column x_size = size(vertices_ptr(1, :)) grid_x(1:x_size) = vertices_ptr(1, :) @@ -210,7 +221,8 @@ function get_grid_x(grid_id, grid_x) result(bmi_status) bind(C, name="get_grid_x end function get_grid_x ! Provides an array (whose length is the number of rows) that gives the y-coordinate for each row. - function get_grid_y(grid_id, grid_y) result(bmi_status) bind(C, name="get_grid_y") + function get_grid_y(grid_id, grid_y) result(bmi_status) & + bind(C, name="get_grid_y") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_y ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -227,17 +239,20 @@ function get_grid_y(grid_id, grid_y) result(bmi_status) bind(C, name="get_grid_y bmi_status = BMI_FAILURE if (get_grid_type(grid_id, grid_type) /= BMI_SUCCESS) return - grid_type_f = char_array_to_string(grid_type, strlen(grid_type)) + grid_type_f = char_array_to_string(grid_type, & + strlen(grid_type, LENGRIDTYPE + 1)) model_name = get_model_name(grid_id) if (grid_type_f == "rectilinear") then - call mem_setptr(grid_shape_ptr, "MSHAPE", create_mem_path(model_name, 'DIS')) + call mem_setptr(grid_shape_ptr, "MSHAPE", & + create_mem_path(model_name, 'DIS')) ! The dimension of y is in the second last element of the shape array. ! + 1 because we count corners, not centers. y_size = grid_shape_ptr(size(grid_shape_ptr - 1)) + 1 grid_y(1:y_size) = [(i, i=y_size - 1, 0, -1)] else if (grid_type_f == "unstructured") then - call mem_setptr(vertices_ptr, "VERTICES", create_mem_path(model_name, 'DIS')) + call mem_setptr(vertices_ptr, "VERTICES", & + create_mem_path(model_name, 'DIS')) ! y-coordinates are in the 2nd column y_size = size(vertices_ptr(2, :)) grid_y(1:y_size) = vertices_ptr(2, :) @@ -250,7 +265,8 @@ end function get_grid_y ! NOTE: node in BMI-terms is a vertex in Modflow terms ! Get the number of nodes in an unstructured grid. - function get_grid_node_count(grid_id, count) result(bmi_status) bind(C, name="get_grid_node_count") + function get_grid_node_count(grid_id, count) result(bmi_status) & + bind(C, name="get_grid_node_count") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_node_count ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -272,7 +288,8 @@ end function get_grid_node_count ! TODO_JH: This currently only works for 2D DISU models ! Get the number of faces in an unstructured grid. - function get_grid_face_count(grid_id, count) result(bmi_status) bind(C, name="get_grid_face_count") + function get_grid_face_count(grid_id, count) result(bmi_status) & + bind(C, name="get_grid_face_count") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_face_count ! -- modules use ListsModule, only: basemodellist @@ -301,7 +318,8 @@ function get_grid_face_count(grid_id, count) result(bmi_status) bind(C, name="ge end function get_grid_face_count ! Get the face-node connectivity. - function get_grid_face_nodes(grid_id, face_nodes) result(bmi_status) bind(C, name="get_grid_face_nodes") + function get_grid_face_nodes(grid_id, face_nodes) result(bmi_status) & + bind(C, name="get_grid_face_nodes") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_face_nodes ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id @@ -335,7 +353,8 @@ function get_grid_face_nodes(grid_id, face_nodes) result(bmi_status) bind(C, nam end function get_grid_face_nodes ! Get the number of nodes for each face. - function get_grid_nodes_per_face(grid_id, nodes_per_face) result(bmi_status) bind(C, name="get_grid_nodes_per_face") + function get_grid_nodes_per_face(grid_id, nodes_per_face) result(bmi_status) & + bind(C, name="get_grid_nodes_per_face") !DIR$ ATTRIBUTES DLLEXPORT :: get_grid_nodes_per_face ! -- dummy variables integer(kind=c_int), intent(in) :: grid_id diff --git a/srcbmi/mf6bmiUtil.f90 b/srcbmi/mf6bmiUtil.f90 index 94609c35cee..4a5f1d1945e 100644 --- a/srcbmi/mf6bmiUtil.f90 +++ b/srcbmi/mf6bmiUtil.f90 @@ -23,18 +23,25 @@ module mf6bmiUtil integer(I4B), parameter :: LENGRIDTYPE = 16 !< max length for Fortran grid type string - integer(c_int), bind(C, name="BMI_LENVARTYPE") :: BMI_LENVARTYPE = LENMEMTYPE + 1 !< max. length for variable type C-strings + integer(c_int), bind(C, name="BMI_LENVARTYPE") :: BMI_LENVARTYPE = & + LENMEMTYPE + 1 !< max. length for variable type C-strings !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENVARTYPE - integer(c_int), bind(C, name="BMI_LENGRIDTYPE") :: BMI_LENGRIDTYPE = LENGRIDTYPE + 1 !< max. length for grid type C-strings + integer(c_int), bind(C, name="BMI_LENGRIDTYPE") :: BMI_LENGRIDTYPE = & + LENGRIDTYPE + 1 !< max. length for grid type C-strings !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENGRIDTYPE - integer(c_int), bind(C, name="BMI_LENVARADDRESS") :: BMI_LENVARADDRESS = LENMEMADDRESS + 1 !< max. length for the variable's address C-string + integer(c_int), bind(C, name="BMI_LENVARADDRESS") :: BMI_LENVARADDRESS = & + LENMEMADDRESS + 1 !< max. length for the variable's address C-string !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENVARADDRESS - integer(c_int), bind(C, name="BMI_LENCOMPONENTNAME") :: BMI_LENCOMPONENTNAME = 256 !< component name length, i.e. 'MODFLOW 6' + integer(c_int), bind(C, name="BMI_LENCOMPONENTNAME") :: BMI_LENCOMPONENTNAME = & + 256 !< component name length, i.e. 'MODFLOW 6' !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENCOMPONENTNAME + integer(c_int), bind(C, name="BMI_LENVERSION") :: BMI_LENVERSION = 256 !< length of version string, e.g. '6.3.1' or '6.4.1-dev' + !DIR$ ATTRIBUTES DLLEXPORT :: BMI_LENVERSION + contains !> @brief Split the variable address string @@ -48,17 +55,18 @@ subroutine split_address(c_var_address, mem_path, var_name, success) use MemoryHelperModule, only: memPathSeparator ! -- dummy variables character(kind=c_char), intent(in) :: c_var_address(*) !< full address of a variable - character(len=LENMEMPATH), intent(out) :: mem_path !< memory path used by the memory manager - character(len=LENVARNAME), intent(out) :: var_name !< name of the variable - logical(LGP), intent(out) :: success !< false when invalid + character(len=LENMEMPATH), intent(out) :: mem_path !< memory path used by the memory manager + character(len=LENVARNAME), intent(out) :: var_name !< name of the variable + logical(LGP), intent(out) :: success !< false when invalid ! -- local variables - character(len=LENMEMPATH) :: var_address + character(len=LENMEMADDRESS) :: var_address logical(LGP) :: valid, found success = .false. ! try and split the address string: - var_address = char_array_to_string(c_var_address, strlen(c_var_address)) + var_address = char_array_to_string(c_var_address, & + strlen(c_var_address, LENMEMADDRESS + 1)) call split_mem_address(var_address, mem_path, var_name, valid) if (.not. valid) then write (bmi_last_error, fmt_invalid_var) trim(var_address) @@ -85,9 +93,9 @@ subroutine check_mem_address(mem_path, var_name, found) use MemoryManagerModule, only: get_from_memorylist use MemoryTypeModule, only: MemoryType ! -- dummy variables - character(len=LENMEMPATH), intent(in) :: mem_path !< memory path used by the memory manager - character(len=LENVARNAME), intent(in) :: var_name !< name of the variable - logical(LGP), intent(out) :: found !< true when found + character(len=LENMEMPATH), intent(in) :: mem_path !< memory path used by the memory manager + character(len=LENVARNAME), intent(in) :: var_name !< name of the variable + logical(LGP), intent(out) :: found !< true when found ! -- local variables type(MemoryType), pointer :: mt @@ -101,10 +109,11 @@ end subroutine check_mem_address !> @brief Returns the string length without the trailing null character !< - pure function strlen(char_array) result(string_length) + pure function strlen(char_array, max_len) result(string_length) ! -- dummy variables - character(c_char), intent(in) :: char_array(LENMEMPATH) !< C-style character string - integer(I4B) :: string_length !< Fortran string length + integer(I4B), intent(in) :: max_len + character(c_char), intent(in) :: char_array(max_len) !< C-style character string + integer(I4B) :: string_length !< Fortran string length ! -- local variables integer(I4B) :: i @@ -122,9 +131,9 @@ end function strlen !< pure function char_array_to_string(char_array, length) result(f_string) ! -- dummy variables - integer(c_int), intent(in) :: length !< string length without terminating null character - character(c_char), intent(in) :: char_array(length) !< string to convert - character(len=length) :: f_string !< Fortran fixed length character string + integer(c_int), intent(in) :: length !< string length without terminating null character + character(c_char), intent(in) :: char_array(length) !< string to convert + character(len=length) :: f_string !< Fortran fixed length character string ! -- local variables integer(I4B) :: i @@ -138,8 +147,8 @@ end function char_array_to_string !< pure function string_to_char_array(string, length) result(c_array) ! -- dummy variables - integer(c_int), intent(in) :: length !< Fortran string length - character(len=length), intent(in) :: string !< string to convert + integer(c_int), intent(in) :: length !< Fortran string length + character(len=length), intent(in) :: string !< string to convert character(kind=c_char, len=1) :: c_array(length + 1) !< C-style character string ! -- local variables integer(I4B) :: i @@ -156,7 +165,7 @@ end function string_to_char_array function extract_model_name(var_address, success) result(model_name) ! -- dummy variables character(len=*), intent(in) :: var_address !< the memory address for the variable - character(len=LENMODELNAME) :: model_name !< the extracted model name + character(len=LENMODELNAME) :: model_name !< the extracted model name logical(LGP), intent(out) :: success ! -- local variables character(len=LENMEMPATH) :: mem_path @@ -183,8 +192,8 @@ function get_model_name(grid_id) result(model_name) use ListsModule, only: basemodellist use BaseModelModule, only: BaseModelType, GetBaseModelFromList ! -- dummy variables - integer(kind=c_int), intent(in) :: grid_id !< grid id - character(len=LENMODELNAME) :: model_name !< model name + integer(kind=c_int), intent(in) :: grid_id !< grid id + character(len=LENMODELNAME) :: model_name !< model name ! -- local variables integer(I4B) :: i class(BaseModelType), pointer :: baseModel @@ -212,7 +221,7 @@ function getSolution(subcomponent_idx) result(solution) use NumericalSolutionModule use ListsModule, only: basesolutionlist, solutiongrouplist ! -- dummy variables - integer(I4B), intent(in) :: subcomponent_idx !< index of solution + integer(I4B), intent(in) :: subcomponent_idx !< index of solution class(NumericalSolutionType), pointer :: solution !< Numerical Solution ! -- local variables class(SolutionGroupType), pointer :: sgp diff --git a/srcbmi/mf6xmi.f90 b/srcbmi/mf6xmi.f90 index ae29bb72923..75560d9e42c 100644 --- a/srcbmi/mf6xmi.f90 +++ b/srcbmi/mf6xmi.f90 @@ -103,11 +103,12 @@ module mf6xmi !! does not allow to alter this value after initialization, so it is ignored !! here. !< - function xmi_prepare_time_step(dt) result(bmi_status) bind(C, name="prepare_time_step") + function xmi_prepare_time_step(dt) result(bmi_status) & + bind(C, name="prepare_time_step") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_prepare_time_step ! -- dummy variables - real(kind=c_double), intent(in) :: dt !< time step - integer(kind=c_int) :: bmi_status !< BMI status code + real(kind=c_double), intent(in) :: dt !< time step + integer(kind=c_int) :: bmi_status !< BMI status code call Mf6PrepareTimestep() bmi_status = BMI_SUCCESS @@ -134,7 +135,8 @@ end function xmi_do_time_step !! This will mostly write output and messages. It is essential !! to call this to finish the time step. !< - function xmi_finalize_time_step() result(bmi_status) bind(C, name="finalize_time_step") + function xmi_finalize_time_step() result(bmi_status) & + bind(C, name="finalize_time_step") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_finalize_time_step ! -- dummy variables integer(kind=c_int) :: bmi_status !< BMI status code @@ -159,20 +161,22 @@ end function xmi_finalize_time_step !! Solution Group. (If you don't know what a Solution Group is, then !! you are most likely not using more than one...) !< - function xmi_get_subcomponent_count(count) result(bmi_status) bind(C, name="get_subcomponent_count") + function xmi_get_subcomponent_count(count) result(bmi_status) & + bind(C, name="get_subcomponent_count") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_get_subcomponent_count ! -- modules use ListsModule, only: solutiongrouplist use SimVariablesModule, only: istdout ! -- dummy variables integer(kind=c_int), intent(out) :: count !< number of solutions - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables class(SolutionGroupType), pointer :: sgp ! the following is true for all calls at this level (subcomponent) if (solutiongrouplist%Count() /= 1) then - write (istdout, *) 'Error: BMI does not support the use of multiple solution groups' + write (istdout, *) & + 'Error: BMI does not support the use of multiple solution groups' count = -1 bmi_status = BMI_FAILURE return @@ -190,7 +194,8 @@ end function xmi_get_subcomponent_count !! in the simulation. The index \p subcomponent_idx runs from 1 to the value returned !! by xmi_get_subcomponent_count(). !< - function xmi_prepare_solve(subcomponent_idx) result(bmi_status) bind(C, name="prepare_solve") + function xmi_prepare_solve(subcomponent_idx) result(bmi_status) & + bind(C, name="prepare_solve") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_prepare_solve ! -- modules use ListsModule, only: solutiongrouplist @@ -198,13 +203,14 @@ function xmi_prepare_solve(subcomponent_idx) result(bmi_status) bind(C, name="pr use SimVariablesModule, only: istdout ! -- dummy variables integer(kind=c_int) :: subcomponent_idx !< index of the subcomponent (i.e. Numerical Solution) - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables class(NumericalSolutionType), pointer :: ns ! people might not call 'xmi_get_subcomponent_count' first, so let's repeat this: if (solutiongrouplist%Count() /= 1) then - write (istdout, *) 'Error: BMI does not support the use of multiple solution groups' + write (istdout, *) & + 'Error: BMI does not support the use of multiple solution groups' bmi_status = BMI_FAILURE return end if @@ -229,14 +235,15 @@ end function xmi_prepare_solve !! which runs from 1 to the value returned by xmi_get_subcomponent_count(). Before calling !! this, a matching call to xmi_prepare_solve() should be done. !< - function xmi_solve(subcomponent_idx, has_converged) result(bmi_status) bind(C, name="solve") + function xmi_solve(subcomponent_idx, has_converged) result(bmi_status) & + bind(C, name="solve") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_solve ! -- modules use NumericalSolutionModule ! -- dummy variables integer(kind=c_int), intent(in) :: subcomponent_idx !< index of the subcomponent (i.e. Numerical Solution) - integer(kind=c_int), intent(out) :: has_converged !< equal to 1 for convergence, 0 otherwise - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int), intent(out) :: has_converged !< equal to 1 for convergence, 0 otherwise + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables class(NumericalSolutionType), pointer :: ns @@ -266,13 +273,14 @@ end function xmi_solve !! @param[in] subcomponent_idx the index of the subcomponent (Numerical Solution) !! @return bmi_status the BMI status code !< - function xmi_finalize_solve(subcomponent_idx) result(bmi_status) bind(C, name="finalize_solve") + function xmi_finalize_solve(subcomponent_idx) result(bmi_status) & + bind(C, name="finalize_solve") !DIR$ ATTRIBUTES DLLEXPORT :: xmi_finalize_solve ! -- modules use NumericalSolutionModule ! -- dummy variables integer(kind=c_int), intent(in) :: subcomponent_idx !< index of the subcomponent (i.e. Numerical Solution) - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables class(NumericalSolutionType), pointer :: ns integer(I4B) :: hasConverged @@ -301,6 +309,29 @@ function xmi_finalize_solve(subcomponent_idx) result(bmi_status) bind(C, name="f end function xmi_finalize_solve + !> @brief Get the version string for this component + !< + function xmi_get_version(mf_version) result(bmi_status) & + bind(C, name="get_version") + !DIR$ ATTRIBUTES DLLEXPORT :: xmi_get_version + ! -- modules + use VersionModule, only: VERSIONNUMBER, IDEVELOPMODE + ! -- dummy variables + character(kind=c_char), intent(out) :: mf_version(BMI_LENVERSION) + integer(kind=c_int) :: bmi_status !< BMI status code + ! -- local variables + character(len=BMI_LENVERSION) :: vstr + + if (IDEVELOPMODE == 1) then + vstr = VERSIONNUMBER//'-dev' + else + vstr = VERSIONNUMBER + end if + mf_version = string_to_char_array(vstr, len_trim(vstr)) + bmi_status = BMI_SUCCESS + + end function xmi_get_version + !> @brief Get the full address string for a variable !! !! This routine constructs the full address string of a variable using the @@ -314,14 +345,15 @@ function get_var_address(c_component_name, c_subcomponent_name, & !DIR$ ATTRIBUTES DLLEXPORT :: get_var_address ! -- modules use MemoryHelperModule, only: create_mem_path, create_mem_address - use ConstantsModule, only: LENCOMPONENTNAME, LENVARNAME, LENMEMPATH, LENMEMADDRESS + use ConstantsModule, only: LENCOMPONENTNAME, LENVARNAME, LENMEMPATH, & + LENMEMADDRESS ! -- dummy variables - character(kind=c_char), intent(in) :: c_component_name(*) !< name of the component (a Model or Solution) - character(kind=c_char), intent(in) :: c_subcomponent_name(*) !< name of the subcomponent (Package), or an empty + character(kind=c_char), intent(in) :: c_component_name(*) !< name of the component (a Model or Solution) + character(kind=c_char), intent(in) :: c_subcomponent_name(*) !< name of the subcomponent (Package), or an empty !! string'' when not applicable - character(kind=c_char), intent(in) :: c_var_name(*) !< name of the variable + character(kind=c_char), intent(in) :: c_var_name(*) !< name of the variable character(kind=c_char), intent(out) :: c_var_address(BMI_LENVARADDRESS) !< full address of the variable - integer(kind=c_int) :: bmi_status !< BMI status code + integer(kind=c_int) :: bmi_status !< BMI status code ! -- local variables character(len=LENCOMPONENTNAME) :: component_name character(len=LENCOMPONENTNAME) :: subcomponent_name @@ -330,9 +362,15 @@ function get_var_address(c_component_name, c_subcomponent_name, & character(len=LENMEMADDRESS) :: mem_address ! convert to Fortran strings - component_name = char_array_to_string(c_component_name, strlen(c_component_name)) - subcomponent_name = char_array_to_string(c_subcomponent_name, strlen(c_subcomponent_name)) - variable_name = char_array_to_string(c_var_name, strlen(c_var_name)) + component_name = char_array_to_string(c_component_name, & + strlen(c_component_name, & + LENCOMPONENTNAME + 1)) + subcomponent_name = char_array_to_string(c_subcomponent_name, & + strlen(c_subcomponent_name, & + LENCOMPONENTNAME + 1)) + variable_name = char_array_to_string(c_var_name, & + strlen(c_var_name, & + LENVARNAME + 1)) ! create memory address if (subcomponent_name == '') then @@ -343,7 +381,8 @@ function get_var_address(c_component_name, c_subcomponent_name, & mem_address = create_mem_address(mem_path, variable_name) ! convert to c string: - c_var_address(1:len(trim(mem_address)) + 1) = string_to_char_array(trim(mem_address), len(trim(mem_address))) + c_var_address(1:len(trim(mem_address)) + 1) = & + string_to_char_array(trim(mem_address), len(trim(mem_address))) bmi_status = BMI_SUCCESS diff --git a/utils/idmloader/README.md b/utils/idmloader/README.md new file mode 100644 index 00000000000..300d55e9811 --- /dev/null +++ b/utils/idmloader/README.md @@ -0,0 +1,3 @@ +# idmloader + +This is a placeholder for the idmloader utility, a standalone tool that populates input memory paths from a supported input source. diff --git a/utils/idmloader/scripts/dfn2f90.py b/utils/idmloader/scripts/dfn2f90.py new file mode 100644 index 00000000000..6bc271c5fc0 --- /dev/null +++ b/utils/idmloader/scripts/dfn2f90.py @@ -0,0 +1,423 @@ +import os +import sys +import json +import yaml +from pathlib import Path +from enum import Enum + +MF6_LENVARNAME = 16 +F90_LINELEN = 82 + + +class Dfn2F90: + """generate idm f90 file from dfn file""" + + def __init__( + self, + dfnfspec: str = None, + ): + """Dfn290 init""" + + self._dfnfspec = dfnfspec + self._var_d = {} + self.component = "" + self.subcomponent = "" + self._param_str = "" + self._aggregate_str = "" + self._block_str = "" + self._param_varnames = [] + self._aggregate_varnames = [] + self._warnings = [] + + self.component, self.subcomponent = self._dfnfspec.stem.upper().split("-") + + print(f"\nprocessing dfn => {self._dfnfspec}") + self._set_var_d() + self._set_param_strs() + + def write_f90(self, odspec=None, gwt_name=False): + if gwt_name: + fname = Path(odspec, f"{self.component.lower()}1{self.subcomponent.lower()}idm.f90") + else: + fname = Path(odspec, f"{self.component.lower()}3{self.subcomponent.lower()}8idm.f90") + with open(fname, "w") as f: + + # file header + f.write(self._source_file_header(self.component, self.subcomponent)) + + # found type + f.write(f" type {self.component.capitalize()}{self.subcomponent.capitalize()}ParamFoundType\n") + for var in self._param_varnames: + varname = var.split(f"{self.component.lower()}{self.subcomponent.lower()}_")[1] + f.write(f" logical :: {varname} = .false.\n") + f.write(f" end type {self.component.capitalize()}{self.subcomponent.capitalize()}ParamFoundType\n\n") + + # params + if len(self._param_varnames): + f.write(self._param_str) + f.write(self._source_params_header(self.component, self.subcomponent)) + f.write(" " + ", &\n ".join(self._param_varnames) + " &\n") + f.write(self._source_list_footer(self.component, self.subcomponent) + "\n") + else: + f.write(self._source_params_header(self.component, self.subcomponent)) + f.write(self._param_str.rsplit(",", 1)[0] + " &\n") + f.write(self._source_list_footer(self.component, self.subcomponent) + "\n") + + # aggregate types + if len(self._aggregate_varnames): + f.write(self._aggregate_str) + f.write(self._source_aggregates_header(self.component, self.subcomponent)) + f.write(" " + ", &\n ".join(self._aggregate_varnames) + " &\n") + f.write(self._source_list_footer(self.component, self.subcomponent) + "\n") + else: + f.write(self._source_aggregates_header(self.component, self.subcomponent)) + f.write(self._aggregate_str.rsplit(",", 1)[0] + " &\n") + f.write(self._source_list_footer(self.component, self.subcomponent) + "\n") + + # blocks + f.write(self._source_blocks_header(self.component, self.subcomponent)) + f.write(self._block_str.rsplit(",", 1)[0] + " &\n") + f.write(self._source_list_footer(self.component, self.subcomponent) + "\n") + + # file footer + f.write(self._source_file_footer(self.component, self.subcomponent)) + + def get_blocknames(self): + blocknames = [] + for var, bname in self._var_d: + if bname not in blocknames: + blocknames.append(bname) + return blocknames + + def warn(self): + if len(self._warnings): + sys.stderr.write("Warnings:\n") + for warn in self._warnings: + sys.stderr.write(" " + warn + "\n") + + def _set_var_d(self): + f = open(self._dfnfspec, "r") + lines = f.readlines() + f.close() + + vardict = {} + vd = {} + + for line in lines: + + # skip blank lines + if len(line.strip()) == 0: + if len(vd) > 0: + name = vd["name"] + if "block" in vd: + block = vd["block"] + key = (name, block) + else: + key = name + if name in vardict: + raise Exception( + "Variable already exists in dictionary: " + name + ) + vardict[key] = vd + vd = {} + continue + + # skip comments + if "#" in line.strip()[0]: + continue + + ll = line.strip().split() + if len(ll) > 1: + k = ll[0] + istart = line.index(" ") + v = line[istart:].strip() + if k in vd: + raise Exception("Attribute already exists in dictionary: " + k) + vd[k] = v + + if len(vd) > 0: + name = vd["name"] + if "block" in vd: + block = vd["block"] + key = (name, block) + else: + key = name + if name in vardict: + raise Exception("Variable already exists in dictionary: " + name) + vardict[key] = vd + + self._var_d = vardict + + def _construct_f90_block_statement( + self, blockname, required=False, aggregate=False + ): + f90statement = f" InputBlockDefinitionType( &\n" + f90statement += f" '{blockname}', & ! blockname\n" + if required: + f90statement += f" .true., & ! required\n" + else: + f90statement += f" .false., & ! required\n" + if aggregate: + f90statement += f" .true. & ! aggregate\n" + else: + f90statement += f" .false. & ! aggregate\n" + f90statement += f" ), &" + + return f90statement + + def _construct_f90_param_statement(self, tuple_list, basename, varname, aggregate=False): + vname = f"{basename.lower()}_{varname.lower()}" + if aggregate: + self._aggregate_varnames.append(vname) + else: + self._param_varnames.append(vname) + f90statement = f" type(InputParamDefinitionType), parameter :: &\n" + f90statement += f" {vname} = InputParamDefinitionType &\n" + f90statement += f" ( &\n" + for i, (value, varname) in enumerate(tuple_list): + comma = "," + if i + 1 == len(tuple_list): + comma = "" + v = f"'{value}'" + if value in [".false.", ".true."]: + v = f"{value}" + f90statement += f" {v}{comma} & ! {varname}\n" + f90statement += f" )\n" + + return f90statement + + def _set_param_strs(self): + blocknames = self.get_blocknames() + for b in blocknames: + self._set_blk_param_strs(b, self.component, self.subcomponent) + + if not self._param_str: + self._param_str += " InputParamDefinitionType ::, &" + + if not self._aggregate_str: + self._aggregate_str += " InputParamDefinitionType ::, &" + + if not self._block_str: + self._aggregate_str += " InputBlockDefinitionType ::, &" + + def _set_blk_param_strs(self, blockname, component, subcomponent): + print(" processing block params => ", blockname) + + required_l = None + required_l = [] + is_aggregate_blk = False + + # comment + s = f" ! {component} {subcomponent} {blockname.upper()}\n" + + r = ".true." + if blockname.upper() == "OPTIONS": + r = ".false." + + for k in self._var_d: + + varname, bname = k + if bname != blockname: + continue + + v = self._var_d[k] + + if "block_variable" in v and v["block_variable"].upper() == "TRUE": + # TODO: add to block defn type + continue + + c = component + sc = subcomponent + b = v["block"].upper() + + # variable name + vn = v["name"].upper() + mf6vn = vn + if "mf6internal" in v: + mf6vn = v["mf6internal"].upper() + + if len(mf6vn) > MF6_LENVARNAME: + self._warnings.append( + f"MF6_LENVARNAME({MF6_LENVARNAME}) exceeded: {component}-{subcomponent}-{blockname}: {mf6vn}" + ) + + t = v["type"].upper() + aggregate_t = t and t.startswith("RECARRAY") + + shape = "" + shapelist = [] + if "shape" in v: + shape = v["shape"] + shape = shape.replace("(", "") + shape = shape.replace(")", "") + shape = shape.replace(",", "") + shape = shape.upper() + shapelist = shape.strip().split() + ndim = len(shapelist) + + if t == "DOUBLE PRECISION": + t = "DOUBLE" + if shape != "" and not aggregate_t and (t == "DOUBLE" or t == "INTEGER"): + t = f"{t}{ndim}D" + + r = ".true." + if "optional" in v: + if v["optional"] == "true": + r = ".false." + else: + r = ".true." + is_required_blk = True + + inrec = ".false." + if "in_record" in v: + if v["in_record"] == "true": + inrec = ".true." + else: + inrec = ".false." + + preserve_case = ".false." + if "preserve_case" in v: + if v["preserve_case"] == "true": + preserve_case = ".true." + else: + preserve_case = ".false." + + layered = ".false." + if "layered" in v: + if v["layered"] == "true": + layered = ".true." + else: + layered = ".false." + + required_l.append(r) + tuple_list = [ + (c, "component"), + (sc, "subcomponent"), + (b, "block"), + (vn, "tag name"), + (mf6vn, "fortran variable"), + (t, "type"), + (shape, "shape"), + (r, "required"), + (inrec, "multi-record"), + (preserve_case, "preserve case"), + (layered, "layered"), + ] + + # assumes recarray type appears before and member + # parameter descriptions in dfn file, adjust + # if necessary + if aggregate_t: + self._aggregate_str += ( + self._construct_f90_param_statement(tuple_list, f"{component}{subcomponent}", mf6vn, True) + "\n" + ) + is_aggregate_blk = True + if not shape: + self._warnings.append( + f"Aggregate type found with no shape: {component}-{subcomponent}-{blockname}: {mf6vn}" + ) + + else: + self._param_str += ( + self._construct_f90_param_statement(tuple_list, f"{component}{subcomponent}", mf6vn) + "\n" + ) + + self._block_str += ( + self._construct_f90_block_statement( + blockname.upper(), + required=(".true." in required_l), + aggregate=is_aggregate_blk, + ) + + "\n" + ) + + def _source_file_header(self, component, subcomponent): + s = f"module {component.title()}{subcomponent.title()}InputModule" + "\n" + s += ( + " use InputDefinitionModule, only: InputParamDefinitionType, &" + + "\n" + + " InputBlockDefinitionType" + + "\n" + ) + s += " private" + "\n" + s += ( + f" public {component.lower()}_{subcomponent.lower()}_param_definitions" + + "\n" + ) + s += ( + f" public {component.lower()}_{subcomponent.lower()}_aggregate_definitions" + + "\n" + ) + s += ( + f" public {component.lower()}_{subcomponent.lower()}_block_definitions" + + "\n" + ) + s += ( + f" public {component.capitalize()}{subcomponent.capitalize()}ParamFoundType" + + "\n\n" + ) + return s + + def _source_params_header(self, component, subcomponent): + s = ( + f" type(InputParamDefinitionType), parameter :: &" + + "\n" + + f" {component.lower()}_{subcomponent.lower()}_param_definitions(*) = &" + + "\n" + ) + s += " [ &" + "\n" + return s + + def _source_aggregates_header(self, component, subcomponent): + s = ( + f" type(InputParamDefinitionType), parameter :: &" + + "\n" + + f" {component.lower()}_{subcomponent.lower()}_aggregate_definitions(*) = &" + + "\n" + ) + s += " [ &" + "\n" + return s + + def _source_blocks_header(self, component, subcomponent): + s = ( + f" type(InputBlockDefinitionType), parameter :: &" + + "\n" + + f" {component.lower()}_{subcomponent.lower()}_block_definitions(*) = &" + + "\n" + ) + s += " [ &" + "\n" + return s + + def _source_list_footer(self, component, subcomponent): + s = " ]" + "\n" + return s + + def _source_file_footer(self, component, subcomponent): + s = f"end module {component.title()}{subcomponent.title()}InputModule" + "\n" + return s + + +if __name__ == "__main__": + + gwf_dfns = [ + Path("../../../doc/mf6io/mf6ivar/dfn", "gwf-dis.dfn"), + Path("../../../doc/mf6io/mf6ivar/dfn", "gwf-disu.dfn"), + Path("../../../doc/mf6io/mf6ivar/dfn", "gwf-disv.dfn"), + Path("../../../doc/mf6io/mf6ivar/dfn", "gwf-npf.dfn"), + ] + + for dfn in gwf_dfns: + converter = Dfn2F90(dfnfspec=dfn) + converter.write_f90(odspec=os.path.join("..", "..", "..", "src", "Model", "GroundWaterFlow")) + converter.warn() + + gwt_dfns = [ + Path("../../../doc/mf6io/mf6ivar/dfn", "gwt-dsp.dfn"), + ] + + for dfn in gwt_dfns: + converter = Dfn2F90(dfnfspec=dfn) + converter.write_f90(odspec=os.path.join("..", "..", "..", "src", "Model", "GroundWaterTransport"), gwt_name=True) + converter.warn() + + print("\n...done.") diff --git a/utils/mf5to6/make/makedefaults b/utils/mf5to6/make/makedefaults index 626daa1fbcd..1aadc335376 100644 --- a/utils/mf5to6/make/makedefaults +++ b/utils/mf5to6/make/makedefaults @@ -1,4 +1,4 @@ -# makedefaults created by pymake (version 1.2.3) for the 'mf5to6' executable. +# makedefaults created by pymake (version 1.2.5) for the 'mf5to6' executable. # determine OS ifeq ($(OS), Windows_NT) diff --git a/utils/mf5to6/make/makefile b/utils/mf5to6/make/makefile index 6ab22ab82ad..9708dc02d99 100644 --- a/utils/mf5to6/make/makefile +++ b/utils/mf5to6/make/makefile @@ -1,14 +1,14 @@ -# makefile created by pymake (version 1.2.3) for the 'mf5to6' executable. +# makefile created by pymake (version 1.2.5) for the 'mf5to6' executable. include ./makedefaults # Define the source file directories SOURCEDIR1=../src -SOURCEDIR2=../src/NWT -SOURCEDIR3=../src/LGR -SOURCEDIR4=../src/Preproc -SOURCEDIR5=../src/MF2005 +SOURCEDIR2=../src/LGR +SOURCEDIR3=../src/MF2005 +SOURCEDIR4=../src/NWT +SOURCEDIR5=../src/Preproc SOURCEDIR6=../../../src/Utilities/Memory SOURCEDIR7=../../../src/Utilities/TimeSeries SOURCEDIR8=../../../src/Utilities @@ -41,6 +41,7 @@ $(OBJDIR)/InputOutput.o \ $(OBJDIR)/TableTerm.o \ $(OBJDIR)/Table.o \ $(OBJDIR)/MemoryHelper.o \ +$(OBJDIR)/CharString.o \ $(OBJDIR)/Memory.o \ $(OBJDIR)/List.o \ $(OBJDIR)/MemoryList.o \ diff --git a/utils/mf5to6/msvs/mf5to6.vfproj b/utils/mf5to6/msvs/mf5to6.vfproj index 7befbbef3e8..0fdd1b971ce 100644 --- a/utils/mf5to6/msvs/mf5to6.vfproj +++ b/utils/mf5to6/msvs/mf5to6.vfproj @@ -90,6 +90,7 @@ + diff --git a/utils/mf5to6/pymake/extrafiles.txt b/utils/mf5to6/pymake/extrafiles.txt index ea9da122442..658c95a6c60 100644 --- a/utils/mf5to6/pymake/extrafiles.txt +++ b/utils/mf5to6/pymake/extrafiles.txt @@ -5,6 +5,7 @@ ../../../src/Utilities/TimeSeries/TimeSeries.f90 ../../../src/Utilities/TimeSeries/TimeSeriesRecord.f90 ../../../src/Utilities/BlockParser.f90 +../../../src/Utilities/CharString.f90 ../../../src/Utilities/Constants.f90 ../../../src/Utilities/SimVariables.f90 ../../../src/Utilities/compilerversion.F90 diff --git a/utils/zonebudget/make/makedefaults b/utils/zonebudget/make/makedefaults index 4d10348ec15..7d681aa2218 100644 --- a/utils/zonebudget/make/makedefaults +++ b/utils/zonebudget/make/makedefaults @@ -1,4 +1,4 @@ -# makedefaults created by pymake (version 1.2.3) for the 'zbud6' executable. +# makedefaults created by pymake (version 1.2.5) for the 'zbud6' executable. # determine OS ifeq ($(OS), Windows_NT) diff --git a/utils/zonebudget/make/makefile b/utils/zonebudget/make/makefile index 387a53fb2aa..4010990d67a 100644 --- a/utils/zonebudget/make/makefile +++ b/utils/zonebudget/make/makefile @@ -1,4 +1,4 @@ -# makefile created by pymake (version 1.2.3) for the 'zbud6' executable. +# makefile created by pymake (version 1.2.5) for the 'zbud6' executable. include ./makedefaults diff --git a/utils/zonebudget/msvs/zonebudget.vfproj b/utils/zonebudget/msvs/zonebudget.vfproj index 4fb91f6bfaa..682849e3f29 100644 --- a/utils/zonebudget/msvs/zonebudget.vfproj +++ b/utils/zonebudget/msvs/zonebudget.vfproj @@ -32,13 +32,13 @@ - + - - - + + + diff --git a/utils/zonebudget/src/budgetdata.f90 b/utils/zonebudget/src/budgetdata.f90 index 718ec86bb0c..1d807889ae7 100644 --- a/utils/zonebudget/src/budgetdata.f90 +++ b/utils/zonebudget/src/budgetdata.f90 @@ -4,15 +4,15 @@ module BudgetDataModule use SimModule, only: store_error, store_error_unit, ustop use ConstantsModule, only: LINELENGTH implicit none - + private public :: budgetdata_init public :: budgetdata_read public :: budgetdata_finalize - public :: budtxt, ia, ja, flowja, nodesrc, nodedst, flowdata, & - dstpackagename, nbudterms, kstp, kper, delt, totim, & + public :: budtxt, ia, ja, flowja, nodesrc, nodedst, flowdata, & + dstpackagename, nbudterms, kstp, kper, delt, totim, & srcmodelname, dstmodelname, hasimeth1flowja - + logical :: hasimeth1flowja = .false. integer(I4B) :: inunit integer(I4B) :: nbudterms = 0 @@ -39,9 +39,9 @@ module BudgetDataModule real(DP), dimension(:, :), allocatable :: flowdata character(len=16) :: dstmodelname character(len=16) :: dstpackagename - - contains - + +contains + subroutine budgetdata_init(iu, iout, ncrbud) ! ****************************************************************************** ! budgetdata_init @@ -65,10 +65,11 @@ subroutine budgetdata_init(iu, iout, ncrbud) call budgetdata_read(success) kstp_last = kstp kper_last = kper - rewind(inunit) + rewind (inunit) ! ! -- Determine number of budget terms within a time step - write(iout, '(a)') 'Reading budget file to determine number of terms per time step.' + write (iout, '(a)') & + 'Reading budget file to determine number of terms per time step.' icount = 1 do call budgetdata_read(success, iout) @@ -78,16 +79,17 @@ subroutine budgetdata_init(iu, iout, ncrbud) nbudterms = nbudterms + 1 if (trim(adjustl(budtxt)) == 'FLOW-JA-FACE' .and. & srcmodelname == dstmodelname) then - if(allocated(nodesrc)) ncrbud = maxval(nodesrc) - endif - enddo - rewind(inunit) - write(iout, '(a, i0, a)') 'Detected ', nbudterms, ' unique flow terms in budget file.' + if (allocated(nodesrc)) ncrbud = maxval(nodesrc) + end if + end do + rewind (inunit) + write (iout, '(a, i0, a)') & + 'Detected ', nbudterms, ' unique flow terms in budget file.' ! ! -- return return end subroutine budgetdata_init - + subroutine budgetdata_read(success, iout_opt) ! ****************************************************************************** ! budgetdata_read @@ -107,7 +109,7 @@ subroutine budgetdata_read(success, iout_opt) iout = iout_opt else iout = 0 - endif + end if ! kstp = 0 kper = 0 @@ -119,64 +121,65 @@ subroutine budgetdata_read(success, iout_opt) srcpackagename = '' dstmodelname = '' dstpackagename = '' - + success = .true. - read(inunit, iostat=iostat) kstp, kper, budtxt, nval, idum1, idum2 + read (inunit, iostat=iostat) kstp, kper, budtxt, nval, idum1, idum2 if (iostat /= 0) then success = .false. return - endif - read(inunit) imeth, delt, pertim, totim - if(imeth == 1) then + end if + read (inunit) imeth, delt, pertim, totim + if (imeth == 1) then if (trim(adjustl(budtxt)) == 'FLOW-JA-FACE') then - if(allocated(flowja)) deallocate(flowja) - allocate(flowja(nval)) - read(inunit) flowja + if (allocated(flowja)) deallocate (flowja) + allocate (flowja(nval)) + read (inunit) flowja hasimeth1flowja = .true. else nval = nval * idum1 * abs(idum2) - if(allocated(flowdata)) deallocate(flowdata) - allocate(flowdata(1, nval)) - if(allocated(nodesrc)) deallocate(nodesrc) - allocate(nodesrc(nval)) - read(inunit) flowdata + if (allocated(flowdata)) deallocate (flowdata) + allocate (flowdata(1, nval)) + if (allocated(nodesrc)) deallocate (nodesrc) + allocate (nodesrc(nval)) + read (inunit) flowdata do i = 1, nval nodesrc(i) = i - enddo - endif + end do + end if elseif (imeth == 6) then ! -- method code 6 - read(inunit) srcmodelname - read(inunit) srcpackagename - read(inunit) dstmodelname - read(inunit) dstpackagename - read(inunit) ndat - if(allocated(auxtxt)) deallocate(auxtxt) - allocate(auxtxt(ndat-1)) - read(inunit) auxtxt - read(inunit) nlist - if(allocated(nodesrc)) deallocate(nodesrc) - allocate(nodesrc(nlist)) - if(allocated(nodedst)) deallocate(nodedst) - allocate(nodedst(nlist)) - if(allocated(flowdata)) deallocate(flowdata) - allocate(flowdata(ndat, nlist)) - read(inunit) (nodesrc(n), nodedst(n), (flowdata(i,n), i = 1, ndat), n = 1, nlist) + read (inunit) srcmodelname + read (inunit) srcpackagename + read (inunit) dstmodelname + read (inunit) dstpackagename + read (inunit) ndat + if (allocated(auxtxt)) deallocate (auxtxt) + allocate (auxtxt(ndat - 1)) + read (inunit) auxtxt + read (inunit) nlist + if (allocated(nodesrc)) deallocate (nodesrc) + allocate (nodesrc(nlist)) + if (allocated(nodedst)) deallocate (nodedst) + allocate (nodedst(nlist)) + if (allocated(flowdata)) deallocate (flowdata) + allocate (flowdata(ndat, nlist)) + read (inunit) & + (nodesrc(n), nodedst(n), (flowdata(i, n), i=1, ndat), n=1, nlist) else - write(errmsg, '(a, a)') 'ERROR READING: ', trim(budtxt) + write (errmsg, '(a, a)') 'ERROR READING: ', trim(budtxt) call store_error(errmsg) - write(errmsg, '(a, i0)') 'INVALID METHOD CODE DETECTED: ', imeth + write (errmsg, '(a, i0)') 'INVALID METHOD CODE DETECTED: ', imeth call store_error(errmsg) call store_error_unit(inunit) - endif + end if if (iout > 0) then - write(iout, '(1pg15.6, a, 1x, a)') totim, budtxt, dstpackagename - endif + write (iout, '(1pg15.6, a, 1x, a)') totim, budtxt, dstpackagename + end if ! ! -- return return end subroutine budgetdata_read - + subroutine budgetdata_finalize() ! ****************************************************************************** ! budgetdata_finalize @@ -185,17 +188,17 @@ subroutine budgetdata_finalize() ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------ - close(inunit) - if(allocated(auxtxt)) deallocate(auxtxt) - if(allocated(ia)) deallocate(ia) - if(allocated(ja)) deallocate(ja) - if(allocated(flowja)) deallocate(flowja) - if(allocated(nodesrc)) deallocate(nodesrc) - if(allocated(nodedst)) deallocate(nodedst) - if(allocated(flowdata)) deallocate(flowdata) + close (inunit) + if (allocated(auxtxt)) deallocate (auxtxt) + if (allocated(ia)) deallocate (ia) + if (allocated(ja)) deallocate (ja) + if (allocated(flowja)) deallocate (flowja) + if (allocated(nodesrc)) deallocate (nodesrc) + if (allocated(nodedst)) deallocate (nodedst) + if (allocated(flowdata)) deallocate (flowdata) ! ! -- return return end subroutine budgetdata_finalize - + end module BudgetDataModule diff --git a/utils/zonebudget/src/grb.f90 b/utils/zonebudget/src/grb.f90 index aa5659ccfa7..ec205703e03 100644 --- a/utils/zonebudget/src/grb.f90 +++ b/utils/zonebudget/src/grb.f90 @@ -6,9 +6,9 @@ module GrbModule implicit none private public :: read_grb - - contains - + +contains + subroutine read_grb(inunit, ia, ja, mshape) ! ****************************************************************************** ! read_grb @@ -39,58 +39,59 @@ subroutine read_grb(inunit, ia, ja, mshape) ! ------------------------------------------------------------------------------ ! ! -- message - write(iout, '(/,a)') 'Processing Binary Grid File' + write (iout, '(/,a)') 'Processing Binary Grid File' ! -- grid keyword - read(inunit) hdrtxt + read (inunit) hdrtxt lloc = 1 call urword(hdrtxt, lloc, istart, istop, 0, i, r, iout, inunit) - if ( hdrtxt(istart:istop) /= 'GRID') then - call store_error('GRB FILE MUST BEGIN WITH WORD GRID. FOUND: ' // hdrtxt(istart:istop)) + if (hdrtxt(istart:istop) /= 'GRID') then + call store_error('GRB FILE MUST BEGIN WITH WORD GRID. FOUND: '// & + hdrtxt(istart:istop)) call store_error_unit(inunit) - endif + end if ! ! -- grid type, allocate mshape accordingly call urword(hdrtxt, lloc, istart, istop, 0, i, r, iout, inunit) if (hdrtxt(istart:istop) == 'DIS') then - write(iout, '(2x, a)') 'Detected regular MODFLOW grid (DIS)' - allocate(mshape(3)) + write (iout, '(2x, a)') 'Detected regular MODFLOW grid (DIS)' + allocate (mshape(3)) elseif (hdrtxt(istart:istop) == 'DISV') then - write(iout, '(2x, a)') 'Detected Discretization by Vertices grid (DISV)' - allocate(mshape(2)) + write (iout, '(2x, a)') 'Detected Discretization by Vertices grid (DISV)' + allocate (mshape(2)) elseif (hdrtxt(istart:istop) == 'DISU') then - write(iout, '(2x, a)') 'Detected unstructured grid (DISU)' - allocate(mshape(1)) + write (iout, '(2x, a)') 'Detected unstructured grid (DISU)' + allocate (mshape(1)) else - call store_error('UNKNOWN GRID TYPE IN GRB FILE: ' // hdrtxt(istart:istop)) + call store_error('UNKNOWN GRID TYPE IN GRB FILE: '//hdrtxt(istart:istop)) call store_error_unit(inunit) - endif + end if mshape(:) = 0 ! ! -- version - read(inunit) hdrtxt - write(iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) + read (inunit) hdrtxt + write (iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) ! ! -- ntxt - read(inunit) hdrtxt - write(iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) - lloc=1 + read (inunit) hdrtxt + write (iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) + lloc = 1 call urword(hdrtxt, lloc, istart, istop, 0, i, r, iout, inunit) call urword(hdrtxt, lloc, istart, istop, 2, ntxt, r, iout, inunit) - + ! -- lentxt - read(inunit) hdrtxt - write(iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) - lloc=1 + read (inunit) hdrtxt + write (iout, '(2x, a, a)') 'Detected ', trim(hdrtxt(1:49)) + lloc = 1 call urword(hdrtxt, lloc, istart, istop, 0, i, r, iout, inunit) call urword(hdrtxt, lloc, istart, istop, 2, lentxt, r, iout, inunit) ! ! -- read txt definitions - allocate(character(len=lentxt)::line) - allocate(character(len=lentxt*ntxt)::dfntxt) - read(inunit) dfntxt + allocate (character(len=lentxt) :: line) + allocate (character(len=lentxt*ntxt) :: dfntxt) + read (inunit) dfntxt ! -- read each data record - do n = 1, lentxt*ntxt, lentxt - line = dfntxt(n:n+lentxt-1) + do n = 1, lentxt * ntxt, lentxt + line = dfntxt(n:n + lentxt - 1) lloc = 1 call urword(line, lloc, istart, istop, 0, i, r, iout, inunit) dataname = line(istart:istop) @@ -98,68 +99,70 @@ subroutine read_grb(inunit, ia, ja, mshape) datatype = line(istart:istop) call urword(line, lloc, istart, istop, 0, i, r, iout, inunit) call urword(line, lloc, istart, istop, 2, ndim, r, iout, inunit) - allocate(ishape(ndim)) + allocate (ishape(ndim)) do j = 1, ndim call urword(line, lloc, istart, istop, 2, ishape(j), r, iout, inunit) - enddo + end do select case (trim(datatype)) - case('INTEGER') - if(ndim == 0)then - read(inunit) i - write(iout, '(2x, a, a, a, i0)') 'Detected ', trim(dataname), ' = ', i - if(trim(dataname) == 'NLAY') mshape(1) = i - if(trim(dataname) == 'NROW') mshape(2) = i - if(trim(dataname) == 'NCOL') mshape(3) = i - if(trim(dataname) == 'NCPL') mshape(2) = i - if(trim(dataname) == 'NJA') nja = i - if(trim(dataname) == 'NCELLS') ncells = i - if(trim(dataname) == 'NODES') then - ncells = i - mshape(1) = i - endif - else - write(iout, '(2x, a, a)') 'Detected integer array ', trim(dataname) - nval = 1 - do j = 1, ndim - nval = nval * ishape(j) - enddo - allocate(itmp(nval)) - read(inunit) itmp - if(trim(dataname) == 'IA') then - allocate (ia(ncells + 1)) - ia = itmp - elseif(trim(dataname) == 'JA') then - allocate (ja(nja)) - ja = itmp - endif - deallocate(itmp) - endif - case('DOUBLE') - if(ndim == 0)then - read(inunit) d - write(iout, '(2x, a, a, a, G0)') 'Detected ', trim(dataname), ' = ', d - else - write(iout, '(2x, a, a)') 'Detected double array ', trim(dataname) - nval = 1 - do j = 1, ndim - nval = nval * ishape(j) - enddo - allocate(dtmp(nval)) - read(inunit) dtmp - deallocate(dtmp) - endif + case ('INTEGER') + if (ndim == 0) then + read (inunit) i + write (iout, '(2x, a, a, a, i0)') & + 'Detected ', trim(dataname), ' = ', i + if (trim(dataname) == 'NLAY') mshape(1) = i + if (trim(dataname) == 'NROW') mshape(2) = i + if (trim(dataname) == 'NCOL') mshape(3) = i + if (trim(dataname) == 'NCPL') mshape(2) = i + if (trim(dataname) == 'NJA') nja = i + if (trim(dataname) == 'NCELLS') ncells = i + if (trim(dataname) == 'NODES') then + ncells = i + mshape(1) = i + end if + else + write (iout, '(2x, a, a)') 'Detected integer array ', trim(dataname) + nval = 1 + do j = 1, ndim + nval = nval * ishape(j) + end do + allocate (itmp(nval)) + read (inunit) itmp + if (trim(dataname) == 'IA') then + allocate (ia(ncells + 1)) + ia = itmp + elseif (trim(dataname) == 'JA') then + allocate (ja(nja)) + ja = itmp + end if + deallocate (itmp) + end if + case ('DOUBLE') + if (ndim == 0) then + read (inunit) d + write (iout, '(2x, a, a, a, G0)') & + 'Detected ', trim(dataname), ' = ', d + else + write (iout, '(2x, a, a)') 'Detected double array ', trim(dataname) + nval = 1 + do j = 1, ndim + nval = nval * ishape(j) + end do + allocate (dtmp(nval)) + read (inunit) dtmp + deallocate (dtmp) + end if end select - deallocate(ishape) - enddo - close(inunit) - write(iout, '(a)') 'Done processing Binary Grid File' + deallocate (ishape) + end do + close (inunit) + write (iout, '(a)') 'Done processing Binary Grid File' ! ! -- deallocate local storage - deallocate(line) - deallocate(dfntxt) + deallocate (line) + deallocate (dfntxt) ! ! -- return return end subroutine read_grb - + end module GrbModule diff --git a/utils/zonebudget/src/zbud6.f90 b/utils/zonebudget/src/zbud6.f90 index 6973370aee0..fedccae4ee9 100644 --- a/utils/zonebudget/src/zbud6.f90 +++ b/utils/zonebudget/src/zbud6.f90 @@ -5,11 +5,11 @@ program zonbudmf6 use SimVariablesModule, only: iout, errmsg use SimModule, only: store_error use GenericUtilitiesModule, only: sim_message, write_centered - use InputOutputModule, only: openfile - + use InputOutputModule, only: openfile + implicit none - - character(len=10), parameter :: mfvnam=' Version 6' + + character(len=10), parameter :: mfvnam = ' Version 6' character(len=LINELENGTH) :: line character(len=LENHUGELINE) :: fnam, flst, fcsv integer(I4B) :: iunit_lst = 20 @@ -19,7 +19,7 @@ program zonbudmf6 integer(I4B) :: iunit_zon = 24 integer(I4B) :: iunit_grb = 25 logical :: exists - + ! -- Write title to screen call write_centered('ZONEBUDGET'//mfvnam, 80) call write_centered('U.S. GEOLOGICAL SURVEY', 80) @@ -28,12 +28,12 @@ program zonbudmf6 ! -- Find name of zone budget name file and lst file fnam = 'zbud.nam' call parse_command_line(fnam, flst, fcsv) - inquire(file=fnam, exist=exists) + inquire (file=fnam, exist=exists) if (.not. exists) then - write(errmsg,'(a)') 'Name file not found. Looking for: ' // trim(fnam) + write (errmsg, '(a)') 'Name file not found. Looking for: '//trim(fnam) call store_error(errmsg, terminate=.TRUE.) - endif - ! + end if + ! ! -- Open list file and write title iout = iunit_lst call openfile(iunit_lst, 0, flst, 'LIST', filstat_opt='REPLACE') @@ -50,10 +50,10 @@ program zonbudmf6 call process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) ! ! -- close output files - write(iunit_lst, '(/, a)') 'Normal Termination' - close(iunit_lst) - close(iunit_csv) - write(line,'(a)') 'Normal Termination' + write (iunit_lst, '(/, a)') 'Normal Termination' + close (iunit_lst) + close (iunit_csv) + write (line, '(a)') 'Normal Termination' call sim_message(line, skipbefore=1) ! ! -- end of program @@ -71,7 +71,7 @@ subroutine read_namefile(iunit_nam, iunit_bud, iunit_zon, iunit_grb) use SimVariablesModule, only: iout, errmsg use SimModule, only: store_error use ConstantsModule, only: LENHUGELINE, LINELENGTH - use InputOutputModule, only: openfile + use InputOutputModule, only: openfile use OpenSpecModule, only: form, access use BlockParserModule, only: BlockParserType implicit none @@ -91,7 +91,7 @@ subroutine read_namefile(iunit_nam, iunit_bud, iunit_zon, iunit_grb) ! call parser%Initialize(iunit_nam, iout) call parser%GetBlock('ZONEBUDGET', isfound, ierr) - if(isfound) then + if (isfound) then do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit @@ -99,40 +99,40 @@ subroutine read_namefile(iunit_nam, iunit_bud, iunit_zon, iunit_grb) fm = 'FORMATTED' acc = 'SEQUENTIAL' select case (keyword) - case ('BUD') - iu = iunit_bud - fm = form - acc = access - call parser%GetString(filename) - case ('ZON') - iu = iunit_zon - call parser%GetString(filename) - case ('GRB') - iu = iunit_grb - fm = form - acc = access - call parser%GetString(filename) - case default - write(errmsg,'(4x,a,a)')'ERROR. UNKNOWN ZONEBUDGET ENTRY: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() - end select - call openfile(iu, iout, trim(filename), trim(keyword), fm, acc) + case ('BUD') + iu = iunit_bud + fm = form + acc = access + call parser%GetString(filename) + case ('ZON') + iu = iunit_zon + call parser%GetString(filename) + case ('GRB') + iu = iunit_grb + fm = form + acc = access + call parser%GetString(filename) + case default + write (errmsg, '(4x,a,a)') 'ERROR. UNKNOWN ZONEBUDGET ENTRY: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() + end select + call openfile(iu, iout, trim(filename), trim(keyword), fm, acc) end do else - write(errmsg,'(1x,a)')'ERROR. REQUIRED ZONEBUDGET BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED ZONEBUDGET BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if ! ! -- close name file - close(iunit_nam) + close (iunit_nam) ! ! -- return return end subroutine read_namefile - + subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) ! ****************************************************************************** ! process_budget @@ -146,20 +146,20 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) use SimVariablesModule, only: iout, errmsg use GenericUtilitiesModule, only: sim_message use SimModule, only: store_error - use BudgetDataModule, only: budgetdata_init, budgetdata_read, & - budgetdata_finalize, & - ia, ja, budtxt, nbudterms, & - nodesrc, nodedst, flowdata, flowja, kper, kstp, & - delt, totim, dstpackagename, hasimeth1flowja, & + use BudgetDataModule, only: budgetdata_init, budgetdata_read, & + budgetdata_finalize, & + ia, ja, budtxt, nbudterms, & + nodesrc, nodedst, flowdata, flowja, kper, kstp, & + delt, totim, dstpackagename, hasimeth1flowja, & srcmodelname, dstmodelname - use ZoneModule, only: zone_init, clear_accumulators, & - flowja_accumulate, flowiaja_accumulate, & - flow_accumulate, & - flowch_setich, flowch_accumulate, & - zone_finalize, nmznfl, vbvl, vbznfl, maxzone - use ZoneOutputModule, only: zoneoutput_init, zoneoutput_write, & + use ZoneModule, only: zone_init, clear_accumulators, & + flowja_accumulate, flowiaja_accumulate, & + flow_accumulate, & + flowch_setich, flowch_accumulate, & + zone_finalize, nmznfl, vbvl, vbznfl, maxzone + use ZoneOutputModule, only: zoneoutput_init, zoneoutput_write, & zoneoutput_finalize - use GrbModule, only: read_grb + use GrbModule, only: read_grb implicit none ! -- dummy integer, intent(in) :: iunit_csv @@ -192,7 +192,7 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) ! -- Check to see if GRB is required, and read it if necessary ncrgrb = 0 if (hasimeth1flowja) then - inquire(unit=iunit_grb, opened=opengrb) + inquire (unit=iunit_grb, opened=opengrb) if (opengrb) then hasiaja = .true. call read_grb(iunit_grb, ia, ja, mshape) @@ -202,21 +202,21 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) call store_error(errmsg) errmsg = 'ADD GRB ENTRY TO ZONE BUDGET NAME FILE.' call store_error(errmsg, terminate=.TRUE.) - endif + end if else - inquire(unit=iunit_grb, opened=opengrb) + inquire (unit=iunit_grb, opened=opengrb) if (opengrb) then errmsg = 'BINARY GRID FILE IS PRESENT, BUT BUDGET FILE DOES NOT HAVE & - &"FLOW-JA-FACE" RECORD IN THE IMETH=1 FORMAT. CHECK TO MAKE SURE & - &FLOWS ARE SAVED TO THE BUDGET FILE' + &"FLOW-JA-FACE" RECORD IN THE IMETH=1 FORMAT. CHECK TO MAKE SURE & + &FLOWS ARE SAVED TO THE BUDGET FILE' call store_error(errmsg, terminate=.TRUE.) - endif + end if ! ! -- At this point, must be a budget file from an advanced package without ! the IMETH=1 flow-ja-face record. - allocate(mshape(1)) + allocate (mshape(1)) mshape(1) = ncrgrb - endif + end if ! ! -- Read the zone file to get number of cells/reaches ncr = ncrgrb @@ -225,24 +225,24 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) ! -- Initialize zone and zoneoutput modules !call zone_init(iunit_zon, nbudterms, ncr) call zoneoutput_init(iout, iunit_csv, maxzone, nbudterms) - allocate(budtxtarray(nbudterms)) - allocate(packagenamearray(nbudterms)) - allocate(internalflow(nbudterms)) + allocate (budtxtarray(nbudterms)) + allocate (packagenamearray(nbudterms)) + allocate (internalflow(nbudterms)) ! ! -- time loop timeloop: do ! ! -- Clear budget accumulators and loop through budget terms call clear_accumulators() - write(iout, '(/, a)') 'Reading records from budget file' + write (iout, '(/, a)') 'Reading records from budget file' do ibudterm = 1, nbudterms ! ! -- read data call budgetdata_read(success, iout) if (.not. success) then - write(iout, '(a)') 'Done reading records. Exiting time loop.' + write (iout, '(a)') 'Done reading records. Exiting time loop.' exit timeloop - endif + end if ! ! -- write message and check call sim_message(cdot, advance=.FALSE.) @@ -254,16 +254,16 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) internalflow(ibudterm) = 1 else internalflow(ibudterm) = 0 - endif + end if else - if (budtxt /= budtxtarray(ibudterm) .or. & + if (budtxt /= budtxtarray(ibudterm) .or. & dstpackagename /= packagenamearray(ibudterm)) then - errmsg = 'Expecting ' // trim(packagenamearray(itime)) // '-' // & - trim(budtxtarray(itime)) // ' but found ' // trim(dstpackagename) & - // '-' // trim(budtxt) + errmsg = 'Expecting '//trim(packagenamearray(itime))//'-'// & + trim(budtxtarray(itime))//' but found '//trim(dstpackagename) & + //'-'//trim(budtxt) call store_error(errmsg, terminate=.TRUE.) - endif - endif + end if + end if ! ! -- Accumulate flow terms (or set ich for constant heads) if (internalflow(ibudterm) == 1) then @@ -271,31 +271,31 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) call flowiaja_accumulate(ia, ja, flowja) else call flowja_accumulate(nodesrc, nodedst, flowdata) - endif + end if else - if(trim(adjustl(budtxt)) == 'CONSTANT HEAD') then + if (trim(adjustl(budtxt)) == 'CONSTANT HEAD') then call flowch_setich(ibudterm, nodesrc) foundchd = .true. else call flow_accumulate(ibudterm, nodesrc, flowdata) - endif - endif + end if + end if ! - enddo - write(iout, '(a)') 'Done reading records from budget file' + end do + write (iout, '(a)') 'Done reading records from budget file' ! ! -- Now that all constant heads read, can process budgets for them - if(hasiaja .and. foundchd) then + if (hasiaja .and. foundchd) then call flowch_accumulate(ia, ja, flowja) - endif + end if ! ! -- Write information for this time - call zoneoutput_write(itime, kstp, kper, delt, totim, nbudterms, nmznfl, & - vbvl, vbznfl, packagenamearray, budtxtarray, & + call zoneoutput_write(itime, kstp, kper, delt, totim, nbudterms, nmznfl, & + vbvl, vbznfl, packagenamearray, budtxtarray, & internalflow) itime = itime + 1 - enddo timeloop + end do timeloop ! ! -- Finalize call sim_message(cdot) @@ -306,8 +306,8 @@ subroutine process_budget(iunit_csv, iunit_bud, iunit_zon, iunit_grb) ! -- return return end subroutine process_budget - - subroutine parse_command_line(fnam, flst, fcsv) + +subroutine parse_command_line(fnam, flst, fcsv) ! ****************************************************************************** ! Parse command line arguments ! Assign zone budget name file as first argument. @@ -316,61 +316,48 @@ subroutine parse_command_line(fnam, flst, fcsv) ! ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ - ! -- modules - use KindModule - use InputOutputModule, only: urword - use ConstantsModule, only: LENHUGELINE - implicit none - ! -- dummy - character(len=*), intent(inout) :: fnam - character(len=*), intent(inout) :: flst - character(len=*), intent(inout) :: fcsv - ! -- local - character(len=LENHUGELINE) :: line - integer(I4B) :: inunit = 0 - integer(I4B) :: ilen - integer(I4B) :: istat - integer(I4B) :: lloc - integer(I4B) :: istart - integer(I4B) :: istop - integer(I4B) :: ival - integer(I4B) :: i - real(DP) :: rval + ! -- modules + use KindModule + implicit none + ! -- dummy + character(len=*), intent(inout) :: fnam + character(len=*), intent(inout) :: flst + character(len=*), intent(inout) :: fcsv + ! -- local + integer(I4B) :: icountcmd + integer(I4B) :: istart + integer(I4B) :: istop + integer(I4B) :: i ! ------------------------------------------------------------------------------ - ! - ! -- Get the command line string - call GET_COMMAND(line, ilen, istat) - ! - ! -- This will read zonebudget executable - lloc = 1 - call urword(line, lloc, istart, istop, 0, ival, rval, 0, inunit) - ! - ! -- This will read first argument (zone budget name file) - call urword(line, lloc, istart, istop, 0, ival, rval, 0, inunit) - if (istart < len(line)) fnam = line(istart:istop) - ! - ! -- Set lst and csv file names by replacing fnam suffix with .lst - istart = 0 - istop = len_trim(fnam) - do i = istop, 1, -1 - if (fnam(i:i) == '.') then - istart = i - exit - endif - enddo - if (istart == 0) istart = istop + 1 - ! - ! -- Create flst name - flst = fnam(1:istart) - istop = istart + 3 - flst(istart:istop) = '.lst' - ! - ! -- Create fcsv name - fcsv = fnam(1:istart) - istop = istart + 3 - fcsv(istart:istop) = '.csv' - ! - ! -- Return - return - end subroutine parse_command_line + ! + ! -- assign fnam to first command line argument + icountcmd = command_argument_count() + if (icountcmd > 0) then + call get_command_argument(1, fnam) + end if + ! + ! -- Set lst and csv file names by replacing fnam suffix with .lst + istart = 0 + istop = len_trim(fnam) + do i = istop, 1, -1 + if (fnam(i:i) == '.') then + istart = i + exit + end if + end do + if (istart == 0) istart = istop + 1 + ! + ! -- Create flst name + flst = fnam(1:istart) + istop = istart + 3 + flst(istart:istop) = '.lst' + ! + ! -- Create fcsv name + fcsv = fnam(1:istart) + istop = istart + 3 + fcsv(istart:istop) = '.csv' + ! + ! -- Return + return +end subroutine parse_command_line diff --git a/utils/zonebudget/src/zone.f90 b/utils/zonebudget/src/zone.f90 index c55864f4134..57c29a59f9e 100644 --- a/utils/zonebudget/src/zone.f90 +++ b/utils/zonebudget/src/zone.f90 @@ -20,7 +20,7 @@ module ZoneModule public :: maxzone public :: iuniqzone public :: nmznfl, vbvl, vbznfl - + integer(I4B) :: ncells integer(I4B) :: maxzone integer(I4B), dimension(:), allocatable :: izoneuser @@ -31,9 +31,9 @@ module ZoneModule real(DP), dimension(:, :, :), allocatable :: vbznfl real(DP), dimension(:, :, :), allocatable :: vbvl character(len=LINELENGTH) :: errmsg, keyword - - contains - + +contains + subroutine zone_init(inunit, nbudterms, ncr, mshape) ! ****************************************************************************** ! zone_init @@ -61,26 +61,26 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) ! -- Read DIMENSIONS block, set NCELLS call parser%Initialize(inunit, iout) call parser%GetBlock('DIMENSIONS', isfound, ierr) - if(isfound) then - write(iout,'(/, a)') 'Processing zone dimensions' + if (isfound) then + write (iout, '(/, a)') 'Processing zone dimensions' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('NCELLS') - ncells = parser%GetInteger() - write(iout,'(4x,a,i0)') 'NCELLS = ', ncells - case default - write(errmsg,'(4x,a,a)')'ERROR. UNKNOWN DIMENSIONS ENTRY: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() - end select + case ('NCELLS') + ncells = parser%GetInteger() + write (iout, '(4x,a,i0)') 'NCELLS = ', ncells + case default + write (errmsg, '(4x,a,a)') 'ERROR. UNKNOWN DIMENSIONS ENTRY: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() + end select end do - write(iout,'(a)') 'End processing zone dimensions' + write (iout, '(a)') 'End processing zone dimensions' else - write(errmsg,'(1x,a)')'ERROR. REQUIRED ZONE DIMENSIONS BLOCK NOT FOUND.' + write (errmsg, '(1x,a)') 'ERROR. REQUIRED ZONE DIMENSIONS BLOCK NOT FOUND.' call store_error(errmsg) call parser%StoreErrorUnit() end if @@ -88,63 +88,64 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) ! -- Validate size and allocate arrays if (ncr > 0) then if (ncells /= ncr) then - write(errmsg, '(a,i0)') 'GRB FILE INDICATES NUMBER OF CELLS OR ' // & + write (errmsg, '(a,i0)') 'GRB FILE INDICATES NUMBER OF CELLS OR '// & 'REACHES IS ', ncr call store_error(errmsg) - write(errmsg, '(a,i0)') 'INSTEAD ZONE ARRAY SPECIFIED AS SIZE ', ncells + write (errmsg, '(a,i0)') 'INSTEAD ZONE ARRAY SPECIFIED AS SIZE ', ncells call store_error(errmsg) - write(errmsg, '(a,i0)') 'CHANGE SIZE OF ZONE ARRAY TO ', ncr + write (errmsg, '(a,i0)') 'CHANGE SIZE OF ZONE ARRAY TO ', ncr call store_error(errmsg) call store_error_unit(inunit) - endif + end if else ! -- Number of cells/reaches not available in grb or no grb specified ! Setting ncr to ncells ncr = ncells - endif - allocate(izoneuser(ncells)) - allocate(izone(ncells)) - allocate(ich(ncells)) + end if + allocate (izoneuser(ncells)) + allocate (izone(ncells)) + allocate (ich(ncells)) ! ! -- get griddata block call parser%GetBlock('GRIDDATA', isfound, ierr) - if(isfound) then - write(iout,'(/, a)') 'Processing zone griddata' + if (isfound) then + write (iout, '(/, a)') 'Processing zone griddata' do call parser%GetNextLine(endOfBlock) if (endOfBlock) exit call parser%GetStringCaps(keyword) select case (keyword) - case ('IZONE') - call parser%GetStringCaps(keyword) - if (keyword .EQ. 'LAYERED') then - if (size(mshape) > 1) then - nlay = mshape(1) - else - write(errmsg,'(4x,a)') 'ERROR. LAYERED INPUT NOT SUPPORTED & - &FOR IZONE. LAYERED INPUT CAN ONLY BE USED FOR IZONE & - &WHEN A BINARY GRID FILE IS PROVIDED AND THE MODEL IS LAYERED' - call store_error(errmsg) - call parser%StoreErrorUnit() - endif - ncpl = ncells / nlay - write(iout, '(4x, a, i0)') 'LAYERED detected. Using NLAY = ', nlay - write(iout, '(4x, a, i0, a)') 'Reading ', ncpl, ' values per layer' - istart = 1 - istop = ncpl - do k = 1, nlay - call ReadArray(inunit, izoneuser(istart:istop), aname, 1, ncpl, iout, k) - istart = istop + 1 - istop = istart + ncpl - 1 - enddo + case ('IZONE') + call parser%GetStringCaps(keyword) + if (keyword .EQ. 'LAYERED') then + if (size(mshape) > 1) then + nlay = mshape(1) else - call ReadArray(inunit, izoneuser, aname, 1, ncells, iout, 0) - endif - case default - write(errmsg,'(4x,a,a)')'ERROR. UNKNOWN ZONE GRIDDATA TAG: ', & - trim(keyword) - call store_error(errmsg) - call parser%StoreErrorUnit() + write (errmsg, '(4x,a)') 'ERROR. LAYERED INPUT NOT SUPPORTED & + &FOR IZONE. LAYERED INPUT CAN ONLY BE USED FOR IZONE & + &WHEN A BINARY GRID FILE IS PROVIDED AND THE MODEL IS LAYERED' + call store_error(errmsg) + call parser%StoreErrorUnit() + end if + ncpl = ncells / nlay + write (iout, '(4x, a, i0)') 'LAYERED detected. Using NLAY = ', nlay + write (iout, '(4x, a, i0, a)') 'Reading ', ncpl, ' values per layer' + istart = 1 + istop = ncpl + do k = 1, nlay + call ReadArray(inunit, izoneuser(istart:istop), aname, 1, ncpl, & + iout, k) + istart = istop + 1 + istop = istart + ncpl - 1 + end do + else + call ReadArray(inunit, izoneuser, aname, 1, ncells, iout, 0) + end if + case default + write (errmsg, '(4x,a,a)') 'ERROR. UNKNOWN ZONE GRIDDATA TAG: ', & + trim(keyword) + call store_error(errmsg) + call parser%StoreErrorUnit() end select end do else @@ -153,7 +154,7 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) end if ! ! -- Write messages - close(inunit) + close (inunit) ! ! -- Find max and min values iminval = HUGE(iminval) @@ -162,18 +163,19 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) izone(n) = izoneuser(n) if (izoneuser(n) /= 0) then if (izoneuser(n) < iminval) then - iminval = izoneuser(n) + iminval = izoneuser(n) end if if (izoneuser(n) > imaxval) then - imaxval = izoneuser(n) + imaxval = izoneuser(n) end if end if end do ! ! -- write minimum and maximum zone numbers - write(iout, '(/, 4x, a, i0)') 'Successfully read zone array with NCELLS = ', ncells - write(iout, '(4x, a, i0)') 'Minimum user-specified zone number is ', iminval - write(iout, '(4x, a, i0)') 'Maximum user-specified zone number is ', imaxval + write (iout, '(/, 4x, a, i0)') & + 'Successfully read zone array with NCELLS = ', ncells + write (iout, '(4x, a, i0)') 'Minimum user-specified zone number is ', iminval + write (iout, '(4x, a, i0)') 'Maximum user-specified zone number is ', imaxval ! ! -- find unique zones call unique_values(izone, iuniqzone) @@ -185,7 +187,7 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) maxzone = size(iuniqzone) ! ! -- allocate and initialize izonecount - allocate(izonecount(0:maxzone)) + allocate (izonecount(0:maxzone)) do i = 0, maxzone izonecount(i) = 0 end do @@ -207,34 +209,34 @@ subroutine zone_init(inunit, nbudterms, ncr, mshape) end do ! ! -- write zone mapping - write(iout, '(//,4x,3(a20,1x))') 'USER ZONE', 'ZONE NUMBER', 'CELL COUNT' - write(iout, '(4x,62("-"))') - write(iout, '(4x,3(i20,1x))') 0, 0, izonecount(0) + write (iout, '(//,4x,3(a20,1x))') 'USER ZONE', 'ZONE NUMBER', 'CELL COUNT' + write (iout, '(4x,62("-"))') + write (iout, '(4x,3(i20,1x))') 0, 0, izonecount(0) do i = 1, maxzone - write(iout, '(4x,3(i20,1x))') iuniqzone(i), i, izonecount(i) + write (iout, '(4x,3(i20,1x))') iuniqzone(i), i, izonecount(i) end do - write(iout, '(4x,62("-"),/)') - + write (iout, '(4x,62("-"),/)') + ! !maxzone = maxval(izone) - write(iout,'(a)') 'End processing zone griddata' + write (iout, '(a)') 'End processing zone griddata' ! ! -- nmznfl is map showing connections between two zones. If 1, then ! there is flow between zones, and zone to zone flow will be written. - allocate(nmznfl(0:maxzone, 0:maxzone)) - allocate(vbznfl(2, 0:maxzone, 0:maxzone)) - allocate(vbvl(2, 0:maxzone, nbudterms)) + allocate (nmznfl(0:maxzone, 0:maxzone)) + allocate (vbznfl(2, 0:maxzone, 0:maxzone)) + allocate (vbvl(2, 0:maxzone, nbudterms)) ! ! -- deallocate local variables - deallocate(izonecount) + deallocate (izonecount) ! ! -- close the zone file - close(inunit) + close (inunit) ! ! -- return return end subroutine zone_init - + subroutine clear_accumulators() ! ****************************************************************************** ! clear_accumulators @@ -280,8 +282,8 @@ subroutine flowja_accumulate(nodesrc, nodedst, flowdata) vbznfl(2, iz1, iz2) = vbznfl(2, iz1, iz2) - q else vbznfl(1, iz1, iz2) = vbznfl(1, iz1, iz2) + q - endif - enddo + end if + end do ! ! -- return return @@ -316,9 +318,9 @@ subroutine flowiaja_accumulate(ia, ja, flowja) vbznfl(2, iz1, iz2) = vbznfl(2, iz1, iz2) - q else vbznfl(1, iz1, iz2) = vbznfl(1, iz1, iz2) + q - endif - enddo - enddo + end if + end do + end do ! ! -- return return @@ -349,13 +351,13 @@ subroutine flow_accumulate(ibudterm, nodesrc, flowdata) vbvl(2, iz1, ibudterm) = vbvl(2, iz1, ibudterm) - q else vbvl(1, iz1, ibudterm) = vbvl(1, iz1, ibudterm) + q - endif - enddo + end if + end do ! ! -- return return end subroutine flow_accumulate - + subroutine flowch_setich(ibudterm, nodesrc) ! ****************************************************************************** ! Set ICH equal to ibudterm for all constant head cells @@ -374,12 +376,12 @@ subroutine flowch_setich(ibudterm, nodesrc) do i = 1, size(nodesrc) n = nodesrc(i) ich(n) = ibudterm - enddo + end do ! ! -- return return end subroutine flowch_setich - + subroutine flowch_accumulate(ia, ja, flowja) ! ****************************************************************************** ! flowiaja_accumulate @@ -416,14 +418,14 @@ subroutine flowch_accumulate(ia, ja, flowja) vbvl(2, iz, ibudterm) = vbvl(2, iz, ibudterm) - q else vbvl(1, iz, ibudterm) = vbvl(1, iz, ibudterm) + q - endif - enddo - enddo + end if + end do + end do ! ! -- return return end subroutine flowch_accumulate - + subroutine pop_zero_zone(ia) ! -- dummy arguments integer(I4B), dimension(:), allocatable, intent(inout) :: ia @@ -449,7 +451,7 @@ subroutine pop_zero_zone(ia) if (ipop /= 0) then ! ! -- allocate ib - allocate(ib(nlen-1)) + allocate (ib(nlen - 1)) ! ! -- fill itmp with everything in ia except 0 n = 1 @@ -462,16 +464,16 @@ subroutine pop_zero_zone(ia) end do ! ! -- deallocate ia - deallocate(ia) + deallocate (ia) ! ! -- allocate ia and fill with ib - allocate(ia(size(ib))) + allocate (ia(size(ib))) do i = 1, size(ib) ia(i) = ib(i) end do ! ! -- deallocate ib - deallocate(ib) + deallocate (ib) end if ! ! -- return @@ -486,15 +488,15 @@ subroutine zone_finalize() ! SPECIFICATIONS: ! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------ - deallocate(izone) - deallocate(ich) - deallocate(nmznfl) - deallocate(vbznfl) - deallocate(vbvl) + deallocate (izone) + deallocate (ich) + deallocate (nmznfl) + deallocate (vbznfl) + deallocate (vbvl) ! ! -- return return end subroutine zone_finalize - + end module ZoneModule diff --git a/utils/zonebudget/src/zoneoutput.f90 b/utils/zonebudget/src/zoneoutput.f90 index e7b7d71e64f..8e3c556d48b 100644 --- a/utils/zonebudget/src/zoneoutput.f90 +++ b/utils/zonebudget/src/zoneoutput.f90 @@ -1,5 +1,5 @@ module ZoneOutputModule - + use KindModule use ConstantsModule, only: LINELENGTH use BudgetModule, only: BudgetType, budget_cr @@ -9,13 +9,13 @@ module ZoneOutputModule public :: zoneoutput_init public :: zoneoutput_write public :: zoneoutput_finalize - + integer(I4B) :: iout integer(I4B) :: ioutcsv = 0 type(BudgetType), dimension(:), allocatable :: budobj - - contains - + +contains + subroutine zoneoutput_init(iunit_out, iunit_csv, maxzone, nbudterms) ! ****************************************************************************** ! zoneoutput_init @@ -37,20 +37,20 @@ subroutine zoneoutput_init(iunit_out, iunit_csv, maxzone, nbudterms) ! ! -- Create the budget objects to that budget tables can be ! written to list file. - allocate(budobj(maxzone)) + allocate (budobj(maxzone)) do izone = 1, maxzone call budobj(izone)%allocate_scalars('ZONEBUDGET') - write(bdzone, '(a,i0)') 'ZONE ', iuniqzone(izone) - call budobj(izone)%budget_df(nbudterms + maxzone, & + write (bdzone, '(a,i0)') 'ZONE ', iuniqzone(izone) + call budobj(izone)%budget_df(nbudterms + maxzone, & labeltitle='PACKAGE/MODEL', bdzone=bdzone) - enddo + end do ! ! -- Return return end subroutine zoneoutput_init - subroutine zoneoutput_write(itime, kstp, kper, delt, totim, nbudterms, & - nmznfl, vbvl, vbznfl, packagenamearray, & + subroutine zoneoutput_write(itime, kstp, kper, delt, totim, nbudterms, & + nmznfl, vbvl, vbznfl, packagenamearray, & budtxtarray, internalflow) ! ****************************************************************************** ! zoneoutput_write @@ -89,143 +89,143 @@ subroutine zoneoutput_write(itime, kstp, kper, delt, totim, nbudterms, & ! to add package name to CSV titles, but only if necessary. Put ! packagename into spntmp if there are multiple butxt entries of the ! same type. - allocate(spntmp(nbudterms)) + allocate (spntmp(nbudterms)) spntmp(:) = '' do ibudterm = 1, nbudterms do j = 1, nbudterms if (j == ibudterm) cycle if (budtxtarray(ibudterm) == budtxtarray(j)) then spntmp(ibudterm) = packagenamearray(ibudterm) - endif - enddo - enddo + end if + end do + end do ! ! -- Write time and zone informatio to CSV header - write(ioutcsv, '(a)', advance='no') 'totim,' - write(ioutcsv, '(a)', advance='no') 'kstp,' - write(ioutcsv, '(a)', advance='no') 'kper,' - write(ioutcsv, '(a)', advance='no') 'zone,' + write (ioutcsv, '(a)', advance='no') 'totim,' + write (ioutcsv, '(a)', advance='no') 'kstp,' + write (ioutcsv, '(a)', advance='no') 'kper,' + write (ioutcsv, '(a)', advance='no') 'zone,' do ibudterm = 1, nbudterms if (internalflow(ibudterm) == 1) cycle txt = '' if (spntmp(ibudterm) /= '') then - txt = trim(adjustl(spntmp(ibudterm))) // '-' - endif - write(txt, '(a, a, a)') trim(txt), & - trim(adjustl(budtxtarray(ibudterm))), & - '-IN,' - write(ioutcsv, '(a)', advance='no') trim(txt) - enddo + txt = trim(adjustl(spntmp(ibudterm)))//'-' + end if + write (txt, '(a, a, a)') trim(txt), & + trim(adjustl(budtxtarray(ibudterm))), & + '-IN,' + write (ioutcsv, '(a)', advance='no') trim(txt) + end do ! ! -- Write budget terms to CSV header do ibudterm = 1, nbudterms if (internalflow(ibudterm) == 1) cycle txt = '' if (spntmp(ibudterm) /= '') then - txt = trim(adjustl(spntmp(ibudterm))) // '-' - endif - write(txt, '(a, a, a)') trim(txt), & - trim(adjustl(budtxtarray(ibudterm))), & - '-OUT,' - write(ioutcsv, '(a)', advance='no') trim(txt) - enddo + txt = trim(adjustl(spntmp(ibudterm)))//'-' + end if + write (txt, '(a, a, a)') trim(txt), & + trim(adjustl(budtxtarray(ibudterm))), & + '-OUT,' + write (ioutcsv, '(a)', advance='no') trim(txt) + end do ! ! -- Write zone to zone flow names to CSV header do izone = 0, maxzone if (izone == 0) then izv = izone - else - izv = iuniqzone(izone) + else + izv = iuniqzone(izone) end if - write(ioutcsv, '(a, i0)', advance='no') 'FROM ZONE ', izv - write(ioutcsv, '(a)', advance='no') ',' - enddo + write (ioutcsv, '(a, i0)', advance='no') 'FROM ZONE ', izv + write (ioutcsv, '(a)', advance='no') ',' + end do do izone = 0, maxzone if (izone == 0) then izv = izone - else - izv = iuniqzone(izone) + else + izv = iuniqzone(izone) end if - write(ioutcsv, '(a, i0)', advance='no') 'TO ZONE ', izv - if (izone < maxzone) write(ioutcsv, '(a)', advance='no') ',' - enddo - write(ioutcsv, *) - endif + write (ioutcsv, '(a, i0)', advance='no') 'TO ZONE ', izv + if (izone < maxzone) write (ioutcsv, '(a)', advance='no') ',' + end do + write (ioutcsv, *) + end if ! ! -- Write a line of CSV entries for each zone zoneloop: do izone = 1, maxzone ! ! -- Time and zone information - write(txt, '(G0)') totim - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) // ',' - write(txt, '(i0)') kstp - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) // ',' - write(txt, '(i0)') kper - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) // ',' - write(txt, '(i0)') iuniqzone(izone) - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) // ',' + write (txt, '(G0)') totim + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt))//',' + write (txt, '(i0)') kstp + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt))//',' + write (txt, '(i0)') kper + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt))//',' + write (txt, '(i0)') iuniqzone(izone) + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt))//',' ! ! -- CSV budget ins and outs do iinout = 1, 2 do ibudterm = 1, nbudterms if (internalflow(ibudterm) == 1) cycle - write(txt, '(G0)') vbvl(iinout, izone, ibudterm) - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) - write(ioutcsv, '(a)', advance='no') ',' - enddo - enddo + write (txt, '(G0)') vbvl(iinout, izone, ibudterm) + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt)) + write (ioutcsv, '(a)', advance='no') ',' + end do + end do ! ! -- CSV file zone to zone flow in and out do iz2 = 0, maxzone val = vbznfl(1, izone, iz2) if (izone == iz2) val = 0.d0 - write(txt, '(G0)') val - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) - write(ioutcsv, '(a)', advance='no') ',' - enddo + write (txt, '(G0)') val + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt)) + write (ioutcsv, '(a)', advance='no') ',' + end do do iz2 = 0, maxzone val = vbznfl(2, izone, iz2) if (izone == iz2) val = 0.d0 - write(txt, '(G0)') val - write(ioutcsv, '(a)', advance='no') trim(adjustl(txt)) - if (iz2 < maxzone) write(ioutcsv, '(a)', advance='no') ',' - enddo + write (txt, '(G0)') val + write (ioutcsv, '(a)', advance='no') trim(adjustl(txt)) + if (iz2 < maxzone) write (ioutcsv, '(a)', advance='no') ',' + end do ! ! -- LST file ins and outs call budobj(izone)%reset() do ibudterm = 1, size(budtxtarray) if (internalflow(ibudterm) == 1) cycle - call budobj(izone)%addentry(vbvl(1, izone, ibudterm), & - vbvl(2, izone, ibudterm), & - delt, budtxtarray(ibudterm), & + call budobj(izone)%addentry(vbvl(1, izone, ibudterm), & + vbvl(2, izone, ibudterm), & + delt, budtxtarray(ibudterm), & rowlabel=packagenamearray(ibudterm)) - enddo + end do ! ! -- LST file zone to zone do iz2 = 0, maxzone if (izone == iz2) cycle if (nmznfl(izone, iz2) == 1) then rin = vbznfl(1, izone, iz2) - rout =vbznfl(2, izone, iz2) + rout = vbznfl(2, izone, iz2) if (iz2 == 0) then izv = iz2 - else - izv = iuniqzone(iz2) + else + izv = iuniqzone(iz2) end if - write(txt, '(a,i0)') 'ZONE ', izv + write (txt, '(a,i0)') 'ZONE ', izv call budobj(izone)%addentry(rin, rout, delt, txt) - endif - enddo + end if + end do call budobj(izone)%budget_ot(kstp, kper, iout) ! ! -- write line ending after each zone - write(ioutcsv, *) - enddo zoneloop + write (ioutcsv, *) + end do zoneloop ! ! -- Return return end subroutine zoneoutput_write - + subroutine zoneoutput_finalize() ! ****************************************************************************** ! zoneoutput_finalize @@ -235,10 +235,10 @@ subroutine zoneoutput_finalize() ! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------ ! - close(ioutcsv) + close (ioutcsv) ! ! -- Return return end subroutine zoneoutput_finalize - + end module ZoneOutputModule diff --git a/version.txt b/version.txt index 69888194b97..41f04b4bc40 100644 --- a/version.txt +++ b/version.txt @@ -1,7 +1,7 @@ # MODFLOW 6 version file automatically created using...make_release.py -# created on...March 04, 2022 11:12:44 +# created on...December 01, 2022 08:04:49 major = 6 -minor = 3 +minor = 4 micro = 0 __version__ = '{:d}.{:d}.{:d}'.format(major, minor, micro)