diff --git a/.github/common/check_format.py b/.github/common/check_format.py new file mode 100644 index 00000000000..a21f7a32c4e --- /dev/null +++ b/.github/common/check_format.py @@ -0,0 +1,133 @@ +import argparse +import os +import sys +import timeit +from itertools import repeat +from queue import Empty +from pathlib import Path +from subprocess import run +from multiprocessing import cpu_count, Pool, Manager + +PROJ_ROOT = Path(__file__).parents[2] + +# exclude these directories from checks +excludedirs = [ + PROJ_ROOT / ".pixi", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "blas", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "daglib", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "rcm", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "sparsekit", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "sparskit2", + PROJ_ROOT / "utils" / "mf5to6", +] + +# exclude these files from checks +excludefiles = [] + +# shared state +manager = Manager() +failures = manager.Queue() +checks = manager.Value("checks", 0) +skips = manager.Value("skips", 0) +lock = manager.Lock() + +# commands +fprettify = "fprettify -c .fprettify.yaml" + + +def excluded(path) -> bool: + path = Path(path) + for f in excludefiles: + if os.path.exists(f) and os.path.samefile(path, f): + return True + for d in excludedirs: + if os.path.exists(d) and path.is_relative_to(d): + return True + return False + + +def check_format(path, write_changes=False, verbose=False): + path = Path(path) + if excluded(path): + if verbose: + print(f"Skipping format check: {path}") + with lock: + skips.value += 1 + return + + if verbose: + print(f"Checking format: {path}") + + diff = "" if write_changes else "-d" + cmd = f"{fprettify} {diff} {path}" + result = run(cmd, capture_output=True, shell=True) + if result.stdout or result.stderr: + failures.put(path) + + with lock: + checks.value += 1 + + +def report(duration: float) -> bool: + def pop(q): + return q.get(block=False) + + n_failures = failures.qsize() + success = n_failures == 0 + print(f"Checked format for {checks.value} Fortran files in {duration:.4f}s") + + if n_failures > 0: + success = False + stats = f"failures: {n_failures} \\" + hr = "".join(repeat("_", len(stats) - 1)) + print(f"{hr}\n{stats}") + while True: + try: + print(f"{fprettify} {pop(failures)}") + except Empty: + break + + print() + return success + + +if __name__ == "__main__": + start = timeit.default_timer() + parser = argparse.ArgumentParser( + "MODFLOW 6 Fortran source code format verification" + ) + parser.add_argument( + "-p", + "--path", + help="path to file or directory", + default=PROJ_ROOT, + ) + parser.add_argument( + "-w", + "--write-changes", + help="write codespell changes in place if possible", + action="store_true", + default=False, + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="verbose", default=False + ) + args = parser.parse_args() + path = Path(args.path).expanduser().absolute() + assert path.exists(), f"Path not found: {path}" + write = args.write_changes + verbose = args.verbose + + if path.is_file(): + check_format(path, verbose) + else: + with Pool(cpu_count()) as pool: + files = [str(p) for p in path.rglob("*.[fF]9[05]")] + if verbose: + msg = f"Checking {len(files)} files in directory: {path}" + print(msg) + print("".join(repeat("-", len(msg)))) + pool.starmap(check_format, [(f, write, verbose) for f in files]) + + stop = timeit.default_timer() + sys.exit(0 if report(stop - start) else 1) diff --git a/.github/common/check_spelling.py b/.github/common/check_spelling.py new file mode 100644 index 00000000000..c9ac0dd77e4 --- /dev/null +++ b/.github/common/check_spelling.py @@ -0,0 +1,135 @@ +import argparse +import os +import sys +import timeit +from itertools import repeat +from queue import Empty +from pathlib import Path +from subprocess import run +from multiprocessing import cpu_count, Pool, Manager + +PROJ_ROOT = Path(__file__).parents[2] + +# exclude these directories from checks +excludedirs = [ + PROJ_ROOT / ".pixi", + PROJ_ROOT / "autotest" / ".pytest_cache", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "blas", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "daglib", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "rcm", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "sparsekit", + PROJ_ROOT / "src" / "Utilities" / "Libraries" / "sparskit2", + PROJ_ROOT / "srcbmi" / "latex", + PROJ_ROOT / "utils" / "mf5to6", +] + +# exclude these files from checks +excludefiles = [] + +# shared state +manager = Manager() +failures = manager.Queue() +checks = manager.Value("checks", 0) +lock = manager.Lock() + +# commands +codespell = "codespell --ignore-words=.codespell.ignore" + + +def excluded(path) -> bool: + path = Path(path) + for f in excludefiles: + if os.path.exists(f) and os.path.samefile(path, f): + return True + for d in excludedirs: + if os.path.exists(d) and path.is_relative_to(d): + return True + return False + + +def check_spelling(path, write_changes=False, verbose=False): + path = Path(path) + if verbose: + print(f"Checking spelling: {path}") + + wc = "-w" if write_changes else "" + cmd = f"{codespell} {wc} {path}" + result = run(cmd, capture_output=True, shell=True) + if result.stdout or result.stderr: + failures.put(path) + + with lock: + checks.value += 1 + + +def report(duration: float) -> bool: + def pop(q): + return q.get(block=False) + + n_failures = failures.qsize() + success = n_failures == 0 + print(f"Checked spelling for {checks.value} files in {duration:.4f}s") + + if n_failures > 0: + success = False + stats = f"failures: {n_failures} \\" + hr = "".join(repeat("_", len(stats) - 1)) + print(f"{hr}\n{stats}") + while True: + try: + print(f"{codespell} {pop(failures)}") + except Empty: + break + + print() + return success + + +if __name__ == "__main__": + start = timeit.default_timer() + parser = argparse.ArgumentParser("MODFLOW 6 spell check verification") + parser.add_argument( + "-p", + "--path", + help="path to file or directory", + default=PROJ_ROOT, + ) + parser.add_argument( + "-e", + "--extension", + help="file extensions to check", + action="append", + default=[".[fF]9[05]", ".dfn", ".tex", ".md"], + ) + parser.add_argument( + "-w", + "--write-changes", + help="write changes in place if possible", + action="store_true", + default=False, + ) + parser.add_argument( + "-v", "--verbose", action="store_true", help="verbose", default=False + ) + args = parser.parse_args() + path = Path(args.path).expanduser().absolute() + assert path.exists(), f"Path not found: {path}" + extensions = args.extension + write = args.write_changes + verbose = args.verbose + + if path.is_file(): + check_spelling(path, write, verbose) + else: + with Pool(cpu_count()) as pool: + files = [] + for ext in extensions: + files.extend([str(p) for p in path.rglob(f"*{ext}") if not excluded(p)]) + if verbose: + msg = f"Checking {len(files)} files in directory: {path}" + print(msg) + print("".join(repeat("-", len(msg)))) + pool.starmap(check_spelling, [(f, write, verbose) for f in files]) + + stop = timeit.default_timer() + sys.exit(0 if report(stop - start) else 1) diff --git a/.github/common/msvs_vfproj_check.py b/.github/common/check_vfproj.py similarity index 100% rename from .github/common/msvs_vfproj_check.py rename to .github/common/check_vfproj.py diff --git a/.github/common/codespell_docs_check.py b/.github/common/codespell_docs_check.py deleted file mode 100644 index dcb035bb060..00000000000 --- a/.github/common/codespell_docs_check.py +++ /dev/null @@ -1,157 +0,0 @@ -import argparse -import glob -import os -import sys -from pathlib import Path -from subprocess import run - -# MODFLOW 6 repository directories to check (relative to root) -searchpaths = [ - "doc", - ".hpc", - ".vscode", - "distribution", -] - -# Exclude these directories from checks -excludedirs = [ - "srcbmi/latex", -] - -# Exclude these files from checks -excludefiles = [] # add excluded files here - - -class CodespellCheck: - """ - Verify MODFLOW 6 fortran source code format - """ - - def __init__(self, root: Path, verbose: bool, write_changes: bool): - self._checkcount = 0 - self._codespellfails = [] - self._exclude_dirs = [] - self._exclude_files = [] - self._root = root.resolve() - self._verbose = verbose - self.write_changes = write_changes - self._entrypath = Path().cwd() - - os.chdir(self._root) - - def add_search_paths(self) -> None: - files = [] - files += Path(".").glob("*.md") - - for dir_path in searchpaths: - p = Path(dir_path) - for e in ("**/*.dfn", "**/*.tex", "**/*.md"): - files += p.glob(e) - - for f in sorted(files): - self._check_docs_codespell(f) - - def add_exclude_dirs(self, excl_dirs: list) -> None: - self._exclude_dirs += excl_dirs - - def add_exclude_files(self, excl_files: list) -> None: - self._exclude_files += excl_files - - def clear_exclude_dirs(self) -> None: - self._exclude_dirs = None - self._exclude_dirs = [] - - def clear_exclude_files(self) -> None: - self._exclude_files = None - self._exclude_files = [] - - def report(self) -> None: - print(f"\nDocument files checked: {self._checkcount}") - print( - f"Document files codespell failures: {len(self._codespellfails)}\n" - ) - - if len(self._codespellfails) > 0: - print(f"codespell failures\n{71*'-'}") - for f in self._codespellfails: - print(f"codespell -w {f} --ignore-words=.codespell.ignore") - print() - - def exit(self) -> int: - os.chdir(self._entrypath) - - if len(self._codespellfails): - return 1 - - return 0 - - def _check_docs_codespell(self, path: Path) -> None: - if self._excluded(path): - return - - self._checkcount += 1 - - if self._verbose: - print(f"{self._checkcount: 5d}: {path}") - - if self.write_changes: - wc_str = "-w" - else: - wc_str = "" - - cmd = f"codespell {wc_str} {path} --ignore-words=.codespell.ignore" - result = run(cmd, capture_output=True, shell=True) - - if result.stdout or result.stderr: - self._codespellfails.append(path) - - def _excluded(self, path: Path) -> bool: - for f in self._exclude_files: - if os.path.exists(f) and os.path.samefile(path, f): - return True - - for d in self._exclude_dirs: - if os.path.exists(d) and os.path.samefile(path.parents[0], d): - return True - - return False - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - "MODFLOW 6 Documents spell check with codespell verification" - ) - parser.add_argument( - "-r", - "--root", - help="path to MODFLOW 6 repository root directory", - ) - parser.add_argument( - "-w", - "--write-changes", - help="write changes in place if possible", - action="store_true", - ) - parser.add_argument( - "-v", - "--verbose", - action="store_true", - help="verbose", - ) - args = parser.parse_args() - - # set MODFLOW 6 repository root - root = Path(args.root).resolve() if args.root else Path(".").resolve() - - doccheck = CodespellCheck( - root=root, - verbose=args.verbose, - write_changes=args.write_changes, - ) - doccheck.add_exclude_dirs(excl_dirs=excludedirs) - doccheck.add_exclude_files(excl_files=excludefiles) - - doccheck.add_search_paths() - - doccheck.report() - sys.exit(doccheck.exit()) diff --git a/.github/common/fortran_format_check.py b/.github/common/fortran_format_check.py deleted file mode 100644 index c1436641ae2..00000000000 --- a/.github/common/fortran_format_check.py +++ /dev/null @@ -1,170 +0,0 @@ -import argparse -import glob -import os -import sys -from pathlib import Path -from subprocess import run - -# MODFLOW 6 repository directories to check (relative to root) -searchpaths = ["src", "srcbmi", "utils/zonebudget/src"] - -# Exclude these directories from checks -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 -] - -# Exclude these files from checks -excludefiles = [] # add excluded files here - - -class FortranFormatCheck: - """ - Verify MODFLOW 6 fortran source code format - """ - - def __init__(self, root: Path, verbose: bool, write_changes: bool): - self._checkcount = 0 - self._fprettifyfails = [] - self._codespellfails = [] - self._exclude_dirs = [] - self._exclude_files = [] - self._root = root.resolve() - self.write_changes = write_changes - self._verbose = verbose - self._entrypath = Path().cwd() - - os.chdir(self._root) - - def add_search_path(self, path: Path) -> None: - p = Path(path) - - for f in p.glob("**/*.[fF]9[05]"): - self._check_src_fprettify(f) - self._check_src_codespell(f) - - def add_exclude_dirs(self, excl_dirs: list) -> None: - self._exclude_dirs += excl_dirs - - def add_exclude_files(self, excl_files: list) -> None: - self._exclude_files += excl_files - - def clear_exclude_dirs(self) -> None: - self._exclude_dirs = None - self._exclude_dirs = [] - - def clear_exclude_files(self) -> None: - self._exclude_files = None - self._exclude_files = [] - - def report(self) -> None: - print(f"\nFortran source files checked: {self._checkcount}") - print( - f"Fortran source files fprettify failures: {len(self._fprettifyfails)}" - ) - print( - f"Fortran source files codespell failures: {len(self._codespellfails)}\n" - ) - - if len(self._fprettifyfails) > 0: - print(f"fprettify failures\n{71*'-'}") - for f in self._fprettifyfails: - print(f"fprettify -c .fprettify.yaml {f}") - print() - - if len(self._codespellfails) > 0: - print(f"codespell failures\n{71*'-'}") - for f in self._codespellfails: - print(f"codespell -w {f} --ignore-words=.codespell.ignore") - print() - - def exit(self) -> int: - os.chdir(self._entrypath) - - if len(self._fprettifyfails) > 0 or len(self._codespellfails) > 0: - return 1 - - return 0 - - def _check_src_fprettify(self, path: Path) -> None: - if self._excluded(path): - return - - self._checkcount += 1 - - if self._verbose: - print(f"{self._checkcount: 5d}: {path}") - - cmd = f"fprettify -d -c .fprettify.yaml {path}" - result = run(cmd, capture_output=True, shell=True) - - if result.stdout or result.stderr: - self._fprettifyfails.append(path) - - def _check_src_codespell(self, path: Path) -> None: - if self._excluded(path): - return - - if self.write_changes: - wc_str = "-w" - else: - wc_str = "" - - cmd = f"codespell {wc_str} {path} --ignore-words=.codespell.ignore" - result = run(cmd, capture_output=True, shell=True) - - if result.stdout or result.stderr: - self._codespellfails.append(path) - - def _excluded(self, path: Path) -> bool: - for f in self._exclude_files: - if os.path.exists(f) and os.path.samefile(path, f): - return True - - for d in self._exclude_dirs: - if os.path.exists(d) and os.path.samefile(path.parents[0], d): - return True - - return False - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - "MODFLOW 6 fortran format source code verification" - ) - parser.add_argument( - "-r", "--root", help="path to MODFLOW 6 repository root directory" - ) - parser.add_argument( - "-w", - "--write-changes", - help="write codespell changes in place if possible", - action="store_true", - ) - parser.add_argument( - "-v", - "--verbose", - action="store_true", - help="verbose", - ) - args = parser.parse_args() - - # set MODFLOW 6 repository root - root = Path(args.root).resolve() if args.root else Path(".").resolve() - - fformat_check = FortranFormatCheck( - root=root, - verbose=args.verbose, - write_changes=args.write_changes, - ) - fformat_check.add_exclude_dirs(excl_dirs=excludedirs) - fformat_check.add_exclude_files(excl_files=excludefiles) - - for path in searchpaths: - fformat_check.add_search_path(path=path) - - fformat_check.report() - sys.exit(fformat_check.exit()) diff --git a/.github/common/wide_compat_reports.py b/.github/common/widen_compat_reports.py similarity index 100% rename from .github/common/wide_compat_reports.py rename to .github/common/widen_compat_reports.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33fc1e55e10..249e5d3af37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,10 +54,10 @@ jobs: pixi-version: v0.19.1 - name: Check Fortran source formatting - run: pixi run fortran-format-check + run: pixi run check-format - name: Check MSVS project files - run: pixi run msvs-vfproj-check + run: pixi run check-vfproj - name: Check CITATION.cff uses: dieghernan/cff-validator@v3 diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 6bf0a90b522..a4dc70e3a2c 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -264,8 +264,8 @@ jobs: working-directory: .github/compat id: merge-reports run: | - python ../common/wide_compat_reports.py "long_comp.csv" "comp.csv" - python ../common/wide_compat_reports.py "long_test.csv" "test.csv" + python ../common/widen_compat_reports.py "long_comp.csv" "comp.csv" + python ../common/widen_compat_reports.py "long_test.csv" "test.csv" # only upload wide CSVs and Markdown tables - name: Upload artifacts diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 254bdc656bd..2806dbb6314 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,8 +27,8 @@ jobs: with: pixi-version: v0.19.1 - - name: Check documents using codespell - run: pixi run check-docs + - name: Check spelling + run: pixi run check-spelling rtd_build: name: Build ReadTheDocs diff --git a/autotest/TestMathUtil.f90 b/autotest/TestMathUtil.f90 index b203e7ba765..773f7604674 100644 --- a/autotest/TestMathUtil.f90 +++ b/autotest/TestMathUtil.f90 @@ -276,7 +276,7 @@ subroutine test_get_perturbation(error) ! test derivative calculation for x ** 2 x = 1.d6 eps = get_perturbation(x) - v1 = ((x + eps) ** 2 - x ** 2) / eps + v1 = ((x + eps)**2 - x**2) / eps v2 = 2 * x call check(error, & is_close(v1, v2, atol=1d-1), & diff --git a/autotest/TestSwfUtils.f90 b/autotest/TestSwfUtils.f90 index d43b71bf5f5..5ef414b1ed1 100644 --- a/autotest/TestSwfUtils.f90 +++ b/autotest/TestSwfUtils.f90 @@ -1,7 +1,8 @@ module TestSwfUtils use KindModule, only: I4B, DP use ConstantsModule, only: DZERO, DHALF, DONE, DTWO, DNODATA, DTWOTHIRDS - use testdrive, only : error_type, unittest_type, new_unittest, check, test_failed, to_string + use testdrive, only: error_type, unittest_type, new_unittest, check, & + test_failed, to_string use SwfCxsUtilsModule, only: get_cross_section_area, & get_wetted_perimeter, & get_conveyance @@ -9,20 +10,22 @@ module TestSwfUtils private public :: collect_swfutils contains - + subroutine collect_swfutils(testsuite) type(unittest_type), allocatable, intent(out) :: testsuite(:) testsuite = [ & - new_unittest("two_point_section", test_two_point_section), & - new_unittest("three_point_section", test_three_point_section), & - new_unittest("test_four_point_rectangular_section", test_four_point_rectangular_section), & - new_unittest("test_n_point_rectangular_section", test_n_point_rectangular_section) & - ] + new_unittest("two_point_section", test_two_point_section), & + new_unittest("three_point_section", test_three_point_section), & + new_unittest("test_four_point_rectangular_section", & + test_four_point_rectangular_section), & + new_unittest("test_n_point_rectangular_section", & + test_n_point_rectangular_section) & + ] end subroutine collect_swfutils subroutine test_two_point_section(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), parameter :: NPTS=2 + integer(I4B), parameter :: NPTS = 2 real(DP), dimension(NPTS) :: xfraction real(DP), dimension(NPTS) :: height real(DP), dimension(NPTS) :: cxs_rf @@ -72,7 +75,7 @@ subroutine test_two_point_section(error) width, rough, depth) conveyance = res call check(error, & - conveyance == area * (area / perimeter) ** (DTWOTHIRDS) / rough, & + conveyance == area * (area / perimeter)**(DTWOTHIRDS) / rough, & "Conveyance correct") if (allocated(error)) then call test_failed(error, "Conveyance incorrect") @@ -82,7 +85,7 @@ end subroutine test_two_point_section subroutine test_three_point_section(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), parameter :: NPTS=3 + integer(I4B), parameter :: NPTS = 3 real(DP), dimension(NPTS) :: xfraction real(DP), dimension(NPTS) :: height real(DP), dimension(NPTS) :: cxs_rf @@ -111,7 +114,7 @@ subroutine test_three_point_section(error) width, depth) perimeter = res call check(error, & - perimeter == DTWO * sqrt((width / DTWO) ** DTWO + depth ** DTWO), & + perimeter == DTWO * sqrt((width / DTWO)**DTWO + depth**DTWO), & "Wetted perimeter correct") if (allocated(error)) then call test_failed(error, "Wetted perimeter incorrect") @@ -138,11 +141,11 @@ subroutine test_three_point_section(error) conveyance = res a = area / DTWO p = perimeter / DTWO - c = DTWO * (a * ((a / p) ** DTWOTHIRDS) / rough) + c = DTWO * (a * ((a / p)**DTWOTHIRDS) / rough) call check(error, & abs(conveyance - c) < 1.d-8, & - "Swf util conveyance " // to_string(conveyance) // & - " /= expected conveyance " // to_string(c)) + "Swf util conveyance "//to_string(conveyance)// & + " /= expected conveyance "//to_string(c)) if (allocated(error)) then call test_failed(error, "Conveyance calculation failed") return @@ -151,7 +154,7 @@ end subroutine test_three_point_section subroutine test_four_point_rectangular_section(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), parameter :: NPTS=4 + integer(I4B), parameter :: NPTS = 4 real(DP), dimension(NPTS) :: xfraction real(DP), dimension(NPTS) :: height real(DP), dimension(NPTS) :: cxs_rf @@ -183,8 +186,8 @@ subroutine test_four_point_rectangular_section(error) p = DTWO * depth + width call check(error, & perimeter == p, & - "Wetted perimeter " // to_string(perimeter) // & - " /= expected value " // to_string(p)) + "Wetted perimeter "//to_string(perimeter)// & + " /= expected value "//to_string(p)) if (allocated(error)) then call test_failed(error, "Wetted perimeter fail") return @@ -199,8 +202,8 @@ subroutine test_four_point_rectangular_section(error) a = depth * width call check(error, & area == a, & - "Area " // to_string(area) // & - " /= expected value " // to_string(a)) + "Area "//to_string(area)// & + " /= expected value "//to_string(a)) if (allocated(error)) then call test_failed(error, "Cross section area incorrect") return @@ -214,11 +217,11 @@ subroutine test_four_point_rectangular_section(error) conveyance = res a = area p = perimeter - c = a / rough * (a / p) ** DTWOTHIRDS + c = a / rough * (a / p)**DTWOTHIRDS call check(error, & abs(conveyance - c) < 1.d-8, & - "Conveyance " // to_string(conveyance) // & - " /= expected value " // to_string(c)) + "Conveyance "//to_string(conveyance)// & + " /= expected value "//to_string(c)) if (allocated(error)) then call test_failed(error, "Conveyance calculation failed") return @@ -230,7 +233,7 @@ subroutine test_four_point_rectangular_section(error) ! highest height point. depth = 1.5d0 - ! confirm wetted perimeter calculation + ! confirm wetted perimeter calculation res = get_wetted_perimeter(NPTS, & xfraction, & height, & @@ -239,8 +242,8 @@ subroutine test_four_point_rectangular_section(error) p = DTWO * height(1) + width call check(error, & perimeter == p, & - "Wetted perimeter " // to_string(perimeter) // & - " /= expected value " // to_string(p)) + "Wetted perimeter "//to_string(perimeter)// & + " /= expected value "//to_string(p)) if (allocated(error)) then call test_failed(error, "Wetted perimeter fail") return @@ -255,8 +258,8 @@ subroutine test_four_point_rectangular_section(error) a = depth * width call check(error, & area == a, & - "Area " // to_string(area) // & - " /= expected value " // to_string(a)) + "Area "//to_string(area)// & + " /= expected value "//to_string(a)) if (allocated(error)) then call test_failed(error, "Cross section area incorrect") return @@ -270,11 +273,11 @@ subroutine test_four_point_rectangular_section(error) conveyance = res a = area p = perimeter - c = a / rough * (a / p) ** DTWOTHIRDS + c = a / rough * (a / p)**DTWOTHIRDS call check(error, & abs(conveyance - c) < 1.d-8, & - "Conveyance " // to_string(conveyance) // & - " /= expected value " // to_string(c)) + "Conveyance "//to_string(conveyance)// & + " /= expected value "//to_string(c)) if (allocated(error)) then call test_failed(error, "Conveyance calculation failed") return @@ -283,12 +286,12 @@ end subroutine test_four_point_rectangular_section !> @brief Test n-point cross section calculations !! - !! Use the 8-point cross section data from the + !! Use the 8-point cross section data from the !< Punxsutawney example of the HEC-HMS tutorial. subroutine test_n_point_rectangular_section(error) type(error_type), allocatable, intent(out) :: error - integer(I4B), parameter :: NPTS=8 - integer(I4B), parameter :: NDEPTHS=12 + integer(I4B), parameter :: NPTS = 8 + integer(I4B), parameter :: NDEPTHS = 12 real(DP), dimension(NPTS) :: xfraction real(DP), dimension(NPTS) :: height real(DP), dimension(NPTS) :: cxs_rf @@ -312,54 +315,55 @@ subroutine test_n_point_rectangular_section(error) ! expected values area_expected = [ & - 0.0000000000000000d0, & - 14.756129265604915d0, & - 37.883172712533252d0, & - 63.615202573234768d0, & - 91.952218847709474d0, & - 139.22191462507655d0, & - 231.01552353826017d0, & - 325.38720871509929d0, & - 422.33697015559397d0, & - 521.86480785974402d0, & - 623.97072182754971d0, & - 728.53880232770473d0 & - ] + 0.0000000000000000d0, & + 14.756129265604915d0, & + 37.883172712533252d0, & + 63.615202573234768d0, & + 91.952218847709474d0, & + 139.22191462507655d0, & + 231.01552353826017d0, & + 325.38720871509929d0, & + 422.33697015559397d0, & + 521.86480785974402d0, & + 623.97072182754971d0, & + 728.53880232770473d0 & + ] wp_expected = [ & - 0.0000000000000000d0, & - 22.416013040258729d0, & - 25.759029889993588d0, & - 29.102046739728443d0, & - 32.445063589463295d0, & - 93.878846225107850d0, & - 97.159078583084536d0, & - 100.43931094106127d0, & - 103.71954329903795d0, & - 106.99977565701464d0, & - 110.28000801499132d0, & - 112.57661057753654d0 & - ] + 0.0000000000000000d0, & + 22.416013040258729d0, & + 25.759029889993588d0, & + 29.102046739728443d0, & + 32.445063589463295d0, & + 93.878846225107850d0, & + 97.159078583084536d0, & + 100.43931094106127d0, & + 103.71954329903795d0, & + 106.99977565701464d0, & + 110.28000801499132d0, & + 112.57661057753654d0 & + ] conveyance_expected = [ & - 0.0000000000000000d0, & - 285.75028108202571d0, & - 1289.7912773134653d0, & - 2876.8119843270820d0, & - 5016.5410818181253d0, & - 7835.1910481243458d0, & - 12094.062268307061d0, & - 17566.086627356817d0, & - 24108.098792137902d0, & - 31647.248549995347d0, & - 40136.606753502856d0, & - 49571.805574496953d0 & - ] + 0.0000000000000000d0, & + 285.75028108202571d0, & + 1289.7912773134653d0, & + 2876.8119843270820d0, & + 5016.5410818181253d0, & + 7835.1910481243458d0, & + 12094.062268307061d0, & + 17566.086627356817d0, & + 24108.098792137902d0, & + 31647.248549995347d0, & + 40136.606753502856d0, & + 49571.805574496953d0 & + ] xfraction = [0.d0, 6.10003658d0, 37.39941478d0, 41.09973177d0, & 61.39965862d0, 68.6021702d0, 96.299683d0, 105.19995123d0] - height = [10.70013411d0, 4.70007315d0, 4.60009754d0, 0.d0, 0.6000061d0, & + height = [10.70013411d0, 4.70007315d0, 4.60009754d0, 0.d0, 0.6000061d0, & 4.60009754d0, 5.d0, 10.70013411d0] cxs_rf = [0.09d0, 0.09d0, 0.04d0, 0.04d0, 0.04d0, 0.09d0, 0.09d0, 0.d0] - depths = [0.d0, 1.d0, 2.d0, 3.d0, 4.d0, 5.d0, 6.d0, 7.d0, 8.d0, 9.d0, 10.d0, 11.d0] + depths = [0.d0, 1.d0, 2.d0, 3.d0, 4.d0, 5.d0, & + 6.d0, 7.d0, 8.d0, 9.d0, 10.d0, 11.d0] width = DONE rough = DONE @@ -370,17 +374,17 @@ subroutine test_n_point_rectangular_section(error) ! confirm cross section area calculation res = get_cross_section_area(NPTS, & - xfraction, & - height, & - width, depth) + xfraction, & + height, & + width, depth) area = res a = area_expected(idepth) difference = abs(area - a) call check(error, & difference < atol, & - "Area " // to_string(area) // & - " /= expected value " // to_string(a) // & - " Difference is " // to_string(difference)) + "Area "//to_string(area)// & + " /= expected value "//to_string(a)// & + " Difference is "//to_string(difference)) if (allocated(error)) then call test_failed(error, "Cross section area incorrect") return @@ -388,17 +392,17 @@ subroutine test_n_point_rectangular_section(error) ! confirm wetted perimeter calculation res = get_wetted_perimeter(NPTS, & - xfraction, & - height, & - width, depth) + xfraction, & + height, & + width, depth) perimeter = res p = wp_expected(idepth) difference = abs(perimeter - p) call check(error, & difference < atol, & - "Wetted perimeter " // to_string(perimeter) // & - " /= expected value " // to_string(p) // & - " Difference is " // to_string(difference)) + "Wetted perimeter "//to_string(perimeter)// & + " /= expected value "//to_string(p)// & + " Difference is "//to_string(difference)) if (allocated(error)) then call test_failed(error, "Wetted perimeter fail") return @@ -406,17 +410,17 @@ subroutine test_n_point_rectangular_section(error) ! confirm composite conveyance calculation = A/n*R^(2/3) res = get_conveyance(NPTS, & - xfraction, & - height, cxs_rf, & - width, rough, depth) + xfraction, & + height, cxs_rf, & + width, rough, depth) conveyance = res c = conveyance_expected(idepth) difference = abs(conveyance - c) call check(error, & difference < atol, & - "Conveyance " // to_string(conveyance) // & - " /= expected value " // to_string(c) // & - " Difference is " // to_string(difference)) + "Conveyance "//to_string(conveyance)// & + " /= expected value "//to_string(c)// & + " Difference is "//to_string(difference)) if (allocated(error)) then call test_failed(error, "Conveyance calculation failed") return @@ -426,4 +430,4 @@ subroutine test_n_point_rectangular_section(error) end subroutine test_n_point_rectangular_section -end module TestSwfUtils \ No newline at end of file +end module TestSwfUtils diff --git a/pixi.toml b/pixi.toml index 584d903e032..fa17f781889 100644 --- a/pixi.toml +++ b/pixi.toml @@ -46,8 +46,9 @@ install = { depends_on = [ ] } # format -fortran-format-check = "python .github/common/fortran_format_check.py" -msvs-vfproj-check = "python .github/common/msvs_vfproj_check.py" +check-format = "python .github/common/check_format.py" +check-vfproj = "python .github/common/check_vfproj.py" +check-spelling = "python .github/common/check_spelling.py" # build/test setup = "meson setup --prefix=$(pwd) --libdir=bin" @@ -60,7 +61,6 @@ autotest = { cmd = "pytest -v -n auto --durations 0 --keep-failed .failed", cwd # dist/docs benchmark = { cmd = "python benchmark.py", cwd = "distribution" } run-mf6ivar = { cmd = "python mf6ivar.py", cwd = "doc/mf6io/mf6ivar" } -check-docs = "python .github/common/codespell_docs_check.py" build-docs = { cmd = "python build_docs.py", cwd = "distribution" } build-dist = { cmd = "python build_dist.py", cwd = "distribution" } build-makefiles = { cmd = "python build_makefiles.py", cwd = "distribution" }