[
  {
    "path": ".github/workflows/build-multiarch.yml",
    "content": "name: Build Multiarch\n\non:\n  push:\n    branches: [release]\n  pull_request:\n    branches: [master, release]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/release' }}\n\njobs:\n  multi-arch-test:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          # Disabled: Docker localhost registry connection refused error on armv6/trixie\n          # - arch: armv6\n          #   distro: trixie\n          - arch: armv7\n            distro: trixie\n          - arch: aarch64\n            distro: trixie\n          - arch: riscv64\n            distro: trixie\n          - arch: s390x\n            distro: trixie\n          - arch: ppc64le\n            distro: trixie\n\n          - arch: armv7\n            distro: ubuntu_latest\n          - arch: aarch64\n            distro: ubuntu_latest\n          - arch: s390x\n            distro: ubuntu_latest\n          - arch: ppc64le\n            distro: ubuntu_latest\n\n          - arch: armv6\n            distro: alpine_latest\n          - arch: armv7\n            distro: alpine_latest\n          - arch: aarch64\n            distro: alpine_latest\n          - arch: riscv64\n            distro: alpine_latest\n          - arch: s390x\n            distro: alpine_latest\n          - arch: ppc64le\n            distro: alpine_latest\n\n    steps:\n      - uses: actions/checkout@v4\n      - name: Install Just\n        uses: extractions/setup-just@v2\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v3\n        with:\n          image: tonistiigi/binfmt:qemu-v8.1.5\n      - name: Run tests on ${{ matrix.arch }}/${{ matrix.distro }}\n        run: just test-arch ${{ matrix.arch }} ${{ matrix.distro }}\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\n\non:\n  push:\n    branches: [master, release]\n  pull_request:\n    branches: [master, release]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/release' }}\n\njobs:\n  build:\n\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.13t', 'pypy3.11']\n        os: [windows-latest, ubuntu-latest, macos-15-intel, macos-latest]\n        architecture: ['x86', 'x64']\n        exclude:\n          # Only test pypy on Linux\n          - os: windows-latest\n            python-version: pypy3.11\n          - os: macos-latest\n            python-version: pypy3.11\n          - os: macos-15-intel\n            python-version: pypy3.11\n          # no python builds available on macos 32 bit, arm or x64\n          - os: macos-latest\n            architecture: x86\n          - os: macos-15-intel\n            architecture: x86\n          # no python builds available on linux 32 bit\n          - os: ubuntu-latest\n            architecture: x86\n          # scipy dropped 32 bit windows builds\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.9\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.10\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.11\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.12\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.13\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.13t\n          - os: windows-latest\n            architecture: x86\n            python-version: 3.14\n          # pandas doesn't have wheels for 3.13t on Windows x64\n          - os: windows-latest\n            architecture: x64\n            python-version: 3.13t\n\n          # These are arm - old versions of Python are not supported\n          - os: macos-latest\n            python-version: 3.9\n          - os: macos-latest\n            python-version: 3.10\n    steps:\n    - uses: actions/checkout@v4\n    - name: Set up Python ${{ matrix.python-version }} ${{ matrix.architecture }}\n      uses: actions/setup-python@v5 \n      with:\n        python-version: ${{ matrix.python-version }}\n        architecture: ${{ matrix.architecture }}\n\n    - name: Install uv\n      if: matrix.python-version != '3.13t'\n      uses: astral-sh/setup-uv@v4\n      with:\n        enable-cache: true\n        cache-dependency-glob: \"pyproject.toml\"\n\n    - name: Install Ubuntu dependencies\n      if: startsWith(runner.os, 'Linux')\n      run: |\n        # Taken from scipy\n        sudo apt-get update\n        sudo apt-get install -y libopenblas-dev libatlas-base-dev liblapack-dev gfortran libgmp-dev libmpfr-dev libsuitesparse-dev ccache libmpc-dev libjpeg-dev zlib1g-dev libtiff-dev libfreetype6-dev liblcms2-dev libwebp-dev\n\n    - name: Install dependencies\n      run: |\n        python -c \"import platform; print(platform.platform()); print(platform.architecture())\"\n        if [[ \"${{ matrix.python-version }}\" == \"3.13t\" ]]; then\n          # Use pip for 3.13t (free-threading) as uv may not fully support it yet\n          python -m pip install --upgrade pip\n          pip install -e .[test]\n        else\n          uv pip install --system -e .[test]\n        fi\n      shell: bash\n    - name: Add numba\n      if: ${{ !contains(fromJSON('[\"pypy3.11\", \"3.13t\"]'), matrix.python-version) }}\n      run: |\n        uv pip install --system -e .[numba]\n    - name: Test with pytest\n      run: |\n        pytest . -v --cov-report html --cov=ht --cov-report term-missing -m \"not online and not thermo\"\n        coveralls || true\n      env:\n        COVERALLS_REPO_TOKEN: ${{ secrets.coveralls }}\n        COVERALLS_PARALLEL: true\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        PYTHON_GIL: ${{ matrix.python-version == '3.13t' && '0' || '' }}\n\n    - name: Upload coverage HTML report\n      if: always()\n      uses: actions/upload-artifact@v4\n      with:\n        name: coverage-html-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.architecture }}\n        path: htmlcov/\n  finish:\n    needs: build\n    runs-on: ubuntu-latest\n    steps:\n    - name: Coveralls Finished\n      env:\n        COVERALLS_REPO_TOKEN: ${{ secrets.coveralls }}\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      run: |\n        curl https://coveralls.io/webhook?repo_token=${{ secrets.coveralls }} -d \"payload[build_num]=${{ github.sha }}&payload[status]=done\"\n"
  },
  {
    "path": ".github/workflows/build_multi_numpy_scipy.yml",
    "content": "name: Build-Test-Multi-Scipy-Numpy\non:\n  push:\n    branches: [release]\n  pull_request:\n    branches: [master, release]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/release' }}\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        numpy: ['2.0.1'] #['1.16.5', '1.18.5', '1.20.3', '1.22.4', '1.24.4', '1.26.4', '2.0.1']\n        scipy: ['1.14.0'] #['1.7.3', '1.8.1', '1.9.3', '1.10.1', '1.12.0', '1.14.0']\n        python-version: ['3.10'] #['3.7', '3.8', '3.9', '3.10']\n        os: [ubuntu-latest]\n        architecture: ['x64']\n        include:\n          - numpy: '1.24.4'\n            scipy: '1.9.3'\n            python-version: '3.10'\n          - numpy: '1.24.4'\n            scipy: '1.12.0'\n            python-version: '3.9'\n          - numpy: '1.26.4'\n            scipy: '1.10.1'\n            python-version: '3.9'\n          - numpy: '1.26.4'\n            scipy: '1.12.0'\n            python-version: '3.9'\n          - numpy: '1.26.4'\n            scipy: '1.14.0'\n            python-version: '3.10'\n          - numpy: '2.0.1'\n            scipy: '1.14.0'\n            python-version: '3.10'\n    steps:\n    - uses: actions/checkout@v4\n    - name: Install uv\n      uses: astral-sh/setup-uv@v4\n      with:\n        enable-cache: true\n        cache-dependency-glob: \"pyproject.toml\"\n    - name: Install Just\n      uses: extractions/setup-just@v2\n    - name: Run tests with specific Python/NumPy/SciPy versions\n      run: just test-multi-single ${{ matrix.python-version }} ${{ matrix.numpy }} ${{ matrix.scipy }}\n"
  },
  {
    "path": ".github/workflows/build_third_party_packagers.yml",
    "content": "name: Check Third-Party Packager Compatibility\n\non:\n  push:\n    branches: [release]\n  pull_request:\n    branches: [master, release]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/release' }}\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        python-version: ['3.13']\n        os: [windows-latest, ubuntu-latest, macos-15-intel, macos-latest]\n        packager: [pyinstaller, cxfreeze, nuitka]\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v5\n      with:\n        python-version: ${{ matrix.python-version }}\n\n    - name: Install uv\n      uses: astral-sh/setup-uv@v7\n      with:\n        enable-cache: true\n        cache-dependency-glob: \"pyproject.toml\"\n\n    - name: Install just\n      uses: extractions/setup-just@v2\n\n    # https://stackoverflow.com/questions/69250165/github-action-windows-runner-how-to-remove-all-sh-exe-from-path/69251820#69251820\n    # https://github.com/actions/runner-images/issues/7253#issuecomment-1500121978\n    # https://github.com/actions/runner-images/discussions/6049\n    - name: Remove windows bash\n      if: runner.os == 'Windows'\n      shell: bash\n      run: rm 'C:/Windows/System32/bash.exe'\n\n    - name: Test ${{ matrix.packager }}\n      if: runner.os != 'Windows'\n      run: |\n        just test-${{ matrix.packager }}\n"
  },
  {
    "path": ".github/workflows/publish-pypi.yml",
    "content": "name: Publish to PyPI\non:\n  release:\n    types: [published]\n\npermissions:\n  id-token: write\n  contents: read\njobs:\n  test:\n    uses: ./.github/workflows/quality.yml\n  \n  publish:\n    # This job publishes to PyPI when a GitHub release is created with a tag starting with 'v' on the release branch.\n    #\n    # Requirements:\n    # - Repository admin must create a release with a tag starting with 'v' (e.g., v1.2.3)\n    # - The tag must be created on the 'release' branch\n    # - The release branch is protected by rulesets requiring all changes go through PR review\n    #\n    # Security notes:\n    # - The tag and branch checks in this job are soft checks (can be bypassed by modifying workflow)\n    # - Real security enforcement comes from the 'pypi' environment which requires manual approval by org admin\n    # - This provides a final gate before any code is published to PyPI\n    needs: test\n    runs-on: ubuntu-latest\n    if: startsWith(github.ref, 'refs/tags/v')\n    environment:\n      name: pypi\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0  # Need full history to check branch ancestry\n\n      - name: Check if tag is on release branch\n        run: |\n          if ! git branch -r --contains ${{ github.ref }} | grep -q 'origin/release'; then\n            echo \"Error: Tag is not on release branch\"\n            exit 1\n          fi\n          echo \"Tag verified to be on release branch\"\n\n      - name: Download distributions\n        uses: actions/download-artifact@v4\n        with:\n          name: distributions\n          path: dist/\n      \n      - name: Upload to PyPI\n        uses: pypa/gh-action-pypi-publish@release/v1        "
  },
  {
    "path": ".github/workflows/quality.yml",
    "content": "name: Quality & Validation\n\non:\n  push:\n    branches: [master, release]\n  pull_request:\n    branches: [master, release]\n  workflow_call:\n    outputs:\n      distributions-artifact:\n        description: \"Name of the distributions artifact\"\n        value: ${{ jobs.quality-validation.outputs.distributions-artifact }}\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/master' && github.ref != 'refs/heads/release' }}\n\njobs:\n  quality-validation:\n    runs-on: ubuntu-latest\n    outputs:\n      distributions-artifact: distributions\n\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@v4\n\n    - name: Set up Python 3.13\n      uses: actions/setup-python@v5\n      with:\n        python-version: '3.13'\n\n    - name: Install uv\n      uses: astral-sh/setup-uv@v7\n      with:\n        enable-cache: true\n        cache-dependency-glob: \"pyproject.toml\"\n\n    - name: Install just\n      uses: extractions/setup-just@v3\n\n    - name: Install Pandoc (required for docs)\n      uses: r-lib/actions/setup-pandoc@v2\n      with:\n        pandoc-version: '3.1.11'\n\n    - name: Install prek (required for just install)\n      run: uv tool install prek\n\n    - name: Install all dependencies\n      run: just install\n\n    # ==================== Pre-commit checks ====================\n    - name: Run pre-commit (prek)\n      run: just precommit\n\n    # ==================== Security scanning ====================\n    - name: Run security scans (pip-audit + bandit)\n      run: just security\n\n    # ==================== Distribution testing ====================\n    - name: Build distributions\n      run: just build\n\n    - name: Check distributions with twine\n      run: just check-dist\n\n    - name: Test wheel installation\n      run: |\n        WHEEL_TEST_DIR=$(mktemp -d)\n        cd $WHEEL_TEST_DIR\n        uv venv venv\n        WHEEL_FILE=$(ls $GITHUB_WORKSPACE/dist/*.whl)\n        uv pip install --python venv/bin/python \"ht[test] @ file://${WHEEL_FILE}\"\n        cp -r $GITHUB_WORKSPACE/tests .\n        cp $GITHUB_WORKSPACE/pyproject.toml .\n        venv/bin/pytest tests/ -vv -m \"not online and not thermo and not numba\"\n\n    - name: Test sdist installation\n      run: |\n        SDIST_TEST_DIR=$(mktemp -d)\n        cd $SDIST_TEST_DIR\n        uv venv venv\n        SDIST_FILE=$(ls $GITHUB_WORKSPACE/dist/*.tar.gz)\n        uv pip install --python venv/bin/python \"ht[test] @ file://${SDIST_FILE}\"\n        cp -r $GITHUB_WORKSPACE/tests .\n        cp $GITHUB_WORKSPACE/pyproject.toml .\n        venv/bin/pytest tests/ -vv -m \"not online and not thermo and not numba\"\n\n    # ==================== Documentation ====================\n    - name: Build Sphinx HTML documentation\n      run: just docs\n\n    # ==================== Upload artifacts ====================\n    - name: Upload distributions as artifacts\n      uses: actions/upload-artifact@v4\n      with:\n        name: distributions\n        path: dist/\n\n    - name: Upload documentation as artifacts\n      uses: actions/upload-artifact@v4\n      with:\n        name: documentation-html\n        path: _build/html/\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/astral-sh/ruff-pre-commit\n    # Ruff version.\n    rev: v0.14.0\n    hooks:\n      # Run the linter.\n      - id: ruff-check\n        args: [--fix]\n        files: ^(ht)/\n\n  - repo: https://github.com/abravalheri/validate-pyproject\n    rev: v0.24.1\n    hooks:\n      - id: validate-pyproject\n\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v5.0.0\n    hooks:\n      - id: check-yaml\n      - id: check-toml\n      - id: check-json\n        exclude: ^asv\\.conf\\.json$\n      - id: check-xml\n      - id: check-merge-conflict\n      - id: check-case-conflict\n      - id: check-executables-have-shebangs\n      - id: check-shebang-scripts-are-executable\n      - id: check-illegal-windows-names\n      - id: debug-statements\n\n  - repo: https://github.com/hukkin/mdformat\n    rev: 1.0.0\n    hooks:\n      - id: mdformat\n"
  },
  {
    "path": ".readthedocs.yaml",
    "content": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\n# Required\nversion: 2\n\n# Set the version of Python and other tools you might need\nbuild:\n  os: ubuntu-22.04\n  tools:\n    python: \"3.11\"\n  apt_packages:\n     - nodejs\n\n# Build documentation in the docs/ directory with Sphinx\nsphinx:\n  configuration: docs/conf.py\n\n# We recommend specifying your dependencies to enable reproducible builds:\n# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html\n\npython:\n  install:\n  - method: pip\n    path: .\n    extra_requirements:\n      - docs\n"
  },
  {
    "path": "AUTHORS",
    "content": "Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\n"
  },
  {
    "path": "Changelog.md",
    "content": "# Changelog\n\n## [Unreleased]\n\n## [1.2.0] - 2025-10-26\n\n### Added\n\n- Project is now PEP 517 compliant and doesn't use deprecated setup.py commands anymore\n- GitHub Actions workflow for publishing to PyPI using environment protection\n- `uv` package manager integration across CI workflows for faster dependency resolution\n- New consolidated `quality.yml` workflow for linting and testing\n- New `build_third_party_packagers.yml` workflow consolidating cx_Freeze, PyInstaller, Nuitka, and py2exe testing\n- Pre-commit hooks configuration\n- Justfile with extensive development automation commands - github actions have been refactored to use this where possible, making them locally debuggable\n\n### Changed\n\n- **Breaking**: Dropped Python 3.8 support; minimum Python version is now 3.9\n- Migrated from setup.py to pyproject.toml-only configuration (PEP 517)\n- Consolidated multiarch CI workflows with reduced test matrix for improved performance\n- Optimized multi-numpy/scipy testing workflow using `uv`\n- Simplified third-party packager testing into single consolidated workflow\n- Moved coverage configuration to pyproject.toml\n- Moved pytest configuration from pytest.ini to pyproject.toml\n- Moved mypy configuration from mypy.ini to pyproject.toml\n- Moved Ruff configuration from .ruff.toml to pyproject.toml\n- Reorganized development requirements into pyproject.toml optional dependencies\n- Updated fluids dependency to >= 1.2.0\n\n### Removed\n\n- Removed setup.py (replaced by pyproject.toml)\n- Removed standalone configuration files: pytest.ini, mypy.ini, .ruff.toml\n- Removed separate workflow files: build_cxfreeze_library.yml, build_nuitka_library.yml, build_py2exe_library.yml, build_pyinstaller_library.yml\n- Removed pre-commit.yml and security.yml workflows (consolidated into quality.yml)\n- Removed separate requirements files (test, docs, multiarch) - now in pyproject.toml\n\n### Security\n\n- Implemented PyPI publishing workflow with manual approval gate\n\n## [1.1.0] - 2025-10-19\n\n### Added\n\n- Python 3.13 and 3.13t (free-threaded) support with PYTHON_GIL=0 configuration\n- Pre-commit configuration with Ruff, mdformat, and file validators\n- New GitHub Actions workflows for pre-commit checks and security scanning\n- Packaging compatibility workflows for cx_Freeze, PyInstaller, and py2exe\n- Standalone test scripts and demo builders for verifying packaged distributions\n- Coverage HTML artifact uploads to all test workflows\n- Concurrency controls to workflows to cancel redundant builds\n- Justfile for streamlined development tasks (setup, docs, test, typecheck, lint)\n- Security scanning with pip-audit and bandit\n\n### Changed\n\n- Minimum Python version raised from 3.6 to 3.8\n- Updated actions to latest versions (setup-qemu v3, run-on-arch v3)\n- Updated macOS CI runners (macos-13 → macos-15-intel, added macos-latest for ARM)\n- Extensive code quality improvements with Ruff linting across entire codebase:\n  - String quote normalization to double quotes\n  - Removed unused imports and variables\n  - Improved code formatting and PEP 8 compliance\n  - Better type hints compatibility\n- Merged type hints across the codebase with improved accuracy\n- Updated copyright year to 2025\n- Fixed numerous typos across documentation files\n- Improved Sphinx configuration for Python 3.13 compatibility\n- Enhanced docstring and markdown formatting\n- Updated README to reflect Python 3.8+ requirement\n\n### Removed\n\n- Dropped Python 3.6 and 3.7 support\n- Removed obsolete platform-specific exclusions\n\n### Security\n\n- Added automated security scanning workflow documented in SECURITY.md\n\n## [1.0.7] - 2024-11-10\n\n### Changed\n\n- Code cleanup and minor optimizations\n- Fix Issue #54 https://github.com/CalebBell/fluids/issues/54\n- Fluids version dependency now >= 1.0.27\n\n## [1.0.6] - 2024-07-26\n\n### Changed\n\n- Compatibility with NumPy 2.0 and SciPy 1.14\n- Fluids version dependency now >= 1.0.26\n\n## [1.0.5] - 2023-06-04\n\n### Changed\n\n- Code cleanup with ruff (experiment)\n\n## [1.0.4] - 2023-04-23\n\n### Added\n\n- Nothing\n\n### Changed\n\n- Internal cleanup\n- Fix to Nu_plate_Martin correlation (see https://github.com/CalebBell/ht/pull/8)\n\n### Removed\n\n- Support for Python before 3.6\n- Drop appveyor and Travis CI\n\n### Fixed\n\n- Nothing\n"
  },
  {
    "path": "Justfile",
    "content": "# Use a strict shell for more predictable recipe execution.\n# The \"-c\" is crucial: it tells bash to treat the recipe lines as commands.\nset shell := [\"bash\", \"-euo\", \"pipefail\", \"-c\"]\n\n# --- Variables ---\n# Define paths to executables within the virtual environment for clarity.\n# This ensures we always use the tools installed in our project's venv.\nVENV_PYTHON := \".venv/bin/python\"\nVENV_PYTEST := \".venv/bin/pytest\"\nVENV_MYPY   := \".venv/bin/mypy\"\nVENV_RUFF   := \".venv/bin/ruff\"\nVENV_PIP_AUDIT := \".venv/bin/pip-audit\"\nVENV_BANDIT := \".venv/bin/bandit\"\n\n# Cross-platform variables for third-party packager tests\nVENV_BIN_DIR := if os_family() == \"windows\" { \"Scripts\" } else { \"bin\" }\nPYTHON_EXE := if os_family() == \"windows\" { \"python.exe\" } else { \"python\" }\nEXE_SUFFIX := if os_family() == \"windows\" { \".exe\" } else { \"\" }\n\n# --- Main Recipes ---\n\n# The default recipe, run when you just type `just`. It lists available commands.\ndefault:\n    @just --list\n\n## ⚙️  install: Create a uv virtual environment and install all dependencies.\ninstall:\n    @echo \">>> Creating virtual environment in ./.venv...\"\n    @uv venv\n    @echo \"\\n>>> Installing 'ht' in editable mode with dev dependencies...\"\n    @uv pip install -e .[dev]\n    @echo \"\\n>>> Installing prek hooks...\"\n    @prek install\n    @echo \"\\n✅ Environment setup complete! You can now run other commands.\"\n\n## 📚 docs: Build the Sphinx documentation.\ndocs:\n    @echo \">>> Building Sphinx docs...\"\n    # Note: -j auto (parallel build) is faster but less stable, can cause JSON decoding crashes\n    @{{VENV_PYTHON}} -m sphinx -b html -d _build/doctrees docs _build/html\n    @echo \"✅ Docs built in _build/html\"\n\n## 🧪 test: Run the test suite with pytest.\ntest *ARGS:\n    @echo \">>> Running pytest...\"\n    @{{VENV_PYTEST}} -n auto {{ARGS}}\n\n## 📊 test-cov: Run tests with coverage report.\ntest-cov:\n    @echo \">>> Running pytest with coverage...\"\n    @{{VENV_PYTEST}} -n auto --cov=ht --cov-report=html --cov-report=term\n    @echo \"✅ Coverage report generated in htmlcov/\"\n\n## 🧐 typecheck: Check static types with mypy.\ntypecheck:\n    @echo \">>> Running mypy...\"\n    @{{VENV_MYPY}} .\n\n## ✨ lint: Check for code style issues and errors with Ruff.\nlint:\n    @echo \">>> Running Ruff...\"\n    @{{VENV_RUFF}} check .\n\n## 🏁 check: Run all checks (linting and type checking).\ncheck: lint typecheck\n\n## 🔒 security: Run security scans with pip-audit and bandit.\nsecurity:\n    @echo \">>> Running pip-audit...\"\n    @{{VENV_PIP_AUDIT}} -r requirements_security.txt\n    @echo \">>> Running bandit...\"\n    @{{VENV_BANDIT}} -r ht -ll\n    @echo \"✅ Security scans complete.\"\n\n## 🪝 precommit: Run pre-commit hooks on all files.\nprecommit:\n    @echo \">>> Running pre-commit hooks...\"\n    @prek run --all-files\n\n## 🔌 hooks-install: Install prek hooks.\nhooks-install:\n    @echo \">>> Installing prek hooks...\"\n    @prek install\n    @echo \"✅ Hooks installed.\"\n\n## 🗑️  hooks-remove: Remove prek hooks.\nhooks-remove:\n    @echo \">>> Removing prek hooks...\"\n    @prek uninstall\n    @echo \"✅ Hooks removed.\"\n\n# asv is broken\n# ## ⚡ bench: Run performance benchmarks.\n# bench:\n#     @echo \">>> Running benchmarks...\"\n#     @asv run\n\n## 📦 build: Build wheel and source distributions.\nbuild:\n    @echo \">>> Building distributions...\"\n    @{{VENV_PYTHON}} -m build\n    @echo \"✅ Distributions built in dist/\"\n\n## 🔍 check-dist: Check built distributions with twine.\ncheck-dist:\n    @echo \">>> Checking distributions with twine...\"\n    @.venv/bin/twine check dist/*\n    @echo \"✅ Distributions are valid.\"\n\n## 🚀 ci: Run all CI checks (lint, typecheck, test).\nci: lint typecheck test\n    @echo \"✅ All CI checks passed!\"\n\n## 🧊 test-cxfreeze: Test cx_Freeze compatibility (build executable and run it).\ntest-cxfreeze py=\"3.13\":\n    @echo \">>> Creating temporary virtual environment with Python {{py}}...\"\n    @uv venv .venv-cxfreeze-{{py}} --python {{py}}\n    @echo \"\\n>>> Installing project and cx_Freeze in temporary environment...\"\n    @uv pip install --python .venv-cxfreeze-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} -e .[test]\n    @uv pip install --python .venv-cxfreeze-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} cx_Freeze\n    @echo \"\\n>>> Building cx_Freeze executable...\"\n    @cd dev/cx_freeze && ../../.venv-cxfreeze-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} cx_freeze_basic_standalone_check_builder.py build && cd ../..\n    @echo \"\\n>>> Testing executable...\"\n    @./dev/cx_freeze/build/exe.*/basic_standalone_ht_check{{EXE_SUFFIX}}\n    @echo \"\\n>>> Cleaning up temporary environment...\"\n    @rm -rf .venv-cxfreeze-{{py}}\n    @echo \"✅ cx_Freeze test complete and cleaned up!\"\n\n## 🔥 test-nuitka: Test Nuitka compatibility (compile module and import it).\ntest-nuitka py=\"3.13\":\n    @echo \">>> Creating temporary virtual environment with Python {{py}}...\"\n    @uv venv .venv-nuitka-{{py}} --python {{py}}\n    @echo \"\\n>>> Installing project and Nuitka in temporary environment...\"\n    @uv pip install --python .venv-nuitka-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} -e .[test,numba]\n    @uv pip install --python .venv-nuitka-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} nuitka\n    @echo \"\\n>>> Preparing build directory...\"\n    @mkdir -p dev/nuitka/build\n    @cp -r ht dev/nuitka/build/\n    @echo \"\\n>>> Building Nuitka module...\"\n    @cd dev/nuitka/build && ../../../.venv-nuitka-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} -m nuitka --module ht --include-package=ht\n    @echo \"\\n>>> Removing original ht folder from build directory...\"\n    @rm -rf dev/nuitka/build/ht/ht\n    @echo \"\\n>>> Testing compiled module can be imported...\"\n    @cd dev/nuitka/build && ../../../.venv-nuitka-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} -c \"import ht; print('Version:', ht.__version__)\"\n    @echo \"\\n>>> Cleaning up temporary environment...\"\n    @rm -rf .venv-nuitka-{{py}}\n    @echo \"✅ Nuitka test complete and cleaned up!\"\n\n## 📦 test-pyinstaller: Test PyInstaller compatibility (build executable and run it).\ntest-pyinstaller py=\"3.13\":\n    @echo \">>> Creating temporary virtual environment with Python {{py}}...\"\n    @uv venv .venv-pyinstaller-{{py}} --python {{py}}\n    @echo \"\\n>>> Installing project and PyInstaller in temporary environment...\"\n    @uv pip install --python .venv-pyinstaller-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} .[test]\n    @uv pip install --python .venv-pyinstaller-{{py}}/{{VENV_BIN_DIR}}/{{PYTHON_EXE}} pyinstaller\n    @rm -rf build\n    @echo \"\\n>>> Preparing build directory...\"\n    @mkdir -p dev/pyinstaller/build\n    @echo \"\\n>>> Building PyInstaller executable...\"\n    @.venv-pyinstaller-{{py}}/{{VENV_BIN_DIR}}/pyinstaller{{EXE_SUFFIX}} --onefile --name basic_standalone_ht_check --distpath dev/pyinstaller/build/dist --workpath dev/pyinstaller/build/build --specpath dev/pyinstaller/build dev/basic_standalone_ht_check.py\n    @echo \"\\n>>> Testing executable...\"\n    @./dev/pyinstaller/build/dist/basic_standalone_ht_check{{EXE_SUFFIX}}\n    @echo \"\\n>>> Cleaning up temporary environment...\"\n    @rm -rf .venv-pyinstaller-{{py}}\n    @echo \"✅ PyInstaller test complete and cleaned up!\"\n\n## 🌍 qemu-setup: Register QEMU interpreters for multi-arch container support.\nqemu-setup:\n    @command -v podman >/dev/null 2>&1 || { echo \"❌ Error: podman is not installed. Please install podman first.\"; exit 1; }\n    @echo \">>> Registering QEMU interpreters with binfmt_misc...\"\n    @podman run --rm --privileged multiarch/qemu-user-static --reset -p yes\n    @echo \"✅ QEMU multi-arch support enabled.\"\n\n## 🎯 prepare-multiarch-image: Build and cache a multiarch image with dependencies (use: just prepare-multiarch-image <arch> <distro>).\nprepare-multiarch-image arch distro=\"trixie\":\n    #!/usr/bin/env bash\n    set -euo pipefail\n\n    # Check for podman\n    command -v podman >/dev/null 2>&1 || { echo \"❌ Error: podman is not installed. Please install podman first.\"; exit 1; }\n\n    # Tag for cached image\n    tag=\"ht-test-{{arch}}-{{distro}}:latest\"\n\n    # Check if image already exists\n    if podman image exists \"$tag\" 2>/dev/null; then\n        echo \"✅ Image $tag already exists, skipping build.\"\n        exit 0\n    fi\n\n    echo \">>> Building cached image for {{arch}} with {{distro}}...\"\n\n    # Map architecture to platform\n    case \"{{arch}}\" in\n        armv6)   platform=\"linux/arm/v6\" ;;\n        armv7)   platform=\"linux/arm/v7\" ;;\n        aarch64) platform=\"linux/arm64\" ;;\n        riscv64) platform=\"linux/riscv64\" ;;\n        s390x)   platform=\"linux/s390x\" ;;\n        ppc64le) platform=\"linux/ppc64le\" ;;\n        *) echo \"Unknown architecture: {{arch}}\"; exit 1 ;;\n    esac\n\n    # Map distro to base image (using slim variants for Debian/Ubuntu)\n    case \"{{distro}}\" in\n        trixie)         image=\"debian:trixie-slim\" ;;\n        ubuntu_latest)  image=\"ubuntu:latest\" ;;\n        ubuntu_devel)   image=\"ubuntu:devel\" ;;\n        alpine_latest)  image=\"alpine:latest\" ;;\n        *) echo \"Unknown distro: {{distro}}\"; exit 1 ;;\n    esac\n\n    echo \"Platform: $platform, Image: $image\"\n\n    # Determine package manager and install commands\n    if [[ \"{{distro}}\" == \"alpine_latest\" ]]; then\n        install_cmd=\"apk update && apk add bash python3 py3-pip py3-scipy py3-matplotlib py3-numpy py3-pandas\"\n    else\n        install_cmd=\"apt-get update && apt-get install -y liblapack-dev gfortran libgmp-dev libmpfr-dev libsuitesparse-dev ccache libmpc-dev python3 python3-pip python3-scipy python3-matplotlib python3-numpy python3-pandas\"\n    fi\n\n    # Create a temporary Containerfile\n    cat > /tmp/Containerfile.ht.{{arch}}.{{distro}} << EOF\n    FROM $image\n    RUN $install_cmd\n    EOF\n\n    # Build the image with the specified platform\n    podman build --platform \"$platform\" -t \"$tag\" -f /tmp/Containerfile.ht.{{arch}}.{{distro}}\n\n    # Clean up\n    rm /tmp/Containerfile.ht.{{arch}}.{{distro}}\n\n    echo \"✅ Cached image $tag built successfully!\"\n\n## 🔄 prepare-all-multiarch-images: Build all cached images for multiarch testing in parallel.\nprepare-all-multiarch-images:\n    #!/usr/bin/env bash\n    set -euo pipefail\n\n    # Check for GNU parallel\n    command -v parallel >/dev/null 2>&1 || { echo \"❌ Error: GNU parallel is not installed. Please install it (e.g., apt install parallel).\"; exit 1; }\n\n    echo \">>> Building all cached multiarch images in parallel (this will take a while)...\"\n\n    # Define all arch/distro combinations\n    # riscv64 ubuntu_devel fails often, on github actions with Illegal Instruction\n    combinations=(\n        \"armv6 trixie\"\n        \"armv7 trixie\"\n        \"aarch64 trixie\"\n        \"riscv64 trixie\"\n        \"s390x trixie\"\n        \"ppc64le trixie\"\n        \"armv7 ubuntu_latest\"\n        \"aarch64 ubuntu_latest\"\n        \"s390x ubuntu_latest\"\n        \"ppc64le ubuntu_latest\"\n        # \"riscv64 ubuntu_devel\"\n        \"armv6 alpine_latest\"\n        \"armv7 alpine_latest\"\n        \"aarch64 alpine_latest\"\n        \"riscv64 alpine_latest\"\n        \"s390x alpine_latest\"\n        \"ppc64le alpine_latest\"\n    )\n\n    # Get number of CPU cores\n    ncores=$(nproc)\n    echo \">>> Using $ncores parallel jobs\"\n\n    # Run all builds in parallel with line-buffered output and keep going on failures\n    failed=0\n    printf '%s\\n' \"${combinations[@]}\" | \\\n        parallel --line-buffer --keep-order --jobs \"$ncores\" --colsep ' ' \\\n        'echo \">>> Starting {1}/{2}\" && just prepare-multiarch-image {1} {2} && echo \"✅ Completed {1}/{2}\" || (echo \"❌ Failed: {1}/{2}\" && exit 1)' \\\n        || failed=1\n\n    echo \"\"\n    if [ $failed -eq 0 ]; then\n        echo \"✅ All cached multiarch images built successfully!\"\n    else\n        echo \"⚠️  Some images failed to build. Check output above for details.\"\n        exit 1\n    fi\n\n## 🏗️  test-arch: Run tests on a specific architecture (use: just test-arch <arch> <distro>).\n## Note: This uses cached images built with prepare-multiarch-image for faster execution.\ntest-arch arch distro=\"trixie\":\n    #!/usr/bin/env bash\n    set -euo pipefail\n\n    # Check for podman\n    command -v podman >/dev/null 2>&1 || { echo \"❌ Error: podman is not installed. Please install podman first.\"; exit 1; }\n\n    echo \">>> Running tests on {{arch}} with {{distro}}...\"\n\n    # Map architecture to platform\n    case \"{{arch}}\" in\n        armv6)   platform=\"linux/arm/v6\" ;;\n        armv7)   platform=\"linux/arm/v7\" ;;\n        aarch64) platform=\"linux/arm64\" ;;\n        riscv64) platform=\"linux/riscv64\" ;;\n        s390x)   platform=\"linux/s390x\" ;;\n        ppc64le) platform=\"linux/ppc64le\" ;;\n        *) echo \"Unknown architecture: {{arch}}\"; exit 1 ;;\n    esac\n\n    # Use cached image\n    image=\"localhost/ht-test-{{arch}}-{{distro}}:latest\"\n    echo \"Platform: $platform, Image: $image\"\n\n    # Build image if it doesn't exist\n    if ! podman image exists \"$image\" 2>/dev/null; then\n        echo \">>> Image $image not found, building it now...\"\n        just prepare-multiarch-image {{arch}} {{distro}}\n    fi\n\n    # Determine pip flags\n    if [[ \"{{distro}}\" == \"alpine_latest\" ]]; then\n        pip_flags=\"--break-system-packages\"\n    else\n        pip_flags=\"--break-system-packages\"\n    fi\n\n    # Run the container with files copied (not mounted)\n    # Note: Removed -it flag for CI compatibility, removed :Z flag for broader compatibility\n    podman run --rm \\\n        --platform \"$platform\" \\\n        -v \"$(pwd):/src:ro\" \\\n        \"$image\" \\\n        bash -c \"\n            mkdir -p /workspace && \\\n            cd /src && \\\n            find . -mindepth 1 -maxdepth 1 ! -name '.*' -exec cp -r {} /workspace/ \\; && \\\n            cd /workspace && \\\n            python3 -m pip install wheel $pip_flags && \\\n            pip3 install -e .[test-multiarch] $pip_flags && \\\n            python3 -m pytest . -v -m 'not online and not numba'\n        \"\n\n    echo \"✅ Tests on {{arch}} with {{distro}} complete!\"\n\n## 🌐 test-multiarch: Run tests on all architectures from CI (requires time!).\ntest-multiarch:\n    @echo \">>> Running multi-arch tests (this will take a while)...\"\n    @echo \"\\n=== Debian Trixie ===\"\n    @just test-arch armv6 trixie || echo \"❌ armv6/trixie failed\"\n    @just test-arch armv7 trixie || echo \"❌ armv7/trixie failed\"\n    @just test-arch aarch64 trixie || echo \"❌ aarch64/trixie failed\"\n    @just test-arch riscv64 trixie || echo \"❌ riscv64/trixie failed\"\n    @just test-arch s390x trixie || echo \"❌ s390x/trixie failed\"\n    @just test-arch ppc64le trixie || echo \"❌ ppc64le/trixie failed\"\n    @echo \"\\n=== Ubuntu Latest ===\"\n    @just test-arch armv7 ubuntu_latest || echo \"❌ armv7/ubuntu_latest failed\"\n    @just test-arch aarch64 ubuntu_latest || echo \"❌ aarch64/ubuntu_latest failed\"\n    @just test-arch s390x ubuntu_latest || echo \"❌ s390x/ubuntu_latest failed\"\n    @just test-arch ppc64le ubuntu_latest || echo \"❌ ppc64le/ubuntu_latest failed\"\n    # @echo \"\\n=== Ubuntu Devel ===\"\n    # @just test-arch riscv64 ubuntu_devel || echo \"❌ riscv64/ubuntu_devel failed\"\n    @echo \"\\n=== Alpine Latest ===\"\n    @just test-arch armv6 alpine_latest || echo \"❌ armv6/alpine_latest failed\"\n    @just test-arch armv7 alpine_latest || echo \"❌ armv7/alpine_latest failed\"\n    @just test-arch aarch64 alpine_latest || echo \"❌ aarch64/alpine_latest failed\"\n    @just test-arch riscv64 alpine_latest || echo \"❌ riscv64/alpine_latest failed\"\n    @just test-arch s390x alpine_latest || echo \"❌ s390x/alpine_latest failed\"\n    @just test-arch ppc64le alpine_latest || echo \"❌ ppc64le/alpine_latest failed\"\n    @echo \"\\n✅ Multi-arch testing complete!\"\n\n## 🧬 test-multi-single: Test with specific Python/NumPy/SciPy versions (e.g., just test-multi-single 3.9 1.26.4 1.12.0).\n## Set KEEP_VENV=1 to keep the virtual environment for debugging (e.g., KEEP_VENV=1 just test-multi-single 3.9 1.26.4 1.12.0).\ntest-multi-single py=\"3.10\" numpy=\"2.0.1\" scipy=\"1.14.0\":\n    @echo \">>> Testing Python {{py}}, NumPy {{numpy}}, SciPy {{scipy}}...\"\n    @echo \">>> Installing Python {{py}} if needed...\"\n    @uv python install {{py}} || true\n    @echo \">>> Creating temporary virtual environment...\"\n    @uv venv .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}} --python {{py}}\n    @echo \">>> Installing dependencies...\"\n    @uv pip install --python .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}}/bin/python -e .[test]\n    @uv pip install --python .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}}/bin/python \"numpy=={{numpy}}\" \"scipy=={{scipy}}\"\n    @echo \">>> Installing numba...\"\n    @uv pip install --python .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}}/bin/python -e .[numba] || echo \"⚠️  Numba install failed, continuing...\"\n    @echo \">>> Running tests (no coverage)...\"\n    @.venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}}/bin/pytest . -m \"not online and not numba\"\n    @if [ -z \"$${KEEP_VENV}\" ]; then \\\n        echo \">>> Cleaning up temporary environment...\"; \\\n        rm -rf .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}}; \\\n    else \\\n        echo \">>> Keeping venv .venv-test-python{{py}}-numpy{{numpy}}-scipy{{scipy}} for debugging (KEEP_VENV is set)\"; \\\n    fi\n    @echo \"✅ Test complete for Python {{py}}, NumPy {{numpy}}, SciPy {{scipy}}!\"\n\n## 🧬 test-multi: Run all Python/NumPy/SciPy combinations from CI locally.\ntest-multi:\n    #!/usr/bin/env bash\n    set -euo pipefail\n\n    # Check for GNU parallel\n    command -v parallel >/dev/null 2>&1 || { echo \"❌ Error: GNU parallel is not installed. Please install it (e.g., apt install parallel).\"; exit 1; }\n\n    echo \">>> Running multi-version tests (this will take a while)...\"\n    echo \">>> This mirrors the CI matrix from build_multi_numpy_scipy.yml\"\n\n    # Define all Python/NumPy/SciPy combinations\n    combinations=(\n        \"3.10 1.24.4 1.9.3\"\n        \"3.10 1.24.4 1.12.0\"\n        \"3.9 1.24.4 1.12.0\"\n        \"3.9 1.26.4 1.10.1\"\n        \"3.9 1.26.4 1.12.0\"\n        \"3.10 1.26.4 1.14.0\"\n        \"3.10 2.0.1 1.14.0\"\n    )\n\n    # Get number of CPU cores\n    ncores=$(nproc)\n    echo \">>> Using $ncores parallel jobs\"\n    echo \"\"\n\n    # Run all tests in parallel with line-buffered output and keep going on failures\n    failed=0\n    printf '%s\\n' \"${combinations[@]}\" | \\\n        parallel --line-buffer --keep-order --jobs \"$ncores\" --colsep ' ' \\\n        'echo \">>> Starting Python {1}, NumPy {2}, SciPy {3}\" && just test-multi-single {1} {2} {3} && echo \"✅ Completed Python {1}, NumPy {2}, SciPy {3}\" || (echo \"❌ Failed: Python {1}, NumPy {2}, SciPy {3}\" && exit 1)' \\\n        || failed=1\n\n    echo \"\"\n    if [ $failed -eq 0 ]; then\n        echo \"✅ All multi-version tests passed!\"\n    else\n        echo \"⚠️  Some tests failed. Check output above for details.\"\n        exit 1\n    fi\n\n## 🧹 clean: Remove build artifacts and Python caches.\nclean:\n    @echo \">>> Cleaning up build artifacts and cache files...\"\n    @rm -rf _build .mypy_cache .pytest_cache dist *.egg-info htmlcov prof dev/cx_freeze/build dev/nuitka/build dev/pyinstaller/build .venv-cxfreeze-* .venv-nuitka-* .venv-pyinstaller-*\n    @rm -rf .venv-test-*\n    @rm -f ht.*.so ht.*.pyd\n    @find . -type d -name \"__pycache__\" -exec rm -rf {} +\n    @echo \"✅ Cleanup complete.\"\n\n## 🐳 clean-multiarch-images: Remove all cached multiarch container images.\nclean-multiarch-images:\n    #!/usr/bin/env bash\n    set -euo pipefail\n\n    # Check for podman\n    command -v podman >/dev/null 2>&1 || { echo \"❌ Error: podman is not installed. Please install podman first.\"; exit 1; }\n\n    echo \">>> Removing cached multiarch container images...\"\n\n    # Find all images matching our naming pattern\n    images=$(podman images --format \"{{{{.Repository}}}}:{{{{.Tag}}}}\" | grep \"^ht-test-\" || true)\n\n    if [ -z \"$images\" ]; then\n        echo \"✅ No multiarch images found to remove.\"\n        exit 0\n    fi\n\n    removed=0\n    while IFS= read -r img; do\n        echo \"  Removing $img...\"\n        podman rmi \"$img\" 2>/dev/null || echo \"  ⚠️  Failed to remove $img\"\n        ((removed++))\n    done <<< \"$images\"\n\n    echo \"\"\n    echo \"✅ Removed $removed multiarch image(s).\"\n\n## 💣 nuke: Remove the virtual environment and all build artifacts.\nnuke: clean\n    @echo \">>> Removing all virtual environments...\"\n    @rm -rf .venv*\n    @echo \"✅ Project completely cleaned.\""
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include LICENSE.txt AUTHORS README.rst pytest.ini\nrecursive-include tests *\nrecursive-include docs *\nrecursive-include _custom_build *.py\nglobal-exclude __pycache__\nglobal-exclude *.py[co]\nglobal-exclude *.coverage\nglobal-exclude *.so\nglobal-exclude *.ipynb_checkpoints\nglobal-exclude ipynb_checkpoints\nglobal-exclude *-checkpoint.ipynb\nglobal-exclude *checkpoint*\nglobal-exclude .*ipynb_checkpoints*\nrecursive-exclude docs *ipynb_checkpoints\n"
  },
  {
    "path": "README.rst",
    "content": "==================\nHeat Transfer (ht)\n==================\n\n.. image:: http://img.shields.io/pypi/v/ht.svg?style=flat\n   :target: https://pypi.python.org/pypi/ht\n   :alt: Version_status\n.. image:: http://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat\n   :target: https://ht.readthedocs.io/en/latest/\n   :alt: Documentation\n.. image:: https://github.com/CalebBell/ht/workflows/Build/badge.svg\n   :target: https://github.com/CalebBell/ht/actions\n   :alt: Build_status\n.. image:: http://img.shields.io/badge/license-MIT-blue.svg?style=flat \n   :target: https://github.com/CalebBell/ht/blob/release/LICENSE.txt\n   :alt: license\n.. image:: https://img.shields.io/pypi/pyversions/ht.svg?\n   :target: https://pypi.python.org/pypi/ht\n   :alt: Supported_versions\n.. image:: https://zenodo.org/badge/48963057.svg?\n   :alt: Zendo\n   :target: https://zenodo.org/badge/latestdoi/48963057\n\n\n.. contents::\n\nWhat is ht?\n-----------\n\nht is open-source software for engineers and technicians working in the\nfields of chemical or mechanical engineering. It includes modules\nfor various heat transfer functions.\n\nAmong the tasks this library can be used for are:\n\n* Sizing a Shell & Tube heat exchanger using any of the Zukauskas, ESDU 73031, or Bell methods\n* Calculating pressure drop in a Hairpin heat exchanger\n* Calculating heat loss of objects, including insulated objects\n* Calculating heat loss from buried pipe\n* Performing radiative heat transfer calculations\n* Conderser and Reboiler rating\n* Detailed heat exchanger evaluation; finding fouling factors\n* Heat transfer in packed beds\n* Sizing a Plate and Frame heat exchanger\n* Modeling an Air Cooler\n* Supercritical CO2 or water heat transfer\n\nThe ht library depends on the SciPy library to provide numerical constants,\ninterpolation, integration, and numerical solving functionality. ht runs on\nall operating systems which support Python, is quick to install, and is free\nof charge. ht is designed to be easy to use while still providing powerful\nfunctionality. If you need to perform some heat transfer calculations, give\nht a try.\n\nInstallation\n------------\n\nGet the latest version of ht from\nhttps://pypi.python.org/pypi/ht/\n\nIf you have an installation of Python with pip, simple install it with:\n\n    $ pip install ht\n\nAlternatively, if you are using `conda <https://conda.io/en/latest/>`_ as your package management, you can simply\ninstall ht in your environment from `conda-forge <https://conda-forge.org/>`_ channel with:\n\n    $ conda install -c conda-forge ht\n\nTo get the git version, run:\n\n    $ git clone git://github.com/CalebBell/ht.git\n\nDocumentation\n-------------\n\nht's documentation is available on the web:\n\n    https://ht.readthedocs.io/en/latest/index.html\n\n\nLatest source code\n------------------\n\nThe latest development version of ht's sources can be obtained at\n\n    https://github.com/CalebBell/ht\n\n\nBug reports\n-----------\n\nTo report bugs, please use the ht's Bug Tracker at:\n\n    https://github.com/CalebBell/ht/issues\n\n\nLicense information\n-------------------\n\nht is MIT licensed. See ``LICENSE.txt`` for information on the terms & \nconditions for usage of this software, and a DISCLAIMER OF ALL WARRANTIES.\n\nAlthough not required by the ht license, if it is convenient for you,\nplease cite ht if used in your work. Please also consider contributing\nany changes you make back, such that they may be incorporated into the\nmain library and all of us will benefit from them.\n\n\nCitation\n--------\n\nTo cite ht in publications use::\n\n    Caleb Bell and Contributors (2016-2025). ht: Heat transfer component of Chemical Engineering Design Library (ChEDL)\n    https://github.com/CalebBell/ht.\n"
  },
  {
    "path": "asv.conf.json",
    "content": "{\n    // The version of the config file format.  Do not change, unless\n    // you know what you are doing.\n    \"version\": 1,\n\n    // The name of the project being benchmarked\n    \"project\": \"ht\",\n\n    // The project's homepage\n    \"project_url\": \"https://github.com/calebbell/ht/\",\n\n    // The URL or local path of the source code repository for the\n    // project being benchmarked\n    \"repo\": \".\",\n\n    // List of branches to benchmark. If not provided, defaults to \"master\"\n    // (for git) or \"default\" (for mercurial).\n    // \"branches\": [\"master\"], // for git\n    // \"branches\": [\"default\"],    // for mercurial\n\n    // The DVCS being used.  If not set, it will be automatically\n    // determined from \"repo\" by looking at the protocol in the URL\n    // (if remote), or by looking for special directories, such as\n    // \".git\" (if local).\n    // \"dvcs\": \"git\",\n\n    // The tool to use to create environments.  May be \"conda\",\n    // \"virtualenv\" or other value depending on the plugins in use.\n    // If missing or the empty string, the tool will be automatically\n    // determined by looking for tools on the PATH environment\n    // variable.\n    \"environment_type\": \"virtualenv\",\n\n    // timeout in seconds for installing any dependencies in environment\n    // defaults to 10 min\n    \"install_timeout\": 600,\n\n    // the base URL to show a commit for the project.\n    \"show_commit_url\": \"http://github.com/calebbell/ht/commit/\",\n\n    // The Pythons you'd like to test against.  If not provided, defaults\n    // to the current version of Python used to run `asv`.\n    \"pythons\": [\"2.7\", \"3.4\"],\n\n    // The matrix of dependencies to test.  Each key is the name of a\n    // package (in PyPI) and the values are version numbers.  An empty\n    // list or empty string indicates to just test against the default\n    // (latest) version. null indicates that the package is to not be\n    // installed. If the package to be tested is only available from\n    // PyPi, and the 'environment_type' is conda, then you can preface\n    // the package name by 'pip+', and the package will be installed via\n    // pip (with all the conda available packages installed first,\n    // followed by the pip installed packages).\n    //\n    \"matrix\": {\n         \"numpy\": [],\n         \"scipy\": [],\n    },\n\n    // Combinations of libraries/python versions can be excluded/included\n    // from the set to test. Each entry is a dictionary containing additional\n    // key-value pairs to include/exclude.\n    //\n    // An exclude entry excludes entries where all values match. The\n    // values are regexps that should match the whole string.\n    //\n    // An include entry adds an environment. Only the packages listed\n    // are installed. The 'python' key is required. The exclude rules\n    // do not apply to includes.\n    //\n    // In addition to package names, the following keys are available:\n    //\n    // - python\n    //     Python version, as in the *pythons* variable above.\n    // - environment_type\n    //     Environment type, as above.\n    // - sys_platform\n    //     Platform, as in sys.platform. Possible values for the common\n    //     cases: 'linux2', 'win32', 'cygwin', 'darwin'.\n    //\n    // \"exclude\": [\n    //     {\"python\": \"3.2\", \"sys_platform\": \"win32\"}, // skip py3.2 on windows\n    //     {\"environment_type\": \"conda\", \"six\": null}, // don't run without six on conda\n    // ],\n    //\n    // \"include\": [\n    //     // additional env for python2.7\n    //     {\"python\": \"2.7\", \"numpy\": \"1.8\"},\n    //     // additional env if run on windows+conda\n    //     {\"platform\": \"win32\", \"environment_type\": \"conda\", \"python\": \"2.7\", \"libpython\": \"\"},\n    // ],\n\n    // The directory (relative to the current directory) that benchmarks are\n    // stored in.  If not provided, defaults to \"benchmarks\"\n     \"benchmark_dir\": \"benchmarks\",\n\n    // The directory (relative to the current directory) to cache the Python\n    // environments in.  If not provided, defaults to \"env\"\n    \"env_dir\": \".asv/env\",\n\n    // The directory (relative to the current directory) that raw benchmark\n    // results are stored in.  If not provided, defaults to \"results\".\n    \"results_dir\": \".asv/results\",\n\n    // The directory (relative to the current directory) that the html tree\n    // should be written to.  If not provided, defaults to \"html\".\n    \"html_dir\": \".asv/html\",\n\n    // The number of characters to retain in the commit hashes.\n    // \"hash_length\": 8,\n\n    // `asv` will cache wheels of the recent builds in each\n    // environment, making them faster to install next time.  This is\n    // number of builds to keep, per environment.\n    // \"wheel_cache_size\": 0\n\n    // The commits after which the regression search in `asv publish`\n    // should start looking for regressions. Dictionary whose keys are\n    // regexps matching to benchmark names, and values corresponding to\n    // the commit (exclusive) after which to start looking for\n    // regressions.  The default is to start from the first commit\n    // with results. If the commit is `null`, regression detection is\n    // skipped for the matching benchmark.\n    //\n    // \"regressions_first_commits\": {\n    //    \"some_benchmark\": \"352cdf\",  // Consider regressions only after this commit\n    //    \"another_benchmark\": null,   // Skip regression detection altogether\n    // }\n\n    // The thresholds for relative change in results, after which `asv\n    // publish` starts reporting regressions. Dictionary of the same\n    // form as in ``regressions_first_commits``, with values\n    // indicating the thresholds.  If multiple entries match, the\n    // maximum is taken. If no entry matches, the default is 5%.\n    //\n    // \"regressions_thresholds\": {\n    //    \"some_benchmark\": 0.01,     // Threshold of 1%\n    //    \"another_benchmark\": 0.5,   // Threshold of 50%\n    // }\n}\n"
  },
  {
    "path": "bench/ht function performance comparison.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from ht import *\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"from math import *\\n\",\n    \"import numpy as np\\n\",\n    \"from scipy.interpolate import *\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"1.93 µs ± 10 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"380 ns ± 5.37 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Rohsenow(Te=4.9, Cpl=4217., kl=0.680, mul=2.79E-4, sigma=0.0589, Hvap=2.257E6, rhol=957.854, rhog=0.595593, Csf=0.011, n=1.26)*4.9\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"1.07 µs ± 27.4 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Stephan_Abdelsalam(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, angle=35, correlation='hydrocarbon')\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"331 ns ± 7.01 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Serth_HEDH(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"342 ns ± 22.4 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nusselt_laminar(Tsat=370, Tw=350, rhog=7.0, rhol=585., kl=0.091, mul=158.9E-6, Hvap=776900, L=0.1)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"425 ns ± 8.24 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Boyko_Kruzhilin(m=100, rhog=6.36, rhol=582.9, kl=0.098, mul=159E-6, Cpl=2520., D=0.03, x=0.85)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"280 ns ± 6.99 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit S_isothermal_pipe_eccentric_to_isothermal_pipe(.1, .4, .05, 10)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"272 ns ± 3.99 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_cylinder_Zukauskas(7992, 0.707, 0.69)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"213 ns ± 4.44 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_cylinder_Whitaker(6071, 0.7)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"243 ns ± 3.85 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"219 ns ± 3.23 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_vertical_cylinder(0.72, 1E7, Method='McAdams, Weiss & Saunders')\\n\",\n    \"%timeit Nu_vertical_cylinder(0.72, 1E7)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"209 ns ± 0.709 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"225 ns ± 1.61 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"326 ns ± 4.33 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_horizontal_cylinder(0.72, 1E7)\\n\",\n    \"%timeit Nu_horizontal_cylinder(0.72, 1E7, Method='Morgan')\\n\",\n    \"%timeit Nu_horizontal_cylinder(0.72, 1E7, Method='Churchill-Chu')\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 13,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"28.1 ns ± 0.347 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)\\n\",\n      \"5.93 ns ± 0.0134 ns per loop (mean ± std. dev. of 7 runs, 100,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit laminar_T_const()\\n\",\n    \"%timeit 3.66\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 14,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"1 µs ± 19.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"393 ns ± 3.8 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"['Churchill-Zajic', 'Petukhov-Kirillov-Popov', 'Gnielinski', 'Bhatti-Shah', 'Dipprey-Sabersky', 'Sandall', 'Webb', 'Friend-Metzner', 'Prandtl', 'von-Karman', 'Gowen-Smith', 'Kawase-Ulbrecht', 'Kawase-De', 'Nunner', 'Dittus-Boelter', 'Sieder-Tate', 'Drexel-McAdams', 'Colburn', 'ESDU', 'Gnielinski smooth low Pr', 'Gnielinski smooth high Pr']\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_conv_internal(Re=1E5, Pr=1.2, fd=0.0185, eD=1E-3)\\n\",\n    \"%timeit Nu_conv_internal_methods(Re=1E5, Pr=1.2, fd=0.0185, eD=1E-3)\\n\",\n    \"print(Nu_conv_internal_methods(Re=1E5, Pr=1.2, fd=0.0185, eD=1E-3))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 15,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"638 ns ± 12.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"868 ns ± 54.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6)\\n\",\n    \"%timeit Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype='radial', isobaric_expansion=0.000303)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 16,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"683 ns ± 13 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit Nu_packed_bed_Gnielinski(dp=8E-4, voidage=0.4, vs=1, rho=1E3, mu=1E-3, Pr=0.7)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 17,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"5.38 µs ± 186 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\\n\",\n      \"4.01 µs ± 188 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\\n\",\n      \"4.09 µs ± 112 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit dP_Kern(m=11., rho=995., mu=0.000803, mu_w=0.000657, DShell=0.584, LSpacing=0.1524, pitch=0.0254, Do=.019, NBaffles=22)\\n\",\n    \"%timeit dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0343, D=0.0164, rho=1.217, Vmax=12.6)\\n\",\n    \"%timeit dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0313, D=0.0164, rho=1.217, Vmax=12.6)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 18,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"225 ns ± 7.3 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"246 ns ± 12.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit LMTD(100., 60., 30., 40.2)\\n\",\n    \"%timeit LMTD(100., 60., 30., 40.2, counterflow=False)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 19,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"7.61 µs ± 122 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)\\n\",\n      \"18.7 µs ± 391 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\\n\",\n      \"24.8 µs ± 200 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit [[Ntubes_Perrys(DBundle=1.184, Ntp=i, Do=.028, angle=j) for i in [1,2,4,6]] for j in [30, 45, 60, 90]]\\n\",\n    \"%timeit [[Ntubes_VDI(DBundle=1.184, Ntp=i, Do=.028, pitch=.036, angle=j) for i in [1,2,4,8]] for j in [30, 45, 60, 90]]\\n\",\n    \"%timeit [Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=i, angle=45.) for i in [1,2,4,6,8]]\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 20,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"24.9 µs ± 290 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\\n\",\n      \"223\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"from ht.insulation import ASHRAE_k, ASHRAE, materials_dict\\n\",\n    \"%timeit [ASHRAE_k(ID) for ID in ASHRAE]\\n\",\n    \"print(len(ASHRAE))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 21,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Bitumen, pure\\n\",\n      \"261 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"a = 'Bitumen'\\n\",\n    \"print(nearest_material(a))\\n\",\n    \"%timeit nearest_material(a)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 22,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"204 ns ± 1.44 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\\n\",\n      \"145 ns ± 2.83 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"%timeit blackbody_spectral_radiance(800., 4E-6)\\n\",\n    \"%timeit q_rad(.85, 400, 305.)\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Conclusion: From 30 ms to 100 ns, not that wide of a range; only 5 orders of magnitude.\\n\",\n    \"String matching is definitely slow, which I know. Definitely menu-driven selection is prefered.\\n\",\n    \"Some complicated functions take a decently long time to work, also not a surprise.\\n\",\n    \"A better alternative to inter1d and interp2d exists; and is equally easy to use. \\n\",\n    \"As a bonus, it provides a degree of smoothing and more control.\\n\",\n    \"The overhead of dealing with strings is not large, but it may still be worth moving out in favor of dictionary comparisons.\\n\",\n    \"By and large, the library is still quick, for Python anyway.\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"language_info\": {\n   \"name\": \"python\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 0\n}\n"
  },
  {
    "path": "conftest.py",
    "content": "import platform\nimport sys\n\n# Detect Python implementation and version\nis_pypy = \"PyPy\" in sys.version\nis_graal = \"Graal\" in sys.version\nis_free_threaded = hasattr(sys, \"_is_gil_enabled\") and not sys._is_gil_enabled()\nver_tup = tuple(int(x) for x in platform.python_version_tuple()[:2])\nis_x86_or_x86_64 = platform.machine().lower() in (\"i386\", \"i686\", \"x86\", \"x86_64\", \"amd64\")\n\n\ndef pytest_ignore_collect( collection_path, config):\n    \"\"\"Determine which paths pytest should ignore during test collection.\"\"\"\n    # Normalize path to string\n    path = str(collection_path)\n\n    # Skip virtual environments and ASV benchmark environments\n    if \"venv\" in path or \"site-packages\" in path or \".asv\" in path:\n        return True\n\n    # Skip utility and development directories\n    skip_paths = (\"cx_freeze\", \"py2exe\", \"manual_runner\", \"make_test_stubs\", \"plot\", \"prerelease\", \"benchmarks\", \"conf.py\", \"_custom_build\")\n    if any(skip_path in path for skip_path in skip_paths):\n        return True\n\n    # Skip notebook benchmarks\n    if \"ipynb\" in path and \"bench\" in path:\n        return True\n\n    # PyPy/GraalVM compatibility exclusions\n    if (is_pypy or is_graal) and \"test_spa\" in path:\n        return True\n\n    if is_graal and \"units\" in path:\n        return True\n\n    # Skip numba and .rst tests for unsupported configurations\n    # Numba requires: CPython 3.9-3.13, x86/x86_64 architecture, GIL-enabled\n    unsupported_for_numba = (\n        ver_tup < (3, 9) or\n        ver_tup >= (3, 14) or\n        is_pypy or\n        is_graal or\n        is_free_threaded or\n        not is_x86_or_x86_64\n    )\n    if unsupported_for_numba:\n        if \"numba\" in path:\n            return True\n        # Skip .rst tests due to rendering differences and missing NUMBER flag support\n        if \".rst\" in path:\n            return True\n\n    return False\n\n\ndef pytest_configure(config):\n    \"\"\"Configure pytest options for doctest support.\"\"\"\n    # Only configure for Python 3\n    if sys.version[0] != \"3\":\n        return\n\n    import pytest\n    pytest_major_version = int(pytest.__version__.split(\".\")[0])\n\n    # Enable doctest modules for pytest >= 6\n    if pytest_major_version >= 6:\n        config.addinivalue_line(\"addopts\", \"--doctest-modules\")\n        config.option.doctestmodules = True\n        config.addinivalue_line(\"doctest_optionflags\", \"NUMBER\")\n\n    # Always normalize whitespace in doctests\n    config.addinivalue_line(\"doctest_optionflags\", \"NORMALIZE_WHITESPACE\")\n"
  },
  {
    "path": "dev/basic_standalone_ht_check.py",
    "content": "import ht\nfrom ht import *\nimport numpy as np\nimport scipy.integrate\nimport scipy.interpolate\nimport scipy.spatial\nimport scipy.special\nimport scipy.optimize\n\ndef check_close(a, b, rtol=1e-7, atol=0):\n    np.all(np.abs(a - b) <= (atol + rtol * np.abs(b)))\n    return True\n\ndef run_checks():\n    checks = []\n\n    # Check LMTD\n    result = LMTD(Thi=100, Tho=60, Tci=30, Tco=40.2)\n    checks.append(check_close(result, 43.200409294131525))\n\n    # Check radiation\n    result = q_rad(emissivity=1, T=400)\n    checks.append(check_close(result, 1451.613952))\n\n    # Check insulation material lookup\n    wood = nearest_material('spruce')\n    checks.append(k_material(wood) == 0.09)\n    checks.append(rho_material(wood) == 400.0)\n\n    return all(checks)\n\nif run_checks():\n    print(\"ht basic checks passed - NumPy and SciPy used successfully\")\nelse:\n    print('Library not OK')\n    exit(1)\n"
  },
  {
    "path": "dev/cx_freeze/cx_freeze_basic_standalone_check_builder.py",
    "content": "from cx_Freeze import setup, Executable\n\nbuild_exe_options = {\n    \"packages\": [\"numpy\", \"scipy\", \"ht\", \"fluids\"],\n    \"excludes\": [\"cairo\", \"locket\", \"setproctitle\", \"bcrypt\", \"beniget\", \"concurrent\", \n    \"curses\", \"et_xmlfile\", \"google\", \"imagesize\", \"olefile\", \"pyasn1_modules\", \"pytest\", \n    \"tabulate\", \"tlz\", \"xxhash\", \"_pydevd_frame_eval\", \"astunparse\", \"backcall\", \"constantly\",\n    \"cssselect\", \"greenlet\", \"html\", \"incremental\", \"iniconfig\", \"ipywidgets\", \n    \"matplotlib_inline\", \"ply\", \"pydoc_data\", \"pygtkcompat\", \"pyximport\", \"tblib\",\n    \"typed_ast\", \"xmlrpc\", \"yapf\", \"zope\", \"asgiref\", \"blib2to3\", \"certifi\", \"cloudpickle\",\n    \"dbm\", \"jupyter_core\", \"kiwisolver\", \"lz4\", \"ptyprocess\", \"PySide2\", \"snappy\", \n    \"sortedcontainers\", \"toml\", \"tomli\", \"tomllib\", \"zoneinfo\", \"blosc\", \"ephem\", \n    \"exceptiongroup\", \"gast\", \"http\", \"jacobi\", \"lazy_object_proxy\", \"llvmlite\",\n    \"mpi4py\", \"mpl_toolkits\", \"msgpack\", \"OpenSSL\", \"past\", \"pydevd_plugins\", \"smmap\",\n    \"wrapt\", \"wsgiref\", \"xml\", \"argcomplete\", \"bs4\", \"executing\", \"ipython_genutils\",\n    \"markupsafe\", \"mdurl\", \"pure_eval\", \"pyasn1\", \"PyQt5\", \"qtpy\", \"service_identity\", \n    \"zstandard\", \"asttokens\", \"bytecode\", \"colorama\", \"contourpy\", \"idna\", \"numexpr\", \n    \"PyQt6\", \"soupsieve\", \"stack_data\", \"wcwidth\", \"nacl\", \"pycparser\", \"traitlets\", \n    \"alabaster\", \"cvxopt\", \"fastjsonschema\", \"pexpect\", \"pluggy\", \"simplejson\", \n    \"tkinter\", \"torchgen\", \"defusedxml\", \"monkeytype\", \"av\", \"charset_normalizer\", \n    \"IPython\", \"opt_einsum\", \"psutil\", \"sphinxcontrib\", \"toolz\", \"torchvision\", \n    \"xlrd\", \"zict\", \"docutils\", \"girepository-1.0\", \"gitdb\", \"jedi\", \"jsonschema\", \n    \"parso\", \"pyparsing\", \"wx\", \"html5lib\", \"lib2to3\", \"cffi\", \"dill\", \"partd\", \n    \"tqdm\", \"babel\", \"click\", \"gi\", \"git\", \"pydev_ipython\", \"pyrsistent\", \"zmq\", \n    \"nbformat\", \"odf\", \"torchaudio\", \"Cython\", \"fsspec\", \"pygments\", \"requests\", \n    \"yaml\", \"django\", \"invoke\", \"markdown_it\", \"black\", \"graphviz\", \"jaxlib\", \n    \"sqlalchemy\", \"hypothesis\", \"openpyxl\", \"attr\", \"_pydev_bundle\", \"fontTools\", \n    \"jinja2\", \"jupyter_client\", \"pyglet\", \"joblib\", \"twisted\", \"patsy\", \"ipykernel\", \n    \"pvlib\", \"statsmodels\", \"tornado\", \"pythran\", \"snowballstemmer\", \"asyncio\", \n    \"tables\", \"h5py\", \"prompt_toolkit\", \"sphinx\", \"coverage\", \"dask\", \"jax\", \n    \"setuptools\", \"numba\", \"sympy\", \"chardet\", \"paramiko\", \"distributed\", \n    \"gevent\", \"rich\", \"torch\", \"matplotlib\", \"pyarrow\", \"PIL\"],\n    \"include_files\": []\n}\n\nbase = None\n\nexecutables = [\n    Executable(\"../basic_standalone_ht_check.py\", base=base)\n]\n\nsetup(\n    name=\"basic_ht_check\",\n    version=\"0.1\",\n    description=\"A simple cx_Freeze script that includes numpy and scipy\",\n    options={\"build_exe\": build_exe_options},\n    executables=executables\n)\n"
  },
  {
    "path": "dev/prerelease.py",
    "content": "import os\nimport shutil\nimport sys\n\nif sys.version_info.major != 3 and sys.version_info.minor != 11:\n\traise ValueError(\"\"\"This prerelease script will only run on Python 3.11.\nSome parts of a library change the last few decimals numbers between releases,\nand other parts only have obsolete dependencies i.e. pint on Python 2.\nFor that reason, while the pytest test suite runs everywhere,\nthe notebooks and doctests only run on one paltform.\"\"\")\n\n\nimport os\nimport sys\nfrom datetime import datetime\n\n\ndef set_file_modification_time(filename, mtime):\n    atime = os.stat(filename).st_atime\n    os.utime(filename, times=(atime, mtime.timestamp()))\n\nnow = datetime.now()\n\nmain_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\n\nremove_folders = ('__pycache__', '.mypy_cache', '_build', '.cache', '.ipynb_checkpoints')\nbad_extensions = ('.pyc', '.nbi', '.nbc')\npaths = [main_dir]\n\nfor p in paths:\n    for (dirpath, dirnames, filenames) in os.walk(p):\n        for bad_folder in remove_folders:\n            if dirpath.endswith(bad_folder):\n                shutil.rmtree(dirpath)\n                continue\n        for filename in filenames:\n            full_path = os.path.join(dirpath, filename)\n            if not os.path.exists(full_path):\n                continue\n            set_file_modification_time(full_path, now)\n            for bad_extension in bad_extensions:\n                if full_path.endswith(bad_extension):\n                    os.remove(full_path)\n\n\nmain_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\ntest_dir = os.path.join(main_dir, 'tests')\nos.chdir(test_dir)\n\n#mod_spec = importlib.util.spec_from_file_location(\"make_test_stubs\", os.path.join(test_dir, \"make_test_stubs.py\"))\n#make_test_stubs = importlib.util.module_from_spec(mod_spec)\n#mod_spec.loader.exec_module(make_test_stubs)\n\nimport pytest\n\nos.chdir(main_dir)\npytest.main([\"--doctest-glob='*.rst'\", \"--doctest-modules\", \"--nbval\", \"-n\", \"8\", \"--dist\", \"loadscope\", \"-v\"])\n"
  },
  {
    "path": "docs/conf.py",
    "content": "#\n# Heat Transfer documentation build configuration file, created by\n# sphinx-quickstart on Sat Jan  2 17:15:23 2016.\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\nimport os\nimport time\n\n#import sys\n#from mock import Mock as MagicMock\n#\n#\n#class Mock(MagicMock):\n#    @classmethod\n#    def __getattr__(cls, name):\n#            return Mock()\n#\n#MOCK_MODULES = ['scipy', 'scipy.interpolate', 'scipy.constants', 'argparse',\n#'numpy', 'pandas', 'scipy.optimize', 'fluids', 'costing', 'fluids.friction',\n#'fluids.piping', 'fluids.friction_factor']\n#sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)\n\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#sys.path.insert(0, os.path.abspath('.'))\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.doctest\",\n    \"sphinx.ext.coverage\",\n    #'sphinx.ext.mathjax',\n    \"sphinx.ext.viewcode\",\n    \"sphinx.ext.autosummary\",\n    \"numpydoc\",\n    \"IPython.sphinxext.ipython_console_highlighting\",\n    \"IPython.sphinxext.ipython_directive\",\n    \"sphinx.ext.intersphinx\",\n    \"nbsphinx\",\n    \"matplotlib.sphinxext.plot_directive\",\n    \"sphinxcontrib.katex\",\n    \"sphinx_sitemap\",\n    \"sphinxcontrib.googleanalytics\",\n]\ngoogleanalytics_id = \"G-7YTWGWHN84\"\n\nkatex_css_path = \\\n    \"https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css\"\nkatex_js_path = \"katex.min.js\"\nkatex_autorender_path = \"auto-render.min.js\"\n\n\nhtml_baseurl = \"https://ht.readthedocs.io/\"\nsitemap_url_scheme = \"{link}\"\nsitemap_filename = \"sitemap2.xml\" # readthedocs generates its own\n\n\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The suffix of source filenames.\nsource_suffix = \".rst\"\n\n# The encoding of source files.\n#source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nmaster_doc = \"index\"\n\n# General information about the project.\nproject = \"Heat Transfer\"\n\nimport datetime\n\nbuild_date = datetime.datetime.utcfromtimestamp(\n    int(os.environ.get(\"SOURCE_DATE_EPOCH\", time.time()))\n)\ncopyright = f\"2016 - {build_date.year}, Caleb Bell and contributors\"\n\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nimport ht\n\nversion = ht.__version__\n# The full version, including alpha/beta/rc tags.\nrelease = ht.__version__\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n#today = ''\n# Else, today_fmt is used as the format for a strftime call.\n#today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = [\"_build\", \"**.ipynb_checkpoints\"]\n\n# The reST default role (used for this markup: `text`) to use for all\n# documents.\n#default_role = None\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\n#add_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\n#add_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\n#show_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"sphinx\"\n\n# A list of ignored prefixes for module index sorting.\n#modindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built documents.\n#keep_warnings = False\n\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = \"nature\"\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#html_theme_options = {}\n\n# Add any paths that contain custom themes here, relative to this directory.\n#html_theme_path = []\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n#html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n#html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\n#html_logo = None\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\n#html_favicon = None\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n\n# Custom CSS files\nhtml_css_files = [\"custom.css\"]\n\n# Add any extra paths that contain custom files (such as robots.txt or\n# .htaccess) here, relative to this directory. These files are copied\n# directly to the root of the documentation.\n#html_extra_path = []\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\n#html_last_updated_fmt = '%b %d, %Y'\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n#html_use_smartypants = True\n\n# Custom sidebar templates, maps document names to template names.\n#html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\n#html_additional_pages = {}\n\n# If false, no module index is generated.\n#html_domain_indices = True\n\n# If false, no index is generated.\n#html_use_index = True\n\n# If true, the index is split into individual pages for each letter.\n#html_split_index = False\n\n# If true, links to the reST sources are added to the pages.\n#html_show_sourcelink = True\n\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\n#html_show_sphinx = True\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\n#html_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\n#html_use_opensearch = ''\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\n#html_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = \"Heat Transferdoc\"\n\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n# The paper size ('letterpaper' or 'a4paper').\n#'papersize': 'letterpaper',\n\n# The font size ('10pt', '11pt' or '12pt').\n#'pointsize': '10pt',\n\n# Additional stuff for the LaTeX preamble.\n#'preamble': '',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [\n  (\"index\", \"Heat Transfer.tex\", \"Heat Transfer Documentation\",\n   \"Caleb Bell\", \"manual\"),\n]\n\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\n#latex_logo = None\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n#latex_use_parts = False\n\n# If true, show page references after internal links.\n#latex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n#latex_show_urls = False\n\n# Documents to append as an appendix to all manuals.\n#latex_appendices = []\n\n# If false, no module index is generated.\n#latex_domain_indices = True\n\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (\"index\", \"ht\", \"Heat Transfer Documentation\",\n     [\"Caleb Bell\"], 1)\n]\n\n# If true, show URL addresses after external links.\n#man_show_urls = False\n\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n  (\"index\", \"Heat Transfer\", \"Heat Transfer Documentation\",\n   \"Caleb Bell\", \"Heat Transfer\", \"One line description of project.\",\n   \"Miscellaneous\"),\n]\nnbsphinx_requirejs_path = \"\" # fixes katex not working\nplot_rcparams = {\"savefig.bbox\": \"tight\"}\nplot_apply_rcparams = True  # if context option is used\nnumpydoc_xref_param_type = True\n# Documents to append as an appendix to all manuals.\n#texinfo_appendices = []\n\n# If false, no module index is generated.\n#texinfo_domain_indices = True\n\n# How to display URL addresses: 'footnote', 'no', or 'inline'.\n#texinfo_show_urls = 'footnote'\n\n# If true, do not generate a @detailmenu in the \"Top\" node's menu.\n#texinfo_no_detailmenu = False\n\nintersphinx_mapping = {\"python\": (\"https://docs.python.org/3\", None),\n                       \"numpy\": (\"http://docs.scipy.org/doc/numpy\", None),\n                       \"scipy\": (\"http://docs.scipy.org/doc/scipy/reference\", None),\n                       \"matplotlib\": (\"http://matplotlib.org/stable/\", None),\n                       \"thermo\": (\"https://thermo.readthedocs.io/\", None),\n                       \"chemicals\": (\"https://chemicals.readthedocs.io/\", None),\n                       \"fluids\": (\"https://fluids.readthedocs.io/\", None)}\nhtml_theme = \"nature\"\nkatex_prerender = True\n\nfrom sphinx.ext.autodoc import between\n\ntry:\n    import ht.numba\nexcept:\n    pass\ndef setup(app):\n    # Register a sphinx.ext.autodoc.between listener to ignore everything\n    # between lines that contain the word IGNORE\n    app.connect(\"autodoc-process-docstring\", between(\"(^Chemical Engineering Design Library).*|(^SOFTWARE.$).*\", exclude=True))\n    return app\n"
  },
  {
    "path": "docs/ht.air_cooler.rst",
    "content": "Air cooler sizing and rating (ht.air_cooler)\n============================================\n\n.. automodule:: ht.air_cooler\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.boiling_flow.rst",
    "content": "\nFlow boiling (ht.boiling_flow)\n==============================\n\n.. automodule:: ht.boiling_flow\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.boiling_nucleic.rst",
    "content": "Nucleic boiling and critical heat flux (ht.boiling_nucleic)\n===========================================================\n\n.. automodule:: ht.boiling_nucleic\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.boiling_plate.rst",
    "content": "\nBoiling in plate and frame exchangers (ht.boiling_plate)\n========================================================\n\n.. automodule:: ht.boiling_plate\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.condensation.rst",
    "content": "Condensation (ht.condensation)\n==============================\n\n.. automodule:: ht.condensation\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conduction.rst",
    "content": "Conduction and shape factors (ht.conduction)\n============================================\n\n.. automodule:: ht.conduction\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_external.rst",
    "content": "External convection (ht.conv_external)\n======================================\n\n.. automodule:: ht.conv_external\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_free_enclosed.rst",
    "content": "Free convection to enclosed bodies (ht.conv_free_enclosed)\n==========================================================\n\n.. automodule:: ht.conv_free_enclosed\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_free_immersed.rst",
    "content": "Free convection to immersed bodies (ht.conv_free_immersed)\n==========================================================\n\n.. automodule:: ht.conv_free_immersed\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_internal.rst",
    "content": "Internal convection (ht.conv_internal)\n======================================\n\n.. automodule:: ht.conv_internal\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_jacket.rst",
    "content": "Convection to jacketed vessels (ht.conv_jacket)\n===============================================\n\n.. automodule:: ht.conv_jacket\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_packed_bed.rst",
    "content": "Convection to packed beds (ht.conv_packed_bed)\n==============================================\n\n.. automodule:: ht.conv_packed_bed\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_plate.rst",
    "content": "Convection to Plate Heat Exchangers (single-phase) (ht.conv_plate)\n=====================================================================\n\n.. automodule:: ht.conv_plate\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_supercritical.rst",
    "content": "Convection with supercritical fluids (ht.conv_supercritical)\n============================================================\n\n.. automodule:: ht.conv_supercritical\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_tube_bank.rst",
    "content": "Heat transfer and pressure drop across tube bundles (ht.conv_tube_bank)\n=======================================================================\n\n.. automodule:: ht.conv_tube_bank\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.conv_two_phase.rst",
    "content": "Non boiling and non condensing two-phase heat transfer (ht.conv_two_phase)\n==========================================================================\n\n.. automodule:: ht.conv_two_phase\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.core.rst",
    "content": "Miscellaneous utilities (ht.core)\n=================================\n\n.. automodule:: ht.core\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.hx.rst",
    "content": "Heat exchanger sizing and rating (ht.hx)\n========================================\n\n.. automodule:: ht.hx\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.insulation.rst",
    "content": "Database of insulating and refractory material properties (ht.insulation)\n=========================================================================\n\n.. automodule:: ht.insulation\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.numba.rst",
    "content": "Support for Numba (ht.numba)\n============================\n\nBasic module which wraps most of ht functions and classes to be compatible with the\n`Numba <https://github.com/numba/numba>`_ dynamic Python compiler.\nSupport for Numba may require the latest version of Numba.\nNumba is rapidly evolving, and hopefully in the future it will support more of\nthe functionality of ht.\n\nUsing the numba-accelerated version of `ht` is easy; simply call functions\nand classes from the ht.numba namespace. The ht.numba module must be\nimported separately; it is not loaded automatically as part of ht.\n\n>>> import ht\n>>> import ht.numba\n>>> ht.numba.Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4)\n0.55050936040\n\nThere is a delay while the code is compiled when using Numba;\nthe speed is not quite free. Most, but not all compilations can be\ncached to save time in future loadings.\n\nIt is easy to compare the speed of a function with and without Numba.\n\n>>> %timeit ht.numba.Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4) # doctest: +SKIP\n1.22 µs ± 41.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n>>> %timeit ht.Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4) # doctest: +SKIP\n5.89 µs ± 274 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n\nNot everything is faster in the numba interface. It is advisable to check \nthat numba is indeed faster for your use case.\n\nFunctions which take strings as inputs are also known to normally get slower;\nthe numerical stuff is still being sped up but the string handling is slow:\n\n>>> %timeit ht.numba.baffle_correction_Bell(0.82, method='spline') # doctest: +SKIP\n16.5 µs ± 538 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n>>> %timeit ht.baffle_correction_Bell(0.82, method='spline') # doctest: +SKIP\n15.6 µs ± 457 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n\nNevertheless, using the function from the numba interface may be preferably,\nto allow an even larger program to be completely compiled in njit mode.\n\nToday, the list of things known not to work is as follows:\n\n- :py:func:`~.dP_Zukauskas` (needs some spline work)\n- :py:func:`~.cylindrical_heat_transfer` (returns dictionaries)\n- :py:func:`~.effectiveness_NTU_method` (returns dictionaries)\n- :py:func:`~.P_NTU_method` (returns dictionaries)\n- :py:func:`~.NTU_from_effectiveness` (does string-to-int conversion)\n- :py:func:`~.DBundle_min` and :py:func:`~.shell_clearance` (needs work)\n- :py:func:`~.wall_factor_Nu` and :py:func:`~.wall_factor_fd` (dictionary lookups)\n- :py:func:`~.solar_spectrum` (external file reading)\n- :py:func:`~.NTU_from_P_basic` (used to work but broke in 0.57 numba release)\n- :py:func:`~.NTU_from_P_J` (used to work but broke in 0.57 numba release)\n- :py:func:`~.NTU_from_P_G` (used to work but broke in 0.57 numba release)\n- :py:func:`~.NTU_from_P_E` (used to work but broke in 0.57 numba release)\n- :py:func:`~.NTU_from_P_H` (used to work but broke in 0.57 numba release)\n- :py:func:`~.NTU_from_P_plate` (used to work but broke in 0.57 numba release)\n- Everything in :py:mod:`ht.insulation`\n\n\nNumpy Support\n-------------\nNumba also allows ht to provide any of its supported functions as a numpy universal\nfunction. Numpy's wonderful broadcasting is implemented, so some arguments can\nbe arrays and some can not.\n\n>>> import ht.numba_vectorized\n>>> import numpy as np\n>>> ht.numba_vectorized.Nu_Grimison_tube_bank(np.linspace(1e4, 1e5, 4), np.array([.708]), np.array([11]), np.array([.05]), np.array([.05]), np.array([.025]))\narray([3.39729780e+06, 3.74551216e+07, 9.86950909e+07, 1.83014426e+08])\n\nUnfortunately, keyword-arguments are not supported by Numba.\nAlso default arguments are not presently supported by Numba.\n\nDespite these limitations is is here that Numba really shines! Arrays are Numba's\nstrength.\n\nPlease note this interface is provided, but what works and what doesn't is\nmostly up to the numba project. This backend is not quite as polished as\ntheir normal engine.\n"
  },
  {
    "path": "docs/ht.radiation.rst",
    "content": "Heat transfer by radiation (ht.radiation)\n=========================================\n\n.. automodule:: ht.radiation\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/ht.vectorized.rst",
    "content": "Support for numpy arrays (ht.vectorized)\n========================================\n\n\nBasic module which wraps all ht functions with numpy's vectorize.\nAll other object - dicts, classes, etc - are not wrapped. Supports star \nimports; so the same objects exported when importing from the main library\nwill be imported from here. \n\n>>> from ht.vectorized import *\n\nInputs do not need to be numpy arrays; they can be any iterable:\n\n>>> import ht.vectorized\n>>> ht.vectorized.LMTD([100, 101], 60., 30., 40.2)\narray([43.20040929, 43.60182765])\n\n"
  },
  {
    "path": "docs/index.rst",
    "content": "ht: Heat Transfer component of Chemical Engineering Design Library (ChEDL)\n==========================================================================\n\n  .. meta::\n      :google-site-verification: wcmDZ88ikLzq1to6urRDGA6R7oIhzya2sN5hOeV1zZw\n\nIntroduction\n------------\n\nht is open-source software for engineers and technicians working in the\nfields of chemical or mechanical engineering. It includes modules\nfor various heat transfer functions.\n\nAmong the tasks this library can be used for are:\n\n* Sizing a Shell & Tube heat exchanger using any of the Zukauskas, ESDU 73031, or Bell methods\n* Calculating pressure drop in a Hairpin heat exchanger\n* Calculating heat loss of objects, including insulated objects\n* Calculating heat loss from buried pipe\n* Performing radiative heat transfer calculations\n* Conderser and Reboiler rating\n* Detailed heat exchanger evaluation; finding fouling factors\n* Heat transfer in packed beds\n* Sizing a Plate and Frame heat exchanger\n* Modeling an Air Cooler\n* Supercritical CO2 or water heat transfer\n\n.. image:: http://img.shields.io/pypi/v/ht.svg?style=flat\n   :target: https://pypi.python.org/pypi/ht\n   :alt: Version_status\n.. image:: http://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat\n   :target: https://ht.readthedocs.io/en/latest/\n   :alt: Documentation\n.. image:: https://github.com/CalebBell/ht/workflows/Build/badge.svg\n   :target: https://github.com/CalebBell/ht/actions\n   :alt: Build_status\n.. image:: http://img.shields.io/badge/license-MIT-blue.svg?style=flat \n   :target: https://github.com/CalebBell/ht/blob/master/LICENSE.txt\n   :alt: license\n.. image:: https://img.shields.io/pypi/pyversions/ht.svg?\n   :target: https://pypi.python.org/pypi/ht\n   :alt: Supported_versions\n.. image:: https://zenodo.org/badge/48963057.svg?\n   :alt: Zendo\n   :target: https://zenodo.org/badge/latestdoi/48963057\n\nModule Contents:\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Tutorial\n\n   tutorial\n\n.. toctree::\n   :maxdepth: 1\n   :caption: API\n\n   ht.air_cooler\n   ht.boiling_flow\n   ht.boiling_nucleic\n   ht.boiling_plate\n   ht.condensation\n   ht.conduction\n   ht.conv_external\n   ht.conv_free_immersed\n   ht.conv_free_enclosed\n   ht.conv_internal\n   ht.conv_jacket\n   ht.conv_packed_bed\n   ht.conv_plate\n   ht.conv_supercritical\n   ht.conv_tube_bank\n   ht.conv_two_phase\n   ht.core\n   ht.hx\n   ht.insulation\n   ht.numba\n   ht.radiation\n   ht.vectorized\n\n\nInstallation\n------------\n\nGet the latest version of ht from\nhttps://pypi.python.org/pypi/ht/\n\nIf you have an installation of Python with pip, simple install it with:\n\n    $ pip install ht\n\nTo get the git version, run:\n\n    $ git clone git://github.com/CalebBell/ht.git\n\nLatest source code\n------------------\n\nThe latest development version of ht's sources can be obtained at\n\n    https://github.com/CalebBell/ht\n\n\nBug reports\n-----------\n\nTo report bugs, please use the ht's Bug Tracker at:\n\n    https://github.com/CalebBell/ht/issues\n\n\nLicense information\n-------------------\n\nht is MIT licensed. See ``LICENSE.txt`` for information on the terms & \nconditions for usage of this software, and a DISCLAIMER OF ALL WARRANTIES.\n\nAlthough not required by the ht license, if it is convenient for you,\nplease cite ht if used in your work. Please also consider contributing\nany changes you make back, such that they may be incorporated into the\nmain library and all of us will benefit from them.\n\n\nCitation\n--------\n\nTo cite ht in publications use::\n\n    Caleb Bell and Contributors (2016-2025). ht: Heat transfer component of Chemical Engineering Design Library (ChEDL)\n    https://github.com/CalebBell/ht.\n\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`modindex`\n* :ref:`search`\n\n"
  },
  {
    "path": "docs/plots/Nu_external_cylinder.py",
    "content": "import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom ht.conv_external import Nu_external_cylinder, conv_external_cylinder_methods\n\nstyles = [\"--\", \"-.\", \"-\", \":\", \".\", \",\", \"o\", \"v\", \"^\", \"<\", \">\", \"1\", \"2\", \"3\", \"4\"]\n\nRes = np.logspace(np.log10(10), np.log10(1E6), 1000)\n\nPrs = np.array([[.7, 2, 6],\n            [.1, .2, .4],\n            [25, 100, 1000]])\n\n\nf, axarr = plt.subplots(3, 3)\n\nfor Pr, axes in zip(Prs.ravel(), axarr.ravel()):\n    for method, style in zip(conv_external_cylinder_methods, styles):\n        Nus = [Nu_external_cylinder(Re=Re, Pr=Pr, Method=method) for Re in Res]\n        axes.semilogx(Res, Nus, label=method) # + ', angle = ' + str(angle)\n\n        axes.set_title(rf\"Pr = {Pr:g}\")\n        for item in ([axes.title, axes.xaxis.label, axes.yaxis.label] +\n             axes.get_xticklabels() + axes.get_yticklabels()):\n            item.set_fontsize(6.5)\n\n        ttl = axes.title.set_position([.5, .98])\n\nplt.subplots_adjust(wspace=.35, hspace=.35)\n\nf.suptitle(\"Comparison of available methods for external convection\\n Reynolds Number (x) vs. Nusselt Number (y)\")\nplt.legend(loc=\"upper center\", bbox_to_anchor=(1.5, 2.4))\nplt.subplots_adjust(right=0.82, top=.85, bottom=.05)\n#plt.show()\n\n\n\n"
  },
  {
    "path": "docs/test_documentation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2021 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport os\n\nimport pytest\n\n\"\"\"\nTests that run aspects of the documentation should go in here.\nThe only bit included right now are the plots, which should run without an\nerror; no contents checking is performed.\n\"\"\"\nplots_folder = os.path.join(os.path.dirname(__file__), \"plots\")\nplot_files = [i for i in os.listdir(plots_folder) if i.endswith(\".py\")]\nprint(plot_files)\n\n@pytest.mark.parametrize(\"file\", plot_files)\ndef test_documentation_plots(file):\n    import matplotlib as mpl\n    mpl.use(\"Agg\")\n    exec(open(os.path.join(plots_folder, file)).read(), globals())\n"
  },
  {
    "path": "docs/tutorial.rst",
    "content": "Tutorial\n========\n\nIntroduction\n------------\n\nht is the heat transfer component of the Chemical Engineering Design Library (ChEDL). \nFunctions are provided to calculate heat transfer in a variety of situations, generally using\ndimensionless factors such as Reynolds and Prandtl number, and giving results in terms of dimensionless\nheat transfer coefficient, the Nusselt number. The 'dimensional' heat transfer coefficient may then be determined \n\n.. math::\n    h = \\frac{k\\cdot \\text{Nu}}{L}\n\nDesign Philosophy\n-----------------\nLike all libraries, this was developed to scratch my own itches. Since its\npublic release it has been found useful by many others, from students across \nthe world to practicing engineers at some of the world's largest companies.\n\nThe bulk of this library's API is considered stable; enhancements to \nfunctions and classes will still happen, and default methods when using a generic \ncorrelation interface may change to newer and more accurate correlations as\nthey are published and reviewed.\n\nTo the extent possible, correlations are implemented depending on the highest\nlevel parameters. The Nu_conv_internal correlation does not accept pipe diameter,\nvelocity, viscosity, density, heat capacity, and thermal conductivity - it accepts \nReynolds number and Prandtl number. This makes the API cleaner and encourages modular design.\n\nAll functions are desiged to accept inputs in base SI units. However, any \nset of consistent units given to a function will return a consistent result;\nfor instance, a function calculating volume doesn't care if given an input in\ninches or meters; the output units will be the cube of those given to it.\nThe user is directed to unit conversion libraries such as \n`pint <https://github.com/hgrecco/pint>`_ to perform unit conversions if they\nprefer not to work in SI units.\n\nThe standard math library is used in all functions except where special\nfunctions from numpy or scipy are necessary. SciPy is used for root finding,\ninterpolation, scientific constants, ode integration, and its many special\nmathematical functions not present in the standard math library. The only other\nrequired library is the `fluids` library, a sister library for fluid dynamics.\nNo other libraries will become required dependencies; anything else is optional.\n\nThere are two ways to use numpy arrays with ht. Easiest to use is a `vectorized` module,\nwhich wraps all of the ht functions with np.vectorize. Instead of importing\nfrom ht, the user can import from :doc:`ht.vectorized <ht.vectorized>`:\n\n>>> from ht.vectorized import *\n>>> LMTD([100, 101], 60., 30., 40.2)\narray([43.20040929, 43.60182765])\n\nIt is possible to switch back and forth between the namespaces with a subsequent\nimport:\n\n>>> from ht import * \n\nThe second way is `Numba <https://github.com/numba/numba>`_. This\noptional dependency provides the speed you expect from NumPy arrays -\nor better. In some cases, much better. The tutorial for using it\nis at :doc:`ht.numba <ht.numba>`, but in general use it the same way but\nwith a different import.\n\n>>> from ht.numba_vectorized import *\n\nInsulation\n----------\n\nInsulating and refractory materials from the VDI Heat Transfer Handbook\nand the ASHRAE Handbook: Fundamentals have been digitized and are programatically\navailable in ht. Density, heat capacity, and thermal conductivity are available\nalthough not all materials have all three.\n\nThe actual data is stored in a series of dictionaries, building_materials, \nASHRAE_board_siding, ASHRAE_flooring, ASHRAE_insulation, ASHRAE_roofing, \nASHRAE_plastering, ASHRAE_masonry, ASHRAE_woods, and refractories.\nA total of 390 different materials are available.\nFunctions have been written to make accessing this data much \nmore convenient. \n\nTo determine the correct string to look up a material by, one can use the\nfunction nearest_material:\n\n>>> from ht import *\n>>> nearest_material('stainless steel')\n'Metals, stainless steel'\n>>> nearest_material('mineral fibre')\n'Mineral fiber'\n\nKnowing a material's ID, the functions k_material, rho_material, and Cp_material\ncan be used to obtain its properties.\n\n>>> wood = nearest_material('spruce')\n>>> k_material(wood)\n0.09\n>>> rho_material(wood)\n400.0\n>>> Cp_material(wood)\n1630.0\n\nMaterials which are refractories, stored in the dictionary `refractories`,\nhave temperature dependent heat capacity and thermal conductivity between\n400 °C and 1200 °C.\n\n>>> C = nearest_material('graphite')\n>>> k_material(C)\n67.0\n>>> k_material(C, T=800)\n62.9851975\n\nThe limiting values are returned outside of this range:\n\n>>> Cp_material(C, T=8000), Cp_material(C, T=1)\n(1588.0, 1108.0)\n\n\nRadiation\n---------\nThe Stefan-Boltzman law is implemented as `q_rad`. Optionally, a surrounding\ntemperature may be specified as well. If the surrounding temperature is higher\nthan the object, the calculated heat flux in W/m^2 will be negative, indicating\nthe object is picking up heat not losing it.\n\n>>> q_rad(emissivity=1, T=400)\n1451.613952\n>>> q_rad(.85, T=400, T2=305.)\n816.7821722650002\n>>> q_rad(.85, T=400, T2=5000) # ouch\n-30122590.815640796\n\nA blackbody's spectral radiance can also be calculated, in units of \nW/steradian/square metre/metre. This calculation requires the temperature\nof the object and the wavelength to be considered.\n\n>>> blackbody_spectral_radiance(T=800., wavelength=4E-6)\n1311694129.7430933\n\nHeat Exchanger Sizing\n---------------------\n\nThere are three popular methods of sizing heat exchangers. The log-mean temperature \ndifference correction factor method, the ε-NTU method, and the P-NTU method.\nEach of those are cannot size a heat exchanger on their own - they do not\ncare about heat transfer coefficients or area - but they must be used first\nto determine the thermal conditions of the heat exchanger. Sizing a heat exchanger\nis a very iterative process, and many designs should be attempted to determine\nthe optimal one based on required performance and cost. The P-NTU method\nsupports the most types of heat exchangers; its form always requires the UA\nterm to be guessed however.\n\n\nLMTD Correction Factor Method\n-----------------------------\n\nThe simplest method, the log-mean temperature difference correction factor method,\nis as follows:\n\n.. math::\n    Q = UA\\Delta T_{lm} F_t\n    \nKnowing the outlet and inlet temperatures of a heat exchanger and `Q`, one could\ndetermine `UA` as follows:\n\n>>> dTlm = LMTD(Tci=15, Tco=85, Thi=130, Tho=110)\n>>> Ft = F_LMTD_Fakheri(Tci=15, Tco=85, Thi=130, Tho=110, shells=1)\n>>> Q = 1E6 # 1 MW\n>>> UA = Q/(dTlm*Ft)\n>>> UA\n15833.566307803789\n\nThis method requires you to know all four temperatures before UA can be calculated.\nFakheri developed a general expression for calculating `Ft`; it is valid for\ncounterflow shell-and-tube exchangers with an even number of tube passes; the \nnumber of shell-side passes can be varied. `Ft` is always less than 1, approaching\n1 with very high numbers of shells:\n\n>>> F_LMTD_Fakheri(Tci=15, Tco=85, Thi=130, Tho=110, shells=10)\n0.9994785295070708\n\nNo other expressions are available to calculate `Ft` for different heat exchanger\ngeometries; only the TEMA F and E exchanger types are really covered by this \nexpression. However, with results from the other methods, `Ft` can always\nbe back-calculated.\n\nLog mean temperature are available for both counterflow (by default) and \nco-current flow. This calculation does not depend on the units of temperature\nprovided.\n\n>>> LMTD(Thi=100, Tho=60, Tci=30, Tco=40.2)\n43.200409294131525\n>>> LMTD(100, 60, 30, 40.2, counterflow=False)\n39.75251118049003\n\n\nEffectiveness-NTU Method\n------------------------\nThis method uses the formula :math:`Q=\\epsilon C_{min}(T_{h,i}-T_{c,i})`. The main\ncomplication of this method is calculating effectiveness `epsilon`, which\nis a function of the mass flows, heat capacities, and UA\n:math:`\\epsilon = f(NTU, C_r)`. The effectiveness-NTU method is implemented in \nin `effectiveness_from_NTU` and `NTU_from_effectiveness`. The supported\nheat exchanger types are somewhat limited; they are:\n\n* Counterflow (ex. double-pipe)\n* Parallel (ex. double pipe inefficient configuration)\n* Shell and tube exchangers with even numbers of tube passes,\n  one or more shells in series (TEMA E (one pass shell) only)\n* Crossflow, single pass, fluids unmixed\n* Crossflow, single pass, Cmax mixed, Cmin unmixed\n* Crossflow, single pass, Cmin mixed, Cmax unmixed\n* Boiler or condenser\n\n\nTo illustrate the method, first the individual methods will be used to \ndetermine the outlet temperatures of a heat exchanger. After, the\nmore convenient and flexible wrapper `effectiveness_NTU_method` is\nshown. Overall case of rating an existing heat exchanger where a known flowrate\nof steam and oil are contacted in crossflow, with the steam side mixed:\n    \n>>> U = 275 # W/m^2/K\n>>> A = 10.82 # m^2\n>>> Cp_oil = 1900 # J/kg/K\n>>> Cp_steam = 1860 # J/kg/K\n>>> m_steam = 5.2 # kg/s\n>>> m_oil = 0.725 # kg/s\n>>> Thi = 130 # °C\n>>> Tci = 15 # °C\n>>> Cmin = calc_Cmin(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n>>> Cmax = calc_Cmax(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n>>> Cr = calc_Cr(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n>>> NTU = NTU_from_UA(UA=U*A, Cmin=Cmin)\n>>> eff = effectiveness_from_NTU(NTU=NTU, Cr=Cr, subtype='crossflow, mixed Cmax')\n>>> Q = eff*Cmin*(Thi - Tci)\n>>> Tco = Tci + Q/(m_oil*Cp_oil)\n>>> Tho = Thi - Q/(m_steam*Cp_steam)\n>>> Cmin, Cmax, Cr\n(1377.5, 9672.0, 0.14242142266335814)\n>>> NTU, eff, Q\n(2.160072595281307, 0.8312180361425988, 131675.32715043944)\n>>> Tco, Tho\n(110.59007415639887, 116.38592564614977)\n\nThat was not very convenient. The more helpful wrapper `effectiveness_NTU_method`\nneeds only the heat capacities and mass flows of each stream, the type of the heat\nexchanger, and one combination of the following inputs is required:\n        \n* Three of the four inlet and outlet stream temperatures\n* Temperatures for the cold outlet and hot outlet and UA\n* Temperatures for the cold inlet and hot inlet and UA\n* Temperatures for the cold inlet and hot outlet and UA\n* Temperatures for the cold outlet and hot inlet and UA\n\nThe function returns all calculated parameters for convenience as a dictionary.\n\nSolve a heat exchanger to determine UA and effectiveness given the\nconfiguration, flows, subtype, the cold inlet/outlet temperatures, and the\nhot stream inlet temperature.\n\n>>> from pprint import pprint\n>>> pprint(effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, \n... subtype='crossflow, mixed Cmax', Tci=15, Tco=85, Thi=130))\n{'Cmax': 9672.0,\n 'Cmin': 2755.0,\n 'Cr': 0.2848428453267163,\n 'NTU': 1.1040839095588,\n 'Q': 192850.0,\n 'Tci': 15,\n 'Tco': 85,\n 'Thi': 130,\n 'Tho': 110.06100082712986,\n 'UA': 3041.751170834494,\n 'effectiveness': 0.6086956521739131}\n\nSolve the same heat exchanger with the UA specified, and known inlet\ntemperatures:\n    \n>>> pprint(effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, \n... subtype='crossflow, mixed Cmax', Tci=15, Thi=130, UA=3041.75))\n{'Cmax': 9672.0,\n 'Cmin': 2755.0,\n 'Cr': 0.2848428453267163,\n 'NTU': 1.1040834845735028,\n 'Q': 192849.96310220254,\n 'Tci': 15,\n 'Tco': 84.99998660697007,\n 'Thi': 130,\n 'Tho': 110.06100464203861,\n 'UA': 3041.75,\n 'effectiveness': 0.6086955357127832}\n\n"
  },
  {
    "path": "ht/air_cooler.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import atan, log10, sin\n\nfrom fluids.constants import hp, minute\nfrom fluids.core import Prandtl, Reynolds\n\nfrom ht.conv_tube_bank import ESDU_tube_row_correction\nfrom ht.core import LMTD, WALL_FACTOR_PRANDTL, fin_efficiency_Kern_Kraus, wall_factor\n\n__all__: list[str] = [\n    \"Ft_aircooler\",\n    \"air_cooler_noise_GPSA\",\n    \"air_cooler_noise_Mukherjee\",\n    \"dP_ESDU_high_fin\",\n    \"dP_ESDU_low_fin\",\n    \"h_Briggs_Young\",\n    \"h_ESDU_high_fin\",\n    \"h_ESDU_low_fin\",\n    \"h_Ganguli_VDI\",\n]\n\nfin_densities_inch = [7, 8, 9, 10, 11] # fins/inch\nfin_densities = [275.6, 315.0, 354.3, 393.7, 433.1] # [round(i/0.0254, 1) for i in fin_densities_inch]\nODs = [1, 1.25, 1.5, 2] # Actually though, just use TEMA. API 661 says 1 inch min.\nfin_heights = [0.010, 0.012, 0.016] # m\n\n\ntube_orientations = [\"vertical (inlet at bottom)\", \"vertical (inlet at top)\", \"horizontal\", \"inclined\"]\n\n_fan_diameters = [0.71, 0.8, 0.9, 1.0, 1.2, 1.24, 1.385, 1.585, 1.78, 1.98, 2.22, 2.475, 2.775, 3.12, 3.515, 4.455, 4.95, 5.545, 6.24, 7.03, 7.92, 8.91, 9.9, 10.4, 11.1, 12.4, 13.85, 15.85]\n\nfan_ring_types = [\"straight\", \"flanged\",  \"bell\", \"15 degree cone\", \"30 degree cone\"]\n\nfin_constructions = [\"extruded\", \"embedded\", \"L-footed\", \"overlapped L-footed\", \"externally bonded\", \"knurled footed\"]\n\nheaders = [\"plug\", \"removable cover\", \"removable bonnet\", \"welded bonnet\"]\nconfigurations = [\"forced draft\", \"natural draft\", \"induced-draft (top drive)\", \"induced-draft (bottom drive)\"]\n\n\n\n\n# Coefs are from: Roetzel and Nicole - 1975 - Mean Temperature Difference for Heat Exchanger Design A General Approximate Explicit Equation\n# Checked twice.\n\n_crossflow_1_row_1_pass = [[-4.62E-1, -3.13E-2, -1.74E-1, -4.2E-2],\n                           [5.08E0, 5.29E-1, 1.32E0, 3.47E-1],\n                           [-1.57E1, -2.37E0, -2.93E0, -8.53E-1],\n                           [1.72E1, 3.18E0, 1.99E0, 6.49E-1]]\n\n_crossflow_2_rows_1_pass = [[-3.34E-1, -1.54E-1, -8.65E-2, 5.53E-2],\n                            [3.3E0, 1.28E0, 5.46E-1, -4.05E-1],\n                            [-8.7E0, -3.35E0, -9.29E-1, 9.53E-1],\n                            [8.7E0, 2.83E0, 4.71E-1, -7.17E-1]]\n\n_crossflow_3_rows_1_pass = [[-8.74E-2, -3.18E-2, -1.83E-2, 7.1E-3],\n                            [1.05E0, 2.74E-1, 1.23E-1, -4.99E-2],\n                            [-2.45E0, -7.46E-1, -1.56E-1, 1.09E-1],\n                            [3.21E0, 6.68E-1, 6.17E-2, -7.46E-2]]\n\n_crossflow_4_rows_1_pass = [[-4.14E-2, -1.39E-2, -7.23E-3, 6.1E-3],\n                            [6.15E-1, 1.23E-1, 5.66E-2, -4.68E-2],\n                            [-1.2E0, -3.45E-1, -4.37E-2, 1.07E-1],\n                            [2.06E0, 3.18E-1, 1.11E-2, -7.57E-2]]\n\n_crossflow_2_rows_2_pass = [[-2.35E-1, -7.73E-2, -5.98E-2, 5.25E-3],\n                            [2.28E0, 6.32E-1, 3.64E-1, -1.27E-2],\n                            [-6.44E0, -1.63E0, -6.13E-1, -1.14E-2],\n                            [6.24E0, 1.35E0, 2.76E-1, 2.72E-2]]\n\n_crossflow_3_rows_3_pass = [[-8.43E-1, 3.02E-2, 4.8E-1, 8.12E-2],\n                            [5.85E0, -9.64E-3, -3.28E0, -8.34E-1],\n                            [-1.28E1, -2.28E-1, 7.11E0, 2.19E0],\n                            [9.24E0, 2.66E-1, -4.9E0, -1.69E0]]\n\n_crossflow_4_rows_4_pass = [[-3.39E-1, 2.77E-2, 1.79E-1, -1.99E-2],\n                            [2.38E0, -9.99E-2, -1.21E0, 4E-2],\n                            [-5.26E0, 9.04E-2, 2.62E0, 4.94E-2],\n                            [3.9E0, -8.45E-4, -1.81E0, -9.81E-2]]\n\n_crossflow_4_rows_2_pass = [[-6.05E-1, 2.31E-2, 2.94E-1, 1.98E-2],\n                            [4.34E0, 5.9E-3, -1.99E0, -3.05E-1],\n                            [-9.72E0, -2.48E-1, 4.32, 8.97E-1],\n                            [7.54E0, 2.87E-1, -3E0, -7.31E-1]]\n\n\n\n\ndef Ft_aircooler(Thi: float, Tho: float, Tci: float, Tco: float, Ntp: int=1, rows: int=1) -> float:\n    r\"\"\"Calculates log-mean temperature difference correction factor for\n    a crossflow heat exchanger, as in an Air Cooler. Method presented in [1]_,\n    fit to other's nonexplicit work. Error is < 0.1%. Requires number of rows\n    and tube passes as well as stream temperatures.\n\n    .. math::\n        F_T = 1 - \\sum_{i=1}^m \\sum_{k=1}^n a_{i,k}(1-r_{1,m})^k\\sin(2i\\arctan R)\n\n    .. math::\n        R = \\frac{T_{hi} - T_{ho}}{T_{co}-T_{ci}}\n\n    .. math::\n        r_{1,m} = \\frac{\\Delta T_{lm}}{T_{hi} - T_{ci}}\n\n    Parameters\n    ----------\n    Thi : float\n        Temperature of hot fluid in [K]\n    Tho : float\n        Temperature of hot fluid out [K]\n    Tci : float\n        Temperature of cold fluid in [K]\n    Tco : float\n        Temperature of cold fluid out [K]\n    Ntp : int\n        Number of passes the tubeside fluid will flow through [-]\n    rows : int\n        Number of rows of tubes [-]\n\n    Returns\n    -------\n    Ft : float\n        Log-mean temperature difference correction factor [-]\n\n    Notes\n    -----\n    This equation assumes that the hot fluid is tubeside, as in the case of air\n    coolers. The model is not symmetric, so ensure to switch around the inputs\n    if using this function for other purposes.\n\n    This equation appears in [1]_. It has been verified.\n    For some cases, approximations are made to match coefficients with the\n    number of tube passes and rows provided.\n    16 coefficients are used for each case; 8 cases are considered:\n\n    * 1 row 1 pass\n    * 2 rows 1 pass\n    * 2 rows 2 passes\n    * 3 rows 1 pass\n    * 3 rows 3 passes\n    * 4 rows 1 pass\n    * 4 rows 2 passes\n    * 4 rows 4 passes\n\n    Examples\n    --------\n    >>> Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4)\n    0.550509360409\n\n    References\n    ----------\n    .. [1] Roetzel, W., and F. J. L. Nicole. \"Mean Temperature Difference for\n       Heat Exchanger Design-A General Approximate Explicit Equation.\" Journal\n       of Heat Transfer 97, no. 1 (February 1, 1975): 5-8.\n       doi:10.1115/1.3450288\n    \"\"\"\n    dTlm = LMTD(Thi=Thi, Tho=Tho, Tci=Tci, Tco=Tco)\n    rlm = dTlm/(Thi-Tci)\n    R = (Thi-Tho)/(Tco-Tci)\n#    P = (Tco-Tci)/(Thi-Tci)\n\n    if Ntp == 1 and rows == 1:\n        coefs = _crossflow_1_row_1_pass\n    elif Ntp == 1 and rows == 2:\n        coefs = _crossflow_2_rows_1_pass\n    elif Ntp == 1 and rows == 3:\n        coefs = _crossflow_3_rows_1_pass\n    elif Ntp == 1 and rows == 4:\n        coefs = _crossflow_4_rows_1_pass\n    elif Ntp == 1 and rows > 4:\n        # A reasonable assumption\n        coefs = _crossflow_4_rows_1_pass\n    elif Ntp == 2 and rows == 2:\n        coefs = _crossflow_2_rows_2_pass\n    elif Ntp == 3 and rows == 3:\n        coefs = _crossflow_3_rows_3_pass\n    elif Ntp == 4 and rows == 4:\n        coefs = _crossflow_4_rows_4_pass\n    elif Ntp > 4 and rows > 4 and Ntp == rows:\n        # A reasonable assumption\n        coefs = _crossflow_4_rows_4_pass\n    elif Ntp  == 2 and rows == 4:\n        coefs = _crossflow_4_rows_2_pass\n    else:\n        # A bad assumption, but hey, gotta pick something.\n        coefs = _crossflow_4_rows_2_pass\n    tot = 0.0\n    atanR2 = 2.0*atan(R)\n    N = len(coefs)\n    sine_terms = [0.0]*N\n    for i in range(N):\n        sine_terms[i] = sin((i + 1.)*atanR2)\n    x0 = one_m_rlm_orig = 1.0 - rlm\n    for k in range(N):\n        coeffs_k = coefs[k]\n        tot_i = 0.0\n        for i in range(N):\n            tot_i += coeffs_k[i]*sine_terms[i]\n        tot += tot_i*x0\n        x0 *= one_m_rlm_orig\n    return 1. - tot\n\n\ndef air_cooler_noise_GPSA(tip_speed: float, power: float) -> float:\n    r\"\"\"Calculates the noise generated by an air cooler bay with one fan\n    according to the GPSA handbook [1]_.\n\n    .. math::\n        \\text{PWL[dB(A)]} = 56 + 30\\log_{10}\\left( \\frac{\\text{tip speed}\n        [m/min]}{304.8 [m/min]}\\right) + 10\\log_{10}( \\text{power}[hp])\n\n    Parameters\n    ----------\n    tip_speed : float\n        Tip speed of the air cooler fan blades, [m/s]\n    power : float\n        Shaft power of single fan motor, [W]\n\n    Returns\n    -------\n    noise : float\n        Sound pressure level at 1 m from source, [dB(A)]\n\n    Notes\n    -----\n    Internal units are in m/minute, and hp.\n\n    Examples\n    --------\n    Example problem from GPSA [1]_.\n\n    >>> air_cooler_noise_GPSA(tip_speed=3177/minute, power=25.1*hp)\n    100.5368047795\n\n    References\n    ----------\n    .. [1] GPSA. \"Engineering Data Book, SI.\" 13th edition. Gas Processors\n       Suppliers Association (2012).\n    \"\"\"\n    tip_speed = tip_speed*minute # convert tip speed to m/minute\n    power = power/hp # convert power from W to hp\n    return 56.0 + 30.0*log10(tip_speed/304.8) + 10.0*log10(power)\n\n\ndef air_cooler_noise_Mukherjee(tip_speed: float, power: float, fan_diameter: float, induced: bool=False) -> float:\n    r\"\"\"Calculates the noise generated by an air cooler bay with one fan\n    according to [1]_.\n\n    .. math::\n        \\text{SPL[dB(A)]} = 46 + 30\\log_{10}\\text{(tip speed)}[m/s]\n        + 10\\log_{10}( \\text{power}[hp]) - 20 \\log_{10}(D_{fan})\n\n    Parameters\n    ----------\n    tip_speed : float\n        Tip speed of the air cooler fan blades, [m/s]\n    power : float\n        Shaft power of single fan motor, [W]\n    fan_diameter : float\n        Diameter of air cooler fan, [m]\n    induced : bool\n        Whether the air cooler is forced air (False) or induced air (True), [-]\n\n    Returns\n    -------\n    noise : float\n        Sound pressure level at 1 m from source (p0=2E-5 Pa), [dB(A)]\n\n    Notes\n    -----\n    Internal units are in m/minute, hp, and m.\n\n    If the air cooler is induced, the sound pressure level is reduced by 3 dB.\n\n    Examples\n    --------\n    >>> air_cooler_noise_Mukherjee(tip_speed=3177/minute, power=25.1*hp, fan_diameter=4.267)\n    99.1102632909\n\n    References\n    ----------\n    .. [1] Mukherjee, R., and Geoffrey Hewitt. Practical Thermal Design of\n       Air-Cooled Heat Exchangers. New York: Begell House Publishers Inc.,U.S.,\n       2007.\n    \"\"\"\n    noise = 46.0 + 30.0*log10(tip_speed) + 10.0*log10(power/hp) - 20.0*log10(fan_diameter)\n    if induced:\n        noise -= 3.0\n    return noise\n\n\ndef h_Briggs_Young(m: float, A: float, A_min: float, A_increase: float, A_fin: float, A_tube_showing: float,\n                   tube_diameter: float, fin_diameter: float, fin_thickness: float, bare_length: float,\n                   rho: float, Cp: float, mu: float, k: float, k_fin: float) -> float:\n    r\"\"\"Calculates the air side heat transfer coefficient for an air cooler\n    or other finned tube bundle with the formulas of Briggs and Young [1]_,\n    [2]_ [3]_.\n\n    .. math::\n        Nu = 0.134Re^{0.681} Pr^{0.33}\\left(\\frac{S}{h}\\right)^{0.2}\n        \\left(\\frac{S}{b}\\right)^{0.1134}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A : float\n        Surface area of combined finned and non-finned area exposed for heat\n        transfer, [m^2]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    A_fin : float\n        Surface area of all fins in the bundle, [m^2]\n    A_tube_showing : float\n        Area of the bare tube which is exposed in the bundle, [m^2]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    fin_diameter : float\n        Outer diameter of each tube after including the fin on both sides,\n        [m]\n    fin_thickness : float\n        Thickness of the fins, [m]\n    bare_length : float\n        Length of bare tube between two fins\n        :math:`\\text{bare length} = \\text{fin interval} - t_{fin}`, [m]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    Cp : float\n        Average (bulk) heat capacity of air across the tube bank, [J/kg/K]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n    k : float\n        Average (bulk) thermal conductivity of air across the tube bank,\n        [W/m/K]\n    k_fin : float\n        Thermal conductivity of the fin, [W/m/K]\n\n    Returns\n    -------\n    h_bare_tube_basis : float\n        Air side heat transfer coefficient on a bare-tube surface area as if\n        there were no fins present basis, [W/K/m^2]\n\n    Notes\n    -----\n    The limits on this equation are 1000 < Re < 8000 ,\n    11.13 mm < D_o < 40.89 mm, 1.42 mm < fin height < 16.57 mm,\n    0.33 mm < fin thickness < 2.02 mm, 1.30 mm < fin pitch < 4.06 mm, and\n    24.49 mm < normal pitch < 111 mm.\n\n    Examples\n    --------\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> from scipy.constants import inch\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=20, tube_length=3,\n    ... tube_diameter=1*inch, fin_thickness=0.000406, fin_density=1/0.002309,\n    ... pitch_normal=.06033, pitch_parallel=.05207,\n    ... fin_height=0.0159, tube_thickness=(.0254-.0186)/2,\n    ... bundles_per_bay=1, parallel_bays=1, corbels=True)\n\n    >>> h_Briggs_Young(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n    ... A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n    ... fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n    ... fin_thickness=AC.fin_thickness,\n    ... rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205)\n    1422.872240323\n\n    References\n    ----------\n    .. [1] Briggs, D.E., and Young, E.H., 1963, \"Convection Heat Transfer and\n       Pressure Drop of Air Flowing across Triangular Banks of Finned Tubes\",\n       Chemical Engineering Progress Symp., Series 41, No. 59. Chem. Eng. Prog.\n       Symp. Series No. 41, \"Heat Transfer - Houston\".\n    .. [2] Mukherjee, R., and Geoffrey Hewitt. Practical Thermal Design of\n       Air-Cooled Heat Exchangers. New York: Begell House Publishers Inc.,U.S.,\n       2007.\n    .. [3] Kroger, Detlev. Air-Cooled Heat Exchangers and Cooling Towers:\n       Thermal-Flow Performance Evaluation and Design, Vol. 1. Tulsa, Okl:\n       PennWell Corp., 2004.\n    \"\"\"\n    fin_height = 0.5*(fin_diameter - tube_diameter)\n\n    V_max = m/(A_min*rho)\n\n    Re = Reynolds(V=V_max, D=tube_diameter, rho=rho, mu=mu)\n    Pr = Prandtl(Cp=Cp, mu=mu, k=k)\n\n    Nu = 0.134*Re**0.681*Pr**(1/3.)*(bare_length/fin_height)**0.2*(bare_length/fin_thickness)**0.1134\n\n    h = k/tube_diameter*Nu\n    efficiency = fin_efficiency_Kern_Kraus(Do=tube_diameter, D_fin=fin_diameter,\n                                           t_fin=fin_thickness, k_fin=k_fin, h=h)\n    h_total_area_basis = (efficiency*A_fin + A_tube_showing)/A*h\n    h_bare_tube_basis = h_total_area_basis*A_increase\n\n    return h_bare_tube_basis\n\n\ndef h_ESDU_high_fin(m: float, A: float, A_min: float, A_increase: float, A_fin: float, A_tube_showing: float,\n                    tube_diameter: float, fin_diameter: float, fin_thickness: float, bare_length: float,\n                    pitch_parallel: float, pitch_normal: float, tube_rows: int,\n                    rho: float, Cp: float, mu: float, k: float, k_fin: float, Pr_wall: None=None) -> float:\n    r\"\"\"Calculates the air side heat transfer coefficient for an air cooler\n    or other finned tube bundle with the formulas of [2]_ as presented in [1]_.\n\n    .. math::\n        Nu = 0.242 Re^{0.658} \\left(\\frac{\\text{bare length}}\n        {\\text{fin height}}\\right)^{0.297}\n        \\left(\\frac{P_1}{P_2}\\right)^{-0.091} P_r^{1/3}\\cdot F_1\\cdot F_2\n\n    .. math::\n        h_{A,total} = \\frac{\\eta A_{fin} + A_{bare, showing}}{A_{total}} h\n\n    .. math::\n        h_{bare,total} = A_{increase} h_{A,total}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A : float\n        Surface area of combined finned and non-finned area exposed for heat\n        transfer, [m^2]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    A_fin : float\n        Surface area of all fins in the bundle, [m^2]\n    A_tube_showing : float\n        Area of the bare tube which is exposed in the bundle, [m^2]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    fin_diameter : float\n        Outer diameter of each tube after including the fin on both sides,\n        [m]\n    fin_thickness : float\n        Thickness of the fins, [m]\n    bare_length : float\n        Length of bare tube between two fins\n        :math:`\\text{bare length} = \\text{fin interval} - t_{fin}`, [m]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    Cp : float\n        Average (bulk) heat capacity of air across the tube bank, [J/kg/K]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n    k : float\n        Average (bulk) thermal conductivity of air across the tube bank,\n        [W/m/K]\n    k_fin : float\n        Thermal conductivity of the fin, [W/m/K]\n    Pr_wall : float, optional\n        Prandtl number at the wall temperature; provide if a correction with\n        the defaults parameters is desired; otherwise apply the correction\n        elsewhere, [-]\n\n    Returns\n    -------\n    h_bare_tube_basis : float\n        Air side heat transfer coefficient on a bare-tube surface area as if\n        there were no fins present basis, [W/K/m^2]\n\n    Notes\n    -----\n    The tube-row count correction factor is 1 for four or more rows, 0.92 for\n    three rows, 0.84 for two rows, and 0.76 for one row according to [1]_.\n\n    The property correction factor can be disabled by not specifying\n    `Pr_wall`. A Prandtl number exponent of 0.26 is recommended in [1]_ for\n    heating and cooling for both liquids and gases.\n\n    Examples\n    --------\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> from scipy.constants import inch\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=20, tube_length=3,\n    ... tube_diameter=1*inch, fin_thickness=0.000406, fin_density=1/0.002309,\n    ... pitch_normal=.06033, pitch_parallel=.05207,\n    ... fin_height=0.0159, tube_thickness=(.0254-.0186)/2,\n    ... bundles_per_bay=1, parallel_bays=1, corbels=True)\n\n    >>> h_ESDU_high_fin(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n    ... A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n    ... fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n    ... fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n    ... pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel,\n    ... rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205)\n    1390.88891804\n\n    References\n    ----------\n    .. [1] Hewitt, G. L. Shires, T. Reg Bott G. F., George L. Shires, and T.\n       R. Bott. Process Heat Transfer. 1st edition. Boca Raton: CRC Press,\n       1994.\n    .. [2] \"High-Fin Staggered Tube Banks: Heat Transfer and Pressure Drop for\n       Turbulent Single Phase Gas Flow.\" ESDU 86022 (October 1, 1986).\n    .. [3] Rabas, T. J., and J. Taborek. \"Survey of Turbulent Forced-Convection\n       Heat Transfer and Pressure Drop Characteristics of Low-Finned Tube Banks\n       in Cross Flow.\"  Heat Transfer Engineering 8, no. 2 (January 1987):\n       49-62.\n    \"\"\"\n    fin_height = 0.5*(fin_diameter - tube_diameter)\n\n    V_max = m/(A_min*rho)\n    Re = Reynolds(V=V_max, D=tube_diameter, rho=rho, mu=mu)\n    Pr = Prandtl(Cp=Cp, mu=mu, k=k)\n    Nu = 0.242*Re**0.658*(bare_length/fin_height)**0.297*(pitch_normal/pitch_parallel)**-0.091*Pr**(1/3.)\n\n    if tube_rows < 2:\n        F2 = 0.76\n    elif tube_rows < 3:\n        F2 = 0.84\n    elif tube_rows < 4:\n        F2 = 0.92\n    else:\n        F2 = 1.0\n\n    Nu *= F2\n    if Pr_wall is not None:\n        F1 = wall_factor(Pr=Pr, Pr_wall=Pr_wall, Pr_heating_coeff=0.26,\n                         Pr_cooling_coeff=0.26,\n                         property_option=WALL_FACTOR_PRANDTL)\n        Nu *= F1\n\n    h = k/tube_diameter*Nu\n    efficiency = fin_efficiency_Kern_Kraus(Do=tube_diameter, D_fin=fin_diameter,\n                                           t_fin=fin_thickness, k_fin=k_fin, h=h)\n\n    h_total_area_basis = (efficiency*A_fin + A_tube_showing)/A*h\n    h_bare_tube_basis =  h_total_area_basis*A_increase\n    return h_bare_tube_basis\n\n\ndef h_ESDU_low_fin(m: float, A: float, A_min: float, A_increase: float, A_fin: float,\n                   A_tube_showing: float, tube_diameter: float,\n                   fin_diameter: float, fin_thickness: float, bare_length: float,\n                   pitch_parallel: float, pitch_normal: float, tube_rows: int,\n                   rho: float, Cp: float, mu: float, k: float, k_fin: float, Pr_wall: float | None=None) -> float:\n    r\"\"\"Calculates the air side heat transfer coefficient for an air cooler\n    or other finned tube bundle with low fins using the formulas of [1]_ as\n    presented in [2]_ (and also [3]_).\n\n    .. math::\n        Nu = 0.183Re^{0.7} \\left(\\frac{\\text{bare length}}{\\text{fin height}}\n        \\right)^{0.36}\\left(\\frac{p_1}{D_{o}}\\right)^{0.06}\n        \\left(\\frac{\\text{fin height}}{D_o}\\right)^{0.11}\n        Pr^{0.36} \\cdot F_1\\cdot F_2\n\n    .. math::\n        h_{A,total} = \\frac{\\eta A_{fin} + A_{bare, showing}}{A_{total}} h\n\n    .. math::\n        h_{bare,total} = A_{increase} h_{A,total}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A : float\n        Surface area of combined finned and non-finned area exposed for heat\n        transfer, [m^2]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    A_fin : float\n        Surface area of all fins in the bundle, [m^2]\n    A_tube_showing : float\n        Area of the bare tube which is exposed in the bundle, [m^2]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    fin_diameter : float\n        Outer diameter of each tube after including the fin on both sides,\n        [m]\n    fin_thickness : float\n        Thickness of the fins, [m]\n    bare_length : float\n        Length of bare tube between two fins\n        :math:`\\text{bare length} = \\text{fin interval} - t_{fin}`, [m]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    Cp : float\n        Average (bulk) heat capacity of air across the tube bank, [J/kg/K]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n    k : float\n        Average (bulk) thermal conductivity of air across the tube bank,\n        [W/m/K]\n    k_fin : float\n        Thermal conductivity of the fin, [W/m/K]\n    Pr_wall : float, optional\n        Prandtl number at the wall temperature; provide if a correction with\n        the defaults parameters is desired; otherwise apply the correction\n        elsewhere, [-]\n\n    Returns\n    -------\n    h_bare_tube_basis : float\n        Air side heat transfer coefficient on a bare-tube surface area as if\n        there were no fins present basis, [W/K/m^2]\n\n    Notes\n    -----\n    The tube-row count correction factor `F2` can be disabled by setting `tube_rows`\n    to 10. The property correction factor `F1` can be disabled by not specifying\n    `Pr_wall`. A Prandtl number exponent of 0.26 is recommended in [1]_ for\n    heating and cooling for both liquids and gases.\n\n    There is a third correction factor in [1]_ for tube angles not 30, 45, or\n    60 degrees, but it is not fully explained and it is not shown in [2]_.\n    Another correction factor is in [2]_ for flow at an angle; however it would\n    not make sense to apply it to finned tube banks due to the blockage by the\n    fins.\n\n    Examples\n    --------\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n    ... tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n    ... pitch_normal=0.0313, pitch_parallel=0.0271, fin_height=0.0041, corbels=True)\n\n    >>> h_ESDU_low_fin(m=0.914, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n    ... A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n    ... fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n    ... fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n    ... pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel,\n    ... rho=1.217, Cp=1007., mu=1.8E-5, k=0.0253, k_fin=15)\n    553.85383647\n\n    References\n    ----------\n    .. [1] Hewitt, G. L. Shires, T. Reg Bott G. F., George L. Shires, and T.\n       R. Bott. Process Heat Transfer. 1st edition. Boca Raton: CRC Press,\n       1994.\n    .. [2] \"High-Fin Staggered Tube Banks: Heat Transfer and Pressure Drop for\n       Turbulent Single Phase Gas Flow.\" ESDU 86022 (October 1, 1986).\n    .. [3] Rabas, T. J., and J. Taborek. \"Survey of Turbulent Forced-Convection\n       Heat Transfer and Pressure Drop Characteristics of Low-Finned Tube Banks\n       in Cross Flow.\"  Heat Transfer Engineering 8, no. 2 (January 1987):\n       49-62.\n    \"\"\"\n    fin_height = 0.5*(fin_diameter - tube_diameter)\n\n    V_max = m/(A_min*rho)\n    Re = Reynolds(V=V_max, D=tube_diameter, rho=rho, mu=mu)\n    Pr = Prandtl(Cp=Cp, mu=mu, k=k)\n    Nu = (0.183*Re**0.7*(bare_length/fin_height)**0.36\n          *(pitch_normal/fin_diameter)**0.06\n          *(fin_height/fin_diameter)**0.11*Pr**0.36)\n\n    staggered = abs(1 - pitch_normal/pitch_parallel) > 0.05\n    F2 = ESDU_tube_row_correction(tube_rows=tube_rows, staggered=staggered)\n    Nu *= F2\n    if Pr_wall is not None:\n        F1 = wall_factor(Pr=Pr, Pr_wall=Pr_wall, Pr_heating_coeff=0.26,\n                         Pr_cooling_coeff=0.26,\n                         property_option=WALL_FACTOR_PRANDTL)\n        Nu *= F1\n\n    h = k/tube_diameter*Nu\n    efficiency = fin_efficiency_Kern_Kraus(Do=tube_diameter,\n                                           D_fin=fin_diameter,\n                                           t_fin=fin_thickness,\n                                           k_fin=k_fin, h=h)\n    h_total_area_basis = (efficiency*A_fin + A_tube_showing)/A*h\n    h_bare_tube_basis = h_total_area_basis*A_increase\n    return h_bare_tube_basis\n\n\ndef h_Ganguli_VDI(m: float, A: float, A_min: float, A_increase: float, A_fin: float,\n                  A_tube_showing: float, tube_diameter: float,\n                  fin_diameter: float, fin_thickness: float, bare_length: float,\n                  pitch_parallel: float, pitch_normal: float, tube_rows: int,\n                  rho: float, Cp: float, mu: float, k: float, k_fin: float) -> float:\n    r\"\"\"Calculates the air side heat transfer coefficient for an air cooler\n    or other finned tube bundle with the formulas of [1]_ as modified in [2]_.\n\n    Inline:\n\n    .. math::\n        Nu_d = 0.22Re_d^{0.6}\\left(\\frac{A}{A_{tube,only}}\\right)^{-0.15}Pr^{1/3}\n\n    Staggered:\n\n    .. math::\n        Nu_d = 0.38 Re_d^{0.6}\\left(\\frac{A}{A_{tube,only}}\\right)^{-0.15}Pr^{1/3}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A : float\n        Surface area of combined finned and non-finned area exposed for heat\n        transfer, [m^2]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    A_fin : float\n        Surface area of all fins in the bundle, [m^2]\n    A_tube_showing : float\n        Area of the bare tube which is exposed in the bundle, [m^2]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    fin_diameter : float\n        Outer diameter of each tube after including the fin on both sides,\n        [m]\n    fin_thickness : float\n        Thickness of the fins, [m]\n    bare_length : float\n        Length of bare tube between two fins\n        :math:`\\text{bare length} = \\text{fin interval} - t_{fin}`, [m]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    Cp : float\n        Average (bulk) heat capacity of air across the tube bank, [J/kg/K]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n    k : float\n        Average (bulk) thermal conductivity of air across the tube bank,\n        [W/m/K]\n    k_fin : float\n        Thermal conductivity of the fin, [W/m/K]\n\n    Returns\n    -------\n    h_bare_tube_basis : float\n        Air side heat transfer coefficient on a bare-tube surface area as if\n        there were no fins present basis, [W/K/m^2]\n\n    Notes\n    -----\n    The VDI modifications were developed in comparison with HTFS and HTRI data\n    according to [2]_.\n\n    For cases where the tube row count is less than four, the coefficients are\n    modified in [2]_. For the inline case, 0.2 replaces 0.22. For the stagered\n    cases, the coefficient is 0.2, 0.33, 0.36 for 1, 2, or 3 tube rows\n    respectively.\n\n    The model is also showin in [4]_.\n\n    Examples\n    --------\n    Example 12.1 in [3]_:\n\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> from scipy.constants import foot, inch\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=56, tube_length=36*foot,\n    ... tube_diameter=1*inch, fin_thickness=0.013*inch, fin_density=10/inch,\n    ... angle=30, pitch_normal=2.5*inch, fin_height=0.625*inch, corbels=True)\n\n    >>> h_Ganguli_VDI(m=130.70315, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n    ... A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n    ... fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n    ... fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n    ... pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal,\n    ... rho=1.2013848, Cp=1009.0188, mu=1.9304793e-05, k=0.027864828, k_fin=238)\n    969.285081857\n\n    References\n    ----------\n    .. [1] Ganguli, A., S. S. Tung, and J. Taborek. \"Parametric Study of\n       Air-Cooled Heat Exchanger Finned Tube Geometry.\" In AIChE Symposium\n       Series, 81:122-28, 1985.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    .. [3] Serth, Robert W., and Thomas Lestina. Process Heat Transfer:\n       Principles, Applications and Rules of Thumb. Academic Press, 2014.\n    .. [4] Kroger, Detlev. Air-Cooled Heat Exchangers and Cooling Towers:\n       Thermal-Flow Performance Evaluation and Design, Vol. 1. Tulsa, Okl:\n       PennWell Corp., 2004.\n    \"\"\"\n    V_max = m/(A_min*rho)\n\n    Re = Reynolds(V=V_max, D=tube_diameter, rho=rho, mu=mu)\n    Pr = Prandtl(Cp=Cp, mu=mu, k=k)\n\n    if abs(1 - pitch_normal/pitch_parallel) < 0.05: # in-line, with a tolerance of 0.05 proximity\n        if tube_rows < 4:\n            coeff = 0.2\n        else:\n            coeff = 0.22\n    else: # staggered\n        if tube_rows == 1:\n            coeff = 0.2\n        elif tube_rows == 2:\n            coeff = 0.33\n        elif tube_rows == 3:\n            coeff = 0.36\n        else:\n            coeff = 0.38\n\n    # VDI example shows the ratio is of the total area, to the original bare tube area\n    # Serth example would match Nu = 47.22 except for lazy rounding\n    Nu = coeff*Re**0.6*Pr**(1/3.)*(A_increase)**-0.15\n    h = k/tube_diameter*Nu\n    efficiency = fin_efficiency_Kern_Kraus(Do=tube_diameter, D_fin=fin_diameter,\n                                           t_fin=fin_thickness, k_fin=k_fin, h=h)\n    h_total_area_basis = (efficiency*A_fin + A_tube_showing)/A*h\n    h_bare_tube_basis = h_total_area_basis*A_increase\n    return h_bare_tube_basis\n\n\ndef dP_ESDU_high_fin(m: float, A_min: float, A_increase: float, flow_area_contraction_ratio: float,\n                     tube_diameter: float, pitch_parallel: float, pitch_normal: float, tube_rows: int,\n                     rho: float, mu: float) -> float:\n    r\"\"\"Calculates the air-side pressure drop for a high-finned tube bank\n    according to the ESDU [1]_ method, as described in [2]_. This includes the\n    effects of friction of the fin, and acceleration.\n\n    .. math::\n        \\Delta P = (K_{acc} + n_{rows} K_{f}) \\frac{1}{2}\\rho v_{max}^2\n\n    .. math::\n        K_{f} = 4.567 Re_D^{-0.242} \\left(\\frac{A}{A_{tube,only}}\n        \\right)^{0.504} \\left(\\frac{p_1}{D_o}\\right)^{-0.376}\n        \\left(\\frac{p_2}{D_{o}}\\right)^{-0.546}\n\n    .. math::\n        K_{acc} = 1 + \\text{(flow area contraction ratio)}^2\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    flow_area_contraction_ratio : float\n        Ratio of `A_min` to `A_face`, [-]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n\n    Returns\n    -------\n    dP : float\n        Overall pressure drop across the finned tube bank, [Pa]\n\n    Notes\n    -----\n    The data used by the ESDU covered:\n        * fin density 4 to 11/inch\n        * tube outer diameters 3/8 to 2 inches\n        * fin heights 1/3 to 5/8 inches\n        * fin tip to fin root diameters 1.2 to 2.4\n        * Reynolds numbers 5000 to 50000\n\n    [1]_ claims 72% of experimental points were within 10% of the results of\n    the correlation.\n\n    The Reynolds number used in this equation is that based on `V_max`,\n    calculated using the minimum flow area.\n\n    Examples\n    --------\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n    ... tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n    ... pitch_normal=0.0313, pitch_parallel=0.0271, fin_height=0.0041, corbels=True)\n\n    >>> dP_ESDU_high_fin(m=0.914, A_min=AC.A_min, A_increase=AC.A_increase, flow_area_contraction_ratio=AC.flow_area_contraction_ratio, tube_diameter=AC.tube_diameter, pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal, tube_rows=AC.tube_rows, rho=1.217,  mu=0.000018)\n    485.630768779\n\n    References\n    ----------\n    .. [1] \"High-Fin Staggered Tube Banks: Heat Transfer and Pressure Drop for\n       Turbulent Single Phase Gas Flow.\" ESDU (October 1, 1986).\n    .. [2] Hewitt, G. L. Shires T. Reg Bott G. F., George L. Shires, and\n       T. R. Bott. Process Heat Transfer. 1E. Boca Raton: CRC Press, 1994.\n    \"\"\"\n    Vmax = m/(A_min*rho)\n    Re = Vmax*tube_diameter*rho/mu\n    Kf = (4.567*Re**-0.242*(A_increase)**0.504\n          *(pitch_normal/tube_diameter)**-0.376\n          *(pitch_parallel/tube_diameter)**-0.546)\n    Ka = 1.0 + flow_area_contraction_ratio*flow_area_contraction_ratio\n    dP = (Ka + tube_rows*Kf)*0.5*rho*Vmax*Vmax\n    return dP\n\n\ndef dP_ESDU_low_fin(m: float, A_min: float, A_increase: float, flow_area_contraction_ratio: float,\n                    tube_diameter: float, fin_height: float, bare_length: float, pitch_parallel: float,\n                    pitch_normal: float, tube_rows: int, rho: float, mu: float) -> float:\n    r\"\"\"Calculates the air-side pressure drop for a low-finned tube bank\n    according to the ESDU [1]_ method, as described in [2]_. This includes the\n    effects of friction of the fin, and acceleration.\n\n    .. math::\n        \\Delta P = (K_{acc} + n_{rows} K_{f}) \\frac{1}{2}\\rho v_{max}^2\n\n    .. math::\n        K_{f} = 4.71 Re_D^{-0.286} \\left(\\frac{\\text{fin height}}\n        {\\text{bare length}}\\right)^{0.51}\n        \\left(\\frac{p_1 - D_o}{p_2 - D_o}\\right)^{0.536}\n        \\left(\\frac{D_o}{p_1 - D_o}\\right)^{0.36}\n\n    .. math::\n        K_{acc} = 1 + \\text{(flow area contraction ratio)}^2\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of air across the tube bank, [kg/s]\n    A_min : float\n        Minimum air flow area, [m^2]\n    A_increase : float\n        Ratio of actual surface area to bare tube surface area\n        :math:`A_{increase} = \\frac{A_{tube}}{A_{bare, total/tube}}`, [-]\n    flow_area_contraction_ratio : float\n        Ratio of `A_min` to `A_face`, [-]\n    tube_diameter : float\n        Diameter of the bare tube, [m]\n    fin_height : float\n        Height above bare tube of the tube fins, [m]\n    bare_length : float\n        Length of bare tube between two fins\n        :math:`\\text{bare length} = \\text{fin interval} - t_{fin}`, [m]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    rho : float\n        Average (bulk) density of air across the tube bank, [kg/m^3]\n    mu : float\n        Average (bulk) viscosity of air across the tube bank, [Pa*s]\n\n    Returns\n    -------\n    dP : float\n        Overall pressure drop across the finned tube bank, [Pa]\n\n    Notes\n    -----\n    Low fins are fins which were formed on the tube outside wall, normally\n    by the cold rolling process. The data used by the ESDU covered:\n\n    * fin density 11 to 32/inch\n    * tube outer diameters 0.5 to 1.25 inches\n    * fin heights 0.03 to 0.1 inches\n    * Reynolds numbers 1000 to 80000\n\n    [1]_ compared this correlation with 81 results and obtained a standard\n    deviation of 7.7%.\n\n    The Reynolds number used in this equation is that based on `V_max`,\n    calculated using the minimum flow area.\n\n    Examples\n    --------\n    >>> from fluids.geometry import AirCooledExchanger\n    >>> AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n    ... tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n    ... pitch_normal=0.0313, pitch_parallel=0.0271, fin_height=0.0041, corbels=True)\n\n    >>> dP_ESDU_low_fin(m=0.914, A_min=AC.A_min, A_increase=AC.A_increase,\n    ... flow_area_contraction_ratio=AC.flow_area_contraction_ratio,\n    ... tube_diameter=AC.tube_diameter, fin_height=AC.fin_height,\n    ... bare_length=AC.bare_length, pitch_parallel=AC.pitch_parallel,\n    ... pitch_normal=AC.pitch_normal, tube_rows=AC.tube_rows, rho=1.217,\n    ... mu=0.000018)\n    464.5433141865\n\n    References\n    ----------\n    .. [1] \"High-Fin Staggered Tube Banks: Heat Transfer and Pressure Drop for\n       Turbulent Single Phase Gas Flow.\" ESDU (October 1, 1986).\n    .. [2] Hewitt, G. L. Shires T. Reg Bott G. F., George L. Shires, and\n       T. R. Bott. Process Heat Transfer. 1E. Boca Raton: CRC Press, 1994.\n    \"\"\"\n    Vmax = m/(A_min*rho)\n    Re = Vmax*tube_diameter*rho/mu\n    Kf = (4.72*Re**-0.286*(fin_height/bare_length)**0.51\n          *((pitch_normal-tube_diameter)/(pitch_parallel-tube_diameter))**0.536\n          *(tube_diameter/(pitch_normal-tube_diameter))**0.36)\n    Ka = 1.0 + flow_area_contraction_ratio*flow_area_contraction_ratio\n    dP = (Ka + tube_rows*Kf)*0.5*rho*Vmax*Vmax\n    return dP\n\n\n\"\"\"Three more correlations -\n\nHeat Transfer and Pressure Drop Characteristics of Dry Tower Extended Surfaces: Data Analysis and Correlation. Pacific Northwest Laboratory, 1976.\n* said to be in common use in http://www.thermopedia.com/content/551/\n\nCao, Eduardo. Heat Transfer in Process Engineering. McGraw Hill Professional, 2009.\n\nKroger - Mirković\n\n\"\"\"\n"
  },
  {
    "path": "ht/boiling_flow.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import atan, exp, log10, pi\n\nfrom fluids.constants import g\nfrom fluids.core import Boiling, Bond, Prandtl, Weber\nfrom fluids.numerics import secant\nfrom fluids.two_phase_voidage import Lockhart_Martinelli_Xtt\n\nfrom ht.boiling_nucleic import Cooper, Forster_Zuber\nfrom ht.conv_internal import turbulent_Dittus_Boelter, turbulent_Gnielinski\n\n__all__: list[str] = [\n    \"Chen_Bennett\",\n    \"Chen_Edelstein\",\n    \"Lazarek_Black\",\n    \"Li_Wu\",\n    \"Liu_Winterton\",\n    \"Sun_Mishima\",\n    \"Thome\",\n    \"Yun_Heo_Kim\",\n]\n\n__numba_additional_funcs__ = (\"to_solve_q_Thome\",)\n\ndef Lazarek_Black(m: float, D: float, mul: float, kl: float, Hvap: float, q: float | None=None, Te: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in vertical tubes for either upward or downward flow. Correlation\n    is as shown in [1]_, and also reviewed in [2]_ and [3]_.\n\n    Either the heat flux or excess temperature is required for the calculation\n    of heat transfer coefficient.\n\n    Quality independent. Requires no properties of the gas.\n    Uses a Reynolds number assuming all the flow is liquid.\n\n    .. math::\n        h_{tp} = 30 Re_{lo}^{0.857} Bg^{0.714} \\frac{k_l}{D}\n\n    .. math::\n        Re_{lo} = \\frac{G_{tp}D}{\\mu_l}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    D : float\n        Diameter of the channel [m]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    q : float, optional\n        Heat flux to wall [W/m^2]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ has been reviewed.\n\n    [2]_ claims it was developed for a range of quality 0-0.6,\n    Relo 860-5500, mass flux 125-750 kg/m^2/s, q of 1.4-38 W/cm^2, and with a\n    pipe diameter of 3.1 mm. Developed with data for R113 only.\n\n    Examples\n    --------\n    >>> Lazarek_Black(m=10, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6, Te=100)\n    9501.932636079293\n\n    References\n    ----------\n    .. [1] Lazarek, G. M., and S. H. Black. \"Evaporative Heat Transfer,\n       Pressure Drop and Critical Heat Flux in a Small Vertical Tube with\n       R-113.\" International Journal of Heat and Mass Transfer 25, no. 7 (July\n       1982): 945-60. doi:10.1016/0017-9310(82)90070-9.\n    .. [2] Fang, Xiande, Zhanru Zhou, and Dingkun Li. \"Review of Correlations\n       of Flow Boiling Heat Transfer Coefficients for Carbon Dioxide.\"\n       International Journal of Refrigeration 36, no. 8 (December 2013):\n       2017-39. doi:10.1016/j.ijrefrig.2013.05.015.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Relo = G*D/mul\n    if q is not None:\n        Bg = Boiling(G=G, q=q, Hvap=Hvap)\n        return 30*Relo**0.857*Bg**0.714*kl/D\n    elif Te is not None:\n        # Solved with sympy\n        return 27000*30**(71/143)*(1./(G*Hvap))**(357/143)*Relo**(857/286)*Te**(357/143)*kl**(500/143)/D**(500/143)\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Li_Wu(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, kl: float, Hvap: float, sigma: float, q: float | None=None, Te: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is as shown in [1]_, and also reviewed in [2]_ and [3]_.\n\n    Either the heat flux or excess temperature is required for the calculation\n    of heat transfer coefficient. Uses liquid Reynolds number, Bond number,\n    and Boiling number.\n\n    .. math::\n        h_{tp} = 334 Bg^{0.3}(Bo\\cdot Re_l^{0.36})^{0.4}\\frac{k_l}{D}\n\n    .. math::\n        Re_{l} = \\frac{G(1-x)D}{\\mu_l}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    q : float, optional\n        Heat flux to wall [W/m^2]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ has been reviewed.\n\n    [1]_ used 18 sets of experimental data to derive the results, covering\n    hydraulic diameters from 0.19 to 3.1 mm and 12 different fluids.\n\n    Examples\n    --------\n    >>> Li_Wu(m=1, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, q=1E5)\n    5345.409399239492\n\n    References\n    ----------\n    .. [1] Li, Wei, and Zan Wu. \"A General Correlation for Evaporative Heat\n       Transfer in Micro/mini-Channels.\" International Journal of Heat and Mass\n       Transfer 53, no. 9-10 (April 2010): 1778-87.\n       doi:10.1016/j.ijheatmasstransfer.2010.01.012.\n    .. [2] Fang, Xiande, Zhanru Zhou, and Dingkun Li. \"Review of Correlations\n       of Flow Boiling Heat Transfer Coefficients for Carbon Dioxide.\"\n       International Journal of Refrigeration 36, no. 8 (December 2013):\n       2017-39. doi:10.1016/j.ijrefrig.2013.05.015.\n    .. [3] Kim, Sung-Min, and Issam Mudawar. \"Review of Databases and\n       Predictive Methods for Pressure Drop in Adiabatic, Condensing and\n       Boiling Mini/micro-Channel Flows.\" International Journal of Heat and\n       Mass Transfer 77 (October 2014): 74-97.\n       doi:10.1016/j.ijheatmasstransfer.2014.04.035.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Rel = G*D*(1-x)/mul\n    Bo = Bond(rhol=rhol, rhog=rhog, sigma=sigma, L=D)\n    if q is not None:\n        Bg = Boiling(G=G, q=q, Hvap=Hvap)\n        return 334*Bg**0.3*(Bo*Rel**0.36)**0.4*kl/D\n    elif Te is not None:\n        A = 334*(Bo*Rel**0.36)**0.4*kl/D\n        return A**(10/7.)*Te**(3/7.)/(G**(3/7.)*Hvap**(3/7.))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Sun_Mishima(m: float, D: float, rhol: float, rhog: float, mul: float, kl: float, Hvap: float, sigma: float, q: float | None=None, Te: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is as shown in [1]_, and also reviewed in [2]_.\n\n    Either the heat flux or excess temperature is required for the calculation\n    of heat transfer coefficient. Uses liquid-only Reynolds number, Weber\n    number, and Boiling number. Weber number is defined in terms of the velocity\n    if all fluid were liquid.\n\n    .. math::\n        h_{tp} = \\frac{ 6 Re_{lo}^{1.05} Bg^{0.54}}\n        {We_l^{0.191}(\\rho_l/\\rho_g)^{0.142}}\\frac{k_l}{D}\n\n    .. math::\n        Re_{lo} = \\frac{G_{tp}D}{\\mu_l}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    q : float, optional\n        Heat flux to wall [W/m^2]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ has been reviewed.\n\n    [1]_ used 2501 data points to derive the results, covering\n    hydraulic diameters from 0.21 to 6.05 mm and 11 different fluids.\n\n\n    Examples\n    --------\n    >>> Sun_Mishima(m=1, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, Te=10)\n    507.6709168372167\n\n    References\n    ----------\n    .. [1] Sun, Licheng, and Kaichiro Mishima. \"An Evaluation of Prediction\n       Methods for Saturated Flow Boiling Heat Transfer in Mini-Channels.\"\n       International Journal of Heat and Mass Transfer 52, no. 23-24 (November\n       2009): 5323-29. doi:10.1016/j.ijheatmasstransfer.2009.06.041.\n    .. [2] Fang, Xiande, Zhanru Zhou, and Dingkun Li. \"Review of Correlations\n       of Flow Boiling Heat Transfer Coefficients for Carbon Dioxide.\"\n       International Journal of Refrigeration 36, no. 8 (December 2013):\n       2017-39. doi:10.1016/j.ijrefrig.2013.05.015.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    V = G/rhol\n    Relo = G*D/mul\n    We = Weber(V=V, L=D, rho=rhol, sigma=sigma)\n    if q is not None:\n        Bg = Boiling(G=G, q=q, Hvap=Hvap)\n        return 6*Relo**1.05*Bg**0.54/(We**0.191*(rhol/rhog)**0.142)*kl/D\n    elif Te is not None:\n        A = 6*Relo**1.05/(We**0.191*(rhol/rhog)**0.142)*kl/D\n        return A**(50/23.)*Te**(27/23.)/(G**(27/23.)*Hvap**(27/23.))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Thome(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, kg: float, Cpl: float, Cpg: float, Hvap: float, sigma: float, Psat: float,\n          Pc: float, q: float | None=None, Te: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is as developed in [1]_ and [2]_, and also reviewed [3]_. This is a\n    complicated model, but expected to have more accuracy as a result.\n\n    Either the heat flux or excess temperature is required for the calculation\n    of heat transfer coefficient. The solution for a specified excess\n    temperature is solved numerically, making it slow.\n\n    .. math::\n        h(z) = \\frac{t_l}{\\tau} h_l(z) +\\frac{t_{film}}{\\tau} h_{film}(z)\n        +  \\frac{t_{dry}}{\\tau} h_{g}(z)\n\n    .. math::\n        h_{l/g}(z) = (Nu_{lam}^4 + Nu_{trans}^4)^{1/4} k/D\n\n    .. math::\n        Nu_{laminar} = 0.91 {Pr}^{1/3} \\sqrt{ReD/L(z)}\n\n    .. math::\n        Nu_{trans} = \\frac{ (f/8) (Re-1000)Pr}{1+12.7 (f/8)^{1/2} (Pr^{2/3}-1)}\n        \\left[ 1 + \\left( \\frac{D}{L(z)}\\right)^{2/3}\\right]\n\n    .. math::\n        f = (1.82 \\log_{10} Re - 1.64 )^{-2}\n\n    .. math::\n        L_l = \\frac{\\tau G_{tp}}{\\rho_l}(1-x)\n\n    .. math::\n        L_{dry} = v_p t_{dry}\n\n    .. math::\n        t_l = \\frac{\\tau}{1 + \\frac{\\rho_l}{\\rho_g}\\frac{x}{1-x}}\n\n    .. math::\n        t_v = \\frac{\\tau}{1 + \\frac{\\rho_g}{\\rho_l}\\frac{1-x}{x}}\n\n    .. math::\n        \\tau = \\frac{1}{f_{opt}}\n\n    .. math::\n        f_{opt} = \\left(\\frac{q}{q_{ref}}\\right)^{n_f}\n\n    .. math::\n        q_{ref} = 3328\\left(\\frac{P_{sat}}{P_c}\\right)^{-0.5}\n\n    .. math::\n        t_{dry,film} = \\frac{\\rho_l \\Delta H_{vap}}{q}[\\delta_0(z) -\n        \\delta_{min}]\n\n    .. math::\n        \\frac{\\delta_0}{D} = C_{\\delta 0}\\left(3\\sqrt{\\frac{\\nu_l}{v_p D}}\n        \\right)^{0.84}\\left[(0.07Bo^{0.41})^{-8} + 0.1^{-8}\\right]^{-1/8}\n\n    .. math::\n        Bo = \\frac{\\rho_l D}{\\sigma} v_p^2\n\n    .. math::\n        v_p = G_{tp} \\left[\\frac{x}{\\rho_g} + \\frac{1-x}{\\rho_l}\\right]\n\n    .. math::\n        h_{film}(z) = \\frac{2 k_l}{\\delta_0(z) + \\delta_{min}(z)}\n\n    .. math::\n        \\delta_{min} = 0.3\\cdot 10^{-6} \\text{m}\n\n    .. math::\n        C_{\\delta,0} = 0.29\n\n    .. math::\n        n_f = 1.74\n\n    if t dry film > tv:\n\n    .. math::\n        \\delta_{end}(x) = \\delta(z, t_v)\n\n    .. math::\n        t_{film} = t_v\n\n    .. math::\n        t_{dry} = 0\n\n    Otherwise:\n\n    .. math::\n        \\delta_{end}(z) = \\delta_{min}\n\n    .. math::\n        t_{film} = t_{dry,film}\n\n    .. math::\n        t_{dry} = t_v - t_{film}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    mug : float\n        Viscosity of gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    kg : float\n        Thermal conductivity of gas [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Cpg : float\n        Heat capacity of gas [J/kg/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    Psat : float\n        Vapor pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    q : float, optional\n        Heat flux to wall [W/m^2]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ and [2]_ have been reviewed, and are accurately reproduced in [3]_.\n\n    [1]_ used data from 7 studies, covering 7 fluids and Dh from 0.7-3.1 mm,\n    heat flux from 0.5-17.8 W/cm^2, x from 0.01-0.99, and G from 50-564\n    kg/m^2/s.\n\n    Liquid and/or gas slugs are both considered, and are hydrodynamically\n    developing. `Ll` is the calculated length of liquid slugs, and `L_dry`\n    is the same for vapor slugs.\n\n    Because of the complexity of the model and that there is some logic in this\n    function, `Te` as an input may lead to a different solution that the\n    calculated `q` will in return.\n\n    Examples\n    --------\n    >>> Thome(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2,\n    ... mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5,\n    ... Psat=1E5, Pc=22E6, q=1E5)\n    1633.008836502032\n\n    References\n    ----------\n    .. [1] Thome, J. R., V. Dupont, and A. M. Jacobi. \"Heat Transfer Model for\n       Evaporation in Microchannels. Part I: Presentation of the Model.\"\n       International Journal of Heat and Mass Transfer 47, no. 14-16 (July\n       2004): 3375-85. doi:10.1016/j.ijheatmasstransfer.2004.01.006.\n    .. [2] Dupont, V., J. R. Thome, and A. M. Jacobi. \"Heat Transfer Model for\n       Evaporation in Microchannels. Part II: Comparison with the Database.\"\n       International Journal of Heat and Mass Transfer 47, no. 14-16 (July\n       2004): 3387-3401. doi:10.1016/j.ijheatmasstransfer.2004.01.007.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    if q is None and Te is not None:\n        q = secant(to_solve_q_Thome, 1E4, args=( m, x, D, rhol, rhog, kl, kg, mul, mug, Cpl, Cpg, sigma, Hvap, Psat, Pc, Te))\n        return Thome(m=m, x=x, D=D, rhol=rhol, rhog=rhog, kl=kl, kg=kg, mul=mul, mug=mug, Cpl=Cpl, Cpg=Cpg, sigma=sigma, Hvap=Hvap, Psat=Psat, Pc=Pc, q=q)\n    elif q is None and Te is None:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n    C_delta0 = 0.3E-6\n    G = m/(pi/4*D**2)\n    Rel = G*D*(1-x)/mul\n    Reg = G*D*x/mug\n    qref = 3328*(Psat/Pc)**-0.5\n    if q is None:\n        q = 1e4 # Make numba happy, their bug, never gets ran\n    fopt = (q/qref)**1.74\n    tau = 1./fopt\n\n    vp = G*(x/rhog + (1-x)/rhol)\n    Bo = rhol*D/sigma*vp**2 # Not standard definition\n    nul = mul/rhol\n    delta0 = D*0.29*(3*(nul/vp/D)**0.5)**0.84*((0.07*Bo**0.41)**-8 + 0.1**-8)**(-1/8.)\n\n    tl = tau/(1 + rhol/rhog*(x/(1.-x)))\n    tv = tau/(1 + rhog/rhol*((1.-x)/x))\n\n    t_dry_film = rhol*Hvap/q*(delta0 - C_delta0)\n    if t_dry_film > tv:\n        t_film = tv\n        delta_end = delta0 - q/rhol/Hvap*tv # what could time possibly be?\n        t_dry = 0\n    else:\n        t_film = t_dry_film\n        delta_end = C_delta0\n        t_dry = tv-t_film\n    Ll = tau*G/rhol*(1-x)\n    Ldry = t_dry*vp\n\n\n    Prg = Prandtl(Cp=Cpg, k=kg, mu=mug)\n    Prl = Prandtl(Cp=Cpl, k=kl, mu=mul)\n    fg = (1.82*log10(Reg) - 1.64)**-2\n    fl = (1.82*log10(Rel) - 1.64)**-2\n\n    Nu_lam_Zl = 2*0.455*(Prl)**(1/3.)*(D*Rel/Ll)**0.5\n    Nu_trans_Zl = turbulent_Gnielinski(Re=Rel, Pr=Prl, fd=fl)*(1 + (D/Ll)**(2/3.))\n    if Ldry == 0:\n        Nu_lam_Zg, Nu_trans_Zg = 0, 0\n    else:\n        Nu_lam_Zg = 2*0.455*(Prg)**(1/3.)*(D*Reg/Ldry)**0.5\n        Nu_trans_Zg = turbulent_Gnielinski(Re=Reg, Pr=Prg, fd=fg)*(1 + (D/Ldry)**(2/3.))\n\n    h_Zg = kg/D*(Nu_lam_Zg**4 + Nu_trans_Zg**4)**0.25\n    h_Zl = kl/D*(Nu_lam_Zl**4 + Nu_trans_Zl**4)**0.25\n\n    h_film = 2*kl/(delta0 + C_delta0)\n    return tl/tau*h_Zl + t_film/tau*h_film + t_dry/tau*h_Zg\n\ndef to_solve_q_Thome(q: float, m: float, x: float, D: float, rhol: float, rhog: float, kl: float, kg: float, mul: float, mug: float, Cpl: float, Cpg: float, sigma: float, Hvap: float, Psat: float, Pc: float, Te: float) -> float:\n    err = q/Thome(m=m, x=x, D=D, rhol=rhol, rhog=rhog, kl=kl, kg=kg, mul=mul, mug=mug, Cpl=Cpl, Cpg=Cpg, sigma=sigma, Hvap=Hvap, Psat=Psat, Pc=Pc, q=q) - Te\n    return err\n\ndef Yun_Heo_Kim(m: float, x: float, D: float, rhol: float, mul: float, Hvap: float, sigma: float, q: float | None=None, Te: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is as shown in [1]_ and [2]_, and also reviewed in [3]_.\n\n    Either the heat flux or excess temperature is required for the calculation\n    of heat transfer coefficient. Uses liquid Reynolds number, Weber\n    number, and Boiling number. Weber number is defined in terms of the velocity\n    if all fluid were liquid.\n\n    .. math::\n        h_{tp} = 136876(Bg\\cdot We_l)^{0.1993} Re_l^{-0.1626}\n\n    .. math::\n        Re_l = \\frac{G D (1-x)}{\\mu_l}\n\n    .. math::\n        We_l = \\frac{G^2 D}{\\rho_l \\sigma}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    q : float, optional\n        Heat flux to wall [W/m^2]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ has been reviewed.\n\n    Examples\n    --------\n    >>> Yun_Heo_Kim(m=1, x=0.4, D=0.3, rhol=567., mul=156E-6, sigma=0.02, Hvap=9E5, q=1E4)\n    9479.313988550184\n\n    References\n    ----------\n    .. [1] Yun, Rin, Jae Hyeok Heo, and Yongchan Kim. \"Evaporative Heat\n       Transfer and Pressure Drop of R410A in Microchannels.\" International\n       Journal of Refrigeration 29, no. 1 (January 2006): 92-100.\n       doi:10.1016/j.ijrefrig.2005.08.005.\n    .. [2] Yun, Rin, Jae Hyeok Heo, and Yongchan Kim. \"Erratum to 'Evaporative\n       Heat Transfer and Pressure Drop of R410A in Microchannels; [Int. J.\n       Refrigeration 29 (2006) 92-100].\" International Journal of Refrigeration\n       30, no. 8 (December 2007): 1468. doi:10.1016/j.ijrefrig.2007.08.003.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    V = G/rhol\n    Rel = G*D*(1-x)/mul\n    We = Weber(V=V, L=D, rho=rhol, sigma=sigma)\n    if q is not None:\n        Bg = Boiling(G=G, q=q, Hvap=Hvap)\n        return 136876*(Bg*We)**0.1993*Rel**-0.1626\n    elif Te is not None:\n        A = 136876*(We)**0.1993*Rel**-0.1626*(Te/G/Hvap)**0.1993\n        return A**(10000/8007.)\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Chen_Edelstein(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, Cpl: float, Hvap: float, sigma: float,\n                   dPsat: float, Te: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is developed in [1]_ and [2]_, and reviewed in [3]_. This model is one of\n    the most often used. It uses the Dittus-Boelter correlation for turbulent\n    convection and the Forster-Zuber correlation for pool boiling, and\n    combines them with two factors `F` and `S`.\n\n\n    .. math::\n        h_{tp} = S\\cdot h_{nb} + F \\cdot h_{sp,l}\n\n    .. math::\n        h_{sp,l} = 0.023 Re_l^{0.8} Pr_l^{0.4} k_l/D\n\n    .. math::\n        Re_l = \\frac{DG(1-x)}{\\mu_l}\n\n    .. math::\n        h_{nb} = 0.00122\\left( \\frac{\\lambda_l^{0.79} c_{p,l}^{0.45}\n        \\rho_l^{0.49}}{\\sigma^{0.5} \\mu^{0.29} H_{vap}^{0.24} \\rho_g^{0.24}}\n        \\right)\\Delta T_{sat}^{0.24} \\Delta p_{sat}^{0.75}\n\n    .. math::\n        F = (1 + X_{tt}^{-0.5})^{1.78}\n\n    .. math::\n        X_{tt} = \\left( \\frac{1-x}{x}\\right)^{0.9} \\left(\\frac{\\rho_g}{\\rho_l}\n        \\right)^{0.5}\\left( \\frac{\\mu_l}{\\mu_g}\\right)^{0.1}\n\n    .. math::\n        S = 0.9622 - 0.5822\\left(\\tan^{-1}\\left(\\frac{Re_L\\cdot F^{1.25}}\n        {6.18\\cdot 10^4}\\right)\\right)\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    mug : float\n        Viscosity of gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    dPsat : float\n        Difference in Saturation pressure of fluid at Te and T, [Pa]\n    Te : float\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ and [2]_ have been reviewed, but the model is only put together in\n    the review of [3]_. Many other forms of this equation exist with different\n    functions for `F` and `S`.\n\n    Examples\n    --------\n    >>> Chen_Edelstein(m=0.106, x=0.2, D=0.0212, rhol=567, rhog=18.09,\n    ... mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730, Hvap=2E5, sigma=0.02,\n    ... dPsat=1E5, Te=3)\n    3289.058731974052\n\n    See Also\n    --------\n    turbulent_Dittus_Boelter\n    Forster_Zuber\n\n    References\n    ----------\n    .. [1] Chen, J. C. \"Correlation for Boiling Heat Transfer to Saturated\n       Fluids in Convective Flow.\" Industrial & Engineering Chemistry Process\n       Design and Development 5, no. 3 (July 1, 1966): 322-29.\n       doi:10.1021/i260019a023.\n    .. [2] Edelstein, Sergio, A. J. Pérez, and J. C. Chen. \"Analytic\n       Representation of Convective Boiling Functions.\" AIChE Journal 30, no.\n       5 (September 1, 1984): 840-41. doi:10.1002/aic.690300528.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Rel = D*G*(1-x)/mul\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    hl = turbulent_Dittus_Boelter(Re=Rel, Pr=Prl)*kl/D\n\n    Xtt = Lockhart_Martinelli_Xtt(x=x, rhol=rhol, rhog=rhog, mul=mul, mug=mug)\n    F = (1 + Xtt**-0.5)**1.78\n    Re = Rel*F**1.25\n    S = 0.9622 - 0.5822*atan(Re/6.18E4)\n    hnb = Forster_Zuber(Te=Te, dPsat=dPsat, Cpl=Cpl, kl=kl, mul=mul, sigma=sigma,\n                       Hvap=Hvap, rhol=rhol, rhog=rhog)\n    return hnb*S + hl*F\n\n\ndef Chen_Bennett(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, Cpl: float, Hvap: float, sigma: float,\n                   dPsat: float, Te: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is developed in [1]_ and [2]_, and reviewed in [3]_. This model is one of\n    the most often used, and replaces the `Chen_Edelstein` correlation. It uses\n    the Dittus-Boelter correlation for turbulent convection and the\n    Forster-Zuber correlation for pool boiling, and combines them with two\n    factors `F` and `S`.\n\n    .. math::\n        h_{tp} = S\\cdot h_{nb} + F \\cdot h_{sp,l}\n\n    .. math::\n       h_{sp,l} = 0.023 Re_l^{0.8} Pr_l^{0.4} k_l/D\n\n    .. math::\n       Re_l = \\frac{DG(1-x)}{\\mu_l}\n\n    .. math::\n       h_{nb} = 0.00122\\left( \\frac{\\lambda_l^{0.79} c_{p,l}^{0.45}\n        \\rho_l^{0.49}}{\\sigma^{0.5} \\mu^{0.29} H_{vap}^{0.24} \\rho_g^{0.24}}\n        \\right)\\Delta T_{sat}^{0.24} \\Delta p_{sat}^{0.75}\n\n    .. math::\n       F = \\left(\\frac{Pr_1+1}{2}\\right)^{0.444}\\cdot (1+X_{tt}^{-0.5})^{1.78}\n\n    .. math::\n       S = \\frac{1-\\exp(-F\\cdot h_{conv} \\cdot X_0/k_l)}\n        {F\\cdot h_{conv}\\cdot X_0/k_l}\n\n    .. math::\n       X_{tt} = \\left( \\frac{1-x}{x}\\right)^{0.9} \\left(\\frac{\\rho_g}{\\rho_l}\n        \\right)^{0.5}\\left( \\frac{\\mu_l}{\\mu_g}\\right)^{0.1}\n\n    .. math::\n       X_0 = 0.041 \\left(\\frac{\\sigma}{g \\cdot (\\rho_l-\\rho_v)}\\right)^{0.5}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    mug : float\n        Viscosity of gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of liquid [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    dPsat : float\n        Difference in Saturation pressure of fluid at Te and T, [Pa]\n    Te : float\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ and [2]_ have been reviewed, but the model is only put together in\n    the review of [3]_. Many other forms of this equation exist with different\n    functions for `F` and `S`.\n\n    Examples\n    --------\n    >>> Chen_Bennett(m=0.106, x=0.2, D=0.0212, rhol=567, rhog=18.09,\n    ... mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730, Hvap=2E5, sigma=0.02,\n    ... dPsat=1E5, Te=3)\n    4938.275351219369\n\n    See Also\n    --------\n    Chen_Edelstein\n    turbulent_Dittus_Boelter\n    Forster_Zuber\n\n    References\n    ----------\n    .. [1] Bennett, Douglas L., and John C. Chen. \"Forced Convective Boiling in\n       Vertical Tubes for Saturated Pure Components and Binary Mixtures.\"\n       AIChE Journal 26, no. 3 (May 1, 1980): 454-61. doi:10.1002/aic.690260317.\n    .. [2] Bennett, Douglas L., M.W. Davies and B.L. Hertzler, The Suppression\n       of Saturated Nucleate Boiling by Forced Convective Flow, American\n       Institute of Chemical Engineers Symposium Series, vol. 76, no. 199.\n       91-103, 1980.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Rel = D*G*(1-x)/mul\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    hl = turbulent_Dittus_Boelter(Re=Rel, Pr=Prl)*kl/D\n    Xtt = Lockhart_Martinelli_Xtt(x=x, rhol=rhol, rhog=rhog, mul=mul, mug=mug)\n    F = ((Prl+1)/2.)**0.444*(1 + Xtt**-0.5)**1.78\n    X0 = 0.041*(sigma/(g*(rhol-rhog)))**0.5\n    S = (1 - exp(-F*hl*X0/kl))/(F*hl*X0/kl)\n\n    hnb = Forster_Zuber(Te=Te, dPsat=dPsat, Cpl=Cpl, kl=kl, mul=mul, sigma=sigma,\n                       Hvap=Hvap, rhol=rhol, rhog=rhog)\n    return hnb*S + hl*F\n\n\ndef Liu_Winterton(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, kl: float, Cpl: float, MW: float, P: float,  Pc: float, Te: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for film boiling of saturated\n    fluid in any orientation of flow. Correlation\n    is as developed in [1]_, also reviewed in [2]_ and [3]_.\n\n    Excess wall temperature is required to use this correlation.\n\n    .. math::\n        h_{tp} = \\sqrt{ (F\\cdot h_l)^2 + (S\\cdot h_{nb})^2}\n\n    .. math::\n       S = \\left( 1+0.055F^{0.1} Re_{L}^{0.16}\\right)^{-1}\n\n    .. math::\n       h_{l} = 0.023 Re_L^{0.8} Pr_l^{0.4} k_l/D\n\n    .. math::\n       Re_L = \\frac{GD}{\\mu_l}\n\n    .. math::\n       F = \\left[ 1+ xPr_{l}(\\rho_l/\\rho_g-1)\\right]^{0.35}\n\n    .. math::\n       h_{nb} = \\left(55\\Delta Te^{0.67} \\frac{P}{P_c}^{(0.12 - 0.2\\log_{10}\n         R_p)}(-\\log_{10} \\frac{P}{P_c})^{-0.55} MW^{-0.5}\\right)^{1/0.33}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    MW : float\n        Molecular weight of the fluid, [g/mol]\n    P : float\n        Pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    Te : float, optional\n        Excess temperature of wall, [K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ has been reviewed, and is accurately reproduced in [3]_.\n\n    Uses the `Cooper` and `turbulent_Dittus_Boelter` correlations.\n\n    A correction for horizontal flow at low Froude numbers is available in\n    [1]_ but has not been implemented and is not recommended in several\n    sources.\n\n    Examples\n    --------\n    >>> Liu_Winterton(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086,\n    ... mul=156E-6, Cpl=2300, P=1E6, Pc=22E6, MW=44.02, Te=7)\n    4747.749477190532\n\n    References\n    ----------\n    .. [1] Liu, Z., and R. H. S. Winterton. \"A General Correlation for\n       Saturated and Subcooled Flow Boiling in Tubes and Annuli, Based on a\n       Nucleate Pool Boiling Equation.\" International Journal of Heat and Mass\n       Transfer 34, no. 11 (November 1991): 2759-66.\n       doi:10.1016/0017-9310(91)90234-6.\n    .. [2] Fang, Xiande, Zhanru Zhou, and Dingkun Li. \"Review of Correlations\n       of Flow Boiling Heat Transfer Coefficients for Carbon Dioxide.\"\n       International Journal of Refrigeration 36, no. 8 (December 2013):\n       2017-39. doi:10.1016/j.ijrefrig.2013.05.015.\n    .. [3] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    ReL = D*G/mul\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    hl = turbulent_Dittus_Boelter(Re=ReL, Pr=Prl)*kl/D\n    F = (1 + x*Prl*(rhol/rhog - 1))**0.35\n    S = (1 + 0.055*F**0.1*ReL**0.16)**-1\n    h_nb = Cooper(Te=Te, P=P, Pc=Pc, MW=MW)\n    return ((F*hl)**2 + (S*h_nb)**2)**0.5\n"
  },
  {
    "path": "ht/boiling_nucleic.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import log10\n\nfrom fluids.constants import g\n\n__all__: list[str] = [\n    \"Bier\",\n    \"Cooper\",\n    \"Forster_Zuber\",\n    \"Gorenflo\",\n    \"HEDH_Montinsky\",\n    \"HEDH_Taborek\",\n    \"McNelly\",\n    \"Montinsky\",\n    \"Rohsenow\",\n    \"Serth_HEDH\",\n    \"Stephan_Abdelsalam\",\n    \"Zuber\",\n    \"h0_Gorenflow_1993\",\n    \"h0_VDI_2e\",\n    \"h_nucleic\",\n    \"h_nucleic_all_methods\",\n    \"h_nucleic_methods\",\n    \"qmax_boiling\",\n    \"qmax_boiling_all_methods\",\n    \"qmax_boiling_methods\",\n]\n\n\ndef Rohsenow(rhol: float, rhog: float, mul: float, kl: float, Cpl: float, Hvap: float, sigma: float, Te: float | None=None, q: float | None=None, Csf: float=0.013,\n             n: float=1.7) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = {{\\mu }_{L}} \\Delta H_{vap} \\left[ \\frac{g( \\rho_L-\\rho_v)}\n        {\\sigma } \\right]^{0.5}\\left[\\frac{C_{p,L}\\Delta T_e^{2/3}}{C_{sf}\n        \\Delta H_{vap} Pr_L^n}\\right]^3\n\n    With `q` specified:\n\n    .. math::\n        h = \\left({{\\mu }_{L}} \\Delta H_{vap} \\left[ \\frac{g( \\rho_L-\\rho_v)}\n        {\\sigma } \\right]^{0.5}\\left[\\frac{C_{p,L}\\Delta T_e^{2/3}}{C_{sf}\n        \\Delta H_{vap} Pr_L^n}\\right]^3\\right)^{1/3}q^{2/3}\n\n    Parameters\n    ----------\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n    Csf : float\n        Rohsenow coefficient specific to fluid and metal [-]\n    n : float\n        Constant, 1 for water, 1.7 (default) for other fluids usually [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    No further work is required on this correlation. Multiple sources confirm\n    its form and rearrangement.\n\n    Examples\n    --------\n    h for water at atmospheric pressure on oxidized aluminum.\n\n    >>> Rohsenow(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217,\n    ... Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26)\n    3723.655267067467\n\n    References\n    ----------\n    .. [1] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [2] Rohsenow, Warren M. \"A Method of Correlating Heat Transfer Data for\n       Surface Boiling of Liquids.\" Technical Report. Cambridge, Mass. : M.I.T.\n       Division of Industrial Cooporation, 1951\n    \"\"\"\n    if Te is not None:\n        return mul*Hvap*(g*(rhol-rhog)/sigma)**0.5*(Cpl*Te**(2/3.)/Csf/Hvap/(Cpl*mul/kl)**n)**3\n    elif q is not None:\n        A = mul*Hvap*(g*(rhol-rhog)/sigma)**0.5*(Cpl/Csf/Hvap/(Cpl*mul/kl)**n)**3\n        return A**(1/3.)*q**(2/3.)\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef McNelly(rhol: float, rhog: float, kl: float, Cpl: float, Hvap: float, sigma: float, P: float, Te: float | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = \\left(0.225\\left(\\frac{\\Delta T_e C_{p,l}}{H_{vap}}\\right)^{0.69}\n        \\left(\\frac{P k_L}{\\sigma}\\right)^{0.31}\n        \\left(\\frac{\\rho_L}{\\rho_V}-1\\right)^{0.33}\\right)^{1/0.31}\n\n    With `q` specified:\n\n    .. math::\n        h = 0.225\\left(\\frac{q C_{p,l}}{H_{vap}}\\right)^{0.69} \\left(\\frac{P\n        k_L}{\\sigma}\\right)^{0.31}\\left(\\frac{\\rho_L}{\\rho_V}-1\\right)^{0.33}\n\n    Parameters\n    ----------\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Further examples for this function are desired.\n\n    Examples\n    --------\n    Water boiling, with excess temperature of 4.3 K.\n\n    >>> McNelly(Te=4.3, P=101325, Cpl=4180., kl=0.688, sigma=0.0588,\n    ... Hvap=2.25E6, rhol=958., rhog=0.597)\n    533.8056972951352\n\n    References\n    ----------\n    .. [1] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [2] McNelly M. J.: \"A correlation of the rates of heat transfer to n\n       ucleate boiling liquids,\" J. Imp Coll. Chem Eng Soc 7:18, 1953.\n    \"\"\"\n    if Te is not None:\n        return (0.225*(Te*Cpl/Hvap)**0.69*(P*kl/sigma)**0.31*(rhol/rhog-1.)**0.33\n            )**(1./0.31)\n    elif q is not None:\n        return 0.225*(q*Cpl/Hvap)**0.69*(P*kl/sigma)**0.31*(rhol/rhog-1.)**0.33\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Forster_Zuber(rhol: float, rhog: float, mul: float, kl: float, Cpl: float, Hvap: float, sigma: float, dPsat: float, Te: float | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = 0.00122\\left(\\frac{k_L^{0.79} C_{p,l}^{0.45}\\rho_L^{0.49}}\n        {\\sigma^{0.5}\\mu_L^{0.29} H_{vap}^{0.24} \\rho_V^{0.24}}\\right)\n        \\Delta T_e^{0.24} \\Delta P_{sat}^{0.75}\n\n    With `q` specified:\n\n    .. math::\n        h = \\left[0.00122\\left(\\frac{k_L^{0.79} C_{p,l}^{0.45}\\rho_L^{0.49}}\n        {\\sigma^{0.5}\\mu_L^{0.29} H_{vap}^{0.24} \\rho_V^{0.24}}\\right) \\Delta\n        P_{sat}^{0.75} q^{0.24}\\right]^{\\frac{1}{1.24}}\n\n    Parameters\n    ----------\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    dPsat : float\n        Difference in saturation pressure of the fluid at Te and T, [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Examples have been found in [1]_ and [3]_ and match exactly.\n\n    Examples\n    --------\n    Water boiling, with excess temperature of 4.3K from [1]_.\n\n    >>> Forster_Zuber(Te=4.3, dPsat=3906*4.3, Cpl=4180., kl=0.688,\n    ... mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    3519.9239897462644\n\n    References\n    ----------\n    .. [1] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [2] Forster, H. K., and N. Zuber. \"Dynamics of Vapor Bubbles and Boiling\n       Heat Transfer.\" AIChE Journal 1, no. 4 (December 1, 1955): 531-35.\n       doi:10.1002/aic.690010425.\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    if Te is not None:\n        return 0.00122*(kl**0.79*Cpl**0.45*rhol**0.49/sigma**0.5/mul**0.29/Hvap**0.24/rhog**0.24)*Te**0.24*dPsat**0.75\n    elif q is not None:\n        return (0.00122*(kl**0.79*Cpl**0.45*rhol**0.49/sigma**0.5/mul**0.29/Hvap**0.24/rhog**0.24)*q**0.24*dPsat**0.75)**(1/1.24)\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Montinsky(P: float, Pc: float, Te: float | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = \\left(0.00417P_c^{0.69} \\Delta Te^{0.7}\\left[1.8(P/P_c)^{0.17} +\n        4(P/P_c)^{1.2} + 10(P/P_c)^{10}\\right]\\right)^{1/0.3}\n\n    With `q` specified:\n\n    .. math::\n        h = 0.00417P_c^{0.69} q^{0.7}\\left[1.8(P/P_c)^{0.17} + 4(P/P_c)^{1.2}\n        + 10(P/P_c)^{10}\\right]\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Formulas has been found consistent in all cited sources. Examples have\n    been found in [1]_ and [3]_.\n\n    The equation for this function is sometimes given with a constant of 3.7E-5\n    instead of 0.00417 if critical pressure is not internally\n    converted to kPa. [3]_ lists a constant of 3.596E-5.\n\n    Examples\n    --------\n    Water boiling at 1 atm, with excess temperature of 4.3K from [1]_.\n\n    >>> Montinsky(P=101325, Pc=22048321, Te=4.3)\n    1185.0509770292663\n\n    References\n    ----------\n    .. [1] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [2] Mostinsky I. L.: \"Application of the rule of corresponding states\n       for the calculation of heat transfer and critical heat flux,\"\n       Teploenergetika 4:66, 1963 English Abstr. Br Chem Eng 8(8):586, 1963\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [4] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    if Te is not None:\n        return (0.00417*(Pc/1000.)**0.69*Te**0.7*(1.8*(P/Pc)**0.17 + 4*(P/Pc)**1.2\n        +10*(P/Pc)**10))**(1/0.3)\n    elif q is not None:\n        return (0.00417*(Pc/1000.)**0.69*q**0.7*(1.8*(P/Pc)**0.17 + 4*(P/Pc)**1.2\n        +10*(P/Pc)**10))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\n_angles_Stephan_Abdelsalam = {\"general\": 35, \"water\": 45, \"hydrocarbon\": 35,\n\"cryogenic\": 1, \"refrigerant\": 35}\n\ndef Stephan_Abdelsalam(rhol: float, rhog: float, mul: float, kl: float, Cpl: float, Hvap: float, sigma: float, Tsat: float, Te: float | None=None,\n                       q: float | None=None, kw: float=401.0, rhow: float=8.96, Cpw: float=384.0, angle: float | None=None,\n                       correlation: str=\"general\") -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n    Five variants are possible.\n\n    Either heat flux or excess temperature is required. The forms for `Te` are\n    not shown here, but are similar to those of the other functions.\n\n    .. math::\n        h = 0.23X_1^{0.674} X_2^{0.35} X_3^{0.371} X_5^{0.297} X_8^{-1.73} k_L/d_B\n\n    .. math::\n        X1 = \\frac{q D_d}{K_L T_{sat}}\n\n    .. math::\n        X2 = \\frac{\\alpha^2 \\rho_L}{\\sigma D_d}\n\n    .. math::\n        X3 = \\frac{C_{p,L} T_{sat} D_d^2}{\\alpha^2}\n\n    .. math::\n        X4 = \\frac{H_{vap} D_d^2}{\\alpha^2}\n\n    .. math::\n        X5 = \\frac{\\rho_V}{\\rho_L}\n\n    .. math::\n        X6 = \\frac{C_{p,l} \\mu_L}{k_L}\n\n    .. math::\n        X7 = \\frac{\\rho_W C_{p,W} k_W}{\\rho_L C_{p,L} k_L}\n\n    .. math::\n        X8 = \\frac{\\rho_L-\\rho_V}{\\rho_L}\n\n    .. math::\n        D_b = 0.0146\\theta\\sqrt{\\frac{2\\sigma}{g(\\rho_L-\\rho_g)}}\n\n    Respectively, the following four correlations are for water, hydrocarbons,\n    cryogenic fluids, and refrigerants.\n\n    .. math::\n        h = 0.246\\times 10^7 X1^{0.673} X4^{-1.58} X3^{1.26}X8^{5.22}k_L/d_B\n\n    .. math::\n        h = 0.0546 X5^{0.335} X1^{0.67} X8^{-4.33} X4^{0.248}k_L/d_B\n\n    .. math::\n        h = 4.82 X1^{0.624} X7^{0.117} X3^{0.374} X4^{-0.329}X5^{0.257} k_L/d_B\n\n    .. math::\n        h = 207 X1^{0.745} X5^{0.581} X6^{0.533} k_L/d_B\n\n    Parameters\n    ----------\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    Tsat : float\n        Saturation temperature at operating pressure [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n    kw : float, optional\n        Thermal conductivity of wall (only for cryogenics) [W/m/K]\n    rhow : float, optional\n        Density of the wall (only for cryogenics) [kg/m^3]\n    Cpw : float, optional\n        Heat capacity of wall (only for cryogenics) [J/kg/K]\n    angle : float, optional\n        Contact angle of bubble with wall [degrees]\n    correlation : str, optional\n        Any of 'general', 'water', 'hydrocarbon', 'cryogenic', or 'refrigerant'\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    If cryogenic correlation is selected, metal properties are used. Default\n    values are the properties of copper at STP.\n\n    The angle is selected automatically if a correlation is selected; if angle\n    is provided anyway, the automatic selection is ignored. A IndexError\n    exception is raised if the correlation is not in the dictionary\n    _angles_Stephan_Abdelsalam.\n\n    Examples\n    --------\n    Example is from [3]_ and matches.\n\n    >>> Stephan_Abdelsalam(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6,\n    ... sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, angle=35)\n    26722.441071108373\n\n    References\n    ----------\n    .. [1] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [2] Stephan, K., and M. Abdelsalam. \"Heat-Transfer Correlations for\n       Natural Convection Boiling.\" International Journal of Heat and Mass\n       Transfer 23, no. 1 (January 1980): 73-87.\n       doi:10.1016/0017-9310(80)90140-4.\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    if Te is None and q is None:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n    if correlation == \"water\":\n        angle = 45.0\n    elif correlation == \"cryogenic\":\n        angle = 1.0\n    elif True:\n        angle = 35.0\n\n    db = 0.0146*angle*(2*sigma/g/(rhol-rhog))**0.5\n    diffusivity_L = kl/rhol/Cpl\n\n    if Te is not None:\n        X1 = db/kl/Tsat*Te\n    elif q is not None:\n        X1 = db/kl/Tsat*q\n    X2 = diffusivity_L**2*rhol/sigma/db\n    X3 = Hvap*db**2/diffusivity_L**2\n    X4 = Hvap*db**2/diffusivity_L**2\n    X5 = rhog/rhol\n    X6 = Cpl*mul/kl\n    X7 = rhow*Cpw*kw/(rhol*Cpl*kl)\n    X8 = (rhol-rhog)/rhol\n\n    if correlation == \"general\":\n        if Te is not None:\n            h = (0.23*X1**0.674*X2**0.35*X3**0.371*X5**0.297*X8**-1.73*kl/db)**(1/0.326)\n        else:\n            h = (0.23*X1**0.674*X2**0.35*X3**0.371*X5**0.297*X8**-1.73*kl/db)\n    elif correlation == \"water\":\n        if Te is not None:\n            h = (0.246E7*X1**0.673*X4**-1.58*X3**1.26*X8**5.22*kl/db)**(1/0.327)\n        else:\n            h = (0.246E7*X1**0.673*X4**-1.58*X3**1.26*X8**5.22*kl/db)\n    elif correlation == \"hydrocarbon\":\n        if Te is not None:\n            h = (0.0546*X5**0.335*X1**0.67*X8**-4.33*X4**0.248*kl/db)**(1/0.33)\n        else:\n            h = (0.0546*X5**0.335*X1**0.67*X8**-4.33*X4**0.248*kl/db)\n    elif correlation == \"cryogenic\":\n        if Te is not None:\n            h = (4.82*X1**0.624*X7**0.117*X3**0.374*X4**-0.329*X5**0.257*kl/db)**(1/0.376)\n        else:\n            h = (4.82*X1**0.624*X7**0.117*X3**0.374*X4**-0.329*X5**0.257*kl/db)\n    else:\n        if Te is not None:\n            h = (207*X1**0.745*X5**0.581*X6**0.533*kl/db)**(1/0.255)\n        else:\n            h = (207*X1**0.745*X5**0.581*X6**0.533*kl/db)\n    return h\n\n\ndef HEDH_Taborek(P: float, Pc: float, Te: float | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to Taborek (1986)\n    as described in [1]_ and as presented in [2]_. Modification of [3]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = \\left(0.00417P_c^{0.69} \\Delta Te^{0.7}\\left[2.1P_r^{0.27} +\n        \\left(9 + (1-Pr^2)^{-1}\\right)P_r^2 \\right]\\right)^{1/0.3}\n\n    With `q` specified:\n\n    .. math::\n        h = 0.00417P_c^{0.69} q^{0.7}\\left[2.1P_r^{0.27} + \\left(9 + (1-Pr^2\n        )^{-1}\\right)P_r^2\\right]\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Example is from [3]_ and matches to within the error of the algebraic\n    manipulation rounding.\n\n    Examples\n    --------\n    >>> HEDH_Taborek(Te=16.2, P=310.3E3, Pc=2550E3)\n    1397.272486525486\n\n    References\n    ----------\n    .. [1] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [2] Mostinsky I. L.: \"Application of the rule of corresponding states\n       for the calculation of heat transfer and critical heat flux,\"\n       Teploenergetika 4:66, 1963 English Abstr. Br Chem Eng 8(8):586, 1963\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    Pr = P/Pc\n    if Te is not None:\n        return (0.00417*(Pc/1000.)**0.69*Te**0.7*(2.1*Pr**0.27\n        + (9 + 1./(1-Pr**2))*Pr**2))**(1/0.3)\n    elif q is not None:\n        return (0.00417*(Pc/1000.)**0.69*q**0.7*(2.1*Pr**0.27\n        + (9 + 1./(1-Pr**2))*Pr**2))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Bier(P: float, Pc: float, Te: float | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [1]_ .\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = \\left(0.00417P_c^{0.69} \\Delta Te^{0.7}\\left[0.7 + 2P_r\\left(4 +\n        \\frac{1}{1-P_r}\\right)  \\right]\\right)^{1/0.3}\n\n    With `q` specified:\n\n    .. math::\n        h = 0.00417P_c^{0.69} \\Delta q^{0.7}\\left[0.7 + 2P_r\\left(4 +\n        \\frac{1}{1-P_r}\\right)  \\right]\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    No examples of this are known. Seems to give very different results than\n    other correlations.\n\n    Examples\n    --------\n    Water boiling at 1 atm, with excess temperature of 4.3 K from [1]_.\n\n    >>> Bier(101325., 22048321.0, Te=4.3)\n    1290.5349471503353\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    Pr = P/Pc\n    if Te is not None:\n        return (0.00417*(Pc/1000.)**0.69*Te**0.7*(0.7 + 2.*Pr*(4. + 1./(1.-Pr))))**(1./0.3)\n    elif q is not None:\n        return 0.00417*(Pc/1000.)**0.69*q**0.7*(0.7 + 2.*Pr*(4. + 1./(1. - Pr)))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\ndef Cooper(P: float, Pc: float, MW: float, Te: float | None=None, q: float | None=None, Rp: float=1E-6) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a evaporator operating\n    in the nucleate boiling regime according to [2]_ as presented in [1]_.\n\n    Either heat flux or excess temperature is required.\n\n    With `Te` specified:\n\n    .. math::\n        h = \\left(55\\Delta Te^{0.67} \\frac{P}{P_c}^{(0.12 - 0.2\\log_{10} R_p)}\n        (-\\log_{10} \\frac{P}{P_c})^{-0.55} MW^{-0.5}\\right)^{1/0.33}\n\n    With `q` specified:\n\n    .. math::\n        h = 55q^{0.67} \\frac{P}{P_c}^{(0.12 - 0.2\\log_{10} R_p)}(-\\log_{10}\n        \\frac{P}{P_c})^{-0.55} MW^{-0.5}\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    MW : float\n        Molecular weight of fluid, [g/mol]\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n    Rp : float, optional\n        Roughness parameter of the surface (1 micrometer default) used by\n        `Cooper` method, [m]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Examples 1 and 2 are for water and benzene, from [1]_.\n    Roughness parameter is with an old definition. Accordingly, it is\n    not used by the h function.\n    If unchanged, the roughness parameter's logarithm gives a value of 0.12\n    as an exponent of reduced pressure.\n\n    Examples\n    --------\n    Water boiling at 1 atm, with excess temperature of 4.3 K from [1]_.\n\n    >>> Cooper(P=101325., Pc=22048321.0, MW=18.02, Te=4.3)\n    1558.1435442153575\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] M. G. Cooper, \"Saturation and Nucleate Pool Boiling: A Simple\n       Correlation,\" Inst. Chem. Eng. Syrup. Ser. (86/2): 785, 1984.\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    Rp*= 1E6\n    if Te is not None:\n        return (55*Te**0.67*(P/Pc)**(0.12 - 0.2*log10(Rp))*(\n             -log10(P/Pc))**-0.55*MW**-0.5)**(1/0.33)\n    elif q is not None:\n        return (55*q**0.67*(P/Pc)**(0.12 - 0.2*log10(Rp))*(\n             -log10(P/Pc))**-0.55*MW**-0.5)\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\nh0_Gorenflow_1993 = {\"74-82-8\": 7000.0, \"74-84-0\": 4500.0, \"74-98-6\": 4000.0,\n\"106-97-8\": 3600.0, \"109-66-0\": 3400.0, \"78-78-4\": 2500.0, \"110-54-3\": 3300.0,\n\"142-82-5\": 3200.0, \"71-43-2\": 2900.0, \"108-88-3\": 2800.0, \"92-52-4\": 2100.0,\n\"67-56-1\": 5400.0, \"64-17-5\": 4400.0, \"71-23-8\": 3800.0, \"67-63-0\": 3000.0,\n\"71-36-3\": 2600.0, \"78-83-1\": 4500.0, \"67-64-1\": 3300.0, \"75-69-4\": 2800.0,\n\"75-71-8\": 4000.0, \"75-72-9\": 3900.0, \"75-63-8\": 3500.0, \"75-45-6\": 3900.0,\n\"75-46-7\": 4400.0, \"76-13-1\": 2650.0, \"76-14-2\": 3800.0, \"76-15-3\": 3200.0,\n\"811-97-2\": 4500.0, \"28987-04-4\": 3700.0, \"431-89-0\": 3800.0, \"115-25-3\": 4200.0,\n\"74-87-3\": 4400.0, \"56-23-5\": 3200.0, \"75-73-0\": 4750.0, \"7732-18-5\": 5600.0,\n\"7664-41-7\": 7000.0, \"124-38-9\": 5100.0, \"2551-62-4\": 3700.0, \"7782-44-7\": 9500.0,\n\"7727-37-9\": 10000.0, \"7440-37-1\": 8200.0, \"7440-01-9\": 20000.0, \"1333-74-0\": 24000.0,\n\"7440-59-7\": 2000.0}\nIS_NUMBA = \"IS_NUMBA\" in globals()\nif IS_NUMBA:\n    h0_Gorenflow_1993_keys = tuple(h0_Gorenflow_1993.keys())\n    h0_Gorenflow_1993_values = tuple(h0_Gorenflow_1993.values())\n\ndef Gorenflo(P: float, Pc: float, q: float | None=None, Te: float | None=None, CASRN: str | None=None, h0: float | None=None, Ra: float=4E-7) -> float:\n    r\"\"\"Calculates heat transfer coefficient for a pool boiling according to\n    [1]_ and also presented in [2]_. Calculation is based on the corresponding\n    states law, with a single regression constant per fluid. P and Pc are\n    always required.\n\n    Either `q` or `Te` may be specified. Either `CASRN` or `h0` may be\n    specified as well. If `CASRN` is specified and the fluid is not in the\n    list of those studied, an error is raises.\n\n    .. math::\n        \\frac{h}{h_0} = C_W F(p^*) \\left(\\frac{q}{q_0}\\right)^n\n\n    .. math::\n        C_W = \\left(\\frac{R_a}{R_{ao}}\\right)^{0.133}\n\n    .. math::\n        q_0 = 20 \\;000 \\frac{\\text{W}}{\\text{m}^{2}}\n\n    .. math::\n        R_{ao} = 0.4 \\mu\\text{m}\n\n    For fluids other than water:\n\n    .. math::\n        n = 0.9 - 0.3 p^{*0.3}\n\n    .. math::\n        f(p^*) = 1.2p^{*0.27} + \\left(2.5 + \\frac{1}{1-p^*}\\right)p^*\n\n    For water:\n\n    .. math::\n        n = 0.9 - 0.3 p^{*0.15}\n\n    .. math::\n        f(p^*) = 1.73p^{*0.27} + \\left(6.1 + \\frac{0.68}{1-p^*}\\right)p^2\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n    q : float, optional\n        Heat flux, [W/m^2]\n    Te : float, optional\n        Excess wall temperature, [K]\n    CASRN : str, optional\n        CASRN of fluid\n    h0 : float\n        Reference heat transfer coefficient for Gorenflo method, [W/m^2/K]\n    Ra : float, optional\n        Roughness parameter of the surface (0.4 micrometer default) for\n        Gorenflo method, [m]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    A more recent set of reference heat fluxes is available. Where a range of\n    values was listed for reference heat fluxes in [1]_, values from the\n    second edition of [1]_ were used instead. 44 values are available, all\n    listed in the dictionary `h0_Gorenflow_1993`. Values range from 2000\n    to 24000 W/m^2/K.\n\n    Examples\n    --------\n    Water boiling at 3 bar and a heat flux of 2E4 W/m^2/K.\n\n    >>> Gorenflo(3E5, 22048320., q=2E4, CASRN='7732-18-5')\n    3043.344595525422\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, VDI. VDI Heat Atlas. Dusseldorf: V.D.I. Verlag,\n       1993. http://digital.ub.uni-paderborn.de/hs/download/pdf/41898?originalFilename=true\n    .. [2] Bertsch, Stefan S., Eckhard A. Groll, and Suresh V. Garimella.\n       \"Review and Comparative Analysis of Studies on Saturated Flow Boiling in\n       Small Channels.\" Nanoscale and Microscale Thermophysical Engineering 12,\n       no. 3 (September 4, 2008): 187-227. doi:10.1080/15567260802317357.\n    \"\"\"\n    Pr = P/Pc\n    Ra0 = 0.4E-6\n    q0 = 2E4\n    if h0 is None: # NUMBA: DELETE\n        try:\n            h0 = h0_Gorenflow_1993[CASRN]\n        except:\n            raise ValueError(\"Reference heat transfer coefficient not known\")\n    if h0 is None:\n        try:\n            h0 = h0_Gorenflow_1993_values[h0_Gorenflow_1993_keys.index(CASRN)]\n        except:\n            raise ValueError(\"Reference heat transfer coefficient not known\")\n    if CASRN != \"7732-18-5\":\n        # Case for not dealing with water\n        n = 0.9 - 0.3*Pr**0.3\n        Fp = 1.2*Pr**0.27 + (2.5 + 1/(1-Pr))*Pr\n    else:\n        # Case for water\n        n = 0.9 - 0.3*Pr**0.15\n        Fp = 1.73*Pr**0.27 + (6.1 + 0.68/(1-Pr))*Pr**2\n    CW = (Ra/Ra0)**0.133\n    if q is not None:\n        return h0*CW*Fp*(q/q0)**n\n    elif Te is not None:\n        A = h0*CW*Fp*(Te/q0)**n\n        return A**(-1./(n - 1.))\n    else:\n        raise ValueError(\"Either q or Te is needed for this correlation\")\n\n\nh0_VDI_2e = {\"74-82-8\": 7200.0, \"74-85-1\": 4200.0, \"74-84-0\": 4600.0,\n\"115-07-1\": 4200.0, \"74-98-6\": 4300.0, \"106-97-8\": 3600.0, \"75-28-5\": 3700.0,\n\"109-66-0\": 3300.0, \"78-78-4\": 3200.0, \"110-54-3\": 3200.0, \"110-82-7\": 3000.0,\n\"142-82-5\": 2900.0, \"71-43-2\": 2900.0, \"108-88-3\": 2800.0, \"92-52-4\": 2100.0,\n\"67-56-1\": 5400.0, \"64-17-5\": 4350.0, \"71-23-8\": 3750.0, \"67-63-0\": 4100.0,\n\"71-36-3\": 2600.0, \"78-83-1\": 4500.0, \"78-92-2\": 3400.0, \"75-07-0\": 3500.0,\n\"67-64-1\": 3300.0, \"124-38-9\": 5500.0, \"75-46-7\": 4800.0, \"75-10-5\": 5000.0,\n\"354-33-6\": 4400.0, \"811-97-2\": 4200.0, \"420-46-2\": 4700.0, \"75-37-6\": 4600.0,\n\"754-12-1\": 3000.0, \"431-89-0\": 4100.0, \"115-25-3\": 4200.0, \"75-73-0\": 4750.0,\n\"306-83-2\": 3000.0, \"75-69-4\": 2800.0, \"75-71-8\": 4000.0, \"75-72-9\": 3900.0,\n\"75-63-8\": 3500.0, \"75-45-6\": 3900.0, \"76-13-1\": 2650.0, \"76-14-2\": 3800.0,\n\"76-15-3\": 4200.0, \"74-87-3\": 4400.0, \"56-23-5\": 3200.0, \"2551-62-4\": 3700.0,\n\"7732-18-5\": 5600.0, \"7664-41-7\": 7000.0, \"7782-44-7\": 9500.0, \"7727-37-9\": 10000.0,\n\"7440-37-1\": 8200.0, \"7440-01-9\": 20000.0, \"1333-74-0\": 24000.0, \"7440-59-7\": 2000.0}\n\n\n\ncryogenics = {\"132259-10-0\": \"Air\", \"7440-37-1\": \"Argon\", \"630-08-0\":\n\"carbon monoxide\", \"7782-39-0\": \"deuterium\", \"7782-41-4\": \"fluorine\",\n\"7440-59-7\": \"helium\", \"1333-74-0\": \"hydrogen\", \"7439-90-9\": \"krypton\",\n\"74-82-8\": \"methane\", \"7440-01-9\": \"neon\", \"7727-37-9\": \"nitrogen\",\n\"7782-44-7\": \"oxygen\", \"7440-63-3\": \"xenon\"}\n\nh_nucleic_all_methods = [\"Stephan-Abdelsalam\", \"Stephan-Abdelsalam water\",\n                     \"Stephan-Abdelsalam cryogenic\", \"HEDH-Taborek\",\n                     \"Forster-Zuber\", \"Rohsenow\", \"Cooper\", \"Bier\",\n                     \"Montinsky\", \"McNelly\", \"Gorenflo (1993)\"]\n\ndef h_nucleic_methods(Te: float | None=None, Tsat: float | None=None, P: float | None=None, dPsat: float | None=None, Cpl: float | None=None,\n          kl: float | None=None, mul: float | None=None, rhol: float | None=None, sigma: float | None=None, Hvap: float | None=None, rhog: float | None=None,\n          MW: float | None=None, Pc: float | None=None, CAS: str | None=None, check_ranges: bool=False) -> list[str]:\n    r\"\"\"This function returns the names of correlations for nucleate boiling\n    heat flux.\n\n    Parameters\n    ----------\n    Te : float, optional\n        Excess wall temperature, [K]\n    Tsat : float, optional\n        Saturation temperature at operating pressure [Pa]\n    P : float, optional\n        Saturation pressure of fluid, [Pa]\n    dPsat : float, optional\n        Difference in saturation pressure of the fluid at Te and T, [Pa]\n    Cpl : float, optional\n        Heat capacity of liquid [J/kg/K]\n    kl : float, optional\n        Thermal conductivity of liquid [W/m/K]\n    mul : float, optional\n        Viscosity of liquid [Pa*s]\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    sigma : float, optional\n        Surface tension of liquid [N/m]\n    Hvap : float, optional\n        Heat of vaporization of the fluid at P, [J/kg]\n    rhog : float, optional\n        Density of the produced gas [kg/m^3]\n    MW : float, optional\n        Molecular weight of fluid, [g/mol]\n    Pc : float, optional\n        Critical pressure of fluid, [Pa]\n    CAS : str, optional\n        CAS of fluid\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `h` with the given inputs\n\n    Examples\n    --------\n    >>> h_nucleic_methods(P=3E5, Pc=22048320., Te=4.0, CAS='7732-18-5')\n    ['Gorenflo (1993)', 'HEDH-Taborek', 'Bier', 'Montinsky']\n    \"\"\"\n    methods = []\n    if P is not None and Pc is not None:\n        if CAS is not None and CAS in h0_Gorenflow_1993: # numba: delete\n#        if CAS is not None and CAS in h0_Gorenflow_1993_keys: # numba: uncomment\n            methods.append(\"Gorenflo (1993)\")\n    if (Te is not None and Tsat is not None and Cpl is not None and kl is not None\n        and mul is not None and sigma is not None and Hvap is not None\n        and rhol is not None and rhog is not None):\n        if CAS is not None and CAS == \"7732-18-5\":\n            methods.append(\"Stephan-Abdelsalam water\")\n        if CAS is not None and CAS in cryogenics:\n            methods.append(\"Stephan-Abdelsalam cryogenic\")\n        methods.append(\"Stephan-Abdelsalam\")\n    if Te is not None and P is not None and Pc is not None:\n        methods.append(\"HEDH-Taborek\")\n    if (Te is not None and dPsat is not None and Cpl is not None and kl is not None\n        and mul is not None and sigma is not None and Hvap is not None\n        and rhol is not None and rhog is not None):\n        methods.append(\"Forster-Zuber\")\n    if (Te is not None and Cpl is not None and kl is not None and mul is not None\n        and sigma is not None and Hvap is not None and rhol is not None\n        and rhog is not None):\n        methods.append(\"Rohsenow\")\n    if MW is not None and Te is not None and P is not None and Pc is not None:\n        methods.append(\"Cooper\")\n    if Te is not None and P is not None and Pc is not None:\n        methods.extend([\"Bier\", \"Montinsky\"])\n    if (Te is not None and P is not None and Cpl is not None and kl is not None\n        and sigma is not None and Hvap is not None and rhol is not None\n        and rhog is not None):\n        methods.append(\"McNelly\")\n    return methods\n\n\ndef h_nucleic(Te: float | None=None, q: float | None=None, Tsat: float | None=None, P: float | None=None, dPsat: float | None=None, Cpl: float | None=None,\n              kl: float | None=None, mul: float | None=None, rhol: float | None=None, sigma: float | None=None, Hvap: float | None=None, rhog: float | None=None,\n              MW: float | None=None, Pc: float | None=None, Csf: float=0.013, n: float=1.7, kw: float=401.0, rhow: float=8.96, Cpw: float=384.0,\n              angle: float=35.0, Rp: float=1e-6, Ra: float=0.4e-6, h0: None=None,\n              CAS: str | None=None, Method: str | None=None) -> float:\n    r\"\"\"This function handles the calculation of nucleate boiling\n    heat flux and chooses the best method for performing the calculation\n    based on the provided information.\n\n    One of `Te` and `q` are always required.\n\n    Parameters\n    ----------\n    Te : float, optional\n        Excess wall temperature, [K]\n    q : float, optional\n        Heat flux, [W/m^2]\n    Tsat : float, optional\n        Saturation temperature at operating pressure [Pa]\n    P : float, optional\n        Saturation pressure of fluid, [Pa]\n    dPsat : float, optional\n        Difference in saturation pressure of the fluid at Te and T, [Pa]\n    Cpl : float, optional\n        Heat capacity of liquid [J/kg/K]\n    kl : float, optional\n        Thermal conductivity of liquid [W/m/K]\n    mul : float, optional\n        Viscosity of liquid [Pa*s]\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    sigma : float, optional\n        Surface tension of liquid [N/m]\n    Hvap : float, optional\n        Heat of vaporization of the fluid at P, [J/kg]\n    rhog : float, optional\n        Density of the produced gas [kg/m^3]\n    MW : float, optional\n        Molecular weight of fluid, [g/mol]\n    Pc : float, optional\n        Critical pressure of fluid, [Pa]\n    Csf : float, optional\n        Rohsenow coefficient specific to fluid and metal [-]\n    n : float, optional\n        Rohsenow constant, 1 for water, 1.7 (default) for other fluids usually [-]\n    kw : float, optional\n        Thermal conductivity of wall (only for cryogenics) [W/m/K]\n    rhow : float, optional\n        Density of the wall (only for cryogenics) [kg/m^3]\n    Cpw : float, optional\n        Heat capacity of wall (only for cryogenics) [J/kg/K]\n    angle : float, optional\n        Contact angle of bubble with wall [degrees]\n    Rp : float, optional\n        Roughness parameter of the surface (1 micrometer default) used by\n        `Cooper` method, [m]\n    Ra : float, optional\n        Roughness parameter of the surface (0.4 micrometer default) for\n        Gorenflo method, [m]\n    h0 : float\n        Reference heat transfer coefficient for Gorenflo method, [W/m^2/K]\n    CAS : str, optional\n        CAS of fluid\n\n    Returns\n    -------\n    h : float\n        Nucleate boiling heat flux [W/m^2]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        The name of the method to use; one of ['Gorenflo (1993)',\n        'Stephan-Abdelsalam water', 'Stephan-Abdelsalam cryogenic',\n        'Stephan-Abdelsalam', 'HEDH-Taborek', 'Forster-Zuber', 'Rohsenow',\n        'Cooper', 'Bier', 'Montinsky', 'McNelly']\n\n    Notes\n    -----\n    The methods Stephan-Abdelsalam, Cooper, and Gorenflo all take other\n    arguments as well such as surface roughness or the thermal properties of\n    the wall material. See them for their documentation. These parameters\n    can also be passed as keyword arguments.\n\n    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5', Ra=1E-6)\n    3437.7726419934147\n\n    Examples\n    --------\n    Water boiling at 3 bar and a heat flux of 2E4 W/m^2/K.\n\n    >>> h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS='7732-18-5')\n    3043.344595525422\n\n    Water, known excess temperature of 4.9 K, Rohsenow method\n\n    >>> h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217,\n    ... Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26,\n    ... Method='Rohsenow')\n    3723.655267067467\n    \"\"\"\n    if Method is None:\n        methods = h_nucleic_methods(Te=Te, Tsat=Tsat, P=P, dPsat=dPsat, Cpl=Cpl,\n              kl=kl, mul=mul, rhol=rhol, sigma=sigma, Hvap=Hvap, rhog=rhog,\n              MW=MW, Pc=Pc, CAS=CAS)\n        if not methods:\n            raise ValueError(\"Insufficient property data for any method.\")\n        Method = methods[0]\n\n    if Method == \"Stephan-Abdelsalam\"and Tsat is not None:\n        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,\n                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,\n                               correlation=\"general\",\n                               kw=kw, rhow=rhow, Cpw=Cpw, angle=angle)\n    elif Method == \"Stephan-Abdelsalam water\" and Tsat is not None:\n        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,\n                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,\n                               correlation=\"water\",\n                               kw=kw, rhow=rhow, Cpw=Cpw, angle=angle)\n    elif Method == \"Stephan-Abdelsalam cryogenic\" and Tsat is not None:\n        return Stephan_Abdelsalam(Te=Te, q=q, Tsat=Tsat, Cpl=Cpl, kl=kl, mul=mul,\n                               sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog,\n                               correlation=\"cryogenic\",\n                               kw=kw, rhow=rhow, Cpw=Cpw, angle=angle)\n    elif Method == \"HEDH-Taborek\" and P is not None and Pc is not None:\n        return HEDH_Taborek(Te=Te, q=q, P=P, Pc=Pc)\n    elif Method == \"Forster-Zuber\" and dPsat is not None:\n        return Forster_Zuber(Te=Te, q=q, dPsat=dPsat, Cpl=Cpl, kl=kl, mul=mul,\n                          sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog)\n    elif Method == \"Rohsenow\":\n        return Rohsenow(Te=Te, q=q, Cpl=Cpl, kl=kl, mul=mul, sigma=sigma, Hvap=Hvap,\n                     rhol=rhol, rhog=rhog, Csf=Csf, n=n)\n    elif Method == \"Cooper\":\n        return Cooper(Te=Te, q=q, P=P, Pc=Pc, MW=MW, Rp=Rp)\n    elif Method == \"Bier\" and P is not None and Pc is not None:\n        return Bier(Te=Te, q=q, P=P, Pc=Pc)\n    elif Method == \"Montinsky\" and P is not None and Pc is not None:\n        return Montinsky(Te=Te, q=q, P=P, Pc=Pc)\n    elif Method == \"McNelly\":\n        return McNelly(Te=Te, q=q, P=P, Cpl=Cpl, kl=kl, sigma=sigma, Hvap=Hvap,\n                    rhol=rhol, rhog=rhog)\n\n    elif Method == \"Gorenflo (1993)\":\n        return Gorenflo(P=P, q=q, Pc=Pc, Te=Te, CASRN=CAS, h0=h0, Ra=Ra)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n\n### Critical Heat Flux\n\n\ndef Zuber(sigma: float, Hvap: float, rhol: float, rhog: float, K: float=0.18) -> float:\n    r\"\"\"Calculates critical heat flux for nucleic boiling of a flat plate\n    or other shape as presented in various sources.\n    K = pi/24 is believed to be the original [1]_ value for K, but 0.149 is\n    now more widely used, a value claimed to be from [2]_ according to [5]_.\n    Cao [4]_ lists a value of 0.18 for K. The Wolverine Tube data book also\n    lists a value of 0.18, and so it is the default.\n\n    .. math::\n        q_c = {KH}_{vap} \\rho_g^{0.5}\\left[\\sigma g (\\rho_L-\\rho_g)\\right]^{0.25}\n\n    Parameters\n    ----------\n    sigma : float\n        Surface tension of liquid [N/m]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n    K : float\n        Constant []\n\n    Returns\n    -------\n    q : float\n        Critical heat flux [W/m^2]\n\n    Notes\n    -----\n    No further work is required on this correlation. Multiple sources confirm\n    its form.\n\n    Examples\n    --------\n    Example from [3]_\n\n    >>> Zuber(sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09, K=0.149)\n    444307.22304342285\n    >>> Zuber(sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09, K=0.18)\n    536746.9808578263\n\n    References\n    ----------\n    .. [1] Zuber N. \"On the stability of boiling heat transfer\". Trans ASME 1958\n        80:711-20.\n    .. [2] Lienhard, J.H., and Dhir, V.K., 1973, Extended Hydrodynamic Theory\n       of the Peak and Minimum Heat Fluxes, NASA CR-2270.\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    .. [4] Cao, Eduardo. Heat Transfer in Process Engineering.\n       McGraw Hill Professional, 2009.\n    .. [5] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer, 7E.Mason, OH: Cengage Learning, 2010.\n    \"\"\"\n    return K*Hvap*rhog**0.5*(g*sigma*(rhol-rhog))**0.25\n\n\ndef Serth_HEDH(D: float, sigma: float, Hvap: float, rhol: float, rhog: float) -> float:\n    r\"\"\"Calculates critical heat flux for nucleic boiling of a tube bundle\n    according to [2]_, citing [3]_, and using [1]_ as the original form.\n\n    .. math::\n        q_c = KH_{vap} \\rho_g^{0.5}\\left[\\sigma g (\\rho_L-\\rho_g)\\right]^{0.25}\n\n    .. math::\n        K = 0.123 (R^*)^{-0.25} \\text{ for 0.12 < R* < 1.17}\n\n    .. math::\n        K = 0.118\n\n    .. math::\n        R^* = \\frac{D}{2} \\left[\\frac{g(\\rho_L-\\rho_G)}{\\sigma}\\right]^{0.5}\n\n    Parameters\n    ----------\n    D : float\n        Diameter of tubes [m]\n    sigma : float\n        Surface tension of liquid [N/m]\n    Hvap : float\n        Heat of vaporization of the fluid at T, [J/kg]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the produced gas [kg/m^3]\n\n    Returns\n    -------\n    q : float\n        Critical heat flux [W/m^2]\n\n    Notes\n    -----\n    A further source for this would be nice.\n\n    Examples\n    --------\n    >>> Serth_HEDH(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    351867.46522901946\n\n    References\n    ----------\n    .. [1] Zuber N. \"On the stability of boiling heat transfer\". Trans ASME\n       1958 80:711-20.\n    .. [2] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    .. [3] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    \"\"\"\n    R = D/2*(g*(rhol-rhog)/sigma)**0.5\n    if 0.12 <= R  <= 1.17:\n        K = 0.125*R**-0.25\n    else:\n        K = 0.118\n    return K*Hvap*rhog**0.5*(g*sigma*(rhol-rhog))**0.25\n\n\ndef HEDH_Montinsky(P: float, Pc: float) -> float:\n    r\"\"\"Calculates critical heat flux\n    in the nucleate boiling regime according to [3]_ as presented in [1]_,\n    using an expression modified from [2]_.\n\n    .. math::\n        q_c = 367 P_cP_r^{0.35}(1-P_r)^{0.9}\n\n    Parameters\n    ----------\n    P : float\n        Saturation pressure of fluid, [Pa]\n    Pc : float\n        Critical pressure of fluid, [Pa]\n\n    Returns\n    -------\n    q : float\n        Critical heat flux [W/m^2]\n\n    Notes\n    -----\n    No further work is required.\n    Units of Pc are kPa internally.\n\n    Examples\n    --------\n    Example is from [3]_ and matches to within the error of the algebraic\n    manipulation rounding.\n\n    >>> HEDH_Montinsky(P=310.3E3, Pc=2550E3)\n    398405.66545181436\n\n    References\n    ----------\n    .. [1] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [2] Mostinsky I. L.: \"Application of the rule of corresponding states\n       for the calculation of heat transfer and critical heat flux,\"\n       Teploenergetika 4:66, 1963 English Abstr. Br Chem Eng 8(8):586, 1963\n    .. [3] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    Pr = P/Pc\n    return 367*(Pc/1000.)*Pr**0.35*(1-Pr)**0.9\n\n\nqmax_boiling_all_methods = [\"Serth-HEDH\", \"Zuber\", \"HEDH-Montinsky\"]\n\ndef qmax_boiling_methods(rhol: int | None=None, rhog: float | None=None, sigma: float | None=None, Hvap: float | None=None, D: float | None=None,\n                         P: float | None=None, Pc: float | None=None, check_ranges: bool=False) -> list[str]:\n    r\"\"\"This function returns a list of methods names which can be used to\n    calculate nucleate boiling critical heat flux.\n    Preferred methods are 'Serth-HEDH' when a tube diameter is specified,\n    and 'Zuber' otherwise.\n\n    Parameters\n    ----------\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    rhog : float, optional\n        Density of the produced gas [kg/m^3]\n    sigma : float, optional\n        Surface tension of liquid [N/m]\n    Hvap : float, optional\n        Heat of vaporization of the fluid at T, [J/kg]\n    D : float, optional\n        Diameter of tubes [m]\n    P : float, optional\n        Saturation pressure of fluid, [Pa]\n    Pc : float, optional\n        Critical pressure of fluid, [Pa]\n    check_ranges : bool, optional\n        Added for Future use only\n\n    Returns\n    -------\n    methods : list\n        List of methods which can be used to calculate qmax with the given inputs\n\n    Examples\n    --------\n    >>> qmax_boiling_methods(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    ['Serth-HEDH', 'Zuber']\n    \"\"\"\n    methods = []\n    if (sigma is not None and Hvap is not None and rhol is not None\n        and rhog is not None and D is not None):\n        methods.append(\"Serth-HEDH\")\n    if (sigma is not None and Hvap is not None and rhol is not None\n        and rhog is not None):\n        methods.append(\"Zuber\")\n    if P is not None and Pc is not None:\n        methods.append(\"HEDH-Montinsky\")\n    return methods\n\n\ndef qmax_boiling(rhol: int | None=None, rhog: float | None=None, sigma: float | None=None, Hvap: float | None=None, D: float | None=None, P: float | None=None,\n                 Pc: float | None=None, Method: str | None=None) -> float:\n    r\"\"\"This function handles the calculation of nucleate boiling critical\n    heat flux and chooses the best method for performing the calculation.\n\n    Preferred methods are 'Serth-HEDH' when a tube diameter is specified,\n    and 'Zuber' otherwise.\n\n    Parameters\n    ----------\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    rhog : float, optional\n        Density of the produced gas [kg/m^3]\n    sigma : float, optional\n        Surface tension of liquid [N/m]\n    Hvap : float, optional\n        Heat of vaporization of the fluid at T, [J/kg]\n    D : float, optional\n        Diameter of tubes [m]\n    P : float, optional\n        Saturation pressure of fluid, [Pa]\n    Pc : float, optional\n        Critical pressure of fluid, [Pa]\n\n    Returns\n    -------\n    q : float\n        Nucleate boiling critical heat flux [W/m^2]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use; one of ('Serth-HEDH', 'Zuber',\n        or 'HEDH-Montinsky')\n\n    Examples\n    --------\n    >>> qmax_boiling(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    351867.46522901946\n    \"\"\"\n    if Method is None:\n        if (sigma is not None and Hvap is not None and rhol is not None\n            and rhog is not None and D is not None):\n            Method2 = \"Serth-HEDH\"\n        elif (sigma is not None and Hvap is not None and rhol is not None\n            and rhog is not None):\n            Method2 = \"Zuber\"\n        elif P is not None and Pc is not None:\n            Method2 = \"HEDH-Montinsky\"\n        else:\n            raise ValueError(\"Insufficient property or geometry data for any \"\n                            \"method.\")\n    else:\n        Method2 = Method\n    if Method2 == \"Serth-HEDH\":\n        return Serth_HEDH(D=D, sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog)\n    elif Method2 == \"Zuber\":\n        return Zuber(sigma=sigma, Hvap=Hvap, rhol=rhol, rhog=rhog)\n    elif Method2 == \"HEDH-Montinsky\":\n        return HEDH_Montinsky(P=P, Pc=Pc)\n    else:\n        raise ValueError(\"Correlation name not recognized; options are \"\n                        \"'Serth-HEDH', 'Zuber' and 'HEDH-Montinsky'\")\n"
  },
  {
    "path": "ht/boiling_plate.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import radians\n\nfrom fluids.constants import g\nfrom fluids.core import Bond, Prandtl, thermal_diffusivity\nfrom fluids.two_phase_voidage import Lockhart_Martinelli_Xtt\n\n__all__: list[str] = [\n    \"h_boiling_Amalfi\",\n    \"h_boiling_Han_Lee_Kim\",\n    \"h_boiling_Huang_Sheer\",\n    \"h_boiling_Lee_Kang_Kim\",\n    \"h_boiling_Yan_Lin\",\n]\n\ndef h_boiling_Amalfi(m: float, x: float, Dh: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, Hvap: float, sigma: float, q: float,\n                     A_channel_flow: float, chevron_angle: float=45.0) -> float:\n    r\"\"\"Calculates the two-phase boiling heat transfer coefficient of a\n    liquid and gas flowing inside a plate and frame heat exchanger, as\n    developed in [1]_ from a wide range of existing correlations and data sets.\n    Expected to be the most accurate correlation currently available.\n\n    For Bond number < 4 (tiny channel case):\n\n    .. math::\n        h= 982 \\left(\\frac{k_l}{D_h}\\right)\\left(\\frac{\\beta}{\\beta_{max}}\\right)^{1.101}\n        \\left(\\frac{G^2 D_h}{\\rho_m \\sigma}\\right)^{0.315}\n        \\left(\\frac{\\rho_l}{\\rho_g}\\right)^{-0.224} Bo^{0.320}\n\n    For Bond number >= 4:\n\n    .. math::\n        h = 18.495 \\left(\\frac{k_l}{D_h}\\right) \\left(\\frac{\\beta}{\\beta_{max}}\n        \\right)^{0.248}\\left(Re_g\\right)^{0.135}\\left(Re_{lo}\\right)^{0.351}\n        \\left(\\frac{\\rho_l}{\\rho_g}\\right)^{-0.223} Bd^{0.235} Bo^{0.198}\n\n    In the above equations, beta max is 45 degrees; Bo is Boiling number;\n    and Bd is Bond number.\n\n    Note that this model depends on the specific heat flux involved.\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific point in the plate exchanger []\n    Dh : float\n        Hydraulic diameter of the plate, :math:`D_h = \\frac{4\\lambda}{\\phi}` [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of the liquid [Pa*s]\n    mug : float\n        Viscosity of the gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of the fluid at the system pressure, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    q : float\n        Heat flux, [W/m^2]\n    A_channel_flow : float\n        The flow area for the fluid, calculated as\n        :math:`A_{ch} = 2\\cdot \\text{width} \\cdot \\text{amplitude}` [m]\n    chevron_angle : float, optional\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. For exchangers with two angles, use the average value. [degrees]\n\n    Returns\n    -------\n    h : float\n        Boiling heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Heat transfer correlation developed from 1903 datum. Fluids included R134a,\n    ammonia, R236fa, R600a, R290, R1270, R1234yf, R410A, R507A, ammonia/water,\n    and air/water mixtures. Wide range of operating conditions, plate geometries.\n\n    Examples\n    --------\n    >>> h_boiling_Amalfi(m=3E-5, x=.4, Dh=0.00172, rhol=567., rhog=18.09,\n    ... kl=0.086, mul=156E-6, mug=7.11E-6, sigma=0.02, Hvap=9E5, q=1E5,\n    ... A_channel_flow=0.0003)\n    776.0781179096225\n\n    References\n    ----------\n    .. [1] Amalfi, Raffaele L., Farzad Vakili-Farahani, and John R. Thome.\n       \"Flow Boiling and Frictional Pressure Gradients in Plate Heat Exchangers.\n       Part 2: Comparison of Literature Methods to Database and New Prediction\n       Methods.\" International Journal of Refrigeration 61 (January 2016):\n       185-203. doi:10.1016/j.ijrefrig.2015.07.009.\n    \"\"\"\n    chevron_angle_max = 45.\n    beta_s = chevron_angle/chevron_angle_max\n\n    rho_s = (rhol/rhog) # rho start in model\n\n    G = m/A_channel_flow # Calculating the area of the channel is normally specified well\n    Bd = Bond(rhol=rhol, rhog=rhog, sigma=sigma, L=Dh)\n\n    rho_h = 1./(x/rhog + (1-x)/rhol) # homogeneous holdup - mixture density calculation\n    We_m = G*G*Dh/sigma/rho_h\n\n    Bo = q/(G*Hvap) # Boiling number\n\n    if Bd < 4:\n        # Should occur normally for \"microscale\" conditions\n        Nu_tp = 982*beta_s**1.101*We_m**0.315*Bo**0.320*rho_s**-0.224\n    else:\n        Re_lo = G*Dh/mul\n        Re_g = G*x*Dh/mug\n        Nu_tp = 18.495*beta_s**0.135*Re_g**0.135*Re_lo**0.351*Bd**0.235*Bo**0.198*rho_s**-0.223\n    return kl/Dh*Nu_tp\n\n\ndef h_boiling_Lee_Kang_Kim(m: float, x: float, D_eq: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, Hvap: float, q: float,\n                           A_channel_flow: float) -> float:\n    r\"\"\"Calculates the two-phase boiling heat transfer coefficient of a\n    liquid and gas flowing inside a plate and frame heat exchanger, as\n    shown in [1]_ and reviewed in [2]_.\n\n    For :math:`Re_g/Re_l < 9`:\n\n    .. math::\n        h = 98.7 \\left(\\frac{k_l}{D_h}\\right)\\left(\\frac{Re_g}{Re_l}\n        \\right)^{-0.0848}Bo^{-0.0597} X_{tt}^{0.0973}\n\n    For :math:`Re_g/Re_l \\ge 9`:\n\n    .. math::\n        h = 234.9 \\left(\\frac{k_l}{D_h}\\right)\\left(\\frac{Re_g}{Re_l}\n        \\right)^{-0.576} Bo^{-0.275} X_{tt}^{0.66}\n\n    .. math::\n        X_{tt} = \\left(\\frac{1-x}{x}\\right)^{0.875} \\left(\\frac{\\rho_g}{\\rho_l}\n        \\right)^{0.5}\\left(\\frac{\\mu_l}{\\mu_g}\\right)^{0.125}\n\n    In the above equations, Bo is Boiling number.\n\n    Note that this model depends on the specific heat flux involved. It also\n    uses equivalent diameter, not hydraulic diameter.\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific point in the plate exchanger []\n    D_eq : float\n        Equivalent diameter of the channels, :math:`D_{eq} = 4a` [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of the liquid [Pa*s]\n    mug : float\n        Viscosity of the gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of the fluid at the system pressure, [J/kg]\n    q : float\n        Heat flux, [W/m^2]\n    A_channel_flow : float\n        The flow area for the fluid, calculated as\n        :math:`A_{ch} = 2\\cdot \\text{width} \\cdot \\text{amplitude}` [m]\n\n    Returns\n    -------\n    h : float\n        Boiling heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    This correlation was developed with mass fluxes from 14.5 to 33.6 kg/m^2/s,\n    heat flux from 15 to 30 kW/m^2, qualities from 0.09 to 0.6, 200 < Re < 600,\n    2.3 < Re_g/Re_l < 32.1, 0.00019 < Bo < 0.001, 0.028 < Xtt < 0.3.\n    Mean average deviation of 4.4%.\n\n    Examples\n    --------\n    >>> h_boiling_Lee_Kang_Kim(m=3E-5, x=.4, D_eq=0.002, rhol=567., rhog=18.09,\n    ... kl=0.086, mul=156E-6, mug=9E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    1229.6271295086806\n\n    References\n    ----------\n    .. [1] Lee, Eungchan, Hoon Kang, and Yongchan Kim. \"Flow Boiling Heat\n       Transfer and Pressure Drop of Water in a Plate Heat Exchanger with\n       Corrugated Channels at Low Mass Flux Conditions.\" International Journal\n       of Heat and Mass Transfer 77 (October 2014): 37-45.\n       doi:10.1016/j.ijheatmasstransfer.2014.05.019.\n    .. [2] Amalfi, Raffaele L., Farzad Vakili-Farahani, and John R. Thome.\n       \"Flow Boiling and Frictional Pressure Gradients in Plate Heat Exchangers.\n       Part 1: Review and Experimental Database.\" International Journal of\n       Refrigeration 61 (January 2016): 166-84.\n       doi:10.1016/j.ijrefrig.2015.07.010.\n    \"\"\"\n    G = m/A_channel_flow\n    Bo = q/(G*Hvap)\n    Re_ratio = x/(1. - x)*mul/mug\n    Xtt = Lockhart_Martinelli_Xtt(x, rhol, rhog, mul, mug, pow_x=0.875, pow_rho=0.5, pow_mu=0.125)\n    if Re_ratio < 9:\n        h = 98.7*kl/D_eq*Re_ratio**-0.0848*Bo**-0.0597*Xtt**0.0973\n    else:\n        h = 234.9*kl/D_eq*Re_ratio**-0.576*Bo**-0.275*Xtt**0.66\n    return h\n\n\ndef h_boiling_Han_Lee_Kim(m: float, x: float, Dh: float, rhol: float, rhog: float, mul: float, kl: float, Hvap: float, Cpl: float, q: float,\n                          A_channel_flow: float, wavelength: float, chevron_angle: int=45.0) -> float:\n    r\"\"\"Calculates the two-phase boiling heat transfer coefficient of a\n    liquid and gas flowing inside a plate and frame heat exchanger, as\n    developed in [1]_ from experiments with three plate exchangers and the\n    working fluids R410A and R22. A well-documented and tested correlation,\n    reviewed in [2]_, [3]_, [4]_, [5]_, and [6]_.\n\n    .. math::\n        h = Ge_1\\left(\\frac{k_l}{D_h}\\right)Re_{eq}^{Ge_2} Pr^{0.4} Bo_{eq}^{0.3}\n\n    .. math::\n        Ge_1 = 2.81\\left(\\frac{\\lambda}{D_h}\\right)^{-0.041}\\left(\\frac{\\pi}{2}\n        -\\beta\\right)^{-2.83}\n\n    .. math::\n        Ge_2 = 0.746\\left(\\frac{\\lambda}{D_h}\\right)^{-0.082}\\left(\\frac{\\pi}\n        {2}-\\beta\\right)^{0.61}\n\n    .. math::\n        Re_{eq} = \\frac{G_{eq} D_h}{\\mu_l}\n\n    .. math::\n        Bo_{eq} = \\frac{q}{G_{eq} H_{vap}}\n\n    .. math::\n        G_{eq} = \\frac{m}{A_{flow}}\\left[1 - x + x\\left(\\frac{\\rho_l}{\\rho_g}\n        \\right)^{1/2}\\right]\n\n    In the above equations, lambda is the wavelength of the corrugations, and\n    the flow area is specified to be (twice the corrugation amplitude times the\n    width of the plate. The mass flow is that per channel. Radians is used in\n    degrees, and the formulas are for the  inclination angle not the\n    chevron angle (it is converted internally).\n    Note that this model depends on the specific heat flux involved.\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific point in the plate exchanger []\n    Dh : float\n        Hydraulic diameter of the plate, :math:`D_h = \\frac{4\\lambda}{\\phi}` [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of the liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of the fluid at the system pressure, [J/kg]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    q : float\n        Heat flux, [W/m^2]\n    A_channel_flow : float\n        The flow area for the fluid, calculated as\n        :math:`A_{ch} = 2\\cdot \\text{width} \\cdot \\text{amplitude}` [m]\n    wavelength : float\n        Distance between the bottoms of two of the ridges (sometimes called\n        pitch), [m]\n    chevron_angle : float, optional\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. For exchangers with two angles, use the average value. [degrees]\n\n    Returns\n    -------\n    h : float\n        Boiling heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Date regression was with the log mean temperature difference, uncorrected\n    for geometry. Developed with three plate heat exchangers with angles of 45,\n    35, and 20 degrees. Mass fluxes ranged from 13 to 34 kg/m^2/s; evaporating\n    temperatures of 5, 10, and 15 degrees, vapor quality 0.9 to 0.15, heat\n    fluxes of 2.5-8.5 kW/m^2.\n\n    Examples\n    --------\n    >>> h_boiling_Han_Lee_Kim(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09,\n    ... kl=0.086, mul=156E-6,  Hvap=9E5, Cpl=2200, q=1E5, A_channel_flow=0.0003,\n    ... wavelength=3.7E-3, chevron_angle=45)\n    675.7322255419421\n\n    References\n    ----------\n    .. [1] Han, Dong-Hyouck, Kyu-Jung Lee, and Yoon-Ho Kim. \"Experiments on the\n       Characteristics of Evaporation of R410A in Brazed Plate Heat Exchangers\n       with Different Geometric Configurations.\" Applied Thermal Engineering 23,\n       no. 10 (July 2003): 1209-25. doi:10.1016/S1359-4311(03)00061-9.\n    .. [2] Amalfi, Raffaele L., Farzad Vakili-Farahani, and John R. Thome.\n       \"Flow Boiling and Frictional Pressure Gradients in Plate Heat Exchangers.\n       Part 1: Review and Experimental Database.\" International Journal of\n       Refrigeration 61 (January 2016): 166-84.\n       doi:10.1016/j.ijrefrig.2015.07.010.\n    .. [3] Eldeeb, Radia, Vikrant Aute, and Reinhard Radermacher. \"A Survey of\n       Correlations for Heat Transfer and Pressure Drop for Evaporation and\n       Condensation in Plate Heat Exchangers.\" International Journal of\n       Refrigeration 65 (May 2016): 12-26. doi:10.1016/j.ijrefrig.2015.11.013.\n    .. [4] Solotych, Valentin, Donghyeon Lee, Jungho Kim, Raffaele L. Amalfi,\n       and John R. Thome. \"Boiling Heat Transfer and Two-Phase Pressure Drops\n       within Compact Plate Heat Exchangers: Experiments and Flow\n       Visualizations.\" International Journal of Heat and Mass Transfer 94\n       (March 2016): 239-253. doi:10.1016/j.ijheatmasstransfer.2015.11.037.\n    .. [5] García-Cascales, J. R., F. Vera-García, J. M. Corberán-Salvador, and\n       J. Gonzálvez-Maciá. \"Assessment of Boiling and Condensation Heat\n       Transfer Correlations in the Modelling of Plate Heat Exchangers.\"\n       International Journal of Refrigeration 30, no. 6 (September 2007):\n       1029-41. doi:10.1016/j.ijrefrig.2007.01.004.\n    .. [6] Huang, Jianchang. \"Performance Analysis of Plate Heat Exchangers\n       Used as Refrigerant Evaporators,\" 2011. Thesis.\n       http://wiredspace.wits.ac.za/handle/10539/9779\n    \"\"\"\n    chevron_angle = radians(chevron_angle)\n    G = m/A_channel_flow # For once, clearly defined in the publication\n    G_eq = G*((1. - x) + x*(rhol/rhog)**0.5)\n    Re_eq = G_eq*Dh/mul\n    Bo_eq = q/(G_eq*Hvap)\n    Pr = Prandtl(Cp=Cpl, k=kl, mu=mul)\n    Ge1 = 2.81*(wavelength/Dh)**-0.041*chevron_angle**-2.83\n    Ge2 = 0.746*(wavelength/Dh)**-0.082*chevron_angle**0.61\n    return Ge1*kl/Dh*Re_eq**Ge2*Bo_eq**0.3*Pr**0.4\n\n\ndef h_boiling_Huang_Sheer(rhol: float, rhog: float, mul: float, kl: float, Hvap: float, sigma: float, Cpl: float, q: float, Tsat: float,\n                          angle: float=35.) -> float:\n    r\"\"\"Calculates the two-phase boiling heat transfer coefficient of a\n    liquid and gas flowing inside a plate and frame heat exchanger, as\n    developed in [1]_ and again in the thesis [2]_. Depends on the properties\n    of the fluid and not the heat exchanger's geometry.\n\n    .. math::\n        h = 1.87\\times10^{-3}\\left(\\frac{k_l}{d_o}\\right)\\left(\\frac{q d_o}\n        {k_l T_{sat}}\\right)^{0.56}\n        \\left(\\frac{H_{vap} d_o^2}{\\alpha_l^2}\\right)^{0.31} Pr_l^{0.33}\n\n    .. math::\n        d_o = 0.0146\\theta\\left[\\frac{2\\sigma}{g(\\rho_l-\\rho_g)}\\right]^{0.5}\\\\\n        \\theta =  35^\\circ\n\n    Note that this model depends on the specific heat flux involved and\n    the saturation temperature of the fluid.\n\n    Parameters\n    ----------\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of the liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of the fluid at the system pressure, [J/kg]\n    sigma : float\n        Surface tension of liquid [N/m]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    q : float\n        Heat flux, [W/m^2]\n    Tsat : float\n        Actual saturation temperature of the fluid at the system pressure, [K]\n    angle : float, optional\n        Contact angle of the bubbles with the wall, assumed 35 for refrigerants\n        in the development of the correlation [degrees]\n\n    Returns\n    -------\n    h : float\n        Boiling heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Developed with 222 data points for R134a and R507A with only two of them\n    for ammonia and R12. Chevron angles ranged from 28 to 60 degrees, heat\n    fluxes from 1.85 kW/m^2 to 10.75 kW/m^2, mass fluxes 5.6 to 52.25 kg/m^2/s,\n    qualities from 0.21 to 0.95, and saturation temperatures in degrees Celcius\n    of 1.9 to 13.04.\n\n    The inclusion of the saturation temperature makes this correlation have\n    limited predictive power for other fluids whose saturation tempratures\n    might be much higher or lower than those used in the development of the\n    correlation. For this reason it should be regarded with caution.\n\n    As first published in [1]_ a power of two was missing in the correlation\n    for bubble diameter in the dimensionless group with a power of 0.31. That\n    made the correlation non-dimensional.\n\n    A second variant of this correlation was also published in [2]_ but with\n    less accuracy because it was designed to mimick the standard pool boiling\n    curve.\n\n    The correlation is reviewed in [3]_, but without the corrected power. It\n    was also changed there to use hydraulic diameter, not bubble diameter.\n    It still ranked as one of the more accurate correlations reviewed.\n    [4]_ also reviewed it without the corrected power but found it predicted\n    the lowest results of those surveyed.\n\n    Examples\n    --------\n    >>> h_boiling_Huang_Sheer(rhol=567., rhog=18.09, kl=0.086, mul=156E-6,\n    ... Hvap=9E5, sigma=0.02, Cpl=2200, q=1E4, Tsat=279.15)\n    4401.055635078054\n\n    References\n    ----------\n    .. [1] Huang, Jianchang, Thomas J. Sheer, and Michael Bailey-McEwan. \"Heat\n       Transfer and Pressure Drop in Plate Heat Exchanger Refrigerant\n       Evaporators.\" International Journal of Refrigeration 35, no. 2 (March\n       2012): 325-35. doi:10.1016/j.ijrefrig.2011.11.002.\n    .. [2] Huang, Jianchang. \"Performance Analysis of Plate Heat Exchangers\n       Used as Refrigerant Evaporators,\" 2011. Thesis.\n       http://wiredspace.wits.ac.za/handle/10539/9779\n    .. [3] Amalfi, Raffaele L., Farzad Vakili-Farahani, and John R. Thome.\n       \"Flow Boiling and Frictional Pressure Gradients in Plate Heat Exchangers.\n       Part 1: Review and Experimental Database.\" International Journal of\n       Refrigeration 61 (January 2016): 166-84.\n       doi:10.1016/j.ijrefrig.2015.07.010.\n    .. [4] Eldeeb, Radia, Vikrant Aute, and Reinhard Radermacher. \"A Survey of\n       Correlations for Heat Transfer and Pressure Drop for Evaporation and\n       Condensation in Plate Heat Exchangers.\" International Journal of\n       Refrigeration 65 (May 2016): 12-26. doi:10.1016/j.ijrefrig.2015.11.013.\n    \"\"\"\n    do = 0.0146*angle*(2.*sigma/(g*(rhol - rhog)))**0.5\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    alpha_l = thermal_diffusivity(k=kl, rho=rhol, Cp=Cpl)\n    h = 1.87E-3*(kl/do)*(q*do/(kl*Tsat))**0.56*(Hvap*do**2/alpha_l**2)**0.31*Prl**0.33\n    return h\n\n\ndef h_boiling_Yan_Lin(m: float, x: float, Dh: float, rhol: float, rhog: float, mul: float, kl: float, Hvap: float, Cpl: float, q: float,\n                      A_channel_flow: float) -> float:\n    r\"\"\"Calculates the two-phase boiling heat transfer coefficient of a\n    liquid and gas flowing inside a plate and frame heat exchanger, as\n    developed in [1]_. Reviewed in [2]_, [3]_, [4]_, and [5]_.\n\n    .. math::\n        h = 1.926\\left(\\frac{k_l}{D_h}\\right) Re_{eq} Pr_l^{1/3} Bo_{eq}^{0.3}\n        Re^{-0.5}\n\n    .. math::\n        Re_{eq} = \\frac{G_{eq} D_h}{\\mu_l}\n\n    .. math::\n        Bo_{eq} = \\frac{q}{G_{eq} H_{vap}}\n\n    .. math::\n        G_{eq} = \\frac{m}{A_{flow}}\\left[1 - x + x\\left(\\frac{\\rho_l}{\\rho_g}\n        \\right)^{1/2}\\right]\n\n    .. math::\n        Re = \\frac{G D_h}{\\mu_l}\n\n    Claimed to be valid for :math:`2000 < Re_{eq} < 10000`.\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific point in the plate exchanger []\n    Dh : float\n        Hydraulic diameter of the plate, :math:`D_h = \\frac{4\\lambda}{\\phi}` [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of the liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Hvap : float\n        Heat of vaporization of the fluid at the system pressure, [J/kg]\n    Cpl : float\n        Heat capacity of liquid [J/kg/K]\n    q : float\n        Heat flux, [W/m^2]\n    A_channel_flow : float\n        The flow area for the fluid, calculated as\n        :math:`A_{ch} = 2\\cdot \\text{width} \\cdot \\text{amplitude}` [m]\n\n    Returns\n    -------\n    h : float\n        Boiling heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Developed with R134a as the refrigerant in a PHD with 2 channels, chevron\n    angle 60 degrees, quality from 0.1 to 0.8, heat flux 11-15 kW/m^2, and mass\n    fluxes of 55 and 70 kg/m^2/s.\n\n    Examples\n    --------\n    >>> h_boiling_Yan_Lin(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09,\n    ... kl=0.086, Cpl=2200, mul=156E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    318.7228565961241\n\n    References\n    ----------\n    .. [1] Yan, Y.-Y., and T.-F. Lin. \"Evaporation Heat Transfer and Pressure\n       Drop of Refrigerant R-134a in a Plate Heat Exchanger.\" Journal of Heat\n       Transfer 121, no. 1 (February 1, 1999): 118-27. doi:10.1115/1.2825924.\n    .. [2] Amalfi, Raffaele L., Farzad Vakili-Farahani, and John R. Thome.\n       \"Flow Boiling and Frictional Pressure Gradients in Plate Heat Exchangers.\n       Part 1: Review and Experimental Database.\" International Journal of\n       Refrigeration 61 (January 2016): 166-84.\n       doi:10.1016/j.ijrefrig.2015.07.010.\n    .. [3] Eldeeb, Radia, Vikrant Aute, and Reinhard Radermacher. \"A Survey of\n       Correlations for Heat Transfer and Pressure Drop for Evaporation and\n       Condensation in Plate Heat Exchangers.\" International Journal of\n       Refrigeration 65 (May 2016): 12-26. doi:10.1016/j.ijrefrig.2015.11.013.\n    .. [4] García-Cascales, J. R., F. Vera-García, J. M. Corberán-Salvador, and\n       J. Gonzálvez-Maciá. \"Assessment of Boiling and Condensation Heat\n       Transfer Correlations in the Modelling of Plate Heat Exchangers.\"\n       International Journal of Refrigeration 30, no. 6 (September 2007):\n       1029-41. doi:10.1016/j.ijrefrig.2007.01.004.\n    .. [5] Huang, Jianchang. \"Performance Analysis of Plate Heat Exchangers\n       Used as Refrigerant Evaporators,\" 2011. Thesis.\n       http://wiredspace.wits.ac.za/handle/10539/9779\n    \"\"\"\n    G = m/A_channel_flow\n    G_eq = G*((1. - x) + x*(rhol/rhog)**0.5)\n    Re_eq = G_eq*Dh/mul\n    Re = G*Dh/mul #  Not actually specified clearly but it is in another paper by them\n    Bo_eq = q/(G_eq*Hvap)\n    Pr_l = Prandtl(Cp=Cpl, k=kl, mu=mul)\n    return 1.926*(kl/Dh)*Re_eq*Pr_l**(1/3.)*Bo_eq**0.3*Re**-0.5\n\n\n\n\n"
  },
  {
    "path": "ht/condensation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import pi, sin\n\nfrom fluids.constants import R, g\nfrom fluids.core import Prandtl, Reynolds\n\nfrom ht.conv_internal import turbulent_Dittus_Boelter\n\n__all__: list[str] = [\n    \"Akers_Deans_Crosser\",\n    \"Boyko_Kruzhilin\",\n    \"Cavallini_Smith_Zecchin\",\n    \"Nusselt_laminar\",\n    \"Shah\",\n    \"h_kinetic\",\n]\n\n\ndef Nusselt_laminar(Tsat: float, Tw: float, rhog: float, rhol: float, kl: float, mul: float, Hvap: float, L: float, angle: float=90.) -> float:\n    r\"\"\"Calculates heat transfer coefficient for laminar film condensation\n    of a pure chemical on a flat plate, as presented in [1]_ according to an\n    analysis performed by Nusselt in 1916.\n\n    .. math::\n        h=0.943\\left[\\frac{g\\sin(\\theta)\\rho_{liq}(\\rho_l-\\rho_v)k_{l}^3\n        \\Delta H_{vap}}{\\mu_l(T_{sat}-T_w)L}\\right]^{0.25}\n\n    Parameters\n    ----------\n    Tsat : float\n        Saturation temperature at operating pressure [K]\n    Tw : float\n        Wall temperature, [K]\n    rhog : float\n        Density of the gas [kg/m^3]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    L : float\n        Length of the plate [m]\n    angle : float, optional\n        Angle of inclination of the plate [degrees]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Optionally, the plate may be inclined.\n    The constant 0.943 is actually:\n\n    .. math::\n        2\\sqrt{2}/3\n\n    Examples\n    --------\n    p. 578 in [1]_, matches exactly.\n\n    >>> Nusselt_laminar(Tsat=370, Tw=350, rhog=7.0, rhol=585., kl=0.091,\n    ... mul=158.9E-6, Hvap=776900, L=0.1)\n    1482.206403453679\n\n    References\n    ----------\n    .. [1] Hewitt, G. L. Shires T. Reg Bott G. F., George L. Shires, and\n       T. R. Bott. Process Heat Transfer. 1E. Boca Raton: CRC Press, 1994.\n    \"\"\"\n    return 2.*2.**0.5/3.*(kl**3*rhol*(rhol - rhog)*g*sin(angle/180.*pi)\n                          *Hvap/(mul*(Tsat - Tw)*L))**0.25\n\n\ndef Boyko_Kruzhilin(m: float, rhog: float, rhol: float, kl: float, mul: float, Cpl: float, D: float, x: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for condensation\n    of a pure chemical inside a vertical tube or tube bundle, as presented in\n    [2]_ according to [1]_.\n\n    .. math::\n        h_f = h_{LO}\\left[1 + x\\left(\\frac{\\rho_L}{\\rho_G} - 1\\right)\\right]^{0.5}\n\n    .. math::\n        h_{LO} = 0.021 \\frac{k_L}{L} Re_{LO}^{0.8} Pr^{0.43}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    rhog : float\n        Density of the gas [kg/m^3]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    D : float\n        Diameter of the tubing [m]\n    x : float\n        Quality at the specific interval [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    To calculate overall heat transfer coefficient during condensation,\n    simply average values at x = 1 and x = 0.\n\n    Examples\n    --------\n    Page 589 in [2]_, matches exactly.\n\n    >>> Boyko_Kruzhilin(m=500*pi/4*.03**2, rhog=6.36, rhol=582.9, kl=0.098,\n    ... mul=159E-6, Cpl=2520., D=0.03, x=0.85)\n    10598.657227479956\n\n    References\n    ----------\n    .. [1] Boyko, L. D., and G. N. Kruzhilin. \"Heat Transfer and Hydraulic\n       Resistance during Condensation of Steam in a Horizontal Tube and in a\n       Bundle of Tubes.\" International Journal of Heat and Mass Transfer 10,\n       no. 3 (March 1, 1967): 361-73. doi:10.1016/0017-9310(67)90152-4.\n    .. [2] Hewitt, G. L. Shires T. Reg Bott G. F., George L. Shires, and\n       T. R. Bott. Process Heat Transfer. 1E. Boca Raton: CRC Press, 1994.\n    \"\"\"\n    Vlo = m/rhol/(pi/4.*D**2)\n    Relo = rhol*Vlo*D/mul\n    Prl = mul*Cpl/kl\n    hlo = 0.021*kl/D*Relo**0.8*Prl**0.43\n    return hlo*(1. + x*(rhol/rhog - 1.))**0.5\n\n\ndef Akers_Deans_Crosser(m: float, rhog: float, rhol: float, kl: float, mul: float, Cpl: float, D: float, x: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for condensation\n    of a pure chemical inside a vertical tube or tube bundle, as presented in\n    [2]_ according to [1]_.\n\n    .. math::\n        Nu = \\frac{hD_i}{k_l} = C Re_e^n Pr_l^{1/3}\n\n    .. math::\n        C = 0.0265, n=0.8 \\text{ for } Re_e > 5\\times10^4\n\n    .. math::\n        C = 5.03, n=\\frac{1}{3} \\text{ for } Re_e < 5\\times10^4\n\n    .. math::\n        Re_e = \\frac{D_i G_e}{\\mu_l}\n\n    .. math::\n        G_e = G\\left[(1-x)+x(\\rho_l/\\rho_g)^{0.5}\\right]\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    rhog : float\n        Density of the gas [kg/m^3]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    D : float\n        Diameter of the tubing [m]\n    x : float\n        Quality at the specific interval [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n\n    Examples\n    --------\n    >>> Akers_Deans_Crosser(m=0.35, rhog=6.36, rhol=582.9, kl=0.098,\n    ... mul=159E-6, Cpl=2520., D=0.03, x=0.85)\n    7117.24177265201\n\n    References\n    ----------\n    .. [1] Akers, W. W., H. A. Deans, and O. K. Crosser. \"Condensing Heat\n       Transfer Within Horizontal Tubes.\" Chem. Eng. Progr. Vol: 55, Symposium\n       Ser. No. 29 (January 1, 1959).\n    .. [2] Kakaç, Sadik, ed. Boilers, Evaporators, and Condensers. 1st.\n       Wiley-Interscience, 1991.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Ge = G*((1-x) + x*(rhol/rhog)**0.5)\n    Ree = D*Ge/mul\n    Prl = mul*Cpl/kl\n    if Ree > 5E4:\n        C, n = 0.0265, 0.8\n    else:\n        C, n = 5.03, 1/3.\n    Nu = C*Ree**n*Prl**(1/3.)\n    return Nu*kl/D\n\n#print([Akers_Deans_Crosser(m=0.01, rhog=6.36, rhol=582.9, kl=0.098, mul=159E-6, Cpl=2520., D=0.03, x=0.85)])\n\n\ndef h_kinetic(T: float, P: float, MW: float, Hvap: float, f: float=1.0) -> float:\n    r\"\"\"Calculates heat transfer coefficient for condensation\n    of a pure chemical inside a vertical tube or tube bundle, as presented in\n    [2]_ according to [1]_.\n\n    .. math::\n        h = \\left(\\frac{2f}{2-f}\\right)\\left(\\frac{MW}{1000\\cdot 2\\pi R T}\n        \\right)^{0.5}\\left(\\frac{H_{vap}^2 P \\cdot MW}{1000\\cdot RT^2}\\right)\n\n    Parameters\n    ----------\n    T : float\n        Vapor temperature, [K]\n    P : float\n        Vapor pressure, [Pa]\n    MW : float\n        Molecular weight of the gas, [g/mol]\n    Hvap : float\n        Heat of vaporization of the fluid at P, [J/kg]\n    f : float\n        Correction factor, [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    f is a correction factor for how the removal of gas particles affects the\n    behavior of the ideal gas in diffusing to the condensing surface. It is\n    quite close to one, and has not been well explored in the literature due\n    to the rarity of the importance of the kinetic resistance.\n\n    Examples\n    --------\n    Water at 1 bar and 300 K:\n\n    >>> h_kinetic(300, 1E5, 18.02, 2441674)\n    30788829.908851154\n\n    References\n    ----------\n    .. [1] Berman, L. D. \"On the Effect of Molecular-Kinetic Resistance upon\n       Heat Transfer with Condensation.\" International Journal of Heat and Mass\n       Transfer 10, no. 10 (October 1, 1967): 1463.\n       doi:10.1016/0017-9310(67)90033-6.\n    .. [2] Kakaç, Sadik, ed. Boilers, Evaporators, and Condensers. 1 edition.\n       Wiley-Interscience, 1991.\n    .. [3] Stephan, Karl. Heat Transfer in Condensation and Boiling. Translated\n       by C. V. Green. Softcover reprint of the original 1st ed. 1992 edition.\n       Berlin; New York: Springer, 2013.\n    \"\"\"\n    return (2*f)/(2-f)*(MW/(1000*2*pi*R*T))**0.5*(Hvap**2*P*MW)/(1000*R*T**2)\n\n\ndef Cavallini_Smith_Zecchin(m: float, x: float, D: float, rhol: float, rhog: float, mul: float, mug: float, kl: float, Cpl: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for condensation\n    of a fluid inside a tube, as presented in\n    [1]_, also given in [2]_ and [3]_.\n\n    .. math::\n        Nu = \\frac{hD_i}{k_l} = 0.05 Re_e^{0.8} Pr_l^{0.33}\n\n    .. math::\n        Re_{eq} = Re_g(\\mu_g/\\mu_l)(\\rho_l/\\rho_g)^{0.5} + Re_l\n\n    .. math::\n        v_{gs} = \\frac{mx}{\\rho_g \\frac{\\pi}{4}D^2}\n\n    .. math::\n        v_{ls} = \\frac{m(1-x)}{\\rho_l \\frac{\\pi}{4}D^2}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific interval [-]\n    D : float\n        Diameter of the channel [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    mug : float\n        Viscosity of gas [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n\n    Examples\n    --------\n    >>> Cavallini_Smith_Zecchin(m=1, x=0.4, D=.3, rhol=800, rhog=2.5, mul=1E-5, mug=1E-3, kl=0.6, Cpl=2300)\n    5578.218369177804\n\n    References\n    ----------\n    .. [1] A. Cavallini, J. R. Smith and R. Zecchin, A dimensionless correlation\n       for heat transfer in forced convection condensation, 6th International\n       Heat Transfer Conference., Tokyo, Japan (1974) 309-313.\n    .. [2] Kakaç, Sadik, ed. Boilers, Evaporators, and Condensers. 1st.\n       Wiley-Interscience, 1991.\n    .. [3] Balcilar, Muhammet, Ahmet Selim Dalkiliç, Berna Bolat, and Somchai\n       Wongwises. \"Investigation of Empirical Correlations on the Determination\n       of Condensation Heat Transfer Characteristics during Downward Annular\n       Flow of R134a inside a Vertical Smooth Tube Using Artificial\n       Intelligence Algorithms.\" Journal of Mechanical Science and Technology\n       25, no. 10 (October 12, 2011): 2683-2701. doi:10.1007/s12206-011-0618-2.\n    \"\"\"\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    Vl = m*(1-x)/(rhol*pi/4*D**2)\n    Vg = m*x/(rhog*pi/4*D**2)\n    Rel = Reynolds(V=Vl, D=D, rho=rhol, mu=mul)\n    Reg = Reynolds(V=Vg, D=D, rho=rhog, mu=mug)\n    \"\"\"The following was coded, and may be used instead of the above lines,\n    to check that the definitions of parameters here provide the same results\n    as those defined in [1]_.\n    G = m/(pi/4*D**2)\n    Re = G*D/mul\n    Rel = Re*(1-x)\n    Reg = Re*x/(mug/mul)\"\"\"\n    Reeq = Reg*(mug/mul)*(rhol/rhog)**0.5 + Rel\n    Nul = 0.05*Reeq**0.8*Prl**0.33\n    return Nul*kl/D # confirmed to be with respect to the liquid\n\n\ndef Shah(m: float, x: float, D: float, rhol: float, mul: float, kl: float, Cpl: float, P: float, Pc: float) -> float:\n    r\"\"\"Calculates heat transfer coefficient for condensation\n    of a fluid inside a tube, as presented in [1]_ and again by the same\n    author in [2]_; also given in [3]_. Requires no properties of the gas.\n    Uses the Dittus-Boelter correlation for single phase heat transfer\n    coefficient, with a Reynolds number assuming all the flow is liquid.\n\n    .. math::\n        h_{TP} = h_L\\left[(1-x)^{0.8} +\\frac{3.8x^{0.76}(1-x)^{0.04}}\n        {P_r^{0.38}}\\right]\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific interval [-]\n    D : float\n        Diameter of the channel [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    mul : float\n        Viscosity of liquid [Pa*s]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    P : float\n        Pressure of the fluid, [Pa]\n    Pc : float\n        Critical pressure of the fluid, [Pa]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ is well written an unambiguous as to how to apply this equation.\n\n    Examples\n    --------\n    >>> Shah(m=1, x=0.4, D=.3, rhol=800, mul=1E-5, kl=0.6, Cpl=2300, P=1E6, Pc=2E7)\n    2561.2593415479214\n\n    References\n    ----------\n    .. [1] Shah, M. M. \"A General Correlation for Heat Transfer during Film\n       Condensation inside Pipes.\" International Journal of Heat and Mass\n       Transfer 22, no. 4 (April 1, 1979): 547-56.\n       doi:10.1016/0017-9310(79)90058-9.\n    .. [2] Shah, M. M., Heat Transfer During Film Condensation in Tubes and\n       Annuli: A Review of the Literature, ASHRAE Transactions, vol. 87, no.\n       3, pp. 1086-1100, 1981.\n    .. [3] Kakaç, Sadik, ed. Boilers, Evaporators, and Condensers. 1st.\n       Wiley-Interscience, 1991.\n    \"\"\"\n    VL = m/(rhol*pi/4*D**2)\n    ReL = Reynolds(V=VL, D=D, rho=rhol, mu=mul)\n    Prl = Prandtl(Cp=Cpl, k=kl, mu=mul)\n    hL = turbulent_Dittus_Boelter(ReL, Prl)*kl/D\n    Pr = P/Pc\n    return hL*((1-x)**0.8 + 3.8*x**0.76*(1-x)**0.04/Pr**0.38)\n\n"
  },
  {
    "path": "ht/conduction.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import acosh, log, pi\n\nfrom fluids.constants import Btu, degree_Fahrenheit, foot, hour, inch\n\n__all__: list[str] = [\n    \"R_cylinder\",\n    \"R_to_k\",\n    \"R_value_to_k\",\n    \"S_isothermal_pipe_eccentric_to_isothermal_pipe\",\n    \"S_isothermal_pipe_normal_to_plane\",\n    \"S_isothermal_pipe_to_isothermal_pipe\",\n    \"S_isothermal_pipe_to_plane\",\n    \"S_isothermal_pipe_to_two_planes\",\n    \"S_isothermal_sphere_to_plane\",\n    \"cylindrical_heat_transfer\",\n    \"k_to_R\",\n    \"k_to_R_value\",\n    \"k_to_thermal_resistivity\",\n    \"thermal_resistivity_to_k\",\n]\n\n\ndef R_to_k(R: float, t: float, A: float=1.) -> float:\n    r\"\"\"Returns the thermal conductivity of a substance given its thickness\n    and thermal resistance.\n\n    .. math::\n        k = \\frac{t}{RA}\n\n    Parameters\n    ----------\n    R : float\n        Thermal resistance of a substance, (K/W) if A is 1 m^2, otherwise must\n        be [m^2*K/W]\n    t : float\n        Thickness of the substance used in the measurement of R, [m]\n    A : float, optional\n        Area; normally 1, [m^2]\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n\n    Examples\n    --------\n    >>> R_to_k(R=0.05, t=0.025)\n    0.5\n\n    Notes\n    -----\n    When solving problems of changing areas, this value may be calculated with\n    an area other than 1 m^2. Values in tables reported as properties of\n    materials are often divided by area already; the conversion holds if A is 1.\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return t/(A*R)\n\n\ndef k_to_R(k: float, t: float, A: float=1.) -> float:\n    r\"\"\"Returns the thermal resistance of a substance given its thickness\n    and thermal conductivity.\n\n    .. math::\n        R = \\frac{t}{kA}\n\n    Parameters\n    ----------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n    t : float\n        Thickness of the substance for a given value of R, [m]\n    A : float, optional\n        Area; normally 1, [m^2]\n\n    Returns\n    -------\n    R : float\n        Thermal resistance of a substance [K/W]\n\n    Examples\n    --------\n    >>> k_to_R(k=0.5, t=0.025)\n    0.05\n\n    Notes\n    -----\n    When solving problems of changing areas, this value may be calculated with\n    an area other than 1 m^2. Values in tables reported as properties of\n    materials are often divided by area already; the conversion holds if A is 1.\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return t/(k*A)\n\n\ndef k_to_thermal_resistivity(k: float) -> float:\n    r\"\"\"Returns the thermal resistivity of a substance given its thermal\n    conductivity.\n\n    .. math::\n        r = \\frac{1}{k}\n\n    Parameters\n    ----------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n\n    Returns\n    -------\n    r : float\n        Thermal resistivity of a substance [m*K/W]\n\n    Examples\n    --------\n    >>> k_to_thermal_resistivity(0.25)\n    4.0\n\n    Notes\n    -----\n    Do not confuse this with thermal resistance! Often not introduced in heat\n    transfer textbooks to avoid further confusion. Used almost exclusively\n    as a description of solids. Thermal resistivity has different units than\n    R-value, but is of the same dimensionality.\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    return 1./k\n\n\ndef thermal_resistivity_to_k(r: float) -> float:\n    r\"\"\"Returns the thermal resistivity of a substance given its thermal\n    conductivity.\n\n    .. math::\n        k = \\frac{1}{r}\n\n    Parameters\n    ----------\n    r : float\n        Thermal resistivity of a substance [m*K/W]\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n\n    Examples\n    --------\n    >>> thermal_resistivity_to_k(4)\n    0.25\n\n    Notes\n    -----\n    Do not confuse this with thermal resistance! Often not introduced in heat\n    as a description of solids. Thermal resistivity has different units than\n    R-value, but is of the same dimensionality.\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    return 1./r\n\n\ndef R_value_to_k(R_value: float, SI: bool=True) -> float:\n    r\"\"\"Returns the thermal conductivity of a substance given its R-value,\n    which can be in either SI units of m^2 K/(W*inch) or the Imperial units\n    of ft^2 deg F*h/(BTU*inch).\n\n    Parameters\n    ----------\n    R_value : float\n        R-value of a substance [m^2 K/(W*inch) or ft^2 deg F*h/(BTU*inch)]\n    SI : bool, optional\n        Whether to use the SI conversion or not\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n\n    Notes\n    -----\n    If given input is SI, it is divided by 0.0254 (multiplied by 39.37) and\n    then inversed. Otherwise, it is multiplied by 6.93347 and then inversed.\n\n    Examples\n    --------\n    >>> R_value_to_k(0.12), R_value_to_k(0.71, SI=False)\n    (0.2116666666, 0.2031378716)\n\n    >>> R_value_to_k(1., SI=False)/R_value_to_k(1.)\n    5.6782633411\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if SI:\n        r = R_value/inch\n    else:\n        r = R_value*(foot*foot*degree_Fahrenheit*hour/Btu/inch)\n    return thermal_resistivity_to_k(r)\n\n\ndef k_to_R_value(k: float, SI: bool=True) -> float:\n    r\"\"\"Returns the R-value of a substance given its thermal conductivity,\n    Will return R-value in SI units unless SI is false. SI units are\n    m^2 K/(W*inch); Imperial units of R-value are ft^2 deg F*h/(BTU*inch).\n\n    Parameters\n    ----------\n    k : float\n        Thermal conductivity of a substance [W/m/K]\n    SI : bool, optional\n        Whether to use the SI conversion or not\n\n    Returns\n    -------\n    R_value : float\n        R-value of a substance [m^2 K/(W*inch) or ft^2 deg F*h/(BTU*inch)]\n\n    Notes\n    -----\n    Provides the reverse conversion of R_value_to_k.\n\n    Examples\n    --------\n    >>> k_to_R_value(R_value_to_k(0.12)), k_to_R_value(R_value_to_k(0.71, SI=False), SI=False)\n    (0.12, 0.71)\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    r = k_to_thermal_resistivity(k)\n    if SI:\n        return r*inch\n    else:\n        return r/(foot*foot*degree_Fahrenheit*hour/Btu/inch)\n\n\ndef R_cylinder(Di: float, Do: float, k: float, L: float) -> float:\n    r\"\"\"Returns the thermal resistance `R` of a cylinder of constant thermal\n    conductivity `k`, of inner and outer diameter `Di` and `Do`, and with a\n    length `L`.\n\n    .. math::\n        (hA)_{\\text{cylinder}}=\\frac{k}{\\ln(D_o/D_i)} \\cdot 2\\pi L\\\\\n        R_{\\text{cylinder}}=\\frac{1}{(hA)_{\\text{cylinder}}}=\n        \\frac{\\ln(D_o/D_i)}{2\\pi Lk}\n\n    Parameters\n    ----------\n    Di : float\n        Inner diameter of the cylinder, [m]\n    Do : float\n        Outer diameter of the cylinder, [m]\n    k : float\n        Thermal conductivity of the cylinder, [W/m/K]\n    L : float\n        Length of the cylinder, [m]\n\n    Returns\n    -------\n    R : float\n        Thermal resistance [K/W]\n\n    Examples\n    --------\n    >>> R_cylinder(0.9, 1., 20, 10)\n    8.38432343682705e-05\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    hA = k*2*pi*L/log(Do/Di)\n    return 1./hA\n\n### Shape Factors\n\ndef S_isothermal_sphere_to_plane(D: float, Z: float) -> float:\n    r\"\"\"Returns the Shape factor `S` of a sphere of constant temperature\n    and of outer diameter `D` which is `Z` distance from an infinite plane.\n\n    .. math::\n        S = \\frac{2\\pi D}{1 - \\frac{D}{4Z}}\n\n    Parameters\n    ----------\n    D : float\n        Diameter of the sphere, [m]\n    Z : float\n        Distance from the middle of the sphere to the infinite plane, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_sphere_to_plane(1, 100)\n    6.298932638776527\n\n    Notes\n    -----\n    No restrictions on the use of this equation.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2*pi*D/(1. - D/(4.*Z))\n\n\ndef S_isothermal_pipe_to_plane(D: float, Z: float, L: float=1) -> float:\n    r\"\"\"Returns the Shape factor `S` of a pipe of constant outer temperature\n    and of outer diameter `D` which is `Z` distance from an infinite plane.\n    Length `L` must be provided, but can be set to 1 to obtain a dimensionless\n    shape factor used in some sources.\n\n    .. math::\n        S = \\frac{2\\pi L}{\\cosh^{-1}(2z/D)}\n\n    Parameters\n    ----------\n    D : float\n        Diameter of the pipe, [m]\n    Z : float\n        Distance from the middle of the pipe to the infinite plane, [m]\n    L : float, optional\n        Length of the pipe, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_pipe_to_plane(1, 100, 3)\n    3.146071454894645\n\n    Notes\n    -----\n    L should be much larger than D.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2.*pi*L/acosh(2.*Z/D)\n\n\ndef S_isothermal_pipe_normal_to_plane(D: float, L: float) -> float:\n    r\"\"\"Returns the Shape factor `S` of a pipe of constant outer temperature\n    and of outer diameter `D` which extends into an infinite medium below an\n    an infinite plane.\n\n    .. math::\n        S = \\frac{2\\pi L}{\\ln(4L/D)}\n\n    Parameters\n    ----------\n    D : float\n        Diameter of the pipe, [m]\n    L : float\n        Length of the pipe, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_pipe_normal_to_plane(1, 100)\n    104.86893910124888\n\n    Notes\n    -----\n    L should be much larger than D.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2.*pi*L/log(4.*L/D)\n\n\ndef S_isothermal_pipe_to_isothermal_pipe(D1: float, D2: float, W: float, L: float=1.) -> float:\n    r\"\"\"Returns the Shape factor `S` of a pipe of constant outer temperature\n    and of outer diameter `D1` which is `w` distance from another infinite\n    pipe of outer diameter`D2`. Length `L` must be provided, but can be set to\n    1 to obtain a dimensionless shape factor used in some sources.\n\n    .. math::\n        S = \\frac{2\\pi L}{\\cosh^{-1}\\left(\\frac{4w^2-D_1^2-D_2^2}{2D_1D_2}\\right)}\n\n    Parameters\n    ----------\n    D1 : float\n        Diameter of one pipe, [m]\n    D2 : float\n        Diameter of the other pipe, [m]\n    W : float\n        Distance from the middle of one pipe to the middle of the other, [m]\n    L : float, optional\n        Length of the pipe, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_pipe_to_isothermal_pipe(.1, .2, 1, 1)\n    1.188711034982268\n\n    Notes\n    -----\n    L should be much larger than both diameters. L should be larger than W.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2.*pi*L/acosh((4*W*W - D1*D1 - D2*D2)/(2.*D1*D2))\n\n\ndef S_isothermal_pipe_to_two_planes(D: float, Z: float, L: float=1.) -> float:\n    r\"\"\"Returns the Shape factor `S` of a pipe of constant outer temperature\n    and of outer diameter `D` which is `Z` distance from two infinite\n    isothermal planes of equal temperatures, parallel to each other and\n    enclosing the pipe. Length `L` must be provided, but can be set to\n    1 to obtain a dimensionless shape factor used in some sources.\n\n    .. math::\n        S = \\frac{2\\pi L}{\\ln\\frac{8z}{\\pi D}}\n\n    Parameters\n    ----------\n    D : float\n        Diameter of the pipe, [m]\n    Z : float\n        Distance from the middle of the pipe to either of the planes, [m]\n    L : float, optional\n        Length of the pipe, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_pipe_to_two_planes(.1, 5, 1)\n    1.2963749299921428\n\n    Notes\n    -----\n    L should be much larger than both diameters. L should be larger than W.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Shape Factors for Heat Conduction Through Bodies with Isothermal or\n       Convective Boundary Conditions, J. E. Sunderland, K. R. Johnson, ASHRAE\n       Transactions, Vol. 70, 1964.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2.*pi*L/log(8.*Z/(pi*D))\n\n\ndef S_isothermal_pipe_eccentric_to_isothermal_pipe(D1: float, D2: float, Z: float, L: float=1.) -> float:\n    r\"\"\"Returns the Shape factor `S` of a pipe of constant outer temperature\n    and of outer diameter `D1` which is `Z` distance from the center of another\n    pipe of outer diameter`D2`. Length `L` must be provided, but can be set to\n    1 to obtain a dimensionless shape factor used in some sources.\n\n    .. math::\n        S = \\frac{2\\pi L}{\\cosh^{-1}\n        \\left(\\frac{D_2^2 + D_1^2 - 4Z^2}{2D_1D_2}\\right)}\n\n    Parameters\n    ----------\n    D1 : float\n        Diameter of inner pipe, [m]\n    D2 : float\n        Diameter of outer pipe, [m]\n    Z : float\n        Distance from the middle of inner pipe to the center of the other, [m]\n    L : float, optional\n        Length of the pipe, [m]\n\n    Returns\n    -------\n    S : float\n        Shape factor [m]\n\n    Examples\n    --------\n    >>> S_isothermal_pipe_eccentric_to_isothermal_pipe(.1, .4, .05, 10)\n    47.709841915608976\n\n    Notes\n    -----\n    L should be much larger than both diameters. D2 should be larger than D1.\n\n    .. math::\n        Q = Sk(T_1 - T_2) \\\\ R_{\\text{shape}}=\\frac{1}{Sk}\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 2.*pi*L/acosh((D2*D2 + D1*D1 - 4.*Z*Z)/(2.*D1*D2))\n\n\n# Specific heat transfer problems of conduction\n\n\ndef cylindrical_heat_transfer(Ti: float, To: float, hi: float, ho: float, Di: float, ts: list[float], ks: list[float]) -> dict[str, float | list[float]]:\n    r\"\"\"Calculation for the heat transfer through a cylindrical wall,\n    as occurs in pipes and cylindrical vessels. This is the core method\n    which calculates the temperatures of each layer - and allows an outer\n    layer to iterate on temperature or duty to meet a fixed specification,\n    or include things like temperature dependent thermal conductivities\n    or radiation.\n\n    Parameters\n    ----------\n    Ti : float\n        Temperature of the inside of the cylinder, [K]\n    To : float\n        External temperature outside the cylinder, away from the cylinder\n        wall, [K]\n    hi : float\n        Inside heat transfer coefficient, [W/m^2/K]\n    ho : float\n        Outside heat transfer coefficient, [W/m^2/K]\n    Di : float\n        Inside diameter of cylinder, [m]\n    ts : list[float]\n        List of thicknesses of each layer of the cylinder, [m]\n    ks : list[float]\n        List of thermal conductivities of each layer of the cylinder, [w/m/K]\n\n    Returns\n    -------\n    results : dict\n        * Q : Heat exchanged through the cylinder (per meter of length), [W/m]\n        * Rs : Thermal resistances of each of the layers, [m*K/W]\n        * Ts : Temperatures of the outside of each of the layers, [K]\n        * UA : Heat transfer coefficient times area (on a per-meter of\n               cylinder) basis, [W/K/m]\n        * U_inner : Heat transfer coefficient with respect to the inside\n                    diameter, [W/K]\n        * U_outer : Heat transfer coefficient with respect to the exterior\n                    diameter, [W/K]\n        * q : Specific heat exchanged (per square meter) through the cylinder\n              (per meter of length), [W/m^3]\n\n    Examples\n    --------\n    >>> from pprint import pprint\n    >>> pprint(cylindrical_heat_transfer(Ti=453.15, To=301.15, hi=1e12, ho=22.697193, Di=0.0779272, ts=[0.0054864, .05], ks=[56.045, 0.0598535265]))\n    {'Q': 73.12000884069367,\n     'Rs': [0.00022201030738405449, 1.189361782070256],\n     'Ts': [453.15, 453.1226455779877, 306.578530147744],\n     'UA': 0.48105268974140575,\n     'U_inner': 1.9649599487726137,\n     'U_outer': 0.8106078714663484,\n     'q': 123.21239646288495}\n    \"\"\"\n    length = 1.0 # basis\n    # Note - fouling is just another layer, should be converted to a thickness/thermal conductivity\n\n    external_diameter = Di + 2.0*sum(ts)\n    A_external = pi*external_diameter*length\n    A_internal = pi*Di*length\n\n    Rs = []\n    Do_running = Di\n    R_layers = 0.0\n    for i in range(len(ts)):\n        Do_running, Di_running = 2.0*ts[i]+Do_running, Do_running\n        Ri = 0.5*external_diameter*log(Do_running/Di_running)/ks[i]\n        R_layers += Ri\n        Rs.append(Ri)\n\n    D_ratio = external_diameter/Di\n    inv_term = D_ratio/hi + R_layers + 1.0/ho\n\n    U_external = 1.0/inv_term\n    UA = A_external*U_external\n    dT = Ti - To\n\n    Q = UA*dT\n    q = Q/A_external\n\n    # Compute the temperature profile\n    Ts = [Ti]\n    for Ri in Rs:\n        Ts.append(Ts[-1] - q*Ri)\n\n    # Convert heat transfer coefficient area basis = U_i*A_i = U_o*A_o, divide\n    ans = {\"Q\": Q, \"q\": q, \"UA\": UA, \"U_outer\": U_external, \"U_inner\": UA/A_internal, \"Ts\": Ts,\n          \"Rs\": Rs}\n    return ans\n"
  },
  {
    "path": "ht/conv_external.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import exp\n\n__all__: list[str] = [\n    \"LAMINAR_TRANSITION_HORIZONTAL_PLATE\",\n    \"Nu_cylinder_Churchill_Bernstein\",\n    \"Nu_cylinder_Fand\",\n    \"Nu_cylinder_McAdams\",\n    \"Nu_cylinder_Perkins_Leppert_1962\",\n    \"Nu_cylinder_Perkins_Leppert_1964\",\n    \"Nu_cylinder_Sanitjai_Goldstein\",\n    \"Nu_cylinder_Whitaker\",\n    \"Nu_cylinder_Zukauskas\",\n    \"Nu_external_cylinder\",\n    \"Nu_external_cylinder_methods\",\n    \"Nu_external_horizontal_plate\",\n    \"Nu_external_horizontal_plate_methods\",\n    \"Nu_horizontal_plate_laminar_Baehr\",\n    \"Nu_horizontal_plate_laminar_Churchill_Ozoe\",\n    \"Nu_horizontal_plate_turbulent_Kreith\",\n    \"Nu_horizontal_plate_turbulent_Schlichting\",\n    \"conv_horizontal_plate_methods\",\n]\n\n### Single Cylinders in Crossflow\n\n\ndef Nu_cylinder_Zukauskas(Re: float, Pr: float, Prw: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube at a\n    specified Re. Method from [1]_, also shown without modification in [2]_.\n    This method applies to both the laminar and turbulent regimes.\n\n    .. math::\n        Nu_{D}=CRe^{m}Pr^{n}\\left(\\frac{Pr}{Pr_s}\\right)^{1/4}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at free stream temperature [-]\n    Prw : float, optional\n        Prandtl number at wall temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    If Prandtl number at wall are not provided, the Prandtl number correction\n    is not used and left to an outside function.\n\n    n is 0.37 if Pr <= 10; otherwise n is 0.36.\n\n    C and m are from the following table. If Re is outside of the ranges shown,\n    the nearest range is used blindly.\n\n    +---------+-------+-----+\n    | Re      | C     | m   |\n    +=========+=======+=====+\n    | 1-40    | 0.75  | 0.4 |\n    +---------+-------+-----+\n    | 40-1E3  | 0.51  | 0.5 |\n    +---------+-------+-----+\n    | 1E3-2E5 | 0.26  | 0.6 |\n    +---------+-------+-----+\n    | 2E5-1E6 | 0.076 | 0.7 |\n    +---------+-------+-----+\n\n    Examples\n    --------\n    Example 7.3 in [2]_, matches.\n\n    >>> Nu_cylinder_Zukauskas(7992, 0.707, 0.69)\n    50.523612661934386\n\n    References\n    ----------\n    .. [1] Zukauskas, A. Heat transfer from tubes in crossflow. In T.F. Irvine,\n       Jr. and J. P. Hartnett, editors, Advances in Heat Transfer, volume 8,\n       pages 93-160. Academic Press, Inc., New York, 1972.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    if Re <= 40:\n        c, m = 0.75, 0.4\n    elif Re < 1E3:\n        c, m = 0.51, 0.5\n    elif Re < 2E5:\n        c, m = 0.26, 0.6\n    else:\n        c, m = 0.076, 0.7\n    if Pr <= 10.0:\n        n = 0.37\n    else:\n        n = 0.36\n    Nu = c*Re**m*Pr**n\n    if Prw is not None:\n        Nu = Nu*(Pr/Prw)**0.25\n    return Nu\n\n\ndef Nu_cylinder_Churchill_Bernstein(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube\n    at a specified `Re` and `Pr`, both evaluated at the film temperature. No\n    other wall correction is necessary for this formulation. Method is\n    shown without modification in [2]_ and many other texts.\n\n    .. math::\n        Nu_D = 0.3 + \\frac{0.62 Re_D^{0.5} Pr^{1/3}}{[1 + (0.4/Pr)^{2/3}\n        ]^{0.25}}\\left[1 + \\left(\\frac{Re_D}{282000}\\right)^{5/8}\\right]^{0.8}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at film temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    May underestimate heat transfer in some cases, as it the formula is\n    described in [1]_ as \"appears to provide a lower bound for RePr > 0.4\".\n    An alternate exponent for a smaller range is also presented in [1]_.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    Example 7.3 in [2]_, matches.\n\n    >>> Nu_cylinder_Churchill_Bernstein(6071, 0.7)\n    40.63708594124974\n\n    References\n    ----------\n    .. [1] Churchill, S. W., and M. Bernstein. \"A Correlating Equation for\n       Forced Convection From Gases and Liquids to a Circular Cylinder in\n       Crossflow.\" Journal of Heat Transfer 99, no. 2 (May 1, 1977):\n       300-306. doi:10.1115/1.3450685.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return 0.3 + (0.62*Re**0.5*Pr**(1/3.))/(1 + (0.4/Pr)**(2/3.))**0.25*(\n    1 +(Re/282000.)**(0.625))**0.8\n\n\ndef Nu_cylinder_Sanitjai_Goldstein(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube\n    at a specified `Re` and `Pr`, both evaluated at the film temperature. No\n    other wall correction is necessary for this formulation. Method is the\n    most recent implemented here and believed to be more accurate than other\n    formulations available.\n\n    .. math::\n        Nu = 0.446Re^{0.5} Pr^{0.35} + 0.528\\left[(6.5\\exp(Re/5000))^{-5}\n        + (0.031Re^{0.8})^{-5}\\right]^{-1/5}Pr^{0.42}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at film temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Developed with test results for water, mixtures of ethylene glycol and\n    water, and air (Pr = 0.7 to 176). Re range from 2E3 to 9E4. Also presents\n    results for local heat transfer coefficients.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_Sanitjai_Goldstein(6071, 0.7)\n    40.38327083519522\n\n    References\n    ----------\n    .. [1] Sanitjai, S., and R. J. Goldstein. \"Forced Convection Heat Transfer\n       from a Circular Cylinder in Crossflow to Air and Liquids.\" International\n       Journal of Heat and Mass Transfer 47, no. 22 (October 2004): 4795-4805.\n       doi:10.1016/j.ijheatmasstransfer.2004.05.012.\n    \"\"\"\n    # Interesting numerical issue:\n    # The power of the  -5 exp Re term is moved inside the exponential to\n    # avoid overflow errors\n    # This occurs easily with a large diameter cylinder (such as a vessel)\n    return 0.446*Re**0.5*Pr**0.35 + 0.528*((6.5**-5*exp(-5*Re/5000.))\n    + (0.031*Re**0.8)**-5)**-0.2*Pr**0.42\n\n\ndef Nu_cylinder_Fand(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube\n    at a specified `Re` and `Pr`, both evaluated at the film temperature. No\n    other wall correction is necessary for this formulation. Also shown in\n    [2]_.\n\n    .. math::\n        Nu = (0.35 + 0.34Re^{0.5} + 0.15Re^{0.58})Pr^{0.3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at film temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Developed with test results for water, and Re from 1E4 to 1E5, but also\n    compared with other data in the literature. Claimed validity of Re from\n    1E-1 to 1E5.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_Fand(6071, 0.7)\n    45.19984325481126\n\n    References\n    ----------\n    .. [1] Fand, R. M. \"Heat Transfer by Forced Convection from a Cylinder to\n       Water in Crossflow.\" International Journal of Heat and Mass Transfer 8,\n       no. 7 (July 1, 1965): 995-1010. doi:10.1016/0017-9310(65)90084-0.\n    .. [2] Sanitjai, S., and R. J. Goldstein. \"Forced Convection Heat Transfer\n       from a Circular Cylinder in Crossflow to Air and Liquids.\" International\n       Journal of Heat and Mass Transfer 47, no. 22 (October 2004): 4795-4805.\n       doi:10.1016/j.ijheatmasstransfer.2004.05.012.\n    \"\"\"\n    return (0.35 + 0.34*Re**0.5 + 0.15*Re**0.58)*Pr**0.3\n\n\ndef Nu_cylinder_McAdams(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube\n    at a specified `Re` and `Pr`, both evaluated at the film temperature. No\n    other wall correction is necessary for this formulation. Also shown in\n    [2]_.\n\n    .. math::\n        Nu = (0.35 + 0.56 Re^{0.52})Pr^{0.3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at film temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Developed with very limited test results for water only.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_McAdams(6071, 0.7)\n    46.98179235867934\n\n    References\n    ----------\n    .. [1] McAdams, William Henry. Heat Transmission. 3E. Malabar, Fla:\n       Krieger Pub Co, 1985.\n    .. [2] Fand, R. M. \"Heat Transfer by Forced Convection from a Cylinder to\n       Water in Crossflow.\" International Journal of Heat and Mass Transfer 8,\n       no. 7 (July 1, 1965): 995-1010. doi:10.1016/0017-9310(65)90084-0.\n    \"\"\"\n    return (0.35 + 0.56*Re**0.52)*Pr**0.3\n\n\ndef Nu_cylinder_Whitaker(Re: float, Pr: float, mu: float | None=None, muw: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube as shown\n    in [1]_ at a specified `Re` and `Pr`, both evaluated at the free stream\n    temperature. Recommends a viscosity exponent correction of 0.25, which is\n    applied only if provided. Also shown in [2]_.\n\n    .. math::\n        Nu_D = (0.4 Re_D^{0.5} + 0.06Re_D^{2/3})Pr^{0.4}\n        \\left(\\frac{\\mu}{\\mu_w}\\right)^{0.25}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at free stream temperature, [-]\n    mu : float, optional\n        Viscosity of fluid at the free stream temperature [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at the wall temperature [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Developed considering data from 1 to 1E5 Re, 0.67 to 300 Pr, and range of\n    viscosity ratios from 0.25 to 5.2. Found experimental data to generally\n    agree with it within 25%.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_Whitaker(6071, 0.7)\n    45.94527461589126\n\n    References\n    ----------\n    .. [1] Whitaker, Stephen. \"Forced Convection Heat Transfer Correlations for\n       Flow in Pipes, Past Flat Plates, Single Cylinders, Single Spheres, and\n       for Flow in Packed Beds and Tube Bundles.\" AIChE Journal 18, no. 2\n       (March 1, 1972): 361-371. doi:10.1002/aic.690180219.\n    .. [2] Sanitjai, S., and R. J. Goldstein. \"Forced Convection Heat Transfer\n       from a Circular Cylinder in Crossflow to Air and Liquids.\" International\n       Journal of Heat and Mass Transfer 47, no. 22 (October 2004): 4795-4805.\n       doi:10.1016/j.ijheatmasstransfer.2004.05.012.\n    \"\"\"\n    Nu = (0.4*Re**0.5 + 0.06*Re**(2/3.))*Pr**0.3\n    if mu is not None and muw is not None:\n        Nu *= (mu/muw)**0.25\n    return Nu\n\n\ndef Nu_cylinder_Perkins_Leppert_1962(Re: float, Pr: float, mu: float | None=None, muw: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube as shown\n    in [1]_ at a specified `Re` and `Pr`, both evaluated at the free stream\n    temperature. Recommends a viscosity exponent correction of 0.25, which is\n    applied only if provided. Also shown in [2]_.\n\n    .. math::\n        Nu = \\left[0.30Re^{0.5} + 0.10Re^{0.67}\\right]Pr^{0.4}\n        \\left(\\frac{\\mu}{\\mu_w}\\right)^{0.25}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at free stream temperature, [-]\n    mu : float, optional\n        Viscosity of fluid at the free stream temperature [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at the wall temperature [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Considered results with Re from 40 to 1E5, Pr from 1 to 300; and viscosity\n    ratios of 0.25 to 4.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_Perkins_Leppert_1962(6071, 0.7)\n    49.97164291175499\n\n    References\n    ----------\n    .. [1] Perkins, Jr., H. C., and G. Leppert. \"Forced Convection Heat\n       Transfer From a Uniformly Heated Cylinder.\" Journal of Heat Transfer 84,\n       no. 3 (August 1, 1962): 257-261. doi:10.1115/1.3684359.\n    .. [2] Sanitjai, S., and R. J. Goldstein. \"Forced Convection Heat Transfer\n       from a Circular Cylinder in Crossflow to Air and Liquids.\" International\n       Journal of Heat and Mass Transfer 47, no. 22 (October 2004): 4795-4805.\n       doi:10.1016/j.ijheatmasstransfer.2004.05.012.\n    \"\"\"\n    Nu = (0.30*Re**0.5 + 0.10*Re**0.67)*Pr**0.4\n    if mu is not None and muw is not None:\n        Nu *= (mu/muw)**0.25\n    return Nu\n\n\ndef Nu_cylinder_Perkins_Leppert_1964(Re: float, Pr: float, mu: float | None=None, muw: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube as shown\n    in [1]_ at a specified `Re` and `Pr`, both evaluated at the free stream\n    temperature. Recommends a viscosity exponent correction of 0.25, which is\n    applied only if provided. Also shown in [2]_.\n\n    .. math::\n        Nu = \\left[0.31Re^{0.5} + 0.11Re^{0.67}\\right]Pr^{0.4}\n        \\left(\\frac{\\mu}{\\mu_w}\\right)^{0.25}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at free stream temperature, [-]\n    mu : float, optional\n        Viscosity of fluid at the free stream temperature [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at the wall temperature [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Considers new data since `Nu_cylinder_Perkins_Leppert_1962`, Re from 2E3 to\n    1.2E5, Pr from 1 to 7, and surface to bulk temperature differences of\n    11 to 66.\n\n    This method applies to both the laminar and turbulent regimes.\n\n    Examples\n    --------\n    >>> Nu_cylinder_Perkins_Leppert_1964(6071, 0.7)\n    53.61767038619986\n\n    References\n    ----------\n    .. [1] Perkins Jr., H. C., and G. Leppert. \"Local Heat-Transfer\n       Coefficients on a Uniformly Heated Cylinder.\" International Journal of\n       Heat and Mass Transfer 7, no. 2 (February 1964): 143-158.\n       doi:10.1016/0017-9310(64)90079-1.\n    .. [2] Sanitjai, S., and R. J. Goldstein. \"Forced Convection Heat Transfer\n       from a Circular Cylinder in Crossflow to Air and Liquids.\" International\n       Journal of Heat and Mass Transfer 47, no. 22 (October 2004): 4795-4805.\n       doi:10.1016/j.ijheatmasstransfer.2004.05.012.\n    \"\"\"\n    Nu = (0.31*Re**0.5 + 0.11*Re**0.67)*Pr**0.4\n    if mu is not None and muw is not None:\n        Nu *= (mu/muw)**0.25\n    return Nu\n\n\nconv_external_cylinder_turbulent_methods = {\n    \"Zukauskas\": (Nu_cylinder_Zukauskas, (\"Re\", \"Pr\", \"Prw\")),\n    \"Churchill-Bernstein\": (Nu_cylinder_Churchill_Bernstein, (\"Re\", \"Pr\")),\n    \"Sanitjai-Goldstein\": (Nu_cylinder_Sanitjai_Goldstein, (\"Re\", \"Pr\")),\n    \"Fand\": (Nu_cylinder_Fand, (\"Re\", \"Pr\")),\n    \"McAdams\": (Nu_cylinder_McAdams, (\"Re\", \"Pr\")),\n    \"Whitaker\": (Nu_cylinder_Whitaker, (\"Re\", \"Pr\", \"mu\", \"muw\")),\n    \"Perkins-Leppert 1962\": (Nu_cylinder_Perkins_Leppert_1962, (\"Re\", \"Pr\", \"mu\", \"muw\")),\n    \"Perkins-Leppert 1964\": (Nu_cylinder_Perkins_Leppert_1964, (\"Re\", \"Pr\", \"mu\", \"muw\")),\n}\n\nconv_external_cylinder_turbulent_methods_ranked = [\"Sanitjai-Goldstein\",\n                                                   \"Churchill-Bernstein\",\n                                                   \"Zukauskas\", \"Whitaker\",\n                                                   \"Perkins-Leppert 1964\",\n                                                   \"McAdams\",  \"Fand\",\n                                                   \"Perkins-Leppert 1962\"]\n\nconv_external_cylinder_methods = conv_external_cylinder_turbulent_methods.copy()\n\n_missing_external_cylinder_method = f\"Correlation name not recognized; the availble methods are {list(conv_external_cylinder_methods.keys())}.\"\n\n\ndef Nu_external_cylinder_methods(Re: float, Pr: float, Prw: float | None=None, mu: float | None=None, muw: float | None=None, check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of correlation names for forced convection\n    over an external cylinder.\n\n    The preferred method 'Sanitjai-Goldstein'.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number of fluid with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at either the free stream or wall temperature\n        depending on the method, [-]\n    Prw : float, optional\n        Prandtl number at wall temperature, [-]\n    mu : float, optional\n        Viscosity of fluid at the free stream temperature [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at the wall temperature [Pa*s]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs\n\n    Examples\n    --------\n    >>> Nu_external_cylinder_methods(0.72, 1E7)[0]\n    'Sanitjai-Goldstein'\n    \"\"\"\n    methods = [\"Sanitjai-Goldstein\", \"Churchill-Bernstein\", \"Fand\", \"McAdams\"]\n    if Prw is not None:\n        methods.append(\"Zukauskas\")\n    if mu is not None and muw is not None:\n        methods.extend([\"Whitaker\", \"Perkins-Leppert 1964\", \"Perkins-Leppert 1962\"])\n    return methods\n\n\ndef Nu_external_cylinder(Re: float, Pr: float, Prw: float | None=None, mu: float | None=None, muw: float | None=None, Method: str | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a single tube at a\n    specified `Re` and `Pr` according to the specified method. Optional\n    parameters are `Prw`, `mu`, and `muw`. This function has eight methods\n    available. The 'Sanitjai-Goldstein' method is\n    the default.\n\n    The front of the cyliner is normally always in a laminar regime; whereas\n    the back is turbulent. The proportions change with `Re`; all correlations\n    take this into account. For this heat transfer case, there is no separation\n    between laminar and turbulent methods.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number of fluid with respect to cylinder diameter, [-]\n    Pr : float\n        Prandtl number at either the free stream or wall temperature\n        depending on the method, [-]\n    Prw : float, optional\n        Prandtl number at wall temperature, [-]\n    mu : float, optional\n        Viscosity of fluid at the free stream temperature [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at the wall temperature [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        conv_external_cylinder_methods.\n\n    Notes\n    -----\n    A comparison of the methods for various Prandtl and Reynolds number ranges\n    is plotted below.\n\n    .. plot:: plots/Nu_external_cylinder.py\n\n    Examples\n    --------\n    >>> Nu_external_cylinder(6071, 0.7)\n    40.38327083519522\n    \"\"\"\n    Method2 = \"Sanitjai-Goldstein\" if Method is None else Method\n\n    if Method2 == \"Sanitjai-Goldstein\":\n        return Nu_cylinder_Sanitjai_Goldstein(Re=Re, Pr=Pr)\n    elif Method2 == \"Churchill-Bernstein\":\n        return Nu_cylinder_Sanitjai_Goldstein(Re=Re, Pr=Pr)\n    elif Method2 == \"Fand\":\n        return Nu_cylinder_Fand(Re=Re, Pr=Pr)\n    elif Method2 == \"McAdams\":\n        return Nu_cylinder_McAdams(Re=Re, Pr=Pr)\n\n    elif Method2 == \"Zukauskas\":\n        return Nu_cylinder_Zukauskas(Re=Re, Pr=Pr, Prw=Prw)\n    elif Method2 == \"Whitaker\":\n        return Nu_cylinder_Whitaker(Re=Re, Pr=Pr, mu=mu, muw=muw)\n    elif Method2 == \"Perkins-Leppert 1962\":\n        return Nu_cylinder_Perkins_Leppert_1962(Re=Re, Pr=Pr, mu=mu, muw=muw)\n    elif Method2 == \"Perkins-Leppert 1964\":\n        return Nu_cylinder_Perkins_Leppert_1964(Re=Re, Pr=Pr, mu=mu, muw=muw)\n    else:\n\n        raise ValueError(_missing_external_cylinder_method)\n\n# Horizontal Plate in crossflow\n\ndef Nu_horizontal_plate_laminar_Baehr(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for laminar flow across an **isothermal**\n    flat plate at a specified `Re` and `Pr`, both evaluated at the bulk\n    temperature. No other wall correction is necessary for this formulation.\n    Four different equations are used for different Prandtl number ranges.\n\n    The equation for the common Prandtl number range is also recommended in\n    [2]_ and [3]_.\n\n    if :math:`\\text{Pr} < 0.005`:\n\n    .. math::\n        \\text{Nu}_L = 1.128\\text{Re}^{0.5}\\text{Pr}^{0.5}\n\n    if :math:`0.005 < \\text{Pr} < 0.05`:\n\n    .. math::\n        \\text{Nu}_L = 1.0\\text{Re}^{0.5}\\text{Pr}^{0.5}\n\n    if :math:`0.6 < \\text{Pr} < 10`:\n\n    .. math::\n        \\text{Nu}_L = 0.664\\text{Re}^{0.5}\\text{Pr}^{1/3}\n\n    if :math:`\\text{Pr} > 10`:\n\n    .. math::\n        \\text{Nu}_L = 0.678\\text{Re}^{0.5}\\text{Pr}^{1/3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to plate length and bulk fluid properties,\n        [-]\n    Pr : float\n        Prandtl number at bulk temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length and bulk temperature, [-]\n\n    Notes\n    -----\n    Does not take into account the impact of free convection, which can\n    increase the convection substantially.\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_laminar_Baehr(1e5, 0.7)\n    186.4378528752262\n\n    References\n    ----------\n    .. [1] Baehr, Hans Dieter, and Karl Stephan. Heat and Mass Transfer.\n       Springer, 2013.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E.\n       Hoboken, NJ: Wiley, 2011.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    if Pr < 0.005:\n        return 1.128*(Re*Pr)**0.5\n    elif Pr < 0.05:\n        return (Re*Pr)**0.5\n    elif Pr < 10.0:\n        # Equation in VDI handbook, G4 as well\n        return 0.664*Re**0.5*Pr**(1/3.)\n    else:\n        return 0.678*Re**0.5*Pr**(1/3.)\n\n\ndef Nu_horizontal_plate_laminar_Churchill_Ozoe(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for laminar flow across an **isothermal**\n    flat plate at a specified `Re` and `Pr`, both evaluated at the bulk\n    temperature. No other wall correction is necessary for this formulation.\n    A single equation covers all Prandtl number ranges.\n\n    .. math::\n        Nu_L = \\frac{0.6774Re_L^{1/2}Pr^{1/3}}{[1+(0.0468/Pr)^{2/3}]^{1/4}}\n\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to plate length and bulk fluid properties,\n        [-]\n    Pr : float\n        Prandtl number at bulk temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length and bulk temperature, [-]\n\n    Notes\n    -----\n    Does not take into account the impact of free convection, which can\n    increase the convection substantially.\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_laminar_Churchill_Ozoe(1e5, 0.7)\n    183.08600782591418\n\n    References\n    ----------\n    .. [1] Churchill, Stuart W., and Hiroyuki Ozoe. \"Correlations for Laminar\n       Forced Convection in Flow Over an Isothermal Flat Plate and in\n       Developing and Fully Developed Flow in an Isothermal Tube.\" Journal of\n       Heat Transfer 95, no. 3 (August 1, 1973): 416\n       https://doi.org/10.1115/1.3450078.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E.\n       Hoboken, NJ: Wiley, 2011.\n    \"\"\"\n    return (0.6774*Re**(0.5)*Pr**(1/3.)\n            *(1.0 + (0.0468/Pr)**(2.0/3.0))**-0.25 )\n\n\ndef Nu_horizontal_plate_turbulent_Schlichting(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for turbulent flow across an **isothermal**\n    flat plate at a specified `Re` and `Pr`, both evaluated at the bulk\n    temperature. The formulation of Schlichting is used, which adds a\n    surface friction term to a formulation from Petukhov and Popov.\n\n    .. math::\n        \\text{Nu}_L = \\frac{0.037\\text{Re}_L^{0.8} \\text{Pr}}\n        {1 + 2.443\\text{Re}_L^{-0.1}(\\text{Pr}^{2/3} - 1)}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to plate length and bulk fluid properties,\n        [-]\n    Pr : float\n        Prandtl number at bulk temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length and bulk temperature, [-]\n\n    Notes\n    -----\n    Does not take into account the impact of free convection, which can\n    increase the convection substantially.\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_turbulent_Schlichting(1e5, 0.7)\n    309.620048541267\n\n    References\n    ----------\n    .. [1] Schlichting, H., and Klaus Gersten. Grenzschicht-Theorie. 9th ed.\n       Berlin Heidelberg: Springer-Verlag, 1997.\n       http://www.springer.com/de/book/9783662075548.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    num = 0.037*Re**0.8*Pr\n    den = (1.0 + 2.443*Re**-0.1*(Pr**(2.0/3.0) - 1.0))\n    return num/den\n\n\ndef Nu_horizontal_plate_turbulent_Kreith(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number for turbulent flow across an **isothermal**\n    flat plate at a specified `Re` and `Pr`, both evaluated at the bulk\n    temperature. The formulation of Kreith is used.\n\n    .. math::\n        \\text{Nu}_L = 0.036\\text{Re}_L^{0.8} \\text{Pr}^{1/3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to plate length and bulk fluid properties,\n        [-]\n    Pr : float\n        Prandtl number at bulk temperature, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length and bulk temperature, [-]\n\n    Notes\n    -----\n    Does not take into account the impact of free convection, which can\n    increase the convection substantially. Applies for turbulent flow only.\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_turbulent_Kreith(1.03e6, 0.71)\n    2074.8740070411122\n\n    References\n    ----------\n    .. [1] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    \"\"\"\n    return 0.036*Pr**(1.0/3.0)*Re**0.8\n\n\nconv_horizontal_plate_laminar_methods = {\n    \"Baehr\": (Nu_horizontal_plate_laminar_Baehr, (\"Re\", \"Pr\")),\n    \"Churchill Ozoe\": (Nu_horizontal_plate_laminar_Churchill_Ozoe, (\"Re\", \"Pr\")),\n}\n\nconv_horizontal_plate_turbulent_methods = {\n    \"Schlichting\": (Nu_horizontal_plate_turbulent_Schlichting, (\"Re\", \"Pr\")),\n    \"Kreith\": (Nu_horizontal_plate_turbulent_Kreith, (\"Re\", \"Pr\")),\n}\n\nconv_horizontal_plate_methods = conv_horizontal_plate_laminar_methods.copy()\nconv_horizontal_plate_methods.update(conv_horizontal_plate_turbulent_methods)\n\nLAMINAR_TRANSITION_HORIZONTAL_PLATE = 5E5\n\ndef Nu_external_horizontal_plate_methods(Re: float, Pr: float, L: float | None=None, x: float | None=None,\n                                   check_ranges: bool=True) -> list[str]:\n    r\"\"\"Returns a list of correlation names for calculating Nusselt number for\n    forced convection across a horizontal plate, supporting both laminar\n    and turbulent regimes.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to bulk properties and plate length, [-]\n    Pr : float\n        Prandtl number with respect to bulk properties, [-]\n    L : float, optional\n        Length of horizontal plate, [m]\n    x : float, optional\n        Length of horizontal plate for specific calculation distance, [m]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs\n\n    Examples\n    --------\n    >>> Nu_external_horizontal_plate_methods(Re=1e7, Pr=.7)[0]\n    'Schlichting'\n    \"\"\"\n    turbulent = Re >= LAMINAR_TRANSITION_HORIZONTAL_PLATE\n    if check_ranges:\n        if turbulent:\n            return [\"Schlichting\", \"Kreith\"]\n        else:\n            return [\"Baehr\", \"Churchill Ozoe\"]\n    else:\n        return [\"Baehr\", \"Churchill Ozoe\", \"Schlichting\", \"Kreith\"]\n\ndef Nu_external_horizontal_plate(Re: float, Pr: float, L: None=None, x: None=None, Method: str | None=None,\n                                 laminar_method: str=\"Baehr\",\n                                 turbulent_method: str=\"Schlichting\",\n                                 Re_transition: float=LAMINAR_TRANSITION_HORIZONTAL_PLATE) -> float:\n    r\"\"\"This function calculates the heat transfer coefficient for external\n    forced convection along a horizontal plate.\n\n    Requires at a minimum a flow's Reynolds and Prandtl numbers `Re` and `Pr`.\n    `L` and `x` are not used by any correlations presently, but are included\n    for future support.\n\n    If no correlation's name is provided as `Method`, the most accurate\n    applicable correlation is selected.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to bulk properties and plate length, [-]\n    Pr : float\n        Prandtl number with respect to bulk properties, [-]\n    L : float, optional\n        Length of horizontal plate, [m]\n    x : float, optional\n        Length of horizontal plate for specific calculation distance, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        conv_horizontal_plate_methods\n    laminar_method : str, optional\n        The prefered method for laminar flow, [-]\n    turbulent_method : str, optional\n        The prefered method for turbulent flow, [-]\n    Re_transition : float, optional\n        The transition Reynolds number for laminar changing to turbulent flow,\n        [-]\n\n    Examples\n    --------\n    Turbulent example\n\n    >>> Nu_external_horizontal_plate(Re=1E7, Pr=.7)\n    11496.952599969829\n    \"\"\"\n    turbulent = not Re < Re_transition\n    if Method is None:\n        Method2 = turbulent_method if turbulent else laminar_method\n    else:\n        Method2 = Method\n\n    if Method2 == \"Baehr\":\n        return Nu_horizontal_plate_laminar_Baehr(Re=Re, Pr=Pr)\n    elif Method2 == \"Churchill Ozoe\":\n        return Nu_horizontal_plate_laminar_Churchill_Ozoe(Re=Re, Pr=Pr)\n    elif Method2 == \"Schlichting\":\n        return Nu_horizontal_plate_turbulent_Schlichting(Re=Re, Pr=Pr)\n    elif Method2 == \"Kreith\":\n        return Nu_horizontal_plate_turbulent_Kreith(Re=Re, Pr=Pr)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n"
  },
  {
    "path": "ht/conv_free_enclosed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import exp, log\n\nfrom fluids.numerics import bisplev, horner, implementation_optimize_tck, secant\n\n__all__: list[str] = [\n    \"Nu_Nusselt_Rayleigh_Hollands\",\n    \"Nu_Nusselt_Rayleigh_Holling_Herwig\",\n    \"Nu_Nusselt_Rayleigh_Probert\",\n    \"Nu_Nusselt_vertical_Thess\",\n    \"Nu_vertical_helical_coil_Ali\",\n    \"Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan\",\n    \"Rac_Nusselt_Rayleigh\",\n    \"Rac_Nusselt_Rayleigh_disk\",\n]\n\n__numba_additional_funcs__ = [\"Nu_Nusselt_Rayleigh_Holling_Herwig_err\"]\n\n\ndef Nu_Nusselt_Rayleigh_Holling_Herwig_err(Nu: float, Ra: float, Ra_third: float, D2: float) -> float:\n    err = Ra_third*(0.1/2.0*log(1.0/16.0*Ra*Nu) + D2)**(-4.0/3.0) - Nu\n    return err\n\n\ndef Nu_Nusselt_Rayleigh_Holling_Herwig(Pr: float, Gr: float, buoyancy: bool=True) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection between two\n    theoretical flat horizontal plates. The height between the plates is infinite, and\n    one of the other dimensions of the plates is much larger than the other.\n\n    This correlation is for the horizontal plate Rayleigh-Benard classic heat\n    transfer problem, not for real finite geometry plates.\n\n    This model is a non-linear equation which is solved numerically.\n    The model can calculate `Nu` for `Ra` ranges between 350 and larger\n    numbers; [1]_ recommends :math:`10^{5} < Ra < 10^{15}`.\n\n    .. math::\n        \\text{Nu} = \\frac{{Ra}^{1/3}}{[0.05\\ln(\\frac{0.078}{16}{Ra}^{1.323})\n        + 2D]^{4/3}}\n\n    .. math::\n        D = -\\frac{14.94}{{Ra}^{0.25}} + 3.43\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - plate\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to height between the two plates, [-]\n\n    Notes\n    -----\n    A range of calculated values are provided in [1]_; they all match the\n    results of this function. This model is recommended in [2]_.\n\n    For :math:`Ra < 1708`, `Nu` = 1; for cases not assited by `buoyancy`,\n    `Nu` is also 1.\n\n    No success has been found finding an analytical solution in the major CAS\n    packages, but the nonlinear function is in fact a function of one variable;\n    this means a pade or chebyshev expansion could be performed.\n\n\n    Examples\n    --------\n    >>> Nu_Nusselt_Rayleigh_Holling_Herwig(5.54, 3.21e8, buoyancy=True)\n    77.54656801896913\n\n    References\n    ----------\n    .. [1] Hölling, M., and H. Herwig. \"Asymptotic Analysis of Heat Transfer in\n       Turbulent Rayleigh-Bénard Convection.\" International Journal of Heat and\n       Mass Transfer 49, no. 5 (March 1, 2006): 1129-36.\n       https://doi.org/10.1016/j.ijheatmasstransfer.2005.09.002.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    if not buoyancy:\n        return 1.0\n    Rac = 1708 # Constant\n\n    Ra = Gr*Pr\n    if Ra < Rac:\n        return 1.0\n\n    Ra_third = Ra**(1.0/3.0)\n    D2 = 2.0*(-14.94*Ra**-0.25 + 3.43)\n    Nu_guess = Ra_third*(0.1/2.0*log(.078/16.0*Ra**1.323) + D2)**(-4.0/3.0)\n    return secant(Nu_Nusselt_Rayleigh_Holling_Herwig_err, Nu_guess, args=(Ra, Ra_third, D2))\n\n\ndef Nu_Nusselt_Rayleigh_Probert(Pr: float, Gr: float, buoyancy: bool=True) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection between two\n    theoretical flat plates. The height between the plates is infinite, and\n    one of the other dimensions of the plates is much larger than the other.\n\n    This correlation is for the horizontal plate Rayleigh-Benard classic heat\n    transfer problem, not for real finite geometry plates.\n\n    Two sets of equations are used.\n\n    For the laminar regime :math:`1708 < \\text{Ra} \\le 2.2\\times 10^{4}`:\n\n    .. math::\n        \\text{Nu} = 0.208(\\text{Ra})^{0.25}\n\n    For the turbulent regime :math:`2.2\\times 10^{4} < \\text{Ra}`:\n\n    .. math::\n        \\text{Nu} = 0.092(\\text{Ra})^{1/3}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - plate\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to height between the two plates, [-]\n\n    Notes\n    -----\n    This model is recommended in [2]_ as a rough model.\n\n    For :math:`Ra < 1708`, `Nu` = 1; for cases not assited by `buoyancy`,\n    `Nu` is also 1.\n\n    Examples\n    --------\n    >>> Nu_Nusselt_Rayleigh_Probert(5.54, 3.21e8, buoyancy=True)\n    111.46181048289132\n\n    References\n    ----------\n    .. [1] Probert, SD, RG Brooks, and M Dixon. \"Heat Transfer across\n       Rectangular Cavities.\" CHEMICAL AND PROCESS ENGINEERING, 1970, 35.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    if not buoyancy:\n        return 1.0\n    Rac = 1708 # Constant\n\n    Ra = Gr*Pr\n    if Ra < Rac:\n        return 1.0\n    elif Ra < 2.2e4:\n        return 0.208*Ra**0.25\n    else:\n        return 0.092*Ra**(1.0/3.0)\n\n\ndef Nu_Nusselt_Rayleigh_Hollands(Pr: float, Gr: float, buoyancy: bool=True, Rac: float=1708) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection between two\n    theoretical flat horizontal plates using the Hollands [1]_ correlation recommended\n    in [2]_. This correlation supports different aspect ratios,\n    so the plates can be real, finite objects and have their heat transfer\n    accurately modeled. The influence comes from the `Rac` term, which should\n    be calculated separately, using `Rac_Nusselt_Rayleigh` or\n    `Rac_Nusselt_Rayleigh_disk`.\n\n    .. math::\n        \\text{Nu} = 1 + \\left[1 - \\frac{1708}{\\text{Ra}} \\right]^*\n        \\left[k_1 + 2 \\left(\\frac{\\text{Ra}^{1/3}}{k_2} \\right)^{1\n        - \\ln({\\text{Ra}}^{1/5}/k_2)} \\right]^*\n        + \\left[\\left(\\frac{\\text{Ra}}{5803}\\right)^{1/3} - 1\\right]^*\n\n    .. math::\n        k_1 = \\frac{1.44}{1 + 0.018/{Pr} + 0.00136/{Pr}^2}\n\n    .. math::\n        k_2 = 75\\exp(1.5\\text{Pr}^{-0.5})\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - plate\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n    Rac : float, optional\n        Critical Rayleigh number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to height between the two plates, [-]\n\n    Notes\n    -----\n    For :math:`Ra < {Ra}_c`, `Nu` = 1; for cases not assited by `buoyancy`,\n    `Nu` is also 1.\n\n    Examples\n    --------\n    >>> Nu_Nusselt_Rayleigh_Hollands(5.54, 3.21e8, buoyancy=True)\n    69.02668649510\n\n    Plates - 1 m height, 2 m long, 0.2 m long vs a 1 m^3 cube\n\n    >>> Nu_Nusselt_Rayleigh_Hollands(.7, 3.21e6, buoyancy=True, Rac=Rac_Nusselt_Rayleigh(H=1, L=2, W=.2, insulated=False))\n    4.666249131876\n\n    >>> Nu_Nusselt_Rayleigh_Hollands(.7, 3.21e6, buoyancy=True, Rac=Rac_Nusselt_Rayleigh(H=1, L=1, W=1, insulated=False))\n    8.786362614129\n\n    References\n    ----------\n    .. [1] Hollands, K. G. T. \"Multi-Prandtl Number Correlation Equations for\n       Natural Convection in Layers and Enclosures.\" International Journal of\n       Heat and Mass Transfer 27, no. 3 (March 1, 1984): 466-68.\n       https://doi.org/10.1016/0017-9310(84)90295-3.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    if not buoyancy:\n        return 1.0\n    Ra = Gr*Pr\n    if Ra < Rac:\n        return 1.0\n\n    k1 = 1.44/(1.0 + 0.018/Pr + 0.00136/(Pr*Pr))\n    k2 = 75*exp(1.5*Pr**-0.5)\n\n    t1 = (1.0 - Rac/Ra)\n    t2 = k1 + 2.0*(Ra**(1.0/3.0)/k2)**(1.0 - log(Ra**(1.0/3.0)/k2))\n    t3 = (Ra/5803.0)**(1.0/3.0) - 1.0\n\n    if Rac != 1708:\n        t4 = max(0.0, (Ra/Rac)**(1.0/3.0) - 1.0)\n        t5 = (1.0 - exp(-0.95*t4))\n    else:\n        t5 = 1.0\n\n    Nu = 1.0 + max(0.0, t1)*max(0.0, t2) + max(0.0, t3)*t5\n    return Nu\n\n\ndef Nu_Nusselt_vertical_Thess(Pr: float, Gr: float, H: int | None=None, L: int | None=None) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection between two\n    theoretical vertical flat plates using the correlation by Thess [1]\n    in [1]_. This is a variant on the horizontal Rayleigh-Benard classic heat\n    transfer problem.\n    This correlation supports different aspect ratios,\n    so the plates can be real, finite objects and have their heat transfer\n    accurately modeled. The recommended range of the correlation is H/L < 80.\n\n    For 1e4 < Ra < 1e7:\n\n    .. math::\n        \\text{Nu} = 0.42{Pr}^{0.012} {Ra}^{0.25} \\left(\\frac{H}{L}\\right)^{-0.25}\n\n    For 1e7 < Ra > 1e9 (or when geometry is unknown):\n\n    .. math::\n         \\text{Nu} = 0.049{Ra}^{0.33}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - plate\n        temperature difference [-]\n    H : float, optional\n        Height of vertical plate, [m]\n    L : float, optional\n        Length of vertical plate, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to distance between the two plates, [-]\n\n    Examples\n    --------\n    >>> Nu_Nusselt_vertical_Thess(.7, 3.21e6)\n    6.112587569602785\n\n    >>> Nu_Nusselt_vertical_Thess(.7, 3.21e6, L=10, H=1)\n    28.79328626041646\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    Ra = Gr*Pr\n    if Ra < 1e7 and H is not None and L is not None:\n        return 0.42*Pr**0.012*Ra**0.25*(L/H)**0.25\n    return 0.049*Ra**0.33\n\n\n\nratios_uninsulated_Catton = [0.125, 0.25, 0.5, 1, 2, 3, 4, 5, 6]\nRacs_uninstulated_Catton = [[9802960, 1554480, 606001, 469377, 444995, 444363, 457007, 473725, 494741],\n[1554480, 638754, 115596, 64270.8, 53529.7, 50816.4, 50136.1, 50088.7, 50410.1],\n[606001, 115596, 48178.9, 14615.3, 11374.5, 9831.6, 9312, 9099.4, 8980.2],\n[469377, 64270.8, 14615.3, 6974, 5138.2, 3906, 3633.6, 3446.2, 3358],\n[444995, 53529.7, 11374.5, 5137.9, 3773.6, 2753.6, 2530.5, 2359.5, 2285.7],\n[444363, 50816.4, 9831.6, 3906, 2753, 2557.4, 2337.2, 2174.44, 2101],\n[457007, 50136.1, 9311.9, 3633.6, 2530.5, 2337.2, 2270.2, 2110.9, 2037.2],\n[473725, 50088.6, 9099.4, 3446.2, 2359.5, 2174.4, 2110.9, 2081.7, 2007.8],\n[494742, 50410.1, 8980.2, 3357.9, 2285.7, 2100.9, 2037.2, 2007.8, 1991.9]]\n\ntck_uninstulated_Catton = implementation_optimize_tck([[0.125, 0.125, 0.125, 0.125, 0.41375910864088195,\n                              0.5819413331927507, 1.9885569998423345, 2.8009586482973834,\n                              3.922852887459219, 6.0, 6.0, 6.0, 6.0],\n                             [0.125, 0.125, 0.125, 0.125, 0.4180739258304788,\n                              0.6521218159098487, 1.4270223336187269,\n                              2.89426640315332, 3.9239774081390215,\n                              6.0, 6.0, 6.0, 6.0],\n [16.098194938851986, 14.026983058722742, 13.35866942808268, 13.043296359953983,\n  13.008470795621905, 12.991279831677808, 13.040841344665466, 13.07803101947673,\n  13.111789672293794, 14.074352449019207, 14.878522936155216, 11.151352953023258,\n  11.096394321545977, 10.813773781060574, 10.796217122120712, 10.78189560829848,\n  10.774336865714089, 10.78004622910552, 13.400086198278455, 11.369928815173187,\n  11.82067779495709, 9.6860949637944, 9.686120336218499, 9.50952376562826,\n  9.444619552074945, 9.452058024482865, 9.441608909473647, 12.933722760010111,\n  10.873615956186896, 8.971126166473885, 8.520162104980807, 8.317346176887659,\n  7.837750498437191, 7.78951404473208, 7.690715685713949, 7.695209247397283,\n  13.025815591825872, 10.75723159025179, 9.734653433466208, 8.569056561731081,\n  8.77031704228521, 7.853798846698488, 7.939088236475908, 7.748880239519593,\n  7.785611785518214, 12.992898431724237, 10.728320934519346, 9.37520794405935,\n  8.247995842200584, 7.753730020752022, 7.937553314495094, 7.6598493250444255,\n  7.673199977054488, 7.63790748099515, 13.041869920313422, 10.713059500923494,\n  9.364505568407685, 8.18000143764639, 7.927764179244221, 7.660718938605501,\n  7.85174473958641, 7.5354388646400965, 7.614740168201775, 13.077057211283323,\n  10.706667262420716, 9.341451094646674, 8.122270764822368, 7.671593316397699,\n  7.697000470802994, 7.530680469875164, 7.720180133976149, 7.59900173760075,\n  13.111791693551362, 10.711047679739433, 9.339770955175847, 8.117021359757253,\n  7.727537757463738, 7.654072928976537, 7.607359118625173, 7.602197791148399,\n  7.596844236081228], 3, 3])\n\nratios_insulated_Catton = [0.125, 0.25, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 12]\nRacs_instulated_Catton = [[3011718, 333013, 70040, 37689, 39798, 36262, 37058, 35875, 36209, 35664, 35794, 35486, 35556, 35380, 35451, 35193],\n[333013, 203163, 28452, 11962, 12540, 11020, 11251, 10757, 10858, 10635, 10666, 10544, 10571, 10499, 10518, 10426],\n[70040, 28452, 17307, 5262, 5341, 4524, 4567, 4330, 4355, 4245, 4261, 4186, 4196, 4158, 4165, 4118],\n[37689, 11962, 5262, 3446, 3270, 2789, 2754, 2622, 2609, 2552, 2545, 2502, 2498, 2480, 2447, 2453],\n[39798, 12540, 5341, 3270, None, None, None, None, None, None, None, None, None, None, None, None],\n[36262, 11020, 4524, 2789, None, 2276, 2222, 2121, 2098, 2057, 2044, 2009, 2001, 1989, 1984, 1967],\n[37058, 11251, 4567, 2754, None, 2222, None, None, None, None, None, None, None, None, None, None],\n[35875, 10757, 4330, 2622, None, 2121, None, 2004, 1978, 1941, 1927, 1897, 1888, 1879, 1871, 1855],\n[36209, 10858, 4355, 2609, None, 2098, None, 1978, None, None, None, None, None, None, None, None],\n[35664, 10635, 4245, 2552, None, 2057, None, 1941, None, 1894, 1878, 1852, 1842, 1833, 1826, 1808],\n[35794, 10666, 4261, 2545, None, 2044, None, 1927, None, 1878, None, None, None, None, None, None],\n[35486, 10544, 4186, 2502, None, 2009, None, 1897, None, 1852, None, None, None, 1810, 1803, 1783],\n[35556, 10571, 4196, 2498, None, 2001, None, 1888, None, 1842, None, None, None, None, None, None],\n[35380, 10499, 4158, 2480, None, 1989, None, 1879, None, 1833, None, 1810, None, 1797, 1789, 1768],\n[35451, 10518, 4165, 2447, None, 1984, None, 1871, None, 1826, None, 1803, None, 1789, None, None],\n[35193, 10426, 4118, 2453, None, 1967, None, 1855, None, 1808, None, 1783, None, 1768, None, 1741]]\n\n\ntck_insulated_Catton = implementation_optimize_tck([[0.125, 0.125, 0.2165763979498294, 0.25, 0.4948545767149843,\n                                                     0.8432690088415454, 2.297018168305444, 5.324310151069744, 12.0, 12.0],\n [0.125, 0.125, 0.125, 0.37135574365684176, 0.8160817162671293, 1.1103105500488575,\n  1.9000136398530074, 3.521092600950009, 12.0, 12.0, 12.0],\n  [14.917942380813974, 12.196391449028951, 10.665084931671647, 10.531834082947338,\n   10.57637568816619, 10.486173564722383, 10.471864979770599, 10.468190753935556,\n   0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 12.715841947316376, 12.462417612931137,\n   9.174421085152083, 9.411191211042704, 9.409695481542864, 9.28122664900159,\n   9.249608368005552, 9.251639244971427, 11.165512470689693, 10.01308504970903,\n   9.75292707527754, 8.509349912597454, 8.566854764542974, 8.372517445356857,\n   8.32618713246236, 8.329704835832104, 10.56848779064929, 9.163970117017675,\n   8.369187019066972, 8.19799054440329, 8.087508877612247, 7.896372367041187,\n   7.806891615973793, 7.835687464634469, 10.509836235182163, 9.041210689705586,\n   8.118960504225761, 7.909354018896528, 7.735269232380504, 7.614379036546508,\n   7.4775491512154515, 7.529024952770015, 10.474423221467699, 8.98482837851057,\n   8.036532362247245, 7.822308882170893, 7.6362269726600065, 7.539826337638537,\n   7.459554042916101, 7.480930154132415, 10.469149134470264, 8.978694786931275,\n   8.024134988827441, 7.811393154091167, 7.627457342156321, 7.521833838146938,\n   7.4376750879045455, 7.462202956737165], 1, 2])\n\n\ndef Rac_Nusselt_Rayleigh(H: float, L: float, W: float, insulated: bool=True) -> float:\n    r\"\"\"Calculates the critical Rayleigh number for free convection to begin\n    in the Nusselt-Rayleigh parallel horizontal plate scenario. There are\n    actually two cases - one for the top plate to be insulated (adiabatic) and\n    the other where it has infinite thermal conductivity/is infinitely thin or\n    not present (perfectly conducting). All real cases will lie between the\n    two.\n\n    Parameters\n    ----------\n    H : float\n        Distance between the two plates, [m]\n    L : float\n        Length of the plates, [m]\n    W : float\n        Width of the plates, [m]\n    insulated : bool, optional\n        Whether the top plate is insulated or uninsulated, [-]\n\n    Returns\n    -------\n    Rac : float\n        Critical Rayleigh number, [-]\n\n    Examples\n    --------\n    >>> Rac_Nusselt_Rayleigh(1, .5, 2, False)\n    2530.500000000005\n    >>> Rac_Nusselt_Rayleigh(1, .5, 2, True)\n    2071.0089443385655\n\n    Notes\n    -----\n    Splines have been fit to data in [1]_ for the uninsulated case and [2]_\n    for the insulated case. The data is presented in the original papers and\n    in [3]_.\n\n    References\n    ----------\n    .. [1] Catton, Ivan. \"Effect of Wall Conduction on the Stability of a Fluid\n       in a Rectangular Region Heated from Below.\" Journal of Heat Transfer 94,\n       no. 4 (November 1, 1972): 446-52. https://doi.org/10.1115/1.3449966.\n    .. [2] Catton, Ivan. \"Convection in a Closed Rectangular Region: The Onset\n       of Motion.\" Journal of Heat Transfer 92, no. 1 (February 1, 1970):\n       186-88. https://doi.org/10.1115/1.3449626.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    H_L_ratio = min(max(H/L, 0.125), 12.0)\n    W_L_ratio = min(max(W/L, 0.125), 12.0)\n\n    if insulated:\n        Rac = exp(bisplev(W_L_ratio, H_L_ratio, tck_insulated_Catton))\n    else:\n        Rac = exp(bisplev(W_L_ratio, H_L_ratio, tck_uninstulated_Catton))\n    return Rac\n\n\nuninsulated_disk_coeffs = [1.3624571738082523, -0.24301326192178863, -6.152310426160362,\n                           1.1950540229805053, 11.401090141352329, -2.405543860763877,\n                           -11.091871509655324, 2.519761389270987, 5.992609902331248,\n                           -1.4345227368881952, -1.7445130176764998, 0.42892571421446996,\n                           0.22897205478499438, -0.042179780698649895, -0.01904413256783342,\n                           0.006771075600246057, 0.13171026423861615]\n\n\ninsulated_disk_coeffs = [0.2173851248644496, 0.09672312658254612, -1.0800494968302843,\n                         -0.3323452633903514, 2.1789014174652115, 0.43391756058946473,\n                         -2.275756526433769, -0.29309565826688255, 1.3153930583762103,\n                         0.14707146242791974, -0.44891166228441826, -0.045070571352735386,\n                         0.08693822836596571, 0.010343944709216, -0.01325209778273359,\n                         0.0035707992137628142, 0.13258956599554672]\n\n\ndef Rac_Nusselt_Rayleigh_disk(H: float, D: float, insulated: bool=True) -> float:\n    r\"\"\"Calculates the critical Rayleigh number for free convection to begin\n    in the parallel horizontal disk scenario. There are\n    actually two cases - one for the top plate to be insulated (adiabatic) and\n    the other where it has infinite thermal conductivity/is infinitely thin or\n    not present (perfectly conducting). All real cases will lie between the\n    two.\n\n    Parameters\n    ----------\n    H : float\n        Distance between the two disks, [m]\n    D : float\n        Diameter of the two disks, [m]\n    insulated : bool, optional\n        Whether the top plate is insulated or uninsulated, [-]\n\n    Returns\n    -------\n    Rac : float\n        Critical Rayleigh number, [-]\n\n    Examples\n    --------\n    >>> Rac_Nusselt_Rayleigh_disk(H=1, D=.4, insulated=False)\n    151199.9999999945\n\n    >>> Rac_Nusselt_Rayleigh_disk(H=1, D=4, insulated=False)\n    1891.520931853363\n\n    >>> Rac_Nusselt_Rayleigh_disk(2, 1, True)\n    24347.31479211917\n\n    Notes\n    -----\n    The range of data covered by this function is `D`/`H` from 0.4 to infinity.\n    As inifinity is not well suited to polynomial form, the upper limit is\n    6 in actuality. Values outside that range are rounded to the limits.\n\n    This function provides 17-coefficient polynomial fits to interpolate in the\n    table of values in [1]_. The source of the coefficients is cited as being\n    from [2]_.\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Buell, J. C., and I. Catton. \"The Effect of Wall Conduction on the\n       Stability of a Fluid in a Right Circular Cylinder Heated From Below.\"\n       Journal of Heat Transfer 105, no. 2 (May 1, 1983): 255-60.\n       https://doi.org/10.1115/1.3245571.\n    \"\"\"\n    x = min(max(D/H, 0.4), 6.0)\n    if insulated:\n        coeffs = insulated_disk_coeffs\n    else:\n        coeffs = uninsulated_disk_coeffs\n    return exp(1.0/horner(coeffs, 0.357142857142857151*(x - 3.2)))\n\n\n### Free convection vertical helical coil\n\ndef Nu_vertical_helical_coil_Ali(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    helical coil inside a tank or other vessel according to the Ali [1]_\n    correlation.\n\n    .. math::\n        Nu_L = 0.555Gr_L^{0.301} Pr^{0.314}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number of the fluid surrounding the coil with properties\n        evaluated at bulk conditions or as described in the notes [-]\n    Gr : float\n        Prandtl number of the fluid surrounding the coil with properties\n        evaluated at bulk conditions or as described in the notes\n        (for the two temperatures, use the average coil fluid temperature and\n        the temperature of the fluid outside the coil) [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to the total length of the helical coil\n        (and bulk thermal conductivity), [-]\n\n    Notes\n    -----\n    In [1]_, the temperature at which the fluid surrounding the coil's\n    properties were evaluated at was calculated in an unusual fashion. The\n    average temperature of the fluid inside the coil\n    :math:`(T_{in} + T_{out})/2` is averaged with the fluid outside the coil's\n    temperature.\n\n    The correlation is valid for Prandtl numbers between 4.4 and 345,\n    and tank diameter/coil outer diameter ratios between 10 and 30.\n\n    Examples\n    --------\n    >>> Nu_vertical_helical_coil_Ali(4.4, 1E11)\n    1808.57749972\n\n    References\n    ----------\n    .. [1] Ali, Mohamed E. \"Natural Convection Heat Transfer from Vertical\n       Helical Coils in Oil.\" Heat Transfer Engineering 27, no. 3 (April 1,\n       2006): 79-85.\n    \"\"\"\n    return 0.555*Gr**0.301*Pr**0.314\n\n\ndef Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    helical coil inside a tank or other vessel according to the Prabhanjan,\n    Rennie, and Raghavan [1]_ correlation.\n\n    .. math::\n        Nu_H = 0.0749\\text{Ra}_H^{0.3421}\n\n    The range of Rayleigh numbers is as follows:\n\n    .. math::\n        9 \\times 10^{9} < \\text{Ra} < 4 \\times 10^{11}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number calculated with the film temperature -\n        wall and temperature very far from the coil average, [-]\n    Gr : float\n        Grashof number calculated with the film temperature -\n        wall and temperature very far from the coil average,\n        and using the total height of the coil [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number using the total height of the coil\n        and the film temperature, [-]\n\n    Notes\n    -----\n    [1]_ also has several other equations using different characteristic\n    lengths.\n\n    Examples\n    --------\n    >>> Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan(4.4, 1E11)\n    720.6211067718227\n\n    References\n    ----------\n    .. [1] Prabhanjan, Devanahalli G., Timothy J. Rennie, and G. S. Vijaya\n       Raghavan. \"Natural Convection Heat Transfer from Helical Coiled Tubes.\"\n       International Journal of Thermal Sciences 43, no. 4 (April 1, 2004):\n       359-65.\n    \"\"\"\n    Ra = Pr*Gr\n    return 0.0749*Ra**0.3421\n"
  },
  {
    "path": "ht/conv_free_immersed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import log\n\n__all__: list[str] = [\n    \"Nu_coil_Xin_Ebadian\",\n    \"Nu_free_horizontal_plate\",\n    \"Nu_free_horizontal_plate_methods\",\n    \"Nu_free_vertical_plate\",\n    \"Nu_free_vertical_plate_methods\",\n    \"Nu_horizontal_cylinder\",\n    \"Nu_horizontal_cylinder_Churchill_Chu\",\n    \"Nu_horizontal_cylinder_Kuehn_Goldstein\",\n    \"Nu_horizontal_cylinder_Morgan\",\n    \"Nu_horizontal_cylinder_methods\",\n    \"Nu_horizontal_plate_McAdams\",\n    \"Nu_horizontal_plate_Rohsenow\",\n    \"Nu_horizontal_plate_VDI\",\n    \"Nu_sphere_Churchill\",\n    \"Nu_vertical_cylinder\",\n    \"Nu_vertical_cylinder_Al_Arabi_Khamis\",\n    \"Nu_vertical_cylinder_Carne_Morgan\",\n    \"Nu_vertical_cylinder_Eigenson_Morgan\",\n    \"Nu_vertical_cylinder_Griffiths_Davis_Morgan\",\n    \"Nu_vertical_cylinder_Hanesian_Kalish_Morgan\",\n    \"Nu_vertical_cylinder_Jakob_Linke_Morgan\",\n    \"Nu_vertical_cylinder_Kreith_Eckert\",\n    \"Nu_vertical_cylinder_McAdams_Weiss_Saunders\",\n    \"Nu_vertical_cylinder_Popiel_Churchill\",\n    \"Nu_vertical_cylinder_Touloukian_Morgan\",\n    \"Nu_vertical_cylinder_methods\",\n    \"Nu_vertical_plate_Churchill\",\n]\n\n\ndef Nu_vertical_plate_Churchill(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    plate according to the Churchill-Chu [1]_ correlation, also presented in\n    [2]_. Plate must be isothermal; an alternate expression exists for constant\n    heat flux.\n\n    .. math::\n        Nu_{L}=\\left[0.825+\\frac{0.387Ra_{L}^{1/6}}\n        {[1+(0.492/Pr)^{9/16}]^{8/27}}\\right]^2\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to height, [-]\n\n    Notes\n    -----\n    Although transition from laminar to turbulent is discrete in reality, this\n    equation provides a smooth transition in value from laminar to turbulent.\n    Checked with the original source.\n\n    Can be applied to vertical cylinders as well, subject to the criteria below:\n\n    .. math::\n        \\frac{D}{L}\\ge \\frac{35}{Gr_L^{1/4}}\n\n    Examples\n    --------\n    From [2]_, Example 9.2, matches:\n\n    >>> Nu_vertical_plate_Churchill(0.69, 2.63E9)\n    147.16185223770603\n\n    References\n    ----------\n    .. [1] Churchill, Stuart W., and Humbert H. S. Chu. \"Correlating Equations\n       for Laminar and Turbulent Free Convection from a Vertical Plate.\"\n       International Journal of Heat and Mass Transfer 18, no. 11\n       (November 1, 1975): 1323-29. doi:10.1016/0017-9310(75)90243-4.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    Ra = Pr*Gr\n    term = (0.825 + (0.387*Ra**(1/6.)*(1.0 + (Pr/0.492)**(-0.5625))**(-8.0/27.0)))\n    return term*term\n\nNu_free_vertical_plate_all_methods = [\"Churchill\"]\n\ndef Nu_free_vertical_plate_methods(Pr: float, Gr: float, H: float | None=None, W: float | None=None, check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of methods for calculating heat transfer\n    coefficient for external free convection from a verical plate.\n\n    Requires at a minimum a fluid's Prandtl number `Pr`, and the Grashof\n    number `Gr` for the system fluid (which require T and P to obtain).\n\n    `L` and `W` are not used by any correlations presently, but are included\n    for future support.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    H : float, optional\n        Height of vertical plate, [m]\n    W : float, optional\n        Width of the vertical plate, [m]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs, [-]\n\n    Examples\n    --------\n    >>> Nu_free_vertical_plate_methods(0.69, 2.63E9)\n    ['Churchill']\n    \"\"\"\n    return Nu_free_vertical_plate_all_methods\n\ndef Nu_free_vertical_plate(Pr: float, Gr: float, buoyancy: None=None, H: float | None=None, W: float | None=None, Method: str | None=None) -> float:\n    r\"\"\"This function calculates the heat transfer coefficient for external\n    free convection from a verical plate.\n\n    Requires at a minimum a fluid's Prandtl number `Pr`, and the Grashof\n    number `Gr` for the system fluid (which require T and P to obtain).\n\n    `L` and `W` are not used by any correlations presently, but are included\n    for future support.\n\n    If no correlation's name is provided as `Method`, the 'Churchill'\n    correlation is selected.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n    H : float, optional\n        Height of vertical plate, [m]\n    W : float, optional\n        Width of the vertical plate, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate height, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use;\n        one of ('Churchill', ).\n\n    Examples\n    --------\n    Turbulent example\n\n    >>> Nu_free_vertical_plate(0.69, 2.63E9, False)\n    147.16185223770603\n    \"\"\"\n    if Method is None:\n        Method2 = \"Churchill\"\n    else:\n        Method2 = Method\n    if Method2 == \"Churchill\":\n        return Nu_vertical_plate_Churchill(Pr, Gr)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n\ndef Nu_horizontal_plate_McAdams(Pr: float, Gr: float, buoyancy: bool=True) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection above a horizontal\n    plate according to the McAdams [1]_ correlations. The plate must be\n    isothermal. Four different equations are used, two each for laminar and\n    turbulent; the two sets of correlations are required because if the plate\n    is hot, buoyancy lifts the fluid off the plate and enhances free convection\n    whereas if the plate is cold, the cold fluid above it settles on it and\n    decreases the free convection.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to length, [-]\n\n    Notes\n    -----\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_McAdams(5.54, 3.21e8, buoyancy=True)\n    181.73121274384457\n    >>> Nu_horizontal_plate_McAdams(5.54, 3.21e8, buoyancy=False)\n    55.44564799362829\n\n    >>> Nu_horizontal_plate_McAdams(.01, 3.21e8, buoyancy=True)\n    22.857041558492334\n    >>> Nu_horizontal_plate_McAdams(.01, 3.21e8, buoyancy=False)\n    11.428520779246167\n\n    References\n    ----------\n    .. [1] McAdams, William Henry. Heat Transmission. 3E. Malabar, Fla:\n       Krieger Pub Co, 1985.\n    \"\"\"\n    Ra = Pr*Gr\n    if buoyancy:\n        if Ra <= 1E7:\n            Nu = .54*Ra**0.25\n        else:\n            Nu = 0.15*Ra**(1.0/3.0)\n    else:\n        if Ra <= 1E10:\n            Nu = .27*Ra**0.25\n        else:\n            Nu = .15*Ra**(1.0/3.0)\n    return Nu\n\n\ndef Nu_horizontal_plate_VDI(Pr: float, Gr: float, buoyancy: bool=True) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection above a horizontal\n    plate according to the VDI [1]_ correlations. The plate must be\n    isothermal. Three different equations are used, one each for laminar and\n    turbulent for the heat transfer happening at upper surface case and one for\n    the case of heat transfer happening at the lower surface. The lower surface\n    correlation is recommened for the laminar flow regime.\n    The two different sets of correlations are required because if the plate\n    is hot, buoyancy lifts the fluid off the plate and enhances free convection\n    whereas if the plate is cold, the cold fluid above it settles on it and\n    decreases the free convection.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to length, [-]\n\n    Notes\n    -----\n    The characteristic length suggested for use is as follows, with `a` and\n    `b` being the length and width of the plate.\n\n    .. math::\n        L = \\frac{ab}{2(a+b)}\n\n    The buoyancy enhanced cases are from [2]_; the other is said to be from\n    [3]_, although the equations there not quite the same and do not include\n    the Prandtl number correction.\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_VDI(5.54, 3.21e8, buoyancy=True)\n    203.89681224927565\n    >>> Nu_horizontal_plate_VDI(5.54, 3.21e8, buoyancy=False)\n    39.16864971535617\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    .. [2] Stewartson, Keith. \"On the Free Convection from a Horizontal Plate.\"\n       Zeitschrift Für Angewandte Mathematik Und Physik ZAMP 9, no. 3\n       (September 1, 1958): 276-82. https://doi.org/10.1007/BF02033031.\n    .. [3] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    \"\"\"\n    Ra = Pr*Gr\n    if buoyancy:\n        f2 = (1.0 + (0.322/Pr)**(0.55))**(20.0/11.0)\n        if Ra*f2 < 7e4:\n            return 0.766*(Ra*f2)**0.2\n        else:\n            return 0.15*(Ra*f2)**(1.0/3.0)\n    else:\n        f1 = (1.0 + (0.492/Pr)**(9.0/16.0))**(-16.0/9.0)\n        return 0.6*(Ra*f1)**0.2\n\n\ndef Nu_horizontal_plate_Rohsenow(Pr: float, Gr: float, buoyancy: bool=True) -> float:\n    r\"\"\"Calculates the Nusselt number for natural convection above a horizontal\n    plate according to the Rohsenow, Hartnett, and Cho (1998) [1]_ correlations.\n    The plate must be isothermal. Three different equations are used, one each\n    for laminar and turbulent for the heat transfer happening at upper surface\n    case and one for the case of heat transfer happening at the lower surface.\n\n    The lower surface correlation is recommened for the laminar flow regime.\n    The two different sets of correlations are required because if the plate\n    is hot, buoyancy lifts the fluid off the plate and enhances free convection\n    whereas if the plate is cold, the cold fluid above it settles on it and\n    decreases the free convection.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to length, [-]\n\n    Notes\n    -----\n    The characteristic length suggested for use is as follows, with `a` and\n    `b` being the length and width of the plate.\n\n    .. math::\n        L = \\frac{ab}{2(a+b)}\n\n\n    Examples\n    --------\n    >>> Nu_horizontal_plate_Rohsenow(5.54, 3.21e8, buoyancy=True)\n    175.91054716322836\n    >>> Nu_horizontal_plate_Rohsenow(5.54, 3.21e8, buoyancy=False)\n    35.95799244863986\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    Ra = Pr*Gr\n    if buoyancy:\n        C_tU = 0.14*((1.0 + 0.01707*Pr)/(1.0 + 0.01*Pr))\n        C_tV = 0.13*Pr**0.22/(1.0 + 0.61*Pr**0.81)**0.42\n\n        t1 = 1.0 # Ah/A # Heated to non heated area ratio\n        t2 = 0.0 # Lf*P/A # Lf vertical distance between lowest and highest point in body\n        # P is perimiter, A is area\n        Cl = (0.0972 - (0.0157 + 0.462*C_tV)*t1\n              + (0.615*C_tV - 0.0548 - 6e-6*Pr)*t2)\n\n        Nu_T = 0.835*Cl*Ra**0.25 # average Cl\n        Nu_l = 1.4/(log(1.0 + 1.4/Nu_T))\n        Nu_t = C_tU*Ra**(1.0/3.0)\n\n        m = 10.0\n        Nu = ((Nu_l)**m + Nu_t**m)**(1.0/m)\n        return Nu\n    else:\n        # No friction/C term\n        Nu_T = 0.527*Ra**0.2/(1.0 + (1.9/Pr)**0.9)**(2.0/9.0)\n        Nu_l = 2.5/(log(1.0 + 2.5/Nu_T))\n        return Nu_l\n\n\nconv_free_horizontal_plate_all_methods = {\n    \"McAdams\": (Nu_horizontal_plate_McAdams, (\"Pr\", \"Gr\", \"buoyancy\")),\n    \"VDI\": (Nu_horizontal_plate_VDI, (\"Pr\", \"Gr\", \"buoyancy\")),\n    \"Rohsenow\": (Nu_horizontal_plate_Rohsenow, (\"Pr\", \"Gr\", \"buoyancy\")),\n}\n\nNu_free_horizontal_plate_all_methods = [\"VDI\", \"McAdams\", \"Rohsenow\"]\n\n\ndef Nu_free_horizontal_plate_methods(Pr: float, Gr: float, buoyancy: bool, L: float | None=None, W: float | None=None,\n                                     check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of methods for calculating heat transfer\n    coefficient for external free convection from a verical plate.\n\n    Requires at a minimum a fluid's Prandtl number `Pr`, and the Grashof\n    number `Gr` for the system fluid, temperatures, and geometry.\n\n    `L` and `W` are not used by any correlations presently, but are included\n    for future support.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n    L : float, optional\n        Length of horizontal plate, [m]\n    W : float, optional\n        Width of the horizontal plate, [m]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs, [-]\n\n    Examples\n    --------\n    >>> Nu_free_horizontal_plate_methods(0.69, 2.63E9, True)\n    ['VDI', 'McAdams', 'Rohsenow']\n    \"\"\"\n    return Nu_free_horizontal_plate_all_methods\n\ndef Nu_free_horizontal_plate(Pr: float, Gr: float, buoyancy: bool, L: float | None=None, W: float | None=None,\n                             Method: str | None=None) -> float:\n    r\"\"\"This function calculates the heat transfer coefficient for external\n    free convection from a horizontal plate.\n\n    Requires at a minimum a fluid's Prandtl number `Pr`, and the Grashof\n    number `Gr` for the system fluid, temperatures, and geometry.\n\n    `L` and `W` are not used by any correlations presently, but are included\n    for future support.\n\n    If no correlation's name is provided as `Method`, the 'VDI' correlation is\n    selected.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to fluid properties [-]\n    Gr : float\n        Grashof number with respect to fluid properties and plate - fluid\n        temperature difference [-]\n    buoyancy : bool, optional\n        Whether or not the plate's free convection is buoyancy assisted (hot\n        plate) or not, [-]\n    L : float, optional\n        Length of horizontal plate, [m]\n    W : float, optional\n        Width of the horizontal plate, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to plate length, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        conv_free_horizontal_plate_methods\n\n    Examples\n    --------\n    Turbulent example\n\n    >>> Nu_free_horizontal_plate(5.54, 3.21e8, buoyancy=True)\n    203.89681224927565\n\n    >>> Nu_free_horizontal_plate(5.54, 3.21e8, buoyancy=True, Method='McAdams')\n    181.73121274384457\n    \"\"\"\n    if Method is None:\n        Method2 = \"VDI\"\n    else:\n        Method2 = Method\n\n    if Method2 == \"VDI\":\n        return Nu_horizontal_plate_VDI(Pr=Pr, Gr=Gr, buoyancy=buoyancy)\n    if Method2 == \"McAdams\":\n        return Nu_horizontal_plate_McAdams(Pr=Pr, Gr=Gr, buoyancy=buoyancy)\n    if Method2 == \"Rohsenow\":\n        return Nu_horizontal_plate_Rohsenow(Pr=Pr, Gr=Gr, buoyancy=buoyancy)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n\ndef Nu_sphere_Churchill(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a sphere\n    according to the Churchill [1]_ correlation. Sphere must be isothermal.\n\n    .. math::\n        Nu_D=2+\\frac{0.589Ra_D^{1/4}} {\\left[1+(0.469/Pr)^{9/16}\\right]^{4/9}}\n        \\cdot\\left\\{1 + \\frac{7.44\\times 10^{-8}Ra}\n        {[1+(0.469/Pr)^{9/16}]^{16/9}}\\right\\}^{1/12}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Although transition from laminar to turbulent is discrete in reality, this\n    equation provides a smooth transition in value from laminar to turbulent.\n    Checked with the original source.\n\n    Good for Ra < 1E13. Limit of Nu is 2 at low Grashof numbers.\n\n    Examples\n    --------\n    >>> Nu_sphere_Churchill(.7, 1E7)\n    25.670869440317578\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    \"\"\"\n    Ra = Pr*Gr\n    Nu = 2 + (0.589*Ra**0.25/(1 + (0.469/Pr)**(9/16.))**(4/9.)*(\n         1 + 7.44E-8*Ra/(1 + (0.469/Pr)**(9/16.))**(16/9.))**(1/12.))\n    return Nu\n\n\n### Vertical cylinders\n\ndef Nu_vertical_cylinder_Griffiths_Davis_Morgan(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by [2]_, as\n    presented in [3]_ and [4]_.\n\n    .. math::\n        Nu_H = 0.67 Ra_H^{0.25},\\; 10^{7} < Ra < 10^{9}\n\n    .. math::\n        Nu_H = 0.0782 Ra_H^{0.357}, \\; 10^{9} < Ra < 10^{11}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Cylinder of diameter 17.43 cm, length from 4.65 to 263.5 cm. Air as fluid.\n    Transition between ranges is not smooth.\n    If outside of range, no warning is given.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Griffiths_Davis_Morgan(.7, 2E10)\n    327.6230596100138\n\n    References\n    ----------\n    .. [1] Griffiths, Ezer, A. H. Davis, and Great Britain. The Transmission of\n       Heat by Radiation and Convection. London: H. M. Stationery off., 1922.\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 1E9 and turbulent is None):\n        Nu = 0.0782*Ra**0.357\n    else:\n        Nu = 0.67*Ra**0.25\n    return Nu\n\n\ndef Nu_vertical_cylinder_Jakob_Linke_Morgan(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by [2]_, as\n    presented in [3]_ and [4]_.\n\n    .. math::\n        Nu_H = 0.555 Ra_H^{0.25},\\; 10^{4} < Ra < 10^{8}\n\n    .. math::\n        Nu_H = 0.129 Ra_H^{1/3},\\; 10^{8} < Ra < 10^{12}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Cylinder of diameter 3.5 cm, length from L/D = 4.3. Air as fluid.\n    Transition between ranges is not smooth.\n    If outside of range, no warning is given. Results are presented rounded in\n    [4]_, and the second range is not shown in [3]_.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Jakob_Linke_Morgan(.7, 2E10)\n    310.90835207860454\n\n    References\n    ----------\n    .. [1] Jakob, M., and Linke, W., Warmeubergang beim Verdampfen von\n       Flussigkeiten an senkrechten und waagerechten Flaschen, Phys. Z.,\n       vol. 36, pp. 267-280, 1935.\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 1E8 and turbulent is None):\n        Nu = 0.129*Ra**(1/3.)\n    else:\n        Nu = 0.555*Ra**0.25\n    return Nu\n\n\ndef Nu_vertical_cylinder_Carne_Morgan(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by [2]_, as\n    presented in [3]_ and [4]_.\n\n    .. math::\n        Nu_H = 1.07 Ra_H^{0.28},\\; 2\\times 10^{6} < Ra < 2\\times 10^{8}\n\n    .. math::\n        Nu_H = 0.152 Ra_H^{0.38},\\; 2\\times 10^{8} < Ra < 2\\times 10^{11}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Cylinder of diameters 0.475 cm to 7.62 cm, L/D from 8 to 127. Isothermal\n    boundary condition was assumed, but not verified. Transition between ranges\n    is not smooth. If outside of range, no warning is given. The higher range\n    of [1]_ is not shown in [3]_, and the formula for the first is actually for\n    the second in [3]_.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Carne_Morgan(.7, 2E8)\n    204.31470629065677\n\n    References\n    ----------\n    .. [1] J. B. Carne. \"LIX. Heat Loss by Natural Convection from Vertical\n       Cylinders.\" The London, Edinburgh, and Dublin Philosophical Magazine and\n       Journal of Science 24, no. 162 (October 1, 1937): 634-53.\n       doi:10.1080/14786443708565140.\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 2E8 and turbulent is None):\n        return 0.152*Ra**0.38\n    else:\n        return 1.07*Ra**0.28\n\n\ndef Nu_vertical_cylinder_Eigenson_Morgan(Pr: float, Gr: float, turbulent: None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by [2]_,\n    presented in [3]_ and in more detail in [4]_.\n\n    .. math::\n        Nu_H = 0.48 Ra_H^{0.25},\\; 10^{9} < Ra\n\n    .. math::\n        Nu_H = 51.5 + 0.0000726 Ra_H^{0.63},\\; 10^{9} < Ra < 1.69 \\times 10^{10}\n\n    .. math::\n        Nu_H = 0.148 Ra_H^{1/3} - 127.6 ,\\; 1.69 \\times 10^{10} < Ra\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Author presents results as appropriate for both flat plates and cylinders.\n    Height of 2.5 m with diameters of 2.4, 7.55, 15, 35, and 50 mm. Another\n    experiment of diameter 58 mm and length of 6.5 m was considered.\n    Cylinder of diameters 0.475 cm to 7.62 cm, L/D from 8 to 127.Transition\n    between ranges is not smooth. If outside of range, no warning is given.\n    Formulas are presented similarly in [3]_ and [4]_, but only [4]_ shows\n    the transition formula.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Eigenson_Morgan(0.7, 2E10)\n    230.55946525499715\n\n    References\n    ----------\n    .. [1] Eigenson L (1940). Les lois gouvernant la transmission de la chaleur\n       aux gaz biatomiques par les parois des cylindres verticaux dans le cas\n       de convection naturelle. Dokl Akad Nauk SSSR 26:440-444\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 1.69E10 and turbulent is None):\n        return 0.148*Ra**(1/3.) - 127.6\n    elif 1E9 < Ra < 1.69E10 and turbulent is not False:\n        return 51.5 + 0.0000726*Ra**0.63\n    else:\n        return 0.48*Ra**0.25\n\n\ndef Nu_vertical_cylinder_Touloukian_Morgan(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by [2]_, as\n    presented in [3]_ and [4]_.\n\n    .. math::\n        Nu_H = 0.726 Ra_H^{0.25},\\; 2\\times 10^{8} < Ra < 4\\times 10^{10}\n\n    .. math::\n        Nu_H = 0.0674 (Gr_H Pr^{1.29})^{1/3},\\; 4\\times 10^{10} < Ra < 9\\times 10^{11}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Cylinder of diameters 2.75 inch, with heights of 6, 18, and 36.25 inch.\n    Temperature was controlled via multiple separately controlled heating\n    sections. Fluids were water and ethylene-glycol. Transition between ranges\n    is not smooth. If outside of range, no warning is given. [2]_, [3]_, and\n    [4]_ are in complete agreement about this formulation.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Touloukian_Morgan(.7, 2E10)\n    249.72879961097854\n\n    References\n    ----------\n    .. [1] Touloukian, Y. S, George A Hawkins, and Max Jakob. Heat Transfer by\n       Free Convection from Heated Vertical Surfaces to Liquids.\n       Trans. ASME 70, 13-18 (1948).\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 4E10 and turbulent is None):\n        return 0.0674*(Gr*Pr**1.29)**(1/3.)\n    else:\n        return 0.726*Ra**0.25\n\n\ndef Nu_vertical_cylinder_McAdams_Weiss_Saunders(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ and [2]_ correlated by\n    [3]_, as presented in [4]_, [5]_, and [6]_.\n\n    .. math::\n        Nu_H = 0.59 Ra_H^{0.25},\\; 10^{4} < Ra < 10^{9}\n\n    .. math::\n        Nu_H = 0.13 Ra_H^{1/3.},\\; 10^{9} < Ra < 10^{12}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Transition between ranges is not smooth. If outside of range, no warning is\n    given. For ranges under 10^4, a graph is provided, not included here.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_McAdams_Weiss_Saunders(.7, 2E10)\n    313.31849434277973\n\n    References\n    ----------\n    .. [1] Weise, Rudolf. \"Warmeubergang durch freie Konvektion an\n       quadratischen Platten.\" Forschung auf dem Gebiet des Ingenieurwesens\n       A 6, no. 6 (November 1935): 281-92. doi:10.1007/BF02592565.\n    .. [2] Saunders, O. A. \"The Effect of Pressure Upon Natural Convection in\n       Air.\" Proceedings of the Royal Society of London A: Mathematical,\n       Physical and Engineering Sciences 157, no. 891 (November 2, 1936):\n       278-91. doi:10.1098/rspa.1936.0194.\n    .. [3] McAdams, William Henry. Heat Transmission. 3E. Malabar, Fla:\n       Krieger Pub Co, 1985.\n    .. [4] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [5] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [6] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 1E9 and turbulent is None):\n        return 0.13*Ra**(1/3.)\n    else:\n        return 0.59*Ra**0.25\n\n\ndef Nu_vertical_cylinder_Kreith_Eckert(Pr: float, Gr: float, turbulent: bool | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_  correlated by\n    [2]_, also as presented in [3]_, [4]_, and [5]_.\n\n    .. math::\n        Nu_H = 0.555 Ra_H^{0.25},\\; 10^{5} < Ra < 10^{9}\n\n    .. math::\n        Nu_H = 0.021 Ra_H^{0.4},\\; 10^{9} < Ra < 10^{12}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Transition between ranges is not smooth. If outside of range, no warning is\n    given.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Kreith_Eckert(.7, 2E10)\n    240.25393473033196\n\n    References\n    ----------\n    .. [1] Eckert, E. R. G., Thomas W. Jackson, and United States. Analysis of\n       Turbulent Free-Convection Boundary Layer on Flat Plate. National\n       Advisory Committee for Aeronautics, no. 2207. Washington, D.C.: National\n       Advisoty Committee for Aeronautics, 1950.\n    .. [2] Kreith, Frank, Raj Manglik, and Mark Bohn. Principles of Heat\n       Transfer. Cengage, 2010.\n    .. [3] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [4] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [5] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if turbulent or (Ra > 1E9 and turbulent is None):\n        return 0.021*Ra**0.4\n    else:\n        return 0.555*Ra**0.25\n\n\ndef Nu_vertical_cylinder_Hanesian_Kalish_Morgan(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to the results of [1]_ correlated by\n    [2]_, also as presented in [3]_ and [4]_.\n\n    .. math::\n        Nu_H = 0.48 Ra_H^{0.23},\\; 10^{6} < Ra < 10^{8}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    For air and fluoro-carbons. If outside of range, no warning is given.\n    Laminar range only!\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Hanesian_Kalish_Morgan(.7, 1E7)\n    18.014150492696604\n\n    References\n    ----------\n    .. [1] Hanesian, D. and Kalish, R. \"Heat Transfer by Natural Convection\n       with Fluorocarbon Gases.\" IEEE Transactions on Parts, Materials and\n       Packaging 6, no. 4 (December 1970): 147-148.\n       doi:10.1109/TPMP.1970.1136270.\n    .. [2] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [3] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [4] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    return 0.48*Ra**0.23\n\n\n### Vertical cylinders, more complex correlations\ndef Nu_vertical_cylinder_Al_Arabi_Khamis(Pr: float, Gr: float, L: float, D: float, turbulent: None=None) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to [1]_, also as presented in [2]_ and [3]_.\n\n    .. math::\n        Nu_H = 2.9Ra_H^{0.25}/Gr_D^{1/12},\\; 9.88 \\times 10^7 \\le Ra_H \\le 2.7\\times10^{9}\n\n    .. math::\n        Nu_H = 0.47 Ra_H^{0.333}/Gr_D^{1/12},\\; 2.7 \\times 10^9 \\le Ra_H \\le 2.95\\times10^{10}\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number with respect to cylinder height [-]\n    L : float\n        Length of vertical cylinder, [m]\n    D : float\n        Diameter of cylinder, [m]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False; leave as None for\n        automatic selection, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    For air. Local Nusselt number results also given in [1]_. D from 12.75 to\n    51 mm; H from 300 to 2000 mm. Temperature kept constant by steam condensing.\n\n    If outside of range, no warning is given. Applies for range of:\n\n    .. math::\n        1.08 \\times 10^4 \\le Gr_D \\le 6.9 \\times 10^5\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Al_Arabi_Khamis(.71, 2E10, 10, 1)\n    280.39793209114765\n\n    References\n    ----------\n    .. [1] Al-Arabi, M., and M. Khamis. \"Natural Convection Heat Transfer from\n       Inclined Cylinders.\" International Journal of Heat and Mass Transfer 25,\n       no. 1 (January 1982): 3-15. doi:10.1016/0017-9310(82)90229-0.\n    .. [2] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [3] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Gr_D = Gr/L**3*D**3\n    Ra = Pr*Gr\n    if turbulent or (Ra > 2.6E9 and turbulent is None):\n        return 0.47*Ra**(1/3.)*Gr_D**(-1/12.)\n    else:\n        return 2.9*Ra**0.25*Gr_D**(-1/12.)\n\n\ndef Nu_vertical_cylinder_Popiel_Churchill(Pr: float, Gr: float, L: float, D: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    isothermal cylinder according to [1]_, also  presented in [2]_.\n\n    .. math::\n        \\frac{Nu}{Nu_{L,fp}} = 1 + B\\left[32^{0.5}Gr_L^{-0.25}\\frac{L}{D}\\right]^C\n\n    .. math::\n        B = 0.0571322 + 0.20305 Pr^{-0.43}\n\n    .. math::\n        C = 0.9165 - 0.0043Pr^{0.5} + 0.01333\\ln Pr + 0.0004809/Pr\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number with respect to cylinder height [-]\n    L : float\n        Length of vertical cylinder, [m]\n    D : float\n        Diameter of cylinder, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    For 0.01 < Pr < 100. Requires a vertical flat plate correlation.\n    Both [2], [3] present a power of 2 instead of 0.5 on the 32 in the equation,\n    but the original has the correct form.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_Popiel_Churchill(0.7, 1E10, 2.5, 1)\n    228.89790055149896\n\n    References\n    ----------\n    .. [1] Popiel, C. O., J. Wojtkowiak, and K. Bober. \"Laminar Free Convective\n       Heat Transfer from Isothermal Vertical Slender Cylinder.\" Experimental\n       Thermal and Fluid Science 32, no. 2 (November 2007): 607-613.\n       doi:10.1016/j.expthermflusci.2007.07.003.\n    .. [2] Popiel, Czeslaw O. \"Free Convection Heat Transfer from Vertical\n       Slender Cylinders: A Review.\" Heat Transfer Engineering 29, no. 6\n       (June 1, 2008): 521-36. doi:10.1080/01457630801891557.\n    .. [3] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    B = 0.0571322 + 0.20305*Pr**-0.43\n    C = 0.9165 - 0.0043*Pr**0.5 + 0.01333*log(Pr) + 0.0004809/Pr\n    Nu_fp = Nu_vertical_plate_Churchill(Pr, Gr)\n    return Nu_fp*(1 + B*(32**0.5*Gr**-0.25*L/D)**C)\n\n\n\n# Nice Name : (function_call, does_turbulent, does_laminar, transition_Ra, is_only_Pr_Gr)\nvertical_cylinder_correlations = {\n\"Churchill Vertical Plate\": (Nu_vertical_plate_Churchill, True, True, None, True),\n\"Griffiths, Davis, & Morgan\": (Nu_vertical_cylinder_Griffiths_Davis_Morgan, True, True, 1.00E+009, True),\n\"Jakob, Linke, & Morgan\": (Nu_vertical_cylinder_Jakob_Linke_Morgan, True, True, 1.00E+008, True),\n\"Carne & Morgan\": (Nu_vertical_cylinder_Carne_Morgan, True, True, 2.00E+008, True),\n\"Eigenson & Morgan\": (Nu_vertical_cylinder_Eigenson_Morgan, True, True, 6.90E+011, True),\n\"Touloukian & Morgan\": (Nu_vertical_cylinder_Touloukian_Morgan, True, True, 4.00E+010, True),\n\"McAdams, Weiss & Saunders\": (Nu_vertical_cylinder_McAdams_Weiss_Saunders, True, True, 1.00E+009, True),\n\"Kreith & Eckert\": (Nu_vertical_cylinder_Kreith_Eckert, True, True, 1.00E+009, True),\n\"Hanesian, Kalish & Morgan\": (Nu_vertical_cylinder_Hanesian_Kalish_Morgan, False, True, 1.00E+008, True),\n\"Al-Arabi & Khamis\": (Nu_vertical_cylinder_Al_Arabi_Khamis, True, True, 2.60E+009, False),\n\"Popiel & Churchill\": (Nu_vertical_cylinder_Popiel_Churchill, False, True, 1.00E+009, False),\n}\n\ndef Nu_vertical_cylinder_methods(Pr: float, Gr: float, L: float | None=None, D: float | None=None, check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of correlation names for free convetion\n    to a vertical cylinder.\n\n    The functions returned are 'Popiel & Churchill' for fully defined geometries,\n    and 'McAdams, Weiss & Saunders' otherwise.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number with respect to cylinder height [-]\n    L : float, optional\n        Length of vertical cylinder, [m]\n    D : float, optional\n        Diameter of cylinder, [m]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder_methods(0.72, 1E7)[0]\n    'McAdams, Weiss & Saunders'\n    \"\"\"\n    if L is None or D is None:\n        return [\"McAdams, Weiss & Saunders\", \"Churchill Vertical Plate\",\n                \"Griffiths, Davis, & Morgan\", \"Jakob, Linke, & Morgan\", \"Carne & Morgan\",\n                \"Eigenson & Morgan\", \"Touloukian & Morgan\", \"Kreith & Eckert\", \"Hanesian, Kalish & Morgan\"]\n    else:\n        return [\"Popiel & Churchill\", \"Churchill Vertical Plate\", \"Griffiths, Davis, & Morgan\",\n                \"Jakob, Linke, & Morgan\", \"Carne & Morgan\", \"Eigenson & Morgan\", \"Touloukian & Morgan\",\n                \"McAdams, Weiss & Saunders\", \"Kreith & Eckert\", \"Hanesian, Kalish & Morgan\",\n                \"Al-Arabi & Khamis\"]\n\n\ndef Nu_vertical_cylinder(Pr: float, Gr: float, L: float | None=None, D: float | None=None, Method: str | None=None) -> float:\n    r\"\"\"This function handles choosing which vertical cylinder free convection\n    correlation is used. Generally this is used by a helper class, but can be\n    used directly. Will automatically select the correlation to use if none is\n    provided; returns None if insufficient information is provided.\n\n    Preferred functions are 'Popiel & Churchill' for fully defined geometries,\n    and 'McAdams, Weiss & Saunders' otherwise.\n\n    Examples\n    --------\n    >>> Nu_vertical_cylinder(0.72, 1E7)\n    30.562236756513943\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number with respect to cylinder height [-]\n    L : float, optional\n        Length of vertical cylinder, [m]\n    D : float, optional\n        Diameter of cylinder, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        vertical_cylinder_correlations\n    \"\"\"\n    if Method is None:\n        if L is None or D is None:\n            Method2 = \"McAdams, Weiss & Saunders\"\n        else:\n            Method2 = \"Popiel & Churchill\"\n    else:\n        Method2 = Method\n\n    if Method2 == \"Churchill Vertical Plate\":\n        return Nu_vertical_plate_Churchill(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Griffiths, Davis, & Morgan\":\n        return Nu_vertical_cylinder_Griffiths_Davis_Morgan(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Jakob, Linke, & Morgan\":\n        return Nu_vertical_cylinder_Jakob_Linke_Morgan(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Carne & Morgan\":\n        return Nu_vertical_cylinder_Carne_Morgan(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Eigenson & Morgan\":\n        return Nu_vertical_cylinder_Eigenson_Morgan(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Touloukian & Morgan\":\n        return Nu_vertical_cylinder_Touloukian_Morgan(Pr=Pr, Gr=Gr)\n    elif Method2 == \"McAdams, Weiss & Saunders\":\n        return Nu_vertical_cylinder_McAdams_Weiss_Saunders(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Kreith & Eckert\":\n        return Nu_vertical_cylinder_Kreith_Eckert(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Hanesian, Kalish & Morgan\":\n        return Nu_vertical_cylinder_Hanesian_Kalish_Morgan(Pr=Pr, Gr=Gr)\n\n    elif Method2 == \"Al-Arabi & Khamis\":\n        return Nu_vertical_cylinder_Al_Arabi_Khamis(Pr=Pr, Gr=Gr, L=L, D=D)\n    elif Method2 == \"Popiel & Churchill\":\n        return Nu_vertical_cylinder_Popiel_Churchill(Pr=Pr, Gr=Gr, L=L, D=D)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n#import matplotlib.pyplot as plt\n#import numpy as np\n##L, D = 1.5, 0.1\n#Pr, Gr = 0.72, 1E8\n#methods = Nu_vertical_cylinder_methods(Pr, Gr)\n#Grs = np.logspace(2, 12, 10000)\n#\n#for method in methods:\n#    Nus = [Nu_vertical_cylinder(Pr=Pr, Gr=i, Method=method) for i in Grs]\n#    plt.loglog(Grs, Nus, label=method)\n#plt.legend()\n#plt.show()\n\n\n### Horizontal Cylinders\n\ndef Nu_horizontal_cylinder_Churchill_Chu(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a horizontal\n    cylinder according to the Churchill-Chu [1]_ correlation, also presented in\n    [2]_. Cylinder must be isothermal; an alternate expression exists for\n    constant heat flux.\n\n    .. math::\n        Nu_{D}=\\left[0.60+\\frac{0.387Ra_{D}^{1/6}}\n        {[1+(0.559/Pr)^{9/16}]^{8/27}}\\right]^2\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number [-]\n    Gr : float\n        Grashof number with respect to cylinder diameter, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Although transition from laminar to turbulent is discrete in reality, this\n    equation provides a smooth transition in value from laminar to turbulent.\n    Checked with the original source, which has its powers unsimplified but\n    is equivalent.\n\n    [1]_ recommends 1E-5 as the lower limit for Ra, but no upper limit. [2]_\n    suggests an upper limit of 1E12.\n\n    Examples\n    --------\n    From [2]_, Example 9.2, matches:\n\n    >>> Nu_horizontal_cylinder_Churchill_Chu(0.69, 2.63E9)\n    139.13493970073597\n\n    References\n    ----------\n    .. [1] Churchill, Stuart W., and Humbert H. S. Chu. \"Correlating Equations\n       for Laminar and Turbulent Free Convection from a Horizontal Cylinder.\"\n       International Journal of Heat and Mass Transfer 18, no. 9\n       (September 1975): 1049-53. doi:10.1016/0017-9310(75)90222-7.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    Ra = Pr*Gr\n    return (0.6 + 0.387*Ra**(1/6.)/(1. + (0.559/Pr)**(9/16.))**(8/27.))**2\n\n\ndef Nu_horizontal_cylinder_Kuehn_Goldstein(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a horizontal\n    cylinder according to the Kuehn-Goldstein [1]_ correlation, also shown in\n    [2]_. Cylinder must be isothermal.\n\n    .. math::\n        \\frac{2}{Nu_D} = \\ln\\left[1 + \\frac{2}{\\left[\\left\\{0.518Ra_D^{0.25}\n        \\left[1 + \\left(\\frac{0.559}{Pr}\\right)^{3/5}\\right]^{-5/12}\n        \\right\\}^{15} + (0.1Ra_D^{1/3})^{15}\\right]^{1/15}}\\right]\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to film temperature [-]\n    Gr : float\n        Grashof number with respect to cylinder diameter, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    [1]_ suggests this expression is valid for all cases except low-Pr fluids.\n    [2]_ suggests no restrictions.\n\n    Examples\n    --------\n    >>> Nu_horizontal_cylinder_Kuehn_Goldstein(0.69, 2.63E9)\n    122.99323525628186\n\n    References\n    ----------\n    .. [1] Kuehn, T. H., and R. J. Goldstein. \"Correlating Equations for\n       Natural Convection Heat Transfer between Horizontal Circular Cylinders.\"\n       International Journal of Heat and Mass Transfer 19, no. 10\n       (October 1976): 1127-34. doi:10.1016/0017-9310(76)90145-9\n    .. [2] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    return 2./log(1 + 2./((0.518*Ra**0.25*(1. + (0.559/Pr)**0.6)**(-5/12.))**15\n                  + (0.1*Ra**(1/3.))**15)**(1/15.))\n\n\ndef Nu_horizontal_cylinder_Morgan(Pr: float, Gr: float) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a horizontal\n    cylinder according to the Morgan [1]_ correlations, a product of a very\n    large review of the literature. Sufficiently common as to be shown in [2]_.\n    Cylinder must be isothermal.\n\n    .. math::\n        Nu_D = C Ra_D^n\n\n    +----------+----------+-------+-------+\n    |  Gr min  |  Gr max  |  C    |  n    |\n    +==========+==========+=======+=======+\n    | 10E-10   |  10E-2   | 0.675 | 0.058 |\n    +----------+----------+-------+-------+\n    | 10E-2    |  10E2    | 1.02  | 0.148 |\n    +----------+----------+-------+-------+\n    | 10E2     |  10E4    | 0.850 | 0.188 |\n    +----------+----------+-------+-------+\n    | 10E4     |  10E7    | 0.480 | 0.250 |\n    +----------+----------+-------+-------+\n    | 10E7     |  10E12   | 0.125 | 0.333 |\n    +----------+----------+-------+-------+\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to film temperature [-]\n    Gr : float\n        Grashof number with respect to cylinder diameter, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Notes\n    -----\n    Most comprehensive review with a new proposed equation to date.\n    Discontinuous among the jumps in range. Blindly runs outside if upper and\n    lower limits without warning.\n\n    Examples\n    --------\n    >>> Nu_horizontal_cylinder_Morgan(0.69, 2.63E9)\n    151.3881997228419\n\n    References\n    ----------\n    .. [1] Morgan, V.T., The Overall Convective Heat Transfer from Smooth\n       Circular Cylinders, in Advances in Heat Transfer, eds. T.F. Irvin and\n       J.P. Hartnett, V 11, 199-264, 1975.\n    .. [2] Boetcher, Sandra K. S. \"Natural Convection Heat Transfer From\n       Vertical Cylinders.\" In Natural Convection from Circular Cylinders,\n       23-42. Springer, 2014.\n    \"\"\"\n    Ra = Pr*Gr\n    if Ra < 1E-2:\n        C, n = 0.675, 0.058\n    elif Ra < 1E2:\n        C, n = 1.02, 0.148\n    elif Ra < 1E4:\n        C, n = 0.850, 0.188\n    elif Ra < 1E7:\n        C, n = 0.480, 0.250\n    else:\n        # up to 1E12\n        C, n = 0.125, 0.333\n    return C*Ra**n\n\n\nhorizontal_cylinder_correlations = {\n\"Churchill-Chu\": (Nu_horizontal_cylinder_Churchill_Chu),\n\"Kuehn & Goldstein\":  (Nu_horizontal_cylinder_Kuehn_Goldstein),\n\"Morgan\": (Nu_horizontal_cylinder_Morgan)\n}\n\ndef Nu_horizontal_cylinder_methods(Pr: float, Gr: float, check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of correlation names for free convetion\n    to a horizontal cylinder.\n\n    Preferred functions are 'Morgan' when discontinuous results are acceptable\n    and 'Churchill-Chu' otherwise.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to film temperature [-]\n    Gr : float\n        Grashof number with respect to cylinder diameter, [-]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list[str]\n        List of methods which can be used to calculate `Nu` with the given\n        inputs\n\n    Examples\n    --------\n    >>> Nu_horizontal_cylinder_methods(0.72, 1E7)[0]\n    'Morgan'\n    \"\"\"\n    return [\"Morgan\", \"Churchill-Chu\", \"Kuehn & Goldstein\"]\n\ndef Nu_horizontal_cylinder(Pr: float, Gr: float, Method: str | None=None) -> float:\n    r\"\"\"This function handles choosing which horizontal cylinder free convection\n    correlation is used. Generally this is used by a helper class, but can be\n    used directly. Will automatically select the correlation to use if none is\n    provided; returns None if insufficient information is provided.\n\n    Preferred functions are 'Morgan' when discontinuous results are acceptable\n    and 'Churchill-Chu' otherwise.\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number with respect to film temperature [-]\n    Gr : float\n        Grashof number with respect to cylinder diameter, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to cylinder diameter, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        horizontal_cylinder_correlations\n\n    Notes\n    -----\n    All fluid properties should be evaluated at the film temperature, the\n    average between the outer surface temperature of the solid, and the fluid\n    temperature far away from the heat transfer interface - normally the same\n    as the temperature before any cooling or heating occurs.\n\n    .. math::\n        T_f = (T_{\\text{surface}} + T_\\infty)/2\n\n    Examples\n    --------\n    >>> Nu_horizontal_cylinder(0.72, 1E7)\n    24.864192615468973\n    \"\"\"\n    if Method is None:\n        Method2 = \"Morgan\"\n    else:\n        Method2 = Method\n    if Method2 == \"Churchill-Chu\":\n        return Nu_horizontal_cylinder_Churchill_Chu(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Kuehn & Goldstein\":\n        return Nu_horizontal_cylinder_Kuehn_Goldstein(Pr=Pr, Gr=Gr)\n    elif Method2 == \"Morgan\":\n        return Nu_horizontal_cylinder_Morgan(Pr=Pr, Gr=Gr)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n\n#import matplotlib.pyplot as plt\n#import numpy as np\n#Pr, Gr = 0.72, 1E8\n#methods = Nu_horizontal_cylinder_methods(Pr, Gr)\n#Grs = np.logspace(-2, 2.5, 10000)\n#\n#for method in methods:\n#    Nus = [Nu_horizontal_cylinder(Pr=Pr, Gr=i, Method=method) for i in Grs]\n#    plt.semilogx(Grs, Nus, label=method)\n#plt.legend()\n#plt.show()\n\n\ndef Nu_coil_Xin_Ebadian(Pr: float, Gr: float, horizontal: bool=False) -> float:\n    r\"\"\"Calculates Nusselt number for natural convection around a vertical\n    or horizontal helical coil suspended in a fluid without\n    forced convection.\n\n    For horizontal cases:\n\n    .. math::\n        Nu_D = 0.318 Ra_D^{0.293},\\; 5 \\times {10}^{3} < Ra < 1 \\times {10}^5\n\n    For vertical cases:\n\n    .. math::\n        Nu_D = 0.290 Ra_D^{0.293},\\; 5 \\times {10}^{3} < Ra < 1 \\times {10}^5\n\n    Parameters\n    ----------\n    Pr : float\n        Prandtl number calculated with the film temperature -\n        wall and temperature very far from the coil average, [-]\n    Gr : float\n        Grashof number calculated with the film temperature -\n        wall and temperature very far from the coil average,\n        and using the outer diameter of the coil [-]\n    horizontal : bool, optional\n        Whether the coil is horizontal or vertical, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number using the outer diameter of the coil\n        and the film temperature, [-]\n\n    Notes\n    -----\n    This correlation is also reviewed in [2]_.\n\n    Examples\n    --------\n    >>> Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=False)\n    4.755689726250451\n    >>> Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=True)\n    5.2148597687849785\n\n    References\n    ----------\n    .. [1] Xin, R. C., and M. A. Ebadian. \"Natural Convection Heat Transfer\n       from Helicoidal Pipes.\" Journal of Thermophysics and Heat Transfer 10,\n       no. 2 (1996): 297-302.\n    .. [2] Prabhanjan, Devanahalli G., Timothy J. Rennie, and G. S. Vijaya\n       Raghavan. \"Natural Convection Heat Transfer from Helical Coiled Tubes.\"\n       International Journal of Thermal Sciences 43, no. 4 (April 1, 2004):\n       359-65.\n    \"\"\"\n    Ra = Pr*Gr\n    if horizontal:\n        return 0.318*Ra**0.293\n    else:\n        return 0.290*Ra**0.293\n"
  },
  {
    "path": "ht/conv_internal.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\n__all__: list[str] = [\n    \"Morimoto_Hotta\",\n    \"Nu_conv_internal\",\n    \"Nu_conv_internal_methods\",\n    \"Nu_laminar_rectangular_Shan_London\",\n    \"conv_tube_laminar_methods\",\n    \"conv_tube_methods\",\n    \"conv_tube_turbulent_methods\",\n    \"helical_turbulent_Nu_Mori_Nakayama\",\n    \"helical_turbulent_Nu_Schmidt\",\n    \"helical_turbulent_Nu_Xin_Ebadian\",\n    \"laminar_Q_const\",\n    \"laminar_T_const\",\n    \"laminar_entry_Baehr_Stephan\",\n    \"laminar_entry_Seider_Tate\",\n    \"laminar_entry_thermal_Hausen\",\n    \"turbulent_Bhatti_Shah\",\n    \"turbulent_Churchill_Zajic\",\n    \"turbulent_Colburn\",\n    \"turbulent_Dipprey_Sabersky\",\n    \"turbulent_Dittus_Boelter\",\n    \"turbulent_Drexel_McAdams\",\n    \"turbulent_ESDU\",\n    \"turbulent_Friend_Metzner\",\n    \"turbulent_Gnielinski\",\n    \"turbulent_Gnielinski_smooth_1\",\n    \"turbulent_Gnielinski_smooth_2\",\n    \"turbulent_Gowen_Smith\",\n    \"turbulent_Kawase_De\",\n    \"turbulent_Kawase_Ulbrecht\",\n    \"turbulent_Martinelli\",\n    \"turbulent_Nunner\",\n    \"turbulent_Petukhov_Kirillov_Popov\",\n    \"turbulent_Prandtl\",\n    \"turbulent_Sandall\",\n    \"turbulent_Sieder_Tate\",\n    \"turbulent_Webb\",\n    \"turbulent_entry_Hausen\",\n    \"turbulent_von_Karman\",\n]\n\nfrom math import exp, log, tanh\n\nfrom fluids.friction import LAMINAR_TRANSITION_PIPE, Clamond\n\n### Laminar\n\ndef laminar_T_const() -> float:\n    r\"\"\"Returns internal convection Nusselt number for laminar flows\n    in pipe according to [1]_, [2]_ and [3]_. Wall temperature is assumed\n    constant.\n    This is entirely theoretically derived and reproduced experimentally.\n\n    .. math::\n        Nu = 3.66\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    This applies only for fully thermally and hydraulically developed and flows.\n\n    References\n    ----------\n    .. [1] Green, Don, and Robert Perry. Perry`s Chemical Engineers` Handbook,\n       Eighth Edition. New York: McGraw-Hill Education, 2007.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ: Wiley, 2011.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n       Berlin ; New York: Springer, 2010.\n    \"\"\"\n    return 3.66\n\n\ndef laminar_Q_const() -> float:\n    r\"\"\"Returns internal convection Nusselt number for laminar flows\n    in pipe according to [1]_, [2]_, and [3]_. Heat flux is assumed constant.\n    This is entirely theoretically derived and reproduced experimentally.\n\n    .. math::\n        Nu = 4.354\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    This applies only for fully thermally and hydraulically developed and flows.\n    Many sources round to 4.36, but [3]_ does not.\n\n    References\n    ----------\n    .. [1] Green, Don, and Robert Perry. Perry`s Chemical Engineers` Handbook,\n       Eighth Edition. New York: McGraw-Hill Education, 2007.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ: Wiley, 2011.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd ed. 2010 edition.\n        Berlin ; New York: Springer, 2010.\n    \"\"\"\n    return 48/11.\n\n### Laminar - entry region\n\ndef laminar_entry_thermal_Hausen(Re: float, Pr: float, L: float, Di: float) -> float:\n    r\"\"\"Calculates average internal convection Nusselt number for laminar flows\n    in pipe during the thermal entry region according to [1]_ as shown in\n    [2]_ and cited by [3]_.\n\n    .. math::\n        Nu_D=3.66+\\frac{0.0668\\frac{D}{L}Re_{D}Pr}{1+0.04{(\\frac{D}{L}\n        Re_{D}Pr)}^{2/3}}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    L : float\n        Length of pipe [m]\n    Di : float\n        Diameter of pipe [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    If Pr >> 1, (5 is a common requirement) this equation also applies to flows\n    with developing velocity profile.\n    As L gets larger, this equation  becomes the constant-temperature Nusselt\n    number.\n\n    Examples\n    --------\n    >>> laminar_entry_thermal_Hausen(Re=100000, Pr=1.1, L=5, Di=.5)\n    39.01352358988535\n\n    References\n    ----------\n    .. [1] Hausen, H. Darstellung des Warmeuberganges in Rohren durch\n       verallgeminerte Potenzbeziehungen, Z. Ver deutsch. Ing Beih.\n       Verfahrenstech., 4, 91-98, 1943\n    .. [2] W. M. Kays. 1953. Numerical Solutions for Laminar Flow Heat Transfer\n       in Circular Tubes.\n    .. [3] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E.\n       Hoboken, NJ: Wiley, 2011.\n    \"\"\"\n    Gz = Di/L*Re*Pr\n    return 3.66 + (0.0668*Gz)/(1+0.04*(Gz)**(2/3.))\n\n\ndef laminar_entry_Seider_Tate(Re: float, Pr: float, L: float, Di: float, mu: float | None=None, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates average internal convection Nusselt number for laminar flows\n    in pipe during the thermal entry region as developed in [1]_, also\n    shown in [2]_.\n\n    .. math::\n        Nu_D=1.86\\left(\\frac{D}{L}Re_DPr\\right)^{1/3}\\left(\\frac{\\mu_b}\n        {\\mu_s}\\right)^{0.14}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    L : float\n        Length of pipe [m]\n    Di : float\n        Diameter of pipe [m]\n    mu : float, optional\n        Viscosity of fluid, [Pa*s]\n    mu_w : float, optional\n        Viscosity of fluid at wall temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Reynolds number should be less than 10000. This should be calculated\n    using pipe diameter.\n    Prandlt number should be no less than air and no more than liquid metals;\n    0.7 < Pr <  16700\n    Viscosities should be the bulk and surface properties; they are optional.\n    Outside the boundaries, this equation is provides very false results.\n\n    Examples\n    --------\n    >>> laminar_entry_Seider_Tate(Re=100000, Pr=1.1, L=5, Di=.5)\n    41.366029684589265\n\n    References\n    ----------\n    .. [1] Sieder, E. N., and G. E. Tate. \"Heat Transfer and Pressure Drop of\n       Liquids in Tubes.\" Industrial & Engineering Chemistry 28, no. 12\n       (December 1, 1936): 1429-35. doi:10.1021/ie50324a027.\n    .. [2] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    Nu = 1.86*(Di/L*Re*Pr)**(1/3.0)\n    if mu_w is not None and mu is not None:\n        Nu *= (mu/mu_w)**0.14\n    return Nu\n\n\ndef laminar_entry_Baehr_Stephan(Re: float, Pr: float, L: float, Di: float) -> float:\n    r\"\"\"Calculates average internal convection Nusselt number for laminar flows\n    in pipe during the thermal and velocity entry region according to [1]_ as\n    shown in [2]_.\n\n    .. math::\n        Nu_D=\\frac{\\frac{3.657}{\\tanh[2.264 Gz_D^{-1/3}+1.7Gz_D^{-2/3}]}\n        +0.0499Gz_D\\tanh(Gz_D^{-1})}{\\tanh(2.432Pr^{1/6}Gz_D^{-1/6})}\n\n    .. math::\n        Gz = \\frac{D}{L}Re_D Pr\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    L : float\n        Length of pipe [m]\n    Di : float\n        Diameter of pipe [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    As L gets larger, this equation becomes the constant-temperature Nusselt\n    number.\n\n    Examples\n    --------\n    >>> laminar_entry_Baehr_Stephan(Re=100000, Pr=1.1, L=5, Di=.5)\n    72.65402046550976\n\n    References\n    ----------\n    .. [1] Baehr, Hans Dieter, and Karl Stephan. Heat and Mass Transfer.\n       Springer, 2013.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E.\n       Hoboken, NJ: Wiley, 2011.\n    \"\"\"\n    Gz = Di/L*Re*Pr\n    return (3.657/tanh(2.264*Gz**(-1/3.)+ 1.7*Gz**(-2/3.0))\n            + 0.0499*Gz*tanh(1./Gz))/tanh(2.432*Pr**(1/6.0)*Gz**(-1/6.0))\n\n\n### Turbulent - Equations with more complicated options\ndef turbulent_Dittus_Boelter(Re: float, Pr: float, heating: bool=True, revised: bool=True) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [1]_, and [2]_, a reprint of [3]_.\n\n    .. math::\n        Nu = m*Re_D^{4/5}Pr^n\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    heating : bool\n        Indicates if the process is heating or cooling, optional\n    revised : bool\n        Indicates if revised coefficients should be used or not\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    The revised coefficient is m = 0.023.\n    The original form of Dittus-Boelter has a linear coefficient of 0.0243\n    for heating and 0.0265 for cooling. These are sometimes rounded to 0.024\n    and 0.026 respectively.\n    The default, heating, provides n = 0.4. Cooling makes n 0.3.\n\n    0.6 ≤ Pr ≤  160\n    Re_{D} ≥ 10000\n    L/D ≥ 10\n\n    Examples\n    --------\n    >>> turbulent_Dittus_Boelter(Re=1E5, Pr=1.2)\n    247.40036409449127\n    >>> turbulent_Dittus_Boelter(Re=1E5, Pr=1.2, heating=False)\n    242.9305927410295\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Dittus, F. W., and L. M. K. Boelter. \"Heat Transfer in Automobile\n       Radiators of the Tubular Type.\" International Communications in Heat\n       and Mass Transfer 12, no. 1 (January 1985): 3-22.\n       doi:10.1016/0735-1933(85)90003-X\n    .. [3] Dittus, F. W., and L. M. K. Boelter, University of California\n       Publications in Engineering, Vol. 2, No. 13, pp. 443-461, October 17,\n       1930.\n    \"\"\"\n    m = 0.023\n    if heating:\n        power = 0.4\n    else:\n        power = 0.3\n\n    if heating and not revised:\n        m = 0.0243\n    elif not heating and not revised:\n        m = 0.0265\n    else:\n        m = 0.023\n    return m*Re**0.8*Pr**power\n\n\ndef turbulent_Sieder_Tate(Re: float, Pr: float, mu: float | None=None, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [1]_ and supposedly [2]_.\n\n    .. math::\n        Nu = 0.027Re^{4/5}Pr^{1/3}\\left(\\frac{\\mu}{\\mu_s}\\right)^{0.14}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    mu : float\n        Viscosity of fluid, [Pa*s]\n    mu_w : float\n        Viscosity of fluid at wall temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    A linear coefficient of 0.023 is often listed with this equation. The\n    source of the discrepancy is not known. The equation is not present in the\n    original paper, but is nevertheless the source usually cited for it.\n\n    Examples\n    --------\n    >>> turbulent_Sieder_Tate(Re=1E5, Pr=1.2)\n    286.9178136793052\n    >>> turbulent_Sieder_Tate(Re=1E5, Pr=1.2, mu=0.01, mu_w=0.067)\n    219.84016455766044\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Sieder, E. N., and G. E. Tate. \"Heat Transfer and Pressure Drop of\n       Liquids in Tubes.\" Industrial & Engineering Chemistry 28, no. 12\n       (December 1, 1936): 1429-35. doi:10.1021/ie50324a027.\n    \"\"\"\n    Nu = 0.027*Re**0.8*Pr**(1/3.)\n    if mu_w is not None and mu is not None:\n        Nu *= (mu/mu_w)**0.14\n    return Nu\n\n\ndef turbulent_entry_Hausen(Re: float, Pr: float, Di: float, x: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for the entry region\n    of a turbulent flow in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = 0.037(Re^{0.75} - 180)Pr^{0.42}[1+(x/D)^{-2/3}]\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    Di : float\n        Inside diameter of pipe, [m]\n    x : float\n        Length inside of pipe for calculation, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.7 < Pr ≤ 3  and 10^4 ≤ Re ≤ 5*10^6.\n\n    Examples\n    --------\n    >>> turbulent_entry_Hausen(Re=1E5, Pr=1.2, Di=0.154, x=0.05)\n    677.7228275901755\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] H. Hausen, \"Neue Gleichungen fÜr die Wärmeübertragung bei freier\n       oder erzwungener Stromung,\"Allg. Warmetchn., (9): 75-79, 1959.\n    \"\"\"\n    return 0.037*(Re**0.75 - 180)*Pr**0.42*(1 + (x/Di)**(-2/3.))\n\n\n### Regular correlations, Re, Pr and fd only\n\n\ndef turbulent_Colburn(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = 0.023Re^{0.8}Pr^{1/3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 < Pr < 3  and 10^4 < Re < 10^5.\n\n    Examples\n    --------\n    >>> turbulent_Colburn(Re=1E5, Pr=1.2)\n    244.41147091200068\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Colburn, Allan P. \"A Method of Correlating Forced Convection\n       Heat-Transfer Data and a Comparison with Fluid Friction.\" International\n       Journal of Heat and Mass Transfer 7, no. 12 (December 1964): 1359-84.\n       doi:10.1016/0017-9310(64)90125-5.\n    \"\"\"\n    return 0.023*Re**0.8*Pr**(1/3.)\n\n\ndef turbulent_Drexel_McAdams(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = 0.021Re^{0.8}Pr^{0.4}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is Pr ≤ 0.7 and 10^4 ≤ Re ≤ 5*10^6.\n\n    Examples\n    --------\n    >>> turbulent_Drexel_McAdams(Re=1E5, Pr=0.6)\n    171.19055301724387\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Drexel, Rober E., and William H. Mcadams. \"Heat-Transfer\n       Coefficients for Air Flowing in Round Tubes, in Rectangular Ducts, and\n       around Finned Cylinders,\" February 1, 1945.\n       http://ntrs.nasa.gov/search.jsp?R=19930090924.\n    \"\"\"\n    return 0.021*Re**0.8*Pr**(0.4)\n\n\ndef turbulent_von_Karman(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)Re Pr}{1 + 5(f/8)^{0.5}\\left[Pr-1+\\ln\\left(\\frac{5Pr+1}\n        {6}\\right)\\right]}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 ≤ Pr ≤ 3  and 10^4 ≤ Re ≤ 10^5.\n\n    Examples\n    --------\n    >>> turbulent_von_Karman(Re=1E5, Pr=1.2, fd=0.0185)\n    255.7243541243272\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] T. von Karman, \"The Analogy Between Fluid Friction and Heat\n       Transfer,\" Trans. ASME, (61):705-710,1939.\n    \"\"\"\n    return (fd/8.0*Re*Pr/(1.0 + 5.0*(fd/8.0)**0.5\n                          *(Pr - 1.0 + log((5.0*Pr + 1.0)/6.))))\n\n\ndef turbulent_Prandtl(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)RePr}{1 + 8.7(f/8)^{0.5}(Pr-1)}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ 0.5 ≤ Pr ≤ 5 and 10^4 ≤ Re ≤ 5*10^6\n\n    Examples\n    --------\n    >>> turbulent_Prandtl(Re=1E5, Pr=1.2, fd=0.0185)\n    256.073339689557\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] L. Prandt, Fuhrrer durch die Stomungslehre, Vieweg, Braunschweig,\n       p. 359, 1944.\n    \"\"\"\n    return (fd/8.)*Re*Pr/(1.0 + 8.7*(fd/8.)**0.5*(Pr - 1.0))\n\n\ndef turbulent_Friend_Metzner(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)RePr}{1.2 + 11.8(f/8)^{0.5}(Pr-1)Pr^{-1/3}}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ 50 < Pr ≤ 600  and 5*10^4 ≤ Re ≤ 5*10^6.\n    The extreme limits on range should be considered!\n\n    Examples\n    --------\n    >>> turbulent_Friend_Metzner(Re=1E5, Pr=100., fd=0.0185)\n    1738.3356262055322\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Friend, W. L., and A. B. Metzner. “Turbulent Heat Transfer inside\n       Tubes and the Analogy among Heat, Mass, and Momentum Transfer.” AIChE\n       Journal 4, no. 4 (December 1, 1958): 393-402. doi:10.1002/aic.690040404.\n    \"\"\"\n    return (fd/8.)*Re*Pr/(1.2 + 11.8*(fd/8.)**0.5*(Pr - 1.)*Pr**(-1/3.))\n\n\ndef turbulent_Petukhov_Kirillov_Popov(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ and [3]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)RePr}{C+12.7(f/8)^{1/2}(Pr^{2/3}-1)}\\\\\n        C = 1.07 + 900/Re - [0.63/(1+10Pr)]\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 < Pr ≤ 10^6  and 4000 ≤ Re ≤ 5*10^6\n\n    Examples\n    --------\n    >>> turbulent_Petukhov_Kirillov_Popov(Re=1E5, Pr=1.2, fd=0.0185)\n    250.11935088905105\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] B. S. Petukhov, and V. V. Kirillov, \"The Problem of Heat Exchange\n       in the Turbulent Flow of Liquids in Tubes,\" (Russian) Teploenergetika,\n       (4): 63-68, 1958\n    .. [3] B. S. Petukhov and V. N. Popov, \"Theoretical Calculation of Heat\n       Exchange in Turbulent Flow in Tubes of an Incompressible Fluidwith\n       Variable Physical Properties,\" High Temp., (111): 69-83, 1963.\n    \"\"\"\n    C = 1.07 + 900./Re - (0.63/(1. + 10.*Pr))\n    return (fd/8.)*Re*Pr/(C + 12.7*(fd/8.)**0.5*(Pr**(2/3.) - 1.))\n\n\ndef turbulent_Webb(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)RePr}{1.07 + 9(f/8)^{0.5}(Pr-1)Pr^{1/4}}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 < Pr ≤ 100  and 10^4 ≤ Re ≤ 5*10^6\n\n    Examples\n    --------\n    >>> turbulent_Webb(Re=1E5, Pr=1.2, fd=0.0185)\n    239.10130376815872\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Webb, Dr R. L. “A Critical Evaluation of Analytical Solutions and\n       Reynolds Analogy Equations for Turbulent Heat and Mass Transfer in\n       Smooth Tubes.” Wärme - Und Stoffübertragung 4, no. 4\n       (December 1, 1971): 197-204. doi:10.1007/BF01002474.\n    \"\"\"\n    return (fd/8.)*Re*Pr/(1.07 + 9.*(fd/8.)**0.5*(Pr - 1.)*Pr**0.25)\n\n\ndef turbulent_Sandall(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_.\n\n    .. math::\n        Nu = \\frac{(f/8)RePr}{12.48Pr^{2/3} - 7.853Pr^{1/3} + 3.613\\ln Pr + 5.8 + C}\\\\\n        C = 2.78\\ln((f/8)^{0.5} Re/45)\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5< Pr ≤ 2000  and 10^4 ≤ Re ≤ 5*10^6.\n\n    Examples\n    --------\n    >>> turbulent_Sandall(Re=1E5, Pr=1.2, fd=0.0185)\n    229.0514352970239\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Sandall, O. C., O. T. Hanna, and P. R. Mazet. “A New Theoretical\n       Formula for Turbulent Heat and Mass Transfer with Gases or Liquids in\n       Tube Flow.” The Canadian Journal of Chemical Engineering 58, no. 4\n       (August 1, 1980): 443-47. doi:10.1002/cjce.5450580404.\n    \"\"\"\n    C = 2.78*log((fd/8.)**0.5*Re/45.)\n    return (fd/8.)**0.5*Re*Pr/(12.48*Pr**(2/3.) - 7.853*Pr**(1/3.)\n                               + 3.613*log(Pr) + 5.8 + C)\n\n\ndef turbulent_Gnielinski(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_. This is the most recent general\n    equation, and is strongly recommended.\n\n    .. math::\n        Nu = \\frac{(f/8)(Re-1000)Pr}{1+12.7(f/8)^{1/2}(Pr^{2/3}-1)}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 < Pr ≤ 2000  and 2300 ≤ Re ≤ 5*10^6.\n\n    Examples\n    --------\n    >>> turbulent_Gnielinski(Re=1E5, Pr=1.2, fd=0.0185)\n    254.62682749359632\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Gnielinski, V. (1976). New Equation for Heat and Mass Transfer in\n       Turbulent Pipe and Channel Flow, International Chemical Engineering,\n       Vol. 16, pp. 359-368.\n    \"\"\"\n    return (fd/8.)*(Re - 1E3)*Pr/(1. + 12.7*(fd/8.)**0.5*(Pr**(2/3.) - 1.))\n\n\ndef turbulent_Gnielinski_smooth_1(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_. This is a simplified case assuming\n    smooth pipe.\n\n    .. math::\n        Nu = 0.0214(Re^{0.8}-100)Pr^{0.4}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 0.5 < Pr ≤ 1.5  and 10^4 ≤ Re ≤ 5*10^6.\n\n    Examples\n    --------\n    >>> turbulent_Gnielinski_smooth_1(Re=1E5, Pr=1.2)\n    227.88800494373442\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Gnielinski, V. (1976). New Equation for Heat and Mass Transfer in\n       Turbulent Pipe and Channel Flow, International Chemical Engineering,\n       Vol. 16, pp. 359-368.\n    \"\"\"\n    return 0.0214*(Re**0.8 - 100.)*Pr**0.4\n\n\ndef turbulent_Gnielinski_smooth_2(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as in [1]_. This is a simplified case assuming\n    smooth pipe.\n\n    .. math::\n        Nu = 0.012(Re^{0.87}-280)Pr^{0.4}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Range according to [1]_ is 1.5 < Pr ≤ 500 and 3*10^3 ≤ Re ≤ 10^6.\n\n    Examples\n    --------\n    >>> turbulent_Gnielinski_smooth_2(Re=1E5, Pr=7.)\n    577.7692524513449\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Gnielinski, V. (1976). New Equation for Heat and Mass Transfer in\n       Turbulent Pipe and Channel Flow, International Chemical Engineering,\n       Vol. 16, pp. 359-368.\n    \"\"\"\n    return 0.012*(Re**0.87 - 280.)*Pr**0.4\n\n\ndef turbulent_Churchill_Zajic(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as developed in [1]_. Has yet to obtain\n    popularity.\n\n    .. math::\n        Nu = \\left\\{\\left(\\frac{Pr_T}{Pr}\\right)\\frac{1}{Nu_{di}} +\n        \\left[1-\\left(\\frac{Pr_T}{Pr}\\right)^{2/3}\\right]\\frac{1}{Nu_{D\\infty}}\n        \\right\\}^{-1}\n\n    .. math::\n        Nu_{di} = \\frac{Re(f/8)}{1 + 145(8/f)^{-5/4}}\n\n    .. math::\n        Nu_{D\\infty} = 0.07343Re\\left(\\frac{Pr}{Pr_T}\\right)^{1/3}(f/8)^{0.5}\n\n    .. math::\n        Pr_T = 0.85 + \\frac{0.015}{Pr}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    No restrictions on range. This is equation is developed with more\n    theoretical work than others.\n\n    Examples\n    --------\n    >>> turbulent_Churchill_Zajic(Re=1E5, Pr=1.2, fd=0.0185)\n    260.5564907817961\n\n    References\n    ----------\n    .. [1] Churchill, Stuart W., and Stefan C. Zajic. “Prediction of Fully\n       Developed Turbulent Convection with Minimal Explicit Empiricism.”\n       AIChE Journal 48, no. 5 (May 1, 2002): 927-40. doi:10.1002/aic.690480503.\n    .. [2] Plawsky, Joel L. Transport Phenomena Fundamentals, Third Edition.\n       CRC Press, 2014.\n    \"\"\"\n    Pr_T = 0.85 + 0.015/Pr\n    Nu_di = Re*(fd/8.)/(1. + 145*(8./fd)**(-1.25))\n    Nu_dinf = 0.07343*Re*(Pr/Pr_T)**(1./3.0)*(fd/8.)**0.5\n    return 1./(Pr_T/Pr/Nu_di + (1. - (Pr_T/Pr)**(2/3.))/Nu_dinf)\n\n\ndef turbulent_ESDU(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to the ESDU as shown in [1]_.\n\n    .. math::\n        Nu = 0.0225Re^{0.795}Pr^{0.495}\\exp(-0.0225\\ln(Pr)^2)\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    4000 < Re < 1E6, 0.3 < Pr < 3000 and L/D > 60.\n    This equation has not been checked. It was developed by a commercial group.\n    This function is a small part of a much larger series of expressions\n    accounting for many factors.\n\n    Examples\n    --------\n    >>> turbulent_ESDU(Re=1E5, Pr=1.2)\n    232.3017143430645\n\n    References\n    ----------\n    .. [1] Hewitt, G. L. Shires, T. Reg Bott G. F., George L. Shires, and\n       T. R. Bott. Process Heat Transfer. 1E. Boca Raton: CRC Press, 1994.\n    \"\"\"\n    return 0.0225*Re**0.795*Pr**0.495*exp(-0.0225*log(Pr)**2)\n\n### Correlations for 'rough' turbulent pipe\n\ndef turbulent_Martinelli(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu  = \\frac{RePr(f/8)^{0.5}}{5[Pr + \\ln(1+5Pr) + 0.5\\ln(Re(f/8)^{0.5}/60)]}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    No range is given for this equation. Liquid metals are probably its only\n    applicability.\n\n    Examples\n    --------\n    >>> turbulent_Martinelli(Re=1E5, Pr=100., fd=0.0185)\n    887.1710686396347\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Martinelli, R. C. (1947). \"Heat transfer to molten metals\".\n       Trans. ASME, 69, 947-959.\n    \"\"\"\n    return Re*Pr*(fd/8.)**0.5/5/(Pr + log(1. + 5.*Pr) + 0.5*log(Re*(fd/8.)**0.5/60.))\n\n\ndef turbulent_Nunner(Re: float, Pr: float, fd: float, fd_smooth: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu = \\frac{RePr(f/8)}{1 + 1.5Re^{-1/8}Pr^{-1/6}[Pr(f/f_s)-1]}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n    fd_smooth : float\n        Darcy friction factor of a smooth pipe [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    Valid for Pr ≅ 0.7; bad results for Pr > 1.\n\n    Examples\n    --------\n    >>> turbulent_Nunner(Re=1E5, Pr=0.7, fd=0.0185, fd_smooth=0.005)\n    101.15841010919947\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] W. Nunner, \"Warmeiibergang und Druckabfall in Rauhen Rohren,\"\n       VDI-Forschungsheft 445, ser. B,(22): 5-39, 1956\n    \"\"\"\n    return Re*Pr*fd/8./(1 + 1.5*Re**-0.125*Pr**(-1/6.)*(Pr*fd/fd_smooth - 1.))\n\n\ndef turbulent_Dipprey_Sabersky(Re: float, Pr: float, fd: float, eD: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu = \\frac{RePr(f/8)}{1 + (f/8)^{0.5}[5.19Re_\\epsilon^{0.2} Pr^{0.44} - 8.48]}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n    eD : float\n        Relative roughness, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    According to [1]_, the limits are:\n    1.2 ≤ Pr ≤ 5.94 and 1.4*10^4 ≤ Re ≤ 5E5 and 0.0024 ≤ eD ≤ 0.049.\n\n    Examples\n    --------\n    >>> turbulent_Dipprey_Sabersky(Re=1E5, Pr=1.2, fd=0.0185, eD=1E-3)\n    288.33365198566656\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Dipprey, D. F., and R. H. Sabersky. “Heat and Momentum Transfer in\n       Smooth and Rough Tubes at Various Prandtl Numbers.” International\n       Journal of Heat and Mass Transfer 6, no. 5 (May 1963): 329-53.\n       doi:10.1016/0017-9310(63)90097-8\n    \"\"\"\n    Re_e = Re*eD*(fd/8.)**0.5\n    return Re*Pr*fd/8./(1 + (fd/8.)**0.5*(5.19*Re_e**0.2*Pr**0.44 - 8.48))\n\n\ndef turbulent_Gowen_Smith(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu = \\frac{Re Pr (f/8)^{0.5}} {4.5 + [0.155(Re(f/8)^{0.5})^{0.54}\n        + (8/f)^{0.5}]Pr^{0.5}}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    0.7 ≤ Pr ≤ 14.3 and 10^4 ≤ Re ≤ 5E4 and 0.0021 ≤ eD ≤ 0.095\n\n    Examples\n    --------\n    >>> turbulent_Gowen_Smith(Re=1E5, Pr=1.2, fd=0.0185)\n    131.72530453824106\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Gowen, R. A., and J. W. Smith. “Turbulent Heat Transfer from Smooth\n       and Rough Surfaces.” International Journal of Heat and Mass Transfer 11,\n       no. 11 (November 1968): 1657-74. doi:10.1016/0017-9310(68)90046-X.\n    \"\"\"\n    return Re*Pr*(fd/8.)**0.5/(4.5 + (0.155*(Re*(fd/8.)**0.5)**0.54 + (8./fd)**0.5)*Pr**0.5)\n\n\ndef turbulent_Kawase_Ulbrecht(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu = 0.0523RePr^{0.5}(f/4)^{0.5}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    No limits are provided.\n\n    Examples\n    --------\n    >>> turbulent_Kawase_Ulbrecht(Re=1E5, Pr=1.2, fd=0.0185)\n    389.6262247333975\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Kawase, Yoshinori, and Jaromir J. Ulbrecht. “Turbulent Heat and Mass\n       Transfer in Dilute Polymer Solutions.” Chemical Engineering Science 37,\n       no. 7 (1982): 1039-46. doi:10.1016/0009-2509(82)80134-6.\n    \"\"\"\n    return 0.0523*Re*Pr**0.5*(fd/4.)**0.5\n\n\ndef turbulent_Kawase_De(Re: float, Pr: float, fd: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_.\n\n    .. math::\n        Nu = 0.0471 RePr^{0.5}(f/4)^{0.5}(1.11 + 0.44Pr^{-1/3} - 0.7Pr^{-1/6})\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    5.1 ≤ Pr ≤ 390 and 5000 ≤ Re ≤ 5E5 and 0.0024 ≤ eD ≤ 0.165.\n\n    Examples\n    --------\n    >>> turbulent_Kawase_De(Re=1E5, Pr=1.2, fd=0.0185)\n    296.5019733271324\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] Kawase, Yoshinori, and Addie De. “Turbulent Heat and Mass Transfer\n       in Newtonian and Dilute Polymer Solutions Flowing through Rough Pipes.”\n       International Journal of Heat and Mass Transfer 27, no. 1\n       (January 1984): 140-42. doi:10.1016/0017-9310(84)90246-1.\n    \"\"\"\n    return 0.0471*Re*Pr**0.5*(fd/4.)**0.5*(1.11 + 0.44*Pr**(-1/3.) - 0.7*Pr**(-1/6.))\n\n\ndef turbulent_Bhatti_Shah(Re: float, Pr: float, fd: float, eD: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent flows\n    in pipe according to [2]_ as shown in [1]_. The most widely used rough\n    pipe turbulent correlation.\n\n    .. math::\n        Nu_D = \\frac{(f/8)Re_DPr}{1+\\sqrt{f/8}(4.5Re_{\\epsilon}^{0.2}Pr^{0.5}-8.48)}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    fd : float\n        Darcy friction factor [-]\n    eD : float\n        Relative roughness, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Notes\n    -----\n    According to [1]_, the limits are:\n    0.5 ≤ Pr ≤  10\n    0.002 ≤ ε/D ≤  0.05\n    10,000 ≤ Re_{D}\n    Another correlation is listed in this equation, with a wider variety\n    of validity.\n\n    Examples\n    --------\n    >>> turbulent_Bhatti_Shah(Re=1E5, Pr=1.2, fd=0.0185, eD=1E-3)\n    302.7037617414273\n\n    References\n    ----------\n    .. [1] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [2] M. S. Bhatti and R. K. Shah. Turbulent and transition flow\n       convective heat transfer in ducts. In S. Kakaç, R. K. Shah, and W.\n       Aung, editors, Handbook of Single-Phase Convective Heat Transfer,\n       chapter 4. Wiley-Interscience, New York, 1987.\n    \"\"\"\n    Re_e = Re*eD*(fd/8.)**0.5\n    return Re*Pr*fd/8./(1 + (fd/8.)**0.5*(4.5*Re_e**0.2*Pr**0.5 - 8.48))\n\n\nconv_tube_laminar_methods = {\n    \"Laminar - constant T\": (laminar_T_const, ()),\n    \"Laminar - constant Q\": (laminar_Q_const, ()),\n    \"Baehr-Stephan laminar thermal/velocity entry\": (laminar_entry_thermal_Hausen, (\"Re\", \"Pr\", \"L\", \"Di\")),\n     \"Hausen laminar thermal entry\": (laminar_entry_Seider_Tate, (\"Re\", \"Pr\", \"L\", \"Di\")),\n    \"Seider-Tate laminar thermal entry\": (laminar_entry_Baehr_Stephan, (\"Re\", \"Pr\", \"L\", \"Di\")),\n}\n\nconv_tube_turbulent_methods = {\n    \"Churchill-Zajic\": (turbulent_Churchill_Zajic, (\"Re\", \"Pr\", \"fd\")),\n    \"Petukhov-Kirillov-Popov\": (turbulent_Petukhov_Kirillov_Popov, (\"Re\", \"Pr\", \"fd\")),\n    \"Gnielinski\": (turbulent_Gnielinski, (\"Re\", \"Pr\", \"fd\")),\n    \"Sandall\": (turbulent_Sandall, (\"Re\", \"Pr\", \"fd\")),\n    \"Webb\": (turbulent_Webb, (\"Re\", \"Pr\", \"fd\")),\n    \"Friend-Metzner\": (turbulent_Friend_Metzner, (\"Re\", \"Pr\", \"fd\")),\n    \"Prandtl\": (turbulent_Prandtl, (\"Re\", \"Pr\", \"fd\")),\n    \"von-Karman\": (turbulent_von_Karman, (\"Re\", \"Pr\", \"fd\")),\n    \"Martinelli\": (turbulent_Martinelli, (\"Re\", \"Pr\", \"fd\")),\n    \"Gowen-Smith\": (turbulent_Gowen_Smith, (\"Re\", \"Pr\", \"fd\")),\n    \"Kawase-Ulbrecht\": (turbulent_Kawase_Ulbrecht, (\"Re\", \"Pr\", \"fd\")),\n    \"Kawase-De\": (turbulent_Kawase_De, (\"Re\", \"Pr\", \"fd\")),\n\n    \"Dittus-Boelter\": (turbulent_Dittus_Boelter, (\"Re\", \"Pr\")),\n    \"Sieder-Tate\": (turbulent_Sieder_Tate, (\"Re\", \"Pr\")),\n    \"Drexel-McAdams\": (turbulent_Drexel_McAdams, (\"Re\", \"Pr\")),\n    \"Colburn\": (turbulent_Colburn, (\"Re\", \"Pr\")),\n    \"ESDU\": (turbulent_ESDU, (\"Re\", \"Pr\")),\n    \"Gnielinski smooth low Pr\": (turbulent_Gnielinski_smooth_1, (\"Re\", \"Pr\")),\n    \"Gnielinski smooth high Pr\": (turbulent_Gnielinski_smooth_2, (\"Re\", \"Pr\")),\n\n    \"Hausen\": (turbulent_entry_Hausen, (\"Re\", \"Pr\", \"Di\", \"x\")),\n    \"Bhatti-Shah\": (turbulent_Bhatti_Shah, (\"Re\", \"Pr\", \"fd\", \"eD\")),\n    \"Dipprey-Sabersky\": (turbulent_Dipprey_Sabersky, (\"Re\", \"Pr\", \"fd\", \"eD\")),\n    \"Nunner\": (turbulent_Nunner, (\"Re\", \"Pr\", \"fd\", \"fd_smooth\")),\n}\n\nconv_tube_methods = conv_tube_laminar_methods.copy()\nconv_tube_methods.update(conv_tube_turbulent_methods)\nconv_tube_methods_list = list(conv_tube_methods.keys())\n\ndef Nu_conv_internal_methods(Re: float, Pr: float, eD: float=0, Di: float | None=None, x: float | None=None, fd: None=None,\n                             check_ranges: bool=True) -> list[str]:\n    r\"\"\"This function returns a list of correlation names for the calculation\n    of heat transfer coefficient for internal convection inside a circular pipe.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    eD : float, optional\n        Relative roughness, [-]\n    Di : float, optional\n        Inside diameter of pipe, [m]\n    x : float, optional\n        Length inside of pipe for calculation, [m]\n    fd : float, optoinal\n        Darcy friction factor [-]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    methods : list\n        List of methods which can be used to calculate `Nu` with the given inputs\n\n    Examples\n    --------\n    Turbulent example\n\n    >>> Nu_conv_internal_methods(Re=1E5, Pr=.7)[0]\n    'Churchill-Zajic'\n\n    Entry length - laminar example\n\n    >>> Nu_conv_internal_methods(Re=1E2, Pr=.7, x=.01, Di=.1)[0]\n    'Baehr-Stephan laminar thermal/velocity entry'\n    \"\"\"\n    methods = []\n    if Re < LAMINAR_TRANSITION_PIPE or not check_ranges:\n        # Laminar!\n        if (Re is not None and Pr is not None and x is not None and Di is not None):\n            methods.append(\"Baehr-Stephan laminar thermal/velocity entry\")\n            methods.append(\"Hausen laminar thermal entry\")\n            methods.append(\"Seider-Tate laminar thermal entry\")\n\n        methods.append(\"Laminar - constant T\")\n        methods.append(\"Laminar - constant Q\")\n    if Re >= LAMINAR_TRANSITION_PIPE or not check_ranges:\n        if (Re is not None and Pr is not None and Pr < 0.03) or not check_ranges:\n            # Liquid metals\n            methods.append(\"Martinelli\")\n        if (Re is not None and Pr is not None and x is not None and Di is not None) or not check_ranges:\n            methods.append(\"Hausen\")\n        if (Re is not None and Pr is not None and (eD is not None or fd is not None)) or not check_ranges:\n            # handle correlations with roughness\n            methods.append(\"Churchill-Zajic\")\n            methods.append(\"Petukhov-Kirillov-Popov\")\n            methods.append(\"Gnielinski\")\n            methods.append(\"Bhatti-Shah\")\n            methods.append(\"Dipprey-Sabersky\")\n            methods.append(\"Sandall\")\n            methods.append(\"Webb\")\n            methods.append(\"Friend-Metzner\")\n            methods.append(\"Prandtl\")\n            methods.append(\"von-Karman\")\n            methods.append(\"Gowen-Smith\")\n            methods.append(\"Kawase-Ulbrecht\")\n            methods.append(\"Kawase-De\")\n            methods.append(\"Nunner\")\n        if (Re is not None and Pr is not None) or not check_ranges:\n            methods.append(\"Dittus-Boelter\")\n            methods.append(\"Sieder-Tate\")\n            methods.append(\"Drexel-McAdams\")\n            methods.append(\"Colburn\")\n            methods.append(\"ESDU\")\n            methods.append(\"Gnielinski smooth low Pr\") # 1\n            methods.append(\"Gnielinski smooth high Pr\") # 2\n    return methods\n\ndef Nu_conv_internal(Re: float, Pr: float, eD: float=0.0, Di: float | None=None, x: float | None=None, fd: float | None=None, Method: str | None=None) -> float:\n    r\"\"\"This function calculates the heat transfer coefficient for internal\n    convection inside a circular pipe.\n\n    Requires at a minimum a flow's Reynolds and Prandtl numbers `Re` and `Pr`.\n    Relative roughness `eD` can be specified to include the enhancement of heat\n    transfer from the added turbulence.\n\n    For laminar flow, thermally and hydraulically developing flow is supported\n    with the pipe diameter `Di` and distance `x` is provided.\n\n    If no correlation's name is provided as `Method`, the most accurate\n    applicable correlation is selected.\n\n    * If laminar, `x` and `Di` provided:  'Baehr-Stephan laminar thermal/velocity entry'\n    * Otherwise if laminar, no entry information provided: 'Laminar - constant T' (Nu = 3.66)\n    * If turbulent and `Pr` < 0.03: 'Martinelli'\n    * If turbulent, `x` and `Di` provided: 'Hausen'\n    * Otherwise if turbulent: 'Churchill-Zajic'\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    Pr : float\n        Prandtl number, [-]\n    eD : float, optional\n        Relative roughness, [-]\n    Di : float, optional\n        Inside diameter of pipe, [m]\n    x : float, optional\n        Length inside of pipe for calculation, [m]\n    fd : float, optoinal\n        Darcy friction factor [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        A string of the function name to use, as in the dictionary\n        vertical_cylinder_correlations\n\n    Examples\n    --------\n    Turbulent example\n\n    >>> Nu_conv_internal(Re=1E5, Pr=.7)\n    183.71057902604906\n\n    Entry length - laminar example\n\n    >>> Nu_conv_internal(Re=1E2, Pr=.7, x=.01, Di=.1)\n    14.91799128769779\n    \"\"\"\n    if Method is None:\n        Method2 = Nu_conv_internal_methods(Re=Re, Pr=Pr, eD=eD, Di=Di, x=x, fd=fd, check_ranges=True)[0]\n    else:\n        Method2 = Method\n\n    L = x\n    if eD is not None and fd is None:\n        fd = Clamond(Re=Re, eD=eD)\n\n    if Method2 == \"Laminar - constant T\":\n        return laminar_T_const()\n    elif Method2 == \"Laminar - constant Q\":\n        return laminar_Q_const()\n    elif Method2 == \"Baehr-Stephan laminar thermal/velocity entry\":\n        return laminar_entry_thermal_Hausen(Re=Re, Pr=Pr, L=L, Di=Di)\n    elif Method2 == \"Hausen laminar thermal entry\":\n        return laminar_entry_Seider_Tate(Re=Re, Pr=Pr, L=L, Di=Di)\n    elif Method2 == \"Seider-Tate laminar thermal entry\":\n        return laminar_entry_Baehr_Stephan(Re=Re, Pr=Pr, L=L, Di=Di)\n    elif Method2 == \"Churchill-Zajic\":\n        return turbulent_Churchill_Zajic(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Petukhov-Kirillov-Popov\":\n        return turbulent_Petukhov_Kirillov_Popov(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Gnielinski\":\n        return turbulent_Gnielinski(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Sandall\":\n        return turbulent_Sandall(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Webb\":\n        return turbulent_Webb(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Friend-Metzner\":\n        return turbulent_Friend_Metzner(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Prandtl\":\n        return turbulent_Prandtl(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"von-Karman\":\n        return turbulent_von_Karman(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Martinelli\":\n        return turbulent_Martinelli(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Gowen-Smith\":\n        return turbulent_Gowen_Smith(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Kawase-Ulbrecht\":\n        return turbulent_Kawase_Ulbrecht(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Kawase-De\":\n        return turbulent_Kawase_De(Re=Re, Pr=Pr, fd=fd)\n    elif Method2 == \"Dittus-Boelter\":\n        return turbulent_Dittus_Boelter(Re=Re, Pr=Pr)\n    elif Method2 == \"Sieder-Tate\":\n        return turbulent_Sieder_Tate(Re=Re, Pr=Pr)\n    elif Method2 == \"Drexel-McAdams\":\n        return turbulent_Drexel_McAdams(Re=Re, Pr=Pr)\n    elif Method2 == \"Colburn\":\n        return turbulent_Colburn(Re=Re, Pr=Pr)\n    elif Method2 == \"ESDU\":\n        return turbulent_ESDU(Re=Re, Pr=Pr)\n    elif Method2 == \"Gnielinski smooth low Pr\":\n        return turbulent_Gnielinski_smooth_1(Re=Re, Pr=Pr)\n    elif Method2 == \"Gnielinski smooth high Pr\":\n        return turbulent_Gnielinski_smooth_2(Re=Re, Pr=Pr)\n    elif Method2 == \"Hausen\":\n        return turbulent_entry_Hausen(Re=Re, Pr=Pr, Di=Di, x=x)\n    elif Method2 == \"Bhatti-Shah\":\n        return turbulent_Bhatti_Shah(Re=Re, Pr=Pr, fd=fd, eD=eD)\n    elif Method2 == \"Dipprey-Sabersky\":\n        return turbulent_Dipprey_Sabersky(Re=Re, Pr=Pr, fd=fd, eD=eD)\n    elif Method2 == \"Nunner\":\n        fd_smooth = Clamond(Re, eD=0.0)\n        return turbulent_Nunner(Re=Re, Pr=Pr, fd=fd, fd_smooth=fd_smooth)\n    else:\n        raise ValueError(\"Correlation name not recognized; see the \"\n                        \"documentation for the available options.\")\n\n\n## Comparison\n#import matplotlib.pyplot as plt\n#import numpy as np\n#from fluids.friction import friction_factor\n#Pr = 0.3\n#Di = 0.0254*4\n#roughness = .00015\n#\n#methods = Nu_conv_internal_methods(Re=10000, Pr=Pr, fd=1.8E-5, x=2.5, Di=0.5)\n#\n#plt.figure()\n#Res = np.logspace(4, 6, 300)\n#for way in methods:\n#    Nus = []\n#    for Re in Res:\n#        fd = friction_factor(Re=Re, eD=roughness/Di)\n#        Nus.append(Nu_conv_internal(Re=Re, Pr=Pr, fd=fd, x=2.5, Di=0.5, Method=way))\n#    plt.plot(Res, Nus, label=way)\n#plt.xlabel(r'Res')\n#plt.ylabel('Nus')\n#plt.legend()\n#\n#plt.show()\n\n\n### Spiral heat exchangers\n\ndef Morimoto_Hotta(Re: float, Pr: float, Dh: float, Rm: float) -> float:\n    r\"\"\"Calculates Nusselt number for flow inside a spiral heat exchanger of\n    spiral mean diameter `Rm` and hydraulic diameter `Dh` according to [1]_,\n    also as shown in [2]_ and [3]_.\n\n    .. math::\n        Nu = 0.0239\\left(1 + 5.54\\frac{D_h}{R_m}\\right)Re^{0.806}Pr^{0.268}\n\n    .. math::\n        D_h = \\frac{2HS}{H+S}\n\n    .. math::\n        R_m = \\frac{R_{min} + R_{max}}{2}\n\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk properties, [-]\n    Pr : float\n        Prandtl number with bulk properties [-]\n    Dh : float\n        Average hydraulic diameter, [m]\n    Rm : float\n        Average spiral radius, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Dh`, [-]\n\n    Notes\n    -----\n    [1]_ is in Japanese.\n\n    Examples\n    --------\n    >>> Morimoto_Hotta(1E5, 5.7, .05, .5)\n    634.4879473869859\n\n    References\n    ----------\n    .. [1] Morimoto, Eiji, and Kazuyuki Hotta. \"Study of Geometric Structure\n       and Heat Transfer Characteristics of Spiral Plate Heat Exchanger.\"\n       Transactions of the Japan Society of Mechanical Engineers Series B 52,\n       no. 474 (1986): 926-33. doi:10.1299/kikaib.52.926.\n    .. [2] Bidabadi, M. and Sadaghiani, A. and Azad, A. \"Spiral heat exchanger\n       optimization using genetic algorithm.\" Transaction on Mechanical\n       Engineering, International Journal of Science and Technology,\n       vol. 20, no. 5 (2013): 1445-1454.\n       http://www.scientiairanica.com/en/ManuscriptDetail?mid=47.\n    .. [3] Turgut, Oğuz Emrah, and Mustafa Turhan Çoban. \"Thermal Design of\n       Spiral Heat Exchangers and Heat Pipes through Global Best Algorithm.\"\n       Heat and Mass Transfer, July 7, 2016, 1-18.\n       doi:10.1007/s00231-016-1861-y.\n    \"\"\"\n    return 0.0239*(1. + 5.54*Dh/Rm)*Re**0.806*Pr**0.268\n\n\n\n### Helical/curved coils\n\n\ndef helical_turbulent_Nu_Mori_Nakayama(Re: float, Pr: float, Di: float, Dc: float) -> float:\n    r\"\"\"Calculates Nusselt number for a fluid flowing inside a curved\n    pipe such as a helical coil under turbulent conditions, using the method of\n    Mori and Nakayama [1]_, also shown in [2]_ and [3]_.\n\n    For :math:`Pr < 1`:\n\n    .. math::\n        Nu = \\frac{Pr}{26.2(Pr^{2/3}-0.074)}Re^{0.8}\\left(\\frac{D_i}{D_c}\n        \\right)^{0.1}\\left[1 + \\frac{0.098}{\\left[Re\\left(\\frac{D_i}{D_c}\n        \\right)^2\\right]^{0.2}}\\right]\n\n    For :math:`Pr \\ge 1`:\n\n    .. math::\n        Nu = \\frac{Pr^{0.4}}{41}Re^{5/6}\\left(\\frac{D_i}{D_c}\\right)^{1/12}\n        \\left[1 + \\frac{0.061}{\\left[Re\\left(\\frac{D_i}{D_c}\\right)^{2.5}\n        \\right]^{1/6}}\\right]\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with `D=Di`, [-]\n    Pr : float\n        Prandtl number with bulk properties [-]\n    Di : float\n        Inner diameter of the coil, [m]\n    Dc : float\n        Diameter of the helix/coil measured from the center of the tube on one\n        side to the center of the tube on the other side, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Di`, [-]\n\n    Notes\n    -----\n    At very low curvatures, the predicted heat transfer coefficient\n    grows unbounded.\n\n    Applicable for :math:`Re\\left(\\frac{D_i}{D_c}\\right)^2 > 0.1`\n\n    Examples\n    --------\n    >>> helical_turbulent_Nu_Mori_Nakayama(2E5, 0.7, 0.01, .2)\n    496.2522480663327\n\n    References\n    ----------\n    .. [1] Mori, Yasuo, and Wataru Nakayama. \"Study on Forced Convective Heat\n       Transfer in Curved Pipes.\" International Journal of Heat and Mass\n       Transfer 10, no. 5 (May 1, 1967): 681-95.\n       doi:10.1016/0017-9310(67)90113-5.\n    .. [2] El-Genk, Mohamed S., and Timothy M. Schriener. \"A Review and\n       Correlations for Convection Heat Transfer and Pressure Losses in\n       Toroidal and Helically Coiled Tubes.\" Heat Transfer Engineering 0, no. 0\n       (June 7, 2016): 1-28. doi:10.1080/01457632.2016.1194693.\n    .. [3] Hardik, B. K., P. K. Baburajan, and S. V. Prabhu. \"Local Heat\n       Transfer Coefficient in Helical Coils with Single Phase Flow.\"\n       International Journal of Heat and Mass Transfer 89 (October 2015):\n       522-38. doi:10.1016/j.ijheatmasstransfer.2015.05.069.\n    \"\"\"\n    D_ratio = Di/Dc\n    if Pr < 1:\n        term1 = Pr/(26.2*(Pr**(2/3.) - 0.074))*Re**0.8*D_ratio**0.1\n        term2 = 1. + 0.098*(Re*D_ratio*D_ratio)**-0.2\n    else:\n        term1 = Pr**0.4/41.*Re**(5/6.)*(Di/Dc)**(1/12.)\n        term2 = 1. + 0.061/(Re*(Di/Dc)**2.5)**(1/6.)\n    return term1*term2\n\n\ndef helical_turbulent_Nu_Schmidt(Re: float, Pr: float, Di: float, Dc: float) -> float:\n    r\"\"\"Calculates Nusselt number for a fluid flowing inside a curved\n    pipe such as a helical coil under turbulent conditions, using the method of\n    Schmidt [1]_, also shown in [2]_, [3]_, and [4]_.\n\n    For :math:`Re_{crit} < Re < 2.2\\times 10 ^4`:\n\n    .. math::\n        Nu = 0.023\\left[1 + 14.8\\left(1 + \\frac{D_i}{D_c}\\right)\\left(\n        \\frac{D_i}{D_c}\\right)^{1/3}\\right]Re^{0.8-0.22\\left(\\frac{D_i}{D_c}\n        \\right)^{0.1}}Pr^{1/3}\n\n    For :math:`2.2\\times 10^4 < Re < 1.5\\times 10^5`:\n\n    .. math::\n        Nu = 0.023\\left[1 + 3.6\\left(1 - \\frac{D_i}{D_c}\\right)\\left(\\frac{D_i}\n        {D_c}\\right)^{0.8}\\right]Re^{0.8}Pr^{1/3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with `D=Di`, [-]\n    Pr : float\n        Prandtl number with bulk properties [-]\n    Di : float\n        Inner diameter of the coil, [m]\n    Dc : float\n        Diameter of the helix/coil measured from the center of the tube on one\n        side to the center of the tube on the other side, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Di`, [-]\n\n    Notes\n    -----\n    For very low curvatures, reasonable results are returned by both cases\n    of Reynolds numbers.\n\n    Examples\n    --------\n    >>> helical_turbulent_Nu_Schmidt(2E5, 0.7, 0.01, .2)\n    466.2569996832083\n\n    References\n    ----------\n    .. [1] Schmidt, Eckehard F. \"Wärmeübergang Und Druckverlust in\n       Rohrschlangen.\" Chemie Ingenieur Technik 39, no. 13 (July 10, 1967):\n       781-89. doi:10.1002/cite.330391302.\n    .. [2] El-Genk, Mohamed S., and Timothy M. Schriener. \"A Review and\n       Correlations for Convection Heat Transfer and Pressure Losses in\n       Toroidal and Helically Coiled Tubes.\" Heat Transfer Engineering 0, no. 0\n       (June 7, 2016): 1-28. doi:10.1080/01457632.2016.1194693.\n    .. [3] Hardik, B. K., P. K. Baburajan, and S. V. Prabhu. \"Local Heat\n       Transfer Coefficient in Helical Coils with Single Phase Flow.\"\n       International Journal of Heat and Mass Transfer 89 (October 2015):\n       522-38. doi:10.1016/j.ijheatmasstransfer.2015.05.069.\n    .. [4] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    D_ratio = Di/Dc\n    if Re <= 2.2E4:\n        term = Re**(0.8 - 0.22*D_ratio**0.1)*Pr**(1/3.)\n        return 0.023*(1. + 14.8*(1. + D_ratio)*D_ratio**(1/3.))*term\n    else:\n        return 0.023*(1. + 3.6*(1. - D_ratio)*D_ratio**0.8)*Re**0.8*Pr**(1/3.)\n\n\ndef helical_turbulent_Nu_Xin_Ebadian(Re: float, Pr: float, Di: float, Dc: float) -> float:\n    r\"\"\"Calculates Nusselt number for a fluid flowing inside a curved\n    pipe such as a helical coil under turbulent conditions, using the method of\n    Xin and Ebadian [1]_, also shown in [2]_ and [3]_.\n\n    For :math:`Re_{crit} < Re < 1\\times 10^5`:\n\n    .. math::\n        Nu = 0.00619Re^{0.92} Pr^{0.4}\\left[1 + 3.455\\left(\\frac{D_i}{D_c}\n        \\right)\\right]\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with `D=Di`, [-]\n    Pr : float\n        Prandtl number with bulk properties [-]\n    Di : float\n        Inner diameter of the coil, [m]\n    Dc : float\n        Diameter of the helix/coil measured from the center of the tube on one\n        side to the center of the tube on the other side, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Di`, [-]\n\n    Notes\n    -----\n    For very low curvatures, reasonable results are returned.\n\n    The correlation was developed with data in the range of\n    :math:`0.7 < Pr < 5; 0.0267 < \\frac{D_i}{D_c} < 0.0884`.\n\n    Examples\n    --------\n    >>> helical_turbulent_Nu_Xin_Ebadian(2E5, 0.7, 0.01, .2)\n    474.11413424344755\n\n    References\n    ----------\n    .. [1] Xin, R. C., and M. A. Ebadian. \"The Effects of Prandtl Numbers on\n       Local and Average Convective Heat Transfer Characteristics in Helical\n       Pipes.\" Journal of Heat Transfer 119, no. 3 (August 1, 1997): 467-73.\n       doi:10.1115/1.2824120.\n    .. [2] El-Genk, Mohamed S., and Timothy M. Schriener. \"A Review and\n       Correlations for Convection Heat Transfer and Pressure Losses in\n       Toroidal and Helically Coiled Tubes.\" Heat Transfer Engineering 0, no. 0\n       (June 7, 2016): 1-28. doi:10.1080/01457632.2016.1194693.\n    .. [3] Hardik, B. K., P. K. Baburajan, and S. V. Prabhu. \"Local Heat\n       Transfer Coefficient in Helical Coils with Single Phase Flow.\"\n       International Journal of Heat and Mass Transfer 89 (October 2015):\n       522-38. doi:10.1016/j.ijheatmasstransfer.2015.05.069.\n    \"\"\"\n    return 0.00619*Re**0.92*Pr**0.4*(1. + 3.455*Di/Dc)\n\n\n### Rectangular Channels\n\ndef Nu_laminar_rectangular_Shan_London(a_r: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for laminar flows\n    in a rectangular pipe of varying aspect ratio, as developed in [1]_.\n\n    This model is derived assuming a constant wall heat flux from all sides.\n    This is entirely theoretically derived and reproduced experimentally.\n\n    .. math::\n        Nu_{lam} = 8.235\\left(1 - 2.0421\\alpha + 3.0853\\alpha^2\n        - 2.4765\\alpha^3 + 1.0578\\alpha^4 - 0.1861\\alpha^5\\right)\n\n    Parameters\n    ----------\n    a_r : float\n        The aspect ratio of the channel, from 0 to 1 [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number of flow in a rectangular channel, [-]\n\n    Notes\n    -----\n    At an aspect ratio of 1 (square channel), the Nusselt number converges to\n    3.610224. The authors of [1]_ also published [2]_, which tabulates in\n    their table 42 some less precise results that are used to check this\n    function.\n\n    Examples\n    --------\n    >>> Nu_laminar_rectangular_Shan_London(.7)\n    3.751762675455\n\n    References\n    ----------\n    .. [1] Shah, R. K, and Alexander Louis London. Supplement 1: Laminar Flow\n       Forced Convection in Ducts: A Source Book for Compact Heat Exchanger\n       Analytical Data. New York: Academic Press, 1978.\n    .. [2] Shah, Ramesh K., and A. L. London. \"Laminar Flow Forced Convection\n       Heat Transfer and Flow Friction in Straight and Curved Ducts - A Summary\n       of Analytical Solutions.\" STANFORD UNIV CA DEPT OF MECHANICAL\n       ENGINEERING, STANFORD UNIV CA DEPT OF MECHANICAL ENGINEERING, November\n       1971. http://www.dtic.mil/docs/citations/AD0736260.\n    \"\"\"\n    return 8.235*(1 - 2.0421*a_r + 3.0853*a_r**2 - 2.4765*a_r**3\n                  + 1.0578*a_r**4 - 0.1861*a_r**5)\n\n"
  },
  {
    "path": "ht/conv_jacket.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import log, pi\n\nfrom fluids.constants import g\nfrom fluids.friction import friction_factor\n\n__all__: list[str] = [\"Lehrer\", \"Stein_Schmidt\"]\n\ndef Lehrer(m: float, Dtank: float, Djacket: float, H: float, Dinlet: float, rho: float, Cp: float, k: float, mu: float, muw: float | None=None,\n           isobaric_expansion: float | None=None, dT: float | None=None, inlettype: str=\"tangential\",\n           inletlocation: str=\"auto\") -> float:\n    r\"\"\"Calculates average heat transfer coefficient for a jacket around a\n    vessel according to [1]_ as described in [2]_.\n\n    .. math::\n        Nu_{S,L} = \\left[\\frac{0.03Re_S^{0.75}Pr}{1 + \\frac{1.74(Pr-1)}\n        {Re_S^{0.125}}}\\right]\\left(\\frac{\\mu}{\\mu_w}\\right)^{0.14}\n\n    .. math::\n        d_g = \\left(\\frac{8}{3}\\right)^{0.5}\\delta\n\n    .. math::\n        v_h = (v_Sv_{inlet})^{0.5} + v_A\n\n    .. math::\n        v_{inlet} = \\frac{Q}{\\frac{\\pi}{4}d_{inlet}^2}\n\n    .. math::\n        v_s = \\frac{Q}{\\frac{\\pi}{4}(D_{jacket}^2 - D_{tank}^2)}\n\n    For Radial inlets:\n\n    .. math::\n        v_A = 0.5(2g H \\beta\\delta \\Delta T)^{0.5}\n\n    For Tangential inlets:\n\n    .. math::\n        v_A = 0\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of fluid, [kg/s]\n    Dtank : float\n        Outer diameter of tank or vessel surrounded by jacket, [m]\n    Djacket : float\n        Inner diameter of jacket surrounding a vessel or tank, [m]\n    H : float\n        Height of the vessel or tank, [m]\n    Dinlet : float\n        Inner diameter of inlet into the jacket, [m]\n    rho : float\n        Density of the fluid at Tm [kg/m^3]\n    Cp : float\n        Heat capacity of fluid at Tm [J/kg/K]\n    k : float\n        Thermal conductivity of fluid at Tm [W/m/K]\n    mu : float\n        Viscosity of fluid at Tm [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at Tw [Pa*s]\n    isobaric_expansion : float, optional\n        Constant pressure expansivity of a fluid, [m^3/mol/K]\n    dT : float, optional\n        Temperature difference of fluid in jacket, [K]\n    inlettype : str, optional\n        Either 'tangential' or 'radial'\n    inletlocation : str, optional\n        Either 'top' or 'bottom' or 'auto'\n\n    Returns\n    -------\n    h : float\n        Average heat transfer coefficient inside the jacket [W/m^2/K]\n\n    Notes\n    -----\n    If the fluid is heated and enters from the bottom, natural convection\n    assists the heat transfer and the Grashof term is added; if it were to enter\n    from the top, it would be subtracted. The situation is reversed if entry\n    is from the top.\n\n    Examples\n    --------\n    Example as in [2]_, matches completely.\n\n    >>> Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20.,\n    ... rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6)\n    2922.128124761829\n\n    Examples similar to in [2]_ but covering the other case:\n\n    >>> Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20.,\n    ... rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6,\n    ... inlettype='radial', isobaric_expansion=0.000303)\n    3269.4389632666557\n\n    References\n    ----------\n    .. [1] Lehrer, Isaac H. \"Jacket-Side Nusselt Number.\" Industrial &\n       Engineering Chemistry Process Design and Development 9, no. 4\n       (October 1, 1970): 553-58. doi:10.1021/i260036a010.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    delta = (Djacket-Dtank)/2.\n    Q = m/rho\n    Pr = Cp*mu/k\n    vs = Q/H/delta\n    vo = Q/(pi/4*Dinlet**2)\n    if dT is not None and isobaric_expansion is not None and inlettype == \"radial\" and inletlocation is not None:\n        if dT > 0: # Heating jacket fluid\n            if inletlocation in (\"auto\", \"bottom\"):\n                va = 0.5*(2*g*H*isobaric_expansion*abs(dT))**0.5\n            else:\n                va = -0.5*(2*g*H*isobaric_expansion*abs(dT))**0.5\n        else: # cooling fluid\n            if inletlocation in (\"auto\", \"top\"):\n                va = 0.5*(2*g*H*isobaric_expansion*abs(dT))**0.5\n            else:\n                va = -0.5*(2*g*H*isobaric_expansion*abs(dT))**0.5\n    else:\n        va = 0\n    vh = (vs*vo)**0.5 + va\n    dg = (8/3.)**0.5*delta\n    Res = vh*dg*rho/mu\n    if muw is not None:\n        NuSL = (0.03*Res**0.75*Pr)/(1 + 1.74*(Pr-1)/Res**0.125)*(mu/muw)**0.14\n    else:\n        NuSL = (0.03*Res**0.75*Pr)/(1 + 1.74*(Pr-1)/Res**0.125)\n    return NuSL*k/dg\n\n\ndef Stein_Schmidt(m: float, Dtank: float, Djacket: float, H: float, Dinlet: float,\n                  rho: float, Cp: float, k: float, mu: float, muw: float | None=None, rhow: float | None=None,\n                  inlettype: str=\"tangential\", inletlocation: str=\"auto\", roughness: float=0.0) -> float:\n    r\"\"\"Calculates average heat transfer coefficient for a jacket around a\n    vessel according to [1]_ as described in [2]_.\n\n    .. math::\n        l_{ch} = \\left[\\left(\\frac{\\pi}{2}\\right)^2 D_{tank}^2+H^2\\right]^{0.5}\n\n    .. math::\n        d_{ch} = 2\\delta\n\n    .. math::\n        Re_j = \\frac{v_{ch}d_{ch}\\rho}{\\mu}\n\n    .. math::\n        Gr_J = \\frac{g\\rho(\\rho-\\rho_w)d_{ch}^3}{\\mu^2}\n\n    .. math::\n        Re_{J,eq} = \\left[Re_J^2\\pm \\left(\\frac{|Gr_J|\\frac{H}{d_{ch}}}{50}\n        \\right)\\right]^{0.5}\n\n    .. math::\n        Nu_J = (Nu_A^3 + Nu_B^3 + Nu_C^3 + Nu_D^3)^{1/3}\\left(\\frac{\\mu}\n        {\\mu_w}\\right)^{0.14}\n\n    .. math::\n        Nu_J = \\frac{h d_{ch}}{k}\n\n    .. math::\n        Nu_A = 3.66\n\n    .. math::\n        Nu_B = 1.62 Pr^{1/3}Re_{J,eq}^{1/3}\\left(\\frac{d_{ch}}{l_{ch}}\n        \\right)^{1/3}\n\n    .. math::\n        Nu_C = 0.664Pr^{1/3}(Re_{J,eq}\\frac{d_{ch}}{l_{ch}})^{0.5}\n\n    .. math::\n        \\text{if } Re_{J,eq} < 2300: Nu_D = 0\n\n    .. math::\n        Nu_D = 0.0115Pr^{1/3}Re_{J,eq}^{0.9}\\left(1 - \\left(\\frac{2300}\n        {Re_{J,eq}}\\right)^{2.5}\\right)\\left(1 + \\left(\\frac{d_{ch}}{l_{ch}}\n        \\right)^{2/3}\\right)\n\n\n    For Radial inlets:\n\n    .. math::\n        v_{ch} = v_{Mit}\\left(\\frac{\\ln\\frac{b_{Mit}}{b_{Ein}}}{1 -\n        \\frac{b_{Ein}}{b_{Mit}}}\\right)\n\n    .. math::\n        b_{Ein} = \\frac{\\pi}{8}\\frac{D_{inlet}^2}{\\delta}\n\n    .. math::\n        b_{Mit} = \\frac{\\pi}{2}D_{tank}\\sqrt{1 + \\frac{\\pi^2}{4}\\frac\n        {D_{tank}^2}{H^2}}\n\n    .. math::\n        v_{Mit} = \\frac{Q}{2\\delta b_{Mit}}\n\n    For Tangential inlets:\n\n    .. math::\n        v_{ch} = (v_x^2 + v_z^2)^{0.5}\n\n    .. math::\n        v_x = v_{inlet}\\left(\\frac{\\ln[1 + \\frac{f_d D_{tank}H}{D_{inlet}^2}\n        \\frac{v_x(0)}{v_{inlet}}]}{\\frac{f_d D_{tank}H}{D_{inlet}^2}}\\right)\n\n    .. math::\n        v_x(0) = K_3 + (K_3^2 + K_4)^{0.5}\n\n    .. math::\n        K_3 = \\frac{v_{inlet}}{4} -\\frac{D_{inlet}^2v_{inlet}}{4f_d D_{tank}H}\n\n    .. math::\n        K_4 = \\frac{D_{inlet}^2v_{inlet}^2}{2f_d D_{tank} H}\n\n    .. math::\n        v_z = \\frac{Q}{\\pi D_{tank}\\delta}\n\n    .. math::\n        v_{inlet} = \\frac{Q}{\\frac{\\pi}{4}D_{inlet}^2}\n\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate of fluid, [kg/m^3]\n    Dtank : float\n        Outer diameter of tank or vessel surrounded by jacket, [m]\n    Djacket : float\n        Inner diameter of jacket surrounding a vessel or tank, [m]\n    H : float\n        Height of the vessel or tank, [m]\n    Dinlet : float\n        Inner diameter of inlet into the jacket, [m]\n    rho : float\n        Density of the fluid at Tm [kg/m^3]\n    Cp : float\n        Heat capacity of fluid at Tm [J/kg/K]\n    k : float\n        Thermal conductivity of fluid at Tm [W/m/K]\n    mu : float\n        Viscosity of fluid at Tm [Pa*s]\n    muw : float, optional\n        Viscosity of fluid at Tw [Pa*s]\n    rhow : float, optional\n        Density of the fluid at Tw [kg/m^3]\n    inlettype : str, optional\n        Either 'tangential' or 'radial'\n    inletlocation : str, optional\n        Either 'top' or 'bottom' or 'auto'\n    roughness : float, optional\n        Roughness of the tank walls [m]\n\n    Returns\n    -------\n    h : float\n        Average  transfer coefficient inside the jacket [W/m^2/K]\n\n    Notes\n    -----\n    [1]_ is in German and has not been reviewed. Multiple other formulations\n    are considered in [1]_.\n\n    If the fluid is heated and enters from the bottom, natural convection\n    assists the heat transfer and the Grashof term is added; if it were to enter\n    from the top, it would be subtracted. The situation is reversed if entry\n    is from the top.\n\n    Examples\n    --------\n    Example as in [2]_, matches in all but friction factor:\n\n    >>> Stein_Schmidt(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025,\n    ... rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, rhow=971.8)\n    5695.2041698088615\n\n    References\n    ----------\n    .. [1] Stein, Prof Dr-Ing Werner Alexander, and Dipl-Ing (FH) Wolfgang\n       Schmidt. \"Wärmeübergang auf der Wärmeträgerseite eines Rührbehälters mit\n       einem einfachen Mantel.\" Forschung im Ingenieurwesen 59, no. 5\n       (May 1993): 73-90. doi:10.1007/BF02561203.\n    .. [2] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    delta = (Djacket-Dtank)/2.\n    Q = m/rho\n    Pr = Cp*mu/k\n    lch = (pi**2/4*Dtank**2 + H**2)**0.5\n    dch = 2*delta\n    if inlettype == \"radial\":\n        bEin = pi/8*Dinlet**2/delta\n        bMit = pi/2*Dtank*(1 + pi**2/4*Dtank**2/H**2)**0.5\n        vMit = Q/(2*delta*bMit)\n        vch = vMit*log(bMit/bEin)/(1 - bEin/bMit)\n        ReJ = vch*dch*rho/mu\n    elif inlettype == \"tangential\":\n        f = friction_factor(1E5, roughness/dch)\n        for run in range(5):\n            vinlet = Q/(pi/4*Dinlet**2)\n            vz = Q/(pi*Dtank*delta)\n            K4 = Dinlet**2*vinlet**2/(2*f*Dtank*H)\n            K3 = vinlet/4. - Dinlet**2*vinlet/(4*f*Dtank*H)\n            vx0 = K3 + (K3**2 + K4)**0.5\n            vx = vinlet*log(1 + f*Dtank*H/Dinlet**2*vx0/vinlet)/(f*Dtank*H/Dinlet**2)\n            vch = (vx**2 + vz**2)**0.5\n            ReJ = vch*dch*rho/mu\n            f = friction_factor(ReJ, roughness/dch)\n    if inletlocation and rhow:\n        GrJ = g*rho*(rho-rhow)*dch**3/mu**2\n        if rhow < rho: # Heating jacket fluid\n            if inletlocation in (\"auto\", \"bottom\"):\n                ReJeq = (ReJ**2 + GrJ*H/dch/50.)**0.5\n            else:\n                ReJeq = (ReJ**2 - GrJ*H/dch/50.)**0.5\n        else: # Cooling jacket fluid\n            if inletlocation in (\"auto\", \"top\"):\n                ReJeq = (ReJ**2 + GrJ*H/dch/50.)**0.5\n            else:\n                ReJeq = (ReJ**2 - GrJ*H/dch/50.)**0.5\n    else:\n        ReJeq = (ReJ**2)**0.5\n    NuA = 3.66\n    NuB = 1.62*Pr**(1/3.)*ReJeq**(1/3.)*(dch/lch)**(1/3.)\n    NuC = 0.664*Pr**(1/3.)*(ReJeq*dch/lch)**0.5\n    if ReJeq < 2300:\n        NuD = 0\n    else:\n        NuD = 0.0115*Pr**(1/3.)*ReJeq**0.9*(1 - (2300./ReJeq)**2.5)*(1 + (dch/lch)**(2/3.))\n    if muw:\n        NuJ = (NuA**3 + NuB**3 + NuC**3 + NuD**3)**(1/3.)*(mu/muw)**0.14\n    else:\n        NuJ = (NuA**3 + NuB**3 + NuC**3 + NuD**3)**(1/3.)\n    return NuJ*k/dch\n"
  },
  {
    "path": "ht/conv_packed_bed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\n__all__: list[str] = [\n    \"Nu_Achenbach\",\n    \"Nu_KTA\",\n    \"Nu_Wakao_Kagei\",\n    \"Nu_packed_bed_Gnielinski\",\n]\n\ndef Nu_packed_bed_Gnielinski(dp: float, voidage: float, vs: float, rho: float, mu: float, Pr: float, fa: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number of a fluid passing over a bed of particles\n    using a correlation shown in [3]_ and cited as from [1]_ and [2]_. Likely\n    the best available model as the author of [1]_ is the same as [2]_ and\n    [3]_.\n\n    .. math::\n        Nu = f_a Nu_{sphere}\n\n    .. math::\n        Nu_{sphere} = 2 + \\sqrt{Nu_{m,lam}^2 + Nu_{m,turb}^2}\n\n    .. math::\n        Nu_{m,lam} = 0.664Re^{0.5} Pr^{1/3}\n\n    .. math::\n        Nu_{m,turb} = \\frac{0.037Re^{0.8} Pr}{1 + 2.443Re^{-0.1}(Pr^{2/3} -1)}\n\n    .. math::\n        Re = \\frac{\\rho v_s d_p}{\\mu \\epsilon}\n\n    Parameters\n    ----------\n    dp : float\n        Equivalent spherical particle diameter of packing [m]\n    voidage : float\n        Void fraction of bed packing [-]\n    vs : float\n        Superficial velocity of the fluid [m/s]\n    rho : float\n        Density of the fluid [kg/m^3]\n    mu : float\n        Viscosity of the fluid, [Pa*s]\n    Pr : float\n        Prandtl number of the fluid []\n    fa : float, optional\n        Fator increasing heat transfer []\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number for heat transfer to the packed bed [-]\n\n    Notes\n    -----\n    `fa` is a factor relating how much more heat transfer happens than would\n    normally, around one sphere. For spheres of the same size,\n    :math:`f_a = 1 + 1.5(1-\\epsilon)`. For cylinders with l/d ratio of\n    0.24 < l/d < 1.2 use fa = 1.6. For cubes, use fa = 1.6 For Raschig rings,\n    use `fa` = 2.1 For Berl saddles, use `fa` = 2.3. fa is calculated with\n    the relationship for spheres if not provided.\n\n    Confirmed with experimental data for a range of :math:`1E-1 < Re <1,000`\n    and :math:`0.4 < Pr < 1000` for spheres. Limits are smaller for other\n    shapes.\n\n    Examples\n    --------\n    >>> Nu_packed_bed_Gnielinski(dp=8E-4, voidage=0.4, vs=1, rho=1E3, mu=1E-3, Pr=0.7)\n    61.37823202546954\n\n    References\n    ----------\n    .. [1] Gnielinski, V. (1981) \"Equations for the calculation of heat and\n       mass transfer during flow through stationary spherical packings at\n       moderate and high Peclet numbers\". International Chemical Engineering\n       21 (3): 378-383\n    .. [2] Gnielinski, V. (1982) \"Berechnung des Warmeund Stoffaustauschs in\n       durchstomten ruhenden Schuttungen\". Verfahrenstechnik 16(1): 36-39\n    .. [3] Gnielinski, V. in G esellschaft, V. D. I., ed. VDI Heat Atlas.\n       2nd ed. 2010 edition. Berlin; New York: Springer, 2010.\n    \"\"\"\n    Re = rho*vs*dp/mu/voidage\n    Nu_lam = 0.664*Re**0.5*Pr**(1/3.)\n    Nu_turb = 0.037*Re**0.8*Pr/(1 + 2.443*Re**-0.1*(Pr**(2/3.)-1))\n    Nu_sphere = 2 + (Nu_lam**2 + Nu_turb**2)**0.5\n    if fa is None:\n        fa = 1.0 + 1.5*(1.0 - voidage)\n    return fa*Nu_sphere\n\n\ndef Nu_Wakao_Kagei(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates Nusselt number of a fluid passing over a bed of particles\n    using a correlation shown in [1]_ and also cited in the review of [2]_.\n    Relatively rough, as it has no dependence on voidage.\n\n    .. math::\n        Nu = 2 + 1.1Pr^{1/3}Re^{0.6}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with pebble diameter as characteristic dimension, [-]\n    Pr : float\n        Prandtl number of the fluid []\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number for heat transfer to the packed bed [-]\n\n    Notes\n    -----\n    Fit for Re from 3 to 3000; claimed reasonableness of fit to to 1E6.\n\n    Examples\n    --------\n    >>> Nu_Wakao_Kagei(2000, 0.7)\n    95.40641328041248\n\n    References\n    ----------\n    .. [1] Wakao, Noriaki, and Seiichirō Kagei. Heat and Mass Transfer in\n       Packed Beds. Taylor & Francis, 1982.\n    .. [2] Abdulmohsin, Rahman S., and Muthanna H. Al-Dahhan. \"Characteristics\n       of Convective Heat Transport in a Packed Pebble-Bed Reactor.\" Nuclear\n       Engineering and Design 284 (April 1, 2015): 143-52.\n       doi:10.1016/j.nucengdes.2014.11.041.\n    \"\"\"\n    return 2 + 1.1*Pr**(1/3.)*Re**0.6\n\n\ndef Nu_Achenbach(Re: float, Pr: float, voidage: float) -> float:\n    r\"\"\"Calculates Nusselt number of a fluid passing over a bed of particles\n    using a correlation shown in [1]_ and also cited in the review of [2]_.\n\n    .. math::\n        Nu = [(1.18Re^{0.58})^4 + (0.23\\left(\\frac{Re}{1-\\epsilon}\n        \\right)^{0.75})^4]^{0.25}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with pebble diameter as characteristic dimension, [-]\n    Pr : float\n        Prandtl number of the fluid []\n    voidage : float\n        Void fraction of bed packing [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number for heat transfer to the packed bed [-]\n\n    Notes\n    -----\n    Claimed value for Re/ε < 7.7E5\n    Developed with tests performed in a wind tunnel at conditions up to 30 bar.\n\n    Examples\n    --------\n    >>> Nu_Achenbach(2000, 0.7, 0.4)\n    117.70343608599121\n\n    References\n    ----------\n    .. [1] Achenbach, E. \"Heat and Flow Characteristics of Packed Beds.\"\n       Experimental Thermal and Fluid Science 10, no. 1 (January 1, 1995):\n       17-27. doi:10.1016/0894-1777(94)00077-L.\n    .. [2] Abdulmohsin, Rahman S., and Muthanna H. Al-Dahhan. \"Characteristics\n       of Convective Heat Transport in a Packed Pebble-Bed Reactor.\" Nuclear\n       Engineering and Design 284 (April 1, 2015): 143-52.\n       doi:10.1016/j.nucengdes.2014.11.041.\n    \"\"\"\n    return ((1.18*Re**0.58)**4 + (0.23*(Re/(1-voidage))**0.75)**4)**0.25\n\n\ndef Nu_KTA(Re: float, Pr: float, voidage: float) -> float:\n    r\"\"\"Calculates Nusselt number of a fluid passing over a bed of particles\n    using a correlation shown in [1]_ and also cited in the review of [2]_.\n\n    .. math::\n        Nu = 1.27\\frac{Pr^{1/3}}{\\epsilon^{1.18}}Re^{0.36}\n        + 0.033\\frac{Pr^{0.5}}{\\epsilon^{1.07}}Re^{0.86}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with pebble diameter as characteristic dimension, [-]\n    Pr : float\n        Prandtl number of the fluid [-]\n    voidage : float\n        Void fraction of bed packing [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number for heat transfer to the packed bed [-]\n\n    Notes\n    -----\n    100 < Re < 1E5;\n    0.36 < ε < 0.42;\n    D/d > 20 with D as bed diameter, d as particle diameter;\n    H > 4d with H as bed height.\n\n    Examples\n    --------\n    >>> Nu_KTA(2000, 0.7, 0.4)\n    102.08516480718129\n\n    References\n    ----------\n    .. [1] Reactor Core Design of High-Temperature Gas-Cooled Reactors Part 2:\n       Heat Transfer in Spherical Fuel Elements (June 1983).\n       http://www.kta-gs.de/e/standards/3100/3102_2_engl_1983_06.pdf\n    .. [2] Abdulmohsin, Rahman S., and Muthanna H. Al-Dahhan. \"Characteristics\n       of Convective Heat Transport in a Packed Pebble-Bed Reactor.\" Nuclear\n       Engineering and Design 284 (April 1, 2015): 143-52.\n       doi:10.1016/j.nucengdes.2014.11.041.\n    \"\"\"\n    return (1.27*Pr**(1/3.)*Re**0.36/voidage**1.18\n            + 0.033*Pr**0.5/voidage**1.07*Re**0.86)\n"
  },
  {
    "path": "ht/conv_plate.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2018, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import pi, radians, sin\n\nfrom fluids.friction import Kumar_beta_list, friction_plate_Martin_1999, friction_plate_Martin_VDI\n\n__all__: list[str] = [\n    \"Nu_plate_Khan_Khan\",\n    \"Nu_plate_Kumar\",\n    \"Nu_plate_Martin\",\n    \"Nu_plate_Muley_Manglik\",\n]\n\n\nKumar_ms = [[0.349, 0.663, 0.663],\n      [0.349, 0.598, 0.663],\n      [0.333, 0.591, 0.732],\n      [0.326, 0.529, 0.703],\n      [0.326, 0.503, 0.718]]\n\nKumar_C1s = [[0.718, 0.348, 0.348],\n       [0.718, 0.400, 0.300],\n       [0.630, 0.291, 0.130],\n       [0.562, 0.306, 0.108],\n       [0.562, 0.331, 0.087]]\n\nKumar_Nu_Res = [[10.0, 10.0],\n          [10.0, 100.0],\n          [20.0, 300.0],\n          [20.0, 400.0],\n          [20.0, 500.0]]\n\n\ndef Nu_plate_Kumar(Re: float, Pr: float, chevron_angle: float, mu: float | None=None, mu_wall: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for single-phase flow in a\n    **well-designed** Chevron-style plate heat exchanger according to [1]_.\n    The data is believed to have been developed by APV International Limited,\n    since acquired by SPX Corporation. This uses a curve fit of that data\n    published in [2]_.\n\n    .. math::\n        Nu = C_1 Re^m Pr^{0.33}\\left(\\frac{\\mu}{\\mu_{wall}}\\right)^{0.17}\n\n    `C1` and `m` are coefficients looked up in a table, with varying ranges\n    of Re validity and chevron angle validity. See the source for their\n    exact values. The wall fluid property correction is included only if the\n    viscosity values are provided.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to the hydraulic diameter of the channels,\n        [-]\n    Pr : float\n        Prandtl number calculated with bulk fluid properties, [-]\n    chevron_angle : float\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. Many plate exchangers use two alternating patterns; use their\n        average angle for that situation [degrees]\n    mu : float, optional\n        Viscosity of the fluid at the bulk (inlet and outlet average)\n        temperature, [Pa*s]\n    mu_wall : float, optional\n        Viscosity of fluid at wall temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Dh`, [-]\n\n    Notes\n    -----\n    Data on graph from Re=0.1 to Re=10000, with chevron angles 30 to 65 degrees.\n    See `PlateExchanger` for further clarification on the definitions.\n\n    It is believed the constants used in this correlation were curve-fit to\n    the actual graph in [1]_ by the author of [2]_ as there is no\n\n    As the coefficients change, there are numerous small discontinuities,\n    although the data on the graphs is continuous with sharp transitions\n    of the slope.\n\n    The author of [1]_ states clearly this correlation is \"applicable only to\n    well designed Chevron PHEs\".\n\n    Examples\n    --------\n    >>> Nu_plate_Kumar(Re=2000, Pr=0.7, chevron_angle=30)\n    47.757818892853955\n\n    With the wall-correction factor included:\n\n    >>> Nu_plate_Kumar(Re=2000, Pr=0.7, chevron_angle=30, mu=1E-3, mu_wall=8E-4)\n    49.604284135097544\n\n    References\n    ----------\n    .. [1] Kumar, H. \"The plate heat exchanger: construction and design.\" In\n       First U.K. National Conference on Heat Transfer: Held at the University\n       of Leeds, 3-5 July 1984, Institute of Chemical Engineering Symposium\n       Series, vol. 86, pp. 1275-1288. 1984.\n    .. [2] Ayub, Zahid H. \"Plate Heat Exchanger Literature Survey and New Heat\n       Transfer and Pressure Drop Correlations for Refrigerant Evaporators.\"\n       Heat Transfer Engineering 24, no. 5 (September 1, 2003): 3-16.\n       doi:10.1080/01457630304056.\n    \"\"\"\n    # Uses the standard diameter as characteristic diameter\n    beta_list_len = len(Kumar_beta_list)\n\n    for i in range(beta_list_len):\n        if chevron_angle <= Kumar_beta_list[i]:\n            C1_options, m_options, Re_ranges = Kumar_C1s[i], Kumar_ms[i], Kumar_Nu_Res[i]\n            break\n        elif i == beta_list_len-1:\n            C1_options, m_options, Re_ranges = Kumar_C1s[-1], Kumar_ms[-1], Kumar_Nu_Res[-1]\n\n    Re_len = len(Re_ranges)\n\n    for j in range(Re_len):\n        if Re <= Re_ranges[j]:\n            C1, m = C1_options[j], m_options[j]\n            break\n        elif j == Re_len-1:\n            C1, m = C1_options[-1], m_options[-1]\n\n    Nu = C1*Re**m*Pr**0.33\n    if mu_wall is not None and mu is not None:\n        Nu *= (mu/mu_wall)**0.17\n    return Nu\n\n\ndef Nu_plate_Martin(Re: float, Pr: float, chevron_angle: float, variant: str=\"1999\") -> float:\n    r\"\"\"Calculates Nusselt number for single-phase flow in a\n    Chevron-style plate heat exchanger according to [1]_, also shown in [2]_\n    and [3]_.\n\n    .. math::\n        Nu = 0.122 Pr^{1/3} \\left[f_d Re^2 \\sin (2\\phi)\\right]^{0.374}\n\n    The Darcy friction factor should be calculated with the Martin (1999)\n    friction factor correlation, as that is what the power of 0.374 was\n    regressed with. It can be altered to a later formulation by Martin in the\n    VDI Heat Atlas 2E, which increases the calculated heat transfer friction\n    slightly.\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to the hydraulic diameter of the channels,\n        [-]\n    Pr : float\n        Prandtl number calculated with bulk fluid properties, [-]\n    chevron_angle : float\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. Many plate exchangers use two alternating patterns; use their\n        average angle for that situation [degrees]\n    variant : str\n        One of '1999' or 'VDI'; chooses between the two Martin friction\n        factor correlations, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Dh`, [-]\n\n    Notes\n    -----\n    Based on experimental data from Re from 200 - 10000 and enhancement\n    factors calculated with chevron angles of 0 to 80 degrees. See\n    `PlateExchanger` for further clarification on the definitions.\n\n    Note there is a discontinuity at Re = 2000 for the transition from\n    laminar to turbulent flow, arising from the friction factor correlation's\n    transition ONLY, although the literature suggests the transition\n    is actually smooth.\n\n    A viscosity correction power for liquid flows of (1/6) is suggested, and\n    for gases, no correction factor.\n\n    Examples\n    --------\n    >>> Nu_plate_Martin(Re=2000.0, Pr=.7, chevron_angle=45.0)\n    30.427601053757\n\n    References\n    ----------\n    .. [1] Martin, Holger. \"A Theoretical Approach to Predict the Performance\n       of Chevron-Type Plate Heat Exchangers.\" Chemical Engineering and\n       Processing: Process Intensification 35, no. 4 (January 1, 1996): 301-10.\n       https://doi.org/10.1016/0255-2701(95)04129-X.\n    .. [2] Martin, Holger. \"Economic optimization of compact heat exchangers.\"\n       EF-Conference on Compact Heat Exchangers and Enhancement Technology for\n       the Process Industries, Banff, Canada, July 18-23, 1999, 1999.\n       https://publikationen.bibliothek.kit.edu/1000034866.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if variant == \"1999\":\n        fd = friction_plate_Martin_1999(Re, chevron_angle)\n    elif variant == \"VDI\":\n        fd = friction_plate_Martin_VDI(Re, chevron_angle)\n    else:\n        raise ValueError(\"Supported friction factor correlations are Martin's\"\n                        \" '1999' correlation or his 'VDI' correlation only\")\n\n    # VDI, original, and Björn Palm and Joachim Claesson recommend 0.122 leading coeff\n    # The 0.205 in some publications is what happens when the friction factor\n    # is in a fanning basis; = 4^0.374*1.22 = 2.048944\n    Nu = 0.122*Pr**(1/3.)*(fd*Re*Re*sin(2.0*radians(chevron_angle)))**0.374\n    return Nu\n\n\ndef Nu_plate_Muley_Manglik(Re: float, Pr: float, chevron_angle: float, plate_enlargement_factor: float) -> float:\n    r\"\"\"Calculates Nusselt number for single-phase flow in a\n    Chevron-style plate heat exchanger according to [1]_, also shown in [2]_.\n\n    .. math::\n        Nu = [0.2668 - 0.006967(\\beta) + 7.244\\times 10^{-5}(\\beta)^2]\n        \\times[20.7803 - 50.9372\\phi + 41.1585\\phi^2 - 10.1507\\phi^3]\n        \\times Re^{[0.728 + 0.0543\\sin[(2\\pi\\beta/90) + 3.7]]} Pr^{1/3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to the hydraulic diameter of the channels,\n        [-]\n    Pr : float\n        Prandtl number calculated with bulk fluid properties, [-]\n    chevron_angle : float\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. Many plate exchangers use two alternating patterns; use their\n        average angle for that situation [degrees]\n    plate_enlargement_factor : float\n        The extra surface area multiplier as compared to a flat plate\n        caused the corrugations, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Dh`, [-]\n\n    Notes\n    -----\n    The correlation as presented in [1]_ suffers from a typo, with a\n    coefficient of 10.51 instead of 10.15. Several more decimal places were\n    published along with the corrected typo in [2]_. This has a *very large*\n    difference if not implemented.\n\n    The viscosity correction power is recommended to be the blanket\n    Sieder and Tate (1936) value of 0.14.\n\n    The correlation is recommended in the range of Reynolds numbers above\n    1000, chevron angles between 30 and 60 degrees, and enlargement factors\n    from 1 to 1.5. Due to its cubic nature it is not likely to give good\n    results if the chevron angle or enlargement factors are out of those\n    ranges.\n\n    Examples\n    --------\n    >>> Nu_plate_Muley_Manglik(Re=2000, Pr=.7, chevron_angle=45,\n    ... plate_enlargement_factor=1.18)\n    36.49087100602062\n\n    References\n    ----------\n    .. [1] Muley, A., and R. M. Manglik. \"Experimental Study of Turbulent Flow\n       Heat Transfer and Pressure Drop in a Plate Heat Exchanger With Chevron\n       Plates.\" Journal of Heat Transfer 121, no. 1 (February 1, 1999): 110-17.\n       doi:10.1115/1.2825923.\n    .. [2] Palm, Björn, and Joachim Claesson. \"Plate Heat Exchangers:\n       Calculation Methods for Single- and Two-Phase Flow (Keynote),\" January\n       1, 2005, 103-13. https://doi.org/10.1115/ICMM2005-75092.\n    \"\"\"\n    beta, phi = chevron_angle, plate_enlargement_factor\n    t1 = (0.2668 - 0.006967*beta + 7.244E-5*beta**2)\n    #t2 = (20.78 - 50.94*phi + 41.16*phi**2 - 10.51*phi**3)\n    # It was the extra decimals which were needed\n    t2 = (20.7803 - 50.9372*phi + 41.1585*phi**2 - 10.1507*phi**3)\n    t3 = (0.728 + 0.0543*sin((2*pi*beta/90) + 3.7))\n    return t1*t2*Re**t3*Pr**(1/3.)\n\n\ndef Nu_plate_Khan_Khan(Re: float, Pr: float, chevron_angle: float) -> float:\n    r\"\"\"Calculates Nusselt number for single-phase flow in a\n    Chevron-style plate heat exchanger according to [1]_.\n\n    .. math::\n        Nu = \\left(0.0161\\frac{\\beta}{\\beta_{max}} + 0.1298\\right)\n        Re^{\\left(0.198 \\frac{\\beta}{\\beta_{max}} + 0.6398\\right)}\n        Pr^{0.35}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to the hydraulic diameter of the channels,\n        [-]\n    Pr : float\n        Prandtl number calculated with bulk fluid properties, [-]\n    chevron_angle : float\n        Angle of the plate corrugations with respect to the vertical axis\n        (the direction of flow if the plates were straight), between 0 and\n        90. Many plate exchangers use two alternating patterns; use their\n        average angle for that situation [degrees]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to `Dh`, [-]\n\n    Notes\n    -----\n    The viscosity correction power is recommended to be the blanket\n    Sieder and Tate (1936) value of 0.14.\n\n    The correlation is recommended in the range of Reynolds numbers from\n    500 to 2500, chevron angles between 30 and 60 degrees, and Prandtl\n    numbers between 3.5 and 6.\n\n    Examples\n    --------\n    >>> Nu_plate_Khan_Khan(Re=1000, Pr=4.5, chevron_angle=30)\n    38.40883639103741\n\n    References\n    ----------\n    .. [1] Khan, T. S., M. S. Khan, Ming-C. Chyu, and Z. H. Ayub. \"Experimental\n       Investigation of Single Phase Convective Heat Transfer Coefficient in a\n       Corrugated Plate Heat Exchanger for Multiple Plate Configurations.\"\n       Applied Thermal Engineering 30, no. 8 (June 1, 2010): 1058-65.\n       https://doi.org/10.1016/j.applthermaleng.2010.01.021.\n    \"\"\"\n    beta_max = 60.\n    beta_ratio = chevron_angle/beta_max\n    Nu = (0.0161*beta_ratio + 0.1298)*Re**(0.198*beta_ratio + 0.6398)*Pr**0.35\n    return Nu\n\n"
  },
  {
    "path": "ht/conv_supercritical.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import log10\n\n__all__: list[str] = [\n    \"Nu_Bishop\",\n    \"Nu_Bringer_Smith\",\n    \"Nu_Gorban\",\n    \"Nu_Griem\",\n    \"Nu_Gupta\",\n    \"Nu_Jackson\",\n    \"Nu_Kitoh\",\n    \"Nu_Krasnoshchekov\",\n    \"Nu_Krasnoshchekov_Protopopov\",\n    \"Nu_McAdams\",\n    \"Nu_Mokry\",\n    \"Nu_Ornatsky\",\n    \"Nu_Petukhov\",\n    \"Nu_Shitsman\",\n    \"Nu_Swenson\",\n    \"Nu_Xu\",\n    \"Nu_Yamagata\",\n    \"Nu_Zhu\",\n]\n\n### Vertical upflow only\n\ndef Nu_McAdams(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    Found in [2]_ to fit the enhanced heat transfer regime with a MAD of 10.3%\n    which was better than and of the other reviewed correlations.\n\n    .. math::\n        Nu_b = 0.0243Re_b^{0.8}Pr_b^{0.4}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    This has also been one of the forms of the Dittus-Boelter correlations.\n    Claimed to fit data for high pressures and low heat fluxes.\n\n\n    Examples\n    --------\n    >>> Nu_McAdams(1E5, 1.2)\n    261.3838629346147\n\n    References\n    ----------\n    .. [1] Mac Adams, William H. Heat Transmission. New York and London, 1942.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    return 0.0243*Re**0.8*Pr**0.4\n\n\ndef Nu_Shitsman(Re: float, Pr_b: float, Pr_w: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_ and\n    [2] as shown in both [3]_ and [4]_.\n\n    .. math::\n        Nu_b = 0.023 Re_b^{0.8}(min(Pr_b, Pr_w))^{0.8}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr_b : float\n        Prandtl number with bulk fluid properties, [-]\n    Pr_w : float\n        Prandtl number with wall fluid properties, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    [3]_ states this correlation was developed with D = 7.8 and 8.2 mm and with\n    a `Pr` approximately 1. [3]_ ranked it third in the enhanced heat transfer\n    category, with a MAD as 11.5%\n\n    [4]_ cites a [1]_ as the source of the correlation. Neither have been\n    reviewed, and both are in Russian. [4]_ lists this as third most accurate\n    of the 14 correlations reviewed from a database of all regimes.\n\n    Examples\n    --------\n    >>> Nu_Shitsman(1E5, 1.2, 1.6)\n    266.1171311047253\n\n    References\n    ----------\n    .. [1] M. E Shitsman, Impairment of the heat transmission at supercritical\n       pressures, High. Temperature, 1963, 1(2): 237-244\n    .. [2] Miropol`skiy ZL, Shitsman ME (1957). Heat transfer to water and\n       steam at variable specific heat. J Tech Phys XXVII(10): 2359-2372\n    .. [3] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [4] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    \"\"\"\n    return 0.023*Re**0.8*min(Pr_b, Pr_w)**0.8\n\n\ndef Nu_Griem(Re: float, Pr: float, H: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_,\n    also shown in [2]_, [3]_ and [4]_. Has complicated rules regarding where\n    properties should be evaluated.\n\n    .. math::\n        Nu_m = 0.0169Re_b^{0.8356} Pr_{sel}^{0.432}\\omega\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number as explained below, [-]\n    Pr : float\n        Prandtl number as explained below, [-]\n    H : float, optional\n        Enthalpy of water (if the fluid is water), [J/kg]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number as explained below, [-]\n\n    Notes\n    -----\n    w is calculated as follows, for water only, with a reference point from\n    the 1967-IFC formulation. It is set to 1 if H is not provided:\n    if Hb < 1.54E6 J/kg, w = 0.82; if Hb > 1.74E6 J/kg, w = 1; otherwise\n    w = 0.82 + 9E-7*(Hb-1.54E6).\n\n    To determine heat capacity to be used, Cp should be calculated at 5 points,\n    and the lowest three points should be averaged.\n    The five points are: Tw, (Tw+Tf)/2, Tf, (Tb+Tf)/2, Tb.\n\n    Viscosity should be the bulk viscosity.\n    Thermal conductivity should be the average of the bulk and wall values.\n    Density should be the bulk density.\n\n    [2]_ states this correlation was developed with D = 10, 14, and 20 mm,\n    P from 22 to 27 MPa, G from 300 to 2500 kg/m^2/s, and q from\n    200 to 700 kW/m^2. It was ranked 6th among the 14 correlations reviewed for\n    enhanced heat transfer, with a MAD of 13.8%, and 6th overall for the three\n    heat transfer conditions with a overall MAD of 14.8%. [3]_ ranked it 8th\n    of 14 correlations for the three heat transfer conditions.\n\n    [2]_ has an almost complete description of the model; both [3]_ and [4]_\n    simplify it.\n\n    Examples\n    --------\n    >>> Nu_Griem(1E5, 1.2)\n    275.4818576600527\n\n    References\n    ----------\n    .. [1] Griem, H. \"A New Procedure for the Prediction of Forced Convection\n       Heat Transfer at near- and Supercritical Pressure.\" Heat and Mass\n       Transfer 31, no. 5 (1996): 301-5. doi:10.1007/BF02184042.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    if H is not None:\n        if H < 1.54E6:\n            w = 0.82\n        elif H > 1.74E6:\n            w = 1.0\n        else:\n            w = 0.82 + 9E-7*(H - 1.54E6)\n    else:\n        w = 1.0\n    Nu = 0.0169*Re**0.8356*Pr**0.432*w\n    return Nu\n\n\ndef Nu_Jackson(Re: float, Pr: float, rho_w: float | None=None, rho_b: float | None=None, Cp_avg: float | None=None, Cp_b: float | None=None, T_b: int | None=None,\n               T_w: int | None=None, T_pc: int | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = 0.0183 Re_b^{0.82} Pr^{0.5}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.3}\n        \\left(\\frac{\\bar C_p}{C_{p,b}}\\right)^n\n\n    .. math::\n        n = 0.4 \\text{ for } T_b < T_w < T_{pc} \\text{ or } 1.2T_{pc} < T_b < T_w\n\n    .. math::\n        n = 0.4 + 0.2(T_w/T_{pc} - 1)[1 - 5(T_b/T_{pc}-1)]\n        \\text{ for } T_{pc} < T_b < 1.2T_{pc} \\text{ and } T_b < T_w\n\n    .. math::\n        n = 0.4 + 0.2(T_w/T_{pc} - 1) \\text{ for } T_b < T_{pc} < T_w\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    Cp_avg : float, optional\n        Average heat capacity between the wall and bulk temperatures, [J/kg/K]\n    Cp_b : float, optional\n        Heat capacity at the bulk temperature, [J/kg/K]\n    T_b : float\n        Bulk temperature, [K]\n    T_w : float\n        Wall temperature, [K]\n    T_pc : float\n        Pseudocritical temperature, i.e. temperature at P where Cp is at a\n        maximum, [K]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    The range of examined parameters is as follows:\n    P from 23.4 to 29.3 MPa; G from 700-3600 kg/m^2/s;\n    q from 46 to 2600 kW/m^2; Re from 8E4 to 5E5; D from 1.6 to 20 mm.\n\n    For enhanced heat transfer database in [2]_, this correlation was the\n    second best with a MAD of 11.5%. In the database in [3]_, the correlation\n    was the second best as well.\n\n    This is sometimes called the Jackson-Hall correlation.\n    If the extra information is not provided, the correlation will be used\n    without the corrections.\n\n    Examples\n    --------\n    >>> Nu_Jackson(1E5, 1.2)\n    252.37231572974918\n\n    References\n    ----------\n    .. [1] Jackson, J. D. \"Consideration of the Heat Transfer Properties of\n       Supercritical Pressure Water in Connection with the Cooling of Advanced\n       Nuclear Reactors\", 2002.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    if T_b is not None and T_w is not None and T_pc is not None:\n        if T_b < T_w < T_pc or 1.2*T_pc < T_b < T_w:\n            n = 0.4\n        elif T_b < T_pc < T_w:\n            n = 0.4 + 0.2*(T_w/T_pc - 1)\n        else:\n            n = 0.4 + 0.2*(T_w/T_pc - 1)*(1 - 5*(T_b/T_pc - 1))\n    else:\n        n = 0.4\n    Nu = 0.0183*Re**0.82*Pr**0.5\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.3\n    if Cp_avg is not None and Cp_b is not None:\n        Nu *= (Cp_avg/Cp_b)**n\n    return Nu\n\n\ndef Nu_Gupta(Re: float, Pr: float, rho_w: int | None=None, rho_b: float | None=None, mu_w: float | None=None, mu_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_w = 0.004 Re_w^{0.923} \\bar{Pr}_w^{0.773}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.186}\n        \\left(\\frac{\\mu_w}{\\mu_b}\\right)^{0.366}\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with wall fluid properties, [-]\n    Pr : float\n        Prandtl number with wall fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    mu_w : float, optional\n        Viscosity at the wall temperature, [Pa*s]\n    mu_b : float, optional\n        Viscosity at the bulk temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with wall fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P was set at 24 MPa, and D\n    was 10 mm. G varied from 200-1500 kg/m^2/s and q varied from 0 to 1250\n    kW/m^2.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    For deteriorated heat transfer, this was the most accurate correlation in\n    [2]_ with a MAD of 18.1%.\n\n    If the extra density and viscosity information is not provided, it will\n    not be used.\n\n    Examples\n    --------\n    >>> Nu_Gupta(1E5, 1.2, 330, 290., 8e-4, 9e-4)\n    186.20135477175126\n\n    References\n    ----------\n    .. [1] Gupta, Sahil, Amjad Farah, Krysten King, Sarah Mokry, and Igor\n       Pioro. \"Developing New Heat-Transfer Correlation for SuperCritical-Water\n       Flow in Vertical Bare Tubes,\" January 1, 2010, 809-17.\n       doi:10.1115/ICONE18-30024.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    Nu = 0.004*Re**0.923*Pr**0.773\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.186\n    if mu_w is not None and mu_b is not None:\n        Nu *= (mu_w/mu_b)**0.366\n    return Nu\n\n\n\ndef Nu_Swenson(Re: float, Pr: float, rho_w: int | None=None, rho_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_w = 0.00459 Re_w^{0.923} Pr_w^{0.613}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.231}\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with wall fluid properties, [-]\n    Pr : float\n        Prandtl number with wall fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with wall fluid properties, [-]\n\n    Notes\n    -----\n    The range of examined parameters is as follows:\n    P from 22.8 to 27.6 MPa; G from 542-2150 kg/m^2/s;\n    Re from 7.5E4 to 3.16E6; T_b from 75 to 576 degrees Celsius and T_w from\n    93 to 649 degrees Celsius.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    For deteriorated heat transfer, this was the most accurate correlation in\n    [2]_ with a MAD of 18.4%. On the overall database in [3]_, it was the\n    9th most accurate correlation.\n\n    If the extra density information is not provided, it will not be used.\n\n    Examples\n    --------\n    >>> Nu_Swenson(1E5, 1.2, 330, 290.)\n    217.92827034803668\n\n    References\n    ----------\n    .. [1] Swenson, H. S., J. R. Carver, and C. R. Kakarala. \"Heat Transfer to\n       Supercritical Water in Smooth-Bore Tubes.\" Journal of Heat Transfer 87,\n       no. 4 (November 1, 1965): 477-83. doi:10.1115/1.3689139.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    Nu = 0.00459*Re**0.923*Pr**0.613\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.231\n    return Nu\n\n\ndef Nu_Xu(Re: float, Pr: float, rho_w: int | None=None, rho_b: float | None=None, mu_w: float | None=None, mu_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = 0.02269 Re_b^{0.8079} \\bar{Pr}_b^{0.9213}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.6638}\n        \\left(\\frac{\\mu_w}{\\mu_b}\\right)^{0.8687}\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    mu_w : float, optional\n        Viscosity at the wall temperature, [Pa*s]\n    mu_b : float, optional\n        Viscosity at the bulk temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P varied from 23 to 30 MPa,\n    and D was 12 mm. G varied from 600-1200 kg/m^2/s and q varied from 100 to\n    600 kW/m^2.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    For deteriorated heat transfer, this was the third most accurate\n    correlation in [2]_ with a MAD of 20.5%.\n\n    If the extra density and viscosity information is not provided, it will\n    not be used.\n\n    Examples\n    --------\n    >>> Nu_Xu(1E5, 1.2, 330, 290., 8e-4, 9e-4)\n    289.133054256742\n\n    References\n    ----------\n    .. [1] Xu, F., Guo, L.J., Mao, Y.F., Jiang, X.E., 2005. \"Experimental\n       investigation to the heat transfer characteristics of water in vertical\n       pipes under supercritical pressure\". J. Xi'an Jiaotong University 39,\n       468-471.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    Nu = 0.02269*Re**0.8079*Pr**0.9213\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.6638\n    if mu_w is not None and mu_b is not None:\n        Nu *= (mu_w/mu_b)**0.8687\n    return Nu\n\n\ndef Nu_Mokry(Re: float, Pr: float, rho_w: int | None=None, rho_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_,\n    and reviewed in [2]_.\n\n    .. math::\n        Nu_b = 0.0061 Re_b^{0.904} \\bar{Pr}_b^{0.684}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.564}\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P was set at 20 MPa, and D\n    was 10 mm. G varied from 200-1500 kg/m^2/s and q varied from 0 to 1250\n    kW/m^2.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    For deteriorated heat transfer, this was the four most accurate correlation\n    in [2]_ with a MAD of 24.0%. It was also the 7th most accurate against\n    enhanced heat transfer, with a MAD of 14.7%, and the most accurate for the\n    normal heat transfer database as well as the top correlation in all\n    categories combined.\n\n    If the extra density information is not provided, it will not be used.\n\n    Examples\n    --------\n    >>> Nu_Mokry(1E5, 1.2, 330, 290.)\n    246.1156319156\n\n    References\n    ----------\n    .. [1] Mokry, Sarah, Igor Pioro, Amjad Farah, Krysten King, Sahil Gupta,\n       Wargha Peiman, and Pavel Kirillov. \"Development of Supercritical Water\n       Heat-Transfer Correlation for Vertical Bare Tubes.\" Nuclear Engineering\n       and Design, International Conference on Nuclear Energy for New Europe\n       2009, 241, no. 4 (April 2011): 1126-36.\n       doi:10.1016/j.nucengdes.2010.06.012.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    Nu = 0.0061*Re**0.904*Pr**0.684\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.564\n    return Nu\n\n\ndef Nu_Bringer_Smith(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under near-supercritical conditions according to\n    [1]_ and as shown in [2]_ and [3]_.\n\n    .. math::\n        Nu_x = 0.0266Re_x^{0.77}Pr_w^{0.55}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with fluid properties at T_ref, [-]\n    Pr : float\n        Prandtl number with wall fluid properties, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with fluid properties at T_ref, [-]\n\n    Notes\n    -----\n    Fit to data somewhat distant from the critical and pseudo-critical regions.\n    Found to fit the data in [3]_ fourth best; in [2]_ however, it was ranked\n    so low that no ranking was given.\n\n    Tref and the properties therein should be evaluated as follows:\n\n    .. math::\n        T_{ref} = T_b \\text{ if } \\frac{T_{pc}-T_b}{T_w-T_b} < 0\n\n    .. math::\n        T_{ref} = T_{pc} \\text{ if } 0 < \\frac{T_{pc}-T_b}{T_w-T_b}  < 1\n\n    .. math::\n        T_{ref} = T_w \\text{ if } \\frac{T_{pc}-T_b}{T_w-T_b} > 1\n\n    Examples\n    --------\n    >>> Nu_Bringer_Smith(1E5, 1.2)\n    208.1763175327\n\n    References\n    ----------\n    .. [1] Bringer, R. P., and J. M. Smith. \"Heat Transfer in the Critical\n       Region.\" AIChE Journal 3, no. 1 (March 1, 1957): 49-55.\n       doi:10.1002/aic.690030110.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    \"\"\"\n    return 0.0266*Re**0.77*Pr**0.55\n\n\ndef Nu_Ornatsky(Re: float, Pr_b: float, Pr_w: float, rho_w: int | None=None, rho_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_ as\n    shown in both [2]_ and [3]_.\n\n    .. math::\n        Nu_b = 0.023Re_b^{0.8}(\\min(Pr_b, Pr_w))^{0.8}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.3}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr_b : float\n        Prandtl number with bulk fluid properties, [-]\n    Pr_w : float\n        Prandtl number with wall fluid properties, [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    [2]_ ranked it thirteenth in the enhanced heat transfer\n    category, with a MAD of 19.8% and 11th in the normal heat transfer with a\n    MAD of 17.6%. [3]_ ranked it seventh on a combined database.\n\n    If the extra density information is not provided, it will not be used.\n\n    Examples\n    --------\n    >>> Nu_Ornatsky(1E5, 1.2, 1.5, 330, 290.)\n    276.6353115083\n\n    References\n    ----------\n    .. [1] Ornatsky A.P., Glushchenko, L.P., Siomin, E.T. (1970). The research\n       of temperature conditions of small diameter parallel tubes cooled by\n       water under supercritical pressures. In: Proceedings of the 4th\n       international heat transfer conference, Paris-Versailles, France.\n       Elsevier, Amsterdam, vol VI, Paper no. B, 8 November 1970\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    \"\"\"\n    Nu = 0.023*Re**0.8*min(Pr_b, Pr_w)**0.8\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.3\n    return Nu\n\n\ndef Nu_Gorban(Re: float, Pr: float) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n    Not recommended.\n\n    .. math::\n        Nu_b = 0.0059Re_b^{0.90}Pr_b^{-0.12}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    Reviewed in [2]_ and [3]_; [2]_ did not even rank it, and [3]_ ranked it\n    12th of 14.\n\n    Examples\n    --------\n    >>> Nu_Gorban(1E5, 1.2)\n    182.536728273\n\n    References\n    ----------\n    .. [1] Gorban LM, Pomet`ko RS, Khryaschev OA (1990) Modeling of water heat\n       transfer with Freon of supercritical pressure, 1766, Institute of\n       Physics and Power Engineering, Obninsk\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    \"\"\"\n    return 0.0059*Re**0.90*Pr**-0.12\n\n\ndef Nu_Zhu(Re: float, Pr: float, rho_w: int | None=None, rho_b: float | None=None, k_w: float | None=None, k_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = 0.0068 Re_b^{0.9} \\bar{Pr}_b^{0.63}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.17}\n        \\left(\\frac{k_w}{k_b}\\right)^{0.29}\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    k_w : float, optional\n        Thermal conductivity at the wall temperature, [W/m/K]\n    k_b : float, optional\n        Thermal conductivity at the bulk temperature, [W/m/K]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P varied from 22 to 30 MPa,\n    and D was 26 mm. G varied from 600-1200 kg/m^2/s and q varied from 200 to\n    600 kW/m^2.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    On the overall database in [2]_, this was the 8th most accurate\n    correlation,and ninth most accurate against normal heat transfer.\n\n    If the extra density and thermal conductivity information is not provided,\n    it will not be used.\n\n    Examples\n    --------\n    >>> Nu_Zhu(1E5, 1.2, 330, 290., 0.63, 0.69)\n    240.145985449\n\n    References\n    ----------\n    .. [1] Zhu, Xiaojing, Qincheng Bi, Dong Yang, and Tingkuan Chen. \"An\n       Investigation on Heat Transfer Characteristics of Different Pressure\n       Steam-Water in Vertical Upward Tube.\" Nuclear Engineering and Design\n       239, no. 2 (February 2009): 381-88. doi:10.1016/j.nucengdes.2008.10.026.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    Nu = 0.0068*Re**0.9*Pr**0.63\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.17\n    if k_w is not None and k_b is not None:\n        Nu *= (k_w/k_b)**0.29\n    return Nu\n\n\ndef Nu_Bishop(Re: float, Pr: float, rho_w: float | None=None, rho_b: float | None=None, D: float | None=None, x: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n    Correlation includes an adjustment for the thermal entry length.\n    One of the most common correlations for supercritical convection.\n\n    .. math::\n        Nu_b = 0.0069 Re_b^{0.9} \\bar Pr_b^{0.66}\n        \\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.43}(1+2.4D/x)\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties and an average heat capacity\n        between the wall and bulk temperatures [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    D : float, optional\n        Diameter of tube, [m]\n    x : float, optional\n        Axial distance along the tube, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with wall fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P varied from 22.8 to 27.6\n    MPa, and D was x/D varied from 30-365. G varied from 651-3662 kg/m^2/s and\n    q varied from 310 to 3460 kW/m^2. T_b varied from 282 to 527 degrees\n    Celsius.\n\n    Cp used in the calculation of Prandtl number should be the average value\n    of those at the wall and the bulk temperatures.\n\n    For enhanced heat transfer, this was the 11th most accurate correlation in\n    [2]_ with a MAD of 19.0%. On the overall database in [3]_, it was the\n    most accurate correlation however.\n\n    If the extra density information is not provided, it will not be used.\n    If both diameter and axial distance are not provided, the entrance\n    correction is not used.\n\n    Examples\n    --------\n    >>> Nu_Bishop(1E5, 1.2, 330, 290., .01, 1.2)\n    265.362005007\n\n    References\n    ----------\n    .. [1] Bishop A.A., Sandberg R.O., Tong L.S. (1965) Forced convection heat\n       transfer to water at near-critical temperature and supercritical\n       pressures. In: AIChE J. Chemical engineering symposium series, no. 2.\n       Institute of Chemical Engineers, London\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    Nu = 0.0069*Re**0.9*Pr**0.66\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.43\n    if D is not None and x is not None:\n        Nu *= (1 + 2.4*D/x)\n    return Nu\n\n\ndef Nu_Yamagata(Re: float, Pr: float, Pr_pc: float | None=None, Cp_avg: float | None=None, Cp_b: float | None=None, T_b: int | None=None,\n               T_w: int | None=None, T_pc: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = 0.0138 Re_b^{0.85}Pr_b^{0.8}F\n\n    .. math::\n        F = \\left(\\frac{\\bar C_p}{C_{p,b}}\\right)^{n_2} \\text{ if }\n        \\frac{T_{pc}-T_b}{T_w-T_b} < 0\n\n    .. math::\n        F = 0.67Pr_{pc}^{-0.05} \\left(\\frac{\\bar C_p}{C_{p,b}}\\right)^{n_1}\n        \\text{ if } 0 < \\frac{T_{pc}-T_b}{T_w-T_b}  < 1\n\n    .. math::\n        F = 1\\text{ if } \\frac{T_{pc}-T_b}{T_w-T_b} > 1\n\n    .. math::\n        n_1 = -0.77(1 + 1/Pr_{pc}) + 1.49\n\n    .. math::\n        n_2 = 1.44(1 + 1/Pr_{pc}) - 0.53\n\n    .. math::\n        \\bar{Cp} = \\frac{H_w-H_b}{T_w-T_b}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n    Pr_pc : float, optional\n        Prandtl number at the pseudocritical temperature, [-]\n    Cp_avg : float, optional\n        Average heat capacity between the wall and bulk temperatures, [J/kg/K]\n    Cp_b : float, optional\n        Heat capacity at the bulk temperature, [J/kg/K]\n    T_b : float\n        Bulk temperature, [K]\n    T_w : float\n        Wall temperature, [K]\n    T_pc : float\n        Pseudocritical temperature, i.e. temperature at P where Cp is at a\n        maximum, [K]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P varied from 22.6 to 29.4\n    MPa, and D was 7.5 and 10 mm. G varied from 310-1830 kg/m^2/s, q varied\n    from 116 to 930 kW/m^2, and bulk temperature varied from 230 to 540 decrees\n    Celsius.\n\n    In the database in [3]_, the correlation was considered but not tested.\n    In [2]_, the correlation was considered but no results were reported.\n\n    For enhanced heat transfer database in [2]_, this correlation was the\n    second best with a MAD of 11.5%. In the database in [3]_, the correlation\n    was the second best as well.\n\n    If the extra information is not provided, the correlation will be used\n    without the corrections.\n\n    Examples\n    --------\n    >>> Nu_Yamagata(Re=1E5, Pr=1.2, Pr_pc=1.5, Cp_avg=2080.845, Cp_b=2048.621, T_b=650, T_w=700, T_pc=600.0)\n    292.347342800\n\n    References\n    ----------\n    .. [1] Yamagata, K, K Nishikawa, S Hasegawa, T Fujii, and S Yoshida.\n       \"Forced Convective Heat Transfer to Supercritical Water Flowing in\n       Tubes.\" International Journal of Heat and Mass Transfer 15, no. 12\n       (December 1, 1972): 2575-93. doi:10.1016/0017-9310(72)90148-2.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    F = 1.0\n    if (T_b is not None and T_w is not None and T_pc is not None\n        and Pr_pc is not None and Cp_avg is not None and Cp_b is not None):\n        E = (T_pc - T_b)/(T_w - T_b)\n        if E < 0.0:\n            n2 = 1.44*(1 + 1/Pr_pc) - 0.53\n            F = (Cp_avg/Cp_b)**n2\n        elif E < 1.0:\n            n1 = -0.77*(1 + 1/Pr_pc) + 1.49\n            F = 0.67*Pr_pc**-0.05*(Cp_avg/Cp_b)**n1\n    return 0.0138*Re**0.85*Pr**0.8*F\n\n\ndef Nu_Kitoh(Re: float, Pr: float, H: float | None=None, G: int | None=None, q: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_,\n    also shown in [2]_, [3]_ and [4]_. Depends on fluid enthalpy, mass flux,\n    and heat flux.\n\n    .. math::\n        Nu_b = 0.015Re_b^{0.85} Pr_b^m\n\n    .. math::\n        m = 0.69 - \\frac{81000}{q_{dht}} + f_cq\n\n    .. math::\n        q_{dht} = 200 G^{1.2}\n\n    .. math::\n        f_c = 2.9\\times10^{-8} + \\frac{0.11}{q_{dht}} \\text{ for }\n        H_b < 1500 \\text{ kJ/kg}\n\n    .. math::\n        f_c = -8.7\\times10^{-8} - \\frac{0.65}{q_{dht}} \\text{ for }\n        1500 \\text{ kJ/kg} < H_b < 3300 \\text{ kJ/kg}\n\n    .. math::\n        f_c = -9.7\\times10^{-7} + \\frac{1.3}{q_{dht}} \\text{ for }\n        H_b > 3300 \\text{ kJ/kg}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n    H : float, optional\n        Enthalpy of water (if the fluid is water), [J/kg]\n    G : float, optional\n        Mass flux of the fluid, [kg/m^2/s]\n    q : float, optional\n        Heat flux to wall, [W/m^2]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number as explained below, [-]\n\n    Notes\n    -----\n    The reference point for the enthalpy values is not stated in [1]_. The\n    upper and lower enthalpy limits for this correlation are 4000 kJ/kg and\n    0 kJ/kg, but these are not enforced in this function.\n\n    If not all of H, G, and q are provided, the correlation is used without\n    the correction.\n\n    This correlation was ranked 6th best in [3]_, and found 4th best for\n    enhanced heat transfer in [2]_ with a MAD of 12.3%.\n\n    For the data used to develop the correlation, G varied from 100-1750\n    kg/m^2/s, q varied from 0 to 1800 kW/m^2, and bulk temperature varied from\n    20 to 550 decrees Celsius.\n\n    This correlation does not have realistic behavior for values outside those\n    used in the study, and should not be used.\n\n    Examples\n    --------\n    >>> Nu_Kitoh(1E5, 1.2, 1.3E6, 1500, 5E6)\n    331.8023413959\n\n    References\n    ----------\n    .. [1] Kitoh, Kazuaki, Seiichi Koshizuka, and Yoshiaki Oka. \"Refinement of\n       Transient Criteria and Safety Analysis for a High-Temperature Reactor\n       Cooled by Supercritical Water.\" Nuclear Technology 135, no. 3\n       (September 1, 2001): 252-64.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    if H is not None and G is not None and q is not None:\n        qht = 200.*G**1.2\n        if H < 1.5E6:\n            fc = 2.9E-8 + 0.11/qht\n        elif 1.5E6 <= H <= 3.3E6:\n            fc = -8.7E-8 - 0.65/qht\n        else:\n            fc = -9.7E-7 + 1.3/qht\n        m = 0.69 - 81000./qht + fc*q\n    else:\n        m = 0.69\n    return 0.015*Re**0.85*Pr**m\n\n\ndef Nu_Krasnoshchekov_Protopopov(Re: float, Pr: float, Cp_avg: int | None=None, Cp_b: float | None=None, k_w: float | None=None,\n                                 k_b: float | None=None, mu_w: float | None=None, mu_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = Nu_0\\left(\\frac{\\mu_w}{\\mu_b}\\right)^{0.11}\\left(\\frac{k_b}{k_w}\n        \\right)^{-0.33}\\left(\\frac{\\bar C_p}{C_{p,b}}\\right)^{0.35}\n\n    .. math::\n        Nu_0 = \\frac{(f/8)Re_b \\bar Pr_b}{1.07+12.7(f/8)^{1/2}\n        (\\bar Pr_b)^{2/3}-1)}\n\n    .. math::\n        fd = [1.82\\log_{10}(Re_b) - 1.64]^{-2}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties [-]\n    Cp_avg : float, optional\n        Average heat capacity between the wall and bulk temperatures, [J/kg/K]\n    Cp_b : float, optional\n        Heat capacity at the bulk temperature, [J/kg/K]\n    k_w : float, optional\n        Thermal conductivity at the wall temperature, [W/m/K]\n    k_b : float, optional\n        Thermal conductivity at the bulk temperature, [W/m/K]\n    mu_w : float, optional\n        Viscosity at the wall temperature, [Pa*s]\n    mu_b : float, optional\n        Viscosity at the bulk temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the data used to develop the correlation, P varied from 22.3 to 32 MPa,\n    Re varied from 2E4 to 8.6E6, Pr from 0.86-86, viscosity ration from 0.9 to\n    3.6, thermal conductivity ratio from 1 to 6, and heat capacity ratio from\n    0.07 to 4.5.\n\n    For the heat transfer database in [3]_, this correlation was 14th most\n    accurate.\n\n    If the extra heat capacity, viscosity, and thermal conductivity\n    information is not provided, it will not be used.\n\n    Examples\n    --------\n    >>> Nu_Krasnoshchekov_Protopopov(1E5, 1.2, 330, 290., 0.62, 0.52, 8e-4, 9e-4)\n    228.8529673740\n\n    References\n    ----------\n    .. [1] Krasnoshchekov EA, Protopopov VS (1959) Heat transfer at\n       supercritical region in flow of carbon dioxide and water in tubes.\n       Therm Eng 12:26-30\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    .. [3] Yu, Jiyang, Baoshan Jia, Dan Wu, and Daling Wang. \"Optimization of\n       Heat Transfer Coefficient Correlation at Supercritical Pressure Using\n       Genetic Algorithms.\" Heat and Mass Transfer 45, no. 6 (January 8, 2009):\n       757-66. doi:10.1007/s00231-008-0475-4.\n    .. [4] Jäger, Wadim, Victor Hugo Sánchez Espinoza, and Antonio Hurtado.\n       \"Review and Proposal for Heat Transfer Predictions at Supercritical\n       Water Conditions Using Existing Correlations and Experiments.\" Nuclear\n       Engineering and Design, (W3MDM) University of Leeds International\n       Symposium: What Where When? Multi-dimensional Advances for Industrial\n       Process Monitoring, 241, no. 6 (June 2011): 2184-2203.\n       doi:10.1016/j.nucengdes.2011.03.022.\n    \"\"\"\n    fd = (1.82*log10(Re) - 1.64)**-2\n    Nu = (fd/8.)*Re*Pr/(1.07 + 12.7*(fd/8.)**0.5*(Pr**(2/3.)-1))\n    if mu_w is not None and mu_b is not None:\n        Nu *= (mu_w/mu_b)**0.11\n    if k_w is not None and k_b is not None:\n        Nu *= (k_w/k_b)**-0.33\n    if Cp_avg is not None and Cp_b is not None:\n        Nu *= (Cp_avg/Cp_b)**0.35\n    return Nu\n\n\ndef Nu_Petukhov(Re: float, Pr: float, rho_w: float | None=None, rho_b: float | None=None, mu_w: float | None=None, mu_b: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = \\frac{(f/8)Re_b \\bar Pr_b}{1+900/Re_b+12.7(f/8)^{1/2}\n        (\\bar Pr_b)^{2/3}-1)}\n\n    .. math::\n        f = f_d\\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.4}\n        \\left(\\frac{\\mu_w}{\\mu_b}\\right)^{0.2}\n\n    .. math::\n        f_d = [1.82\\log_{10}(Re_b) - 1.64]^{-2}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    mu_w : float, optional\n        Viscosity at the wall temperature, [Pa*s]\n    mu_b : float, optional\n        Viscosity at the bulk temperature, [Pa*s]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    For the heat transfer database in [2]_, this correlation was 5th most\n    accurate in the enhanced heat transfer category, and second in the normal\n    heat transfer category with MADs of 13.8% and 12.0% respectively.\n\n    If the extra viscosity and density information is not provided, it will not\n    be used.\n\n    Examples\n    --------\n    >>> Nu_Petukhov(1E5, 1.2, 330, 290., 8e-4, 9e-4)\n    254.825859846\n\n    References\n    ----------\n    .. [1] Petukhov, B.S., V.A. Kurganov, and V.B. Ankudinov. \"HEAT TRANSFER\n       AND FLOW RESISTANCE IN THE TURBULENT PIPE FLOW OF A FLUID WITH\n       NEAR-CRITICAL STATE PARAMETERS.\" High Temperature 21, no. 1 (1983):\n       81-89.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    fd = (1.82*log10(Re) - 1.64)**-2\n    if rho_w is not None and rho_b is not None:\n        fd *= (rho_w/rho_b)**0.4\n    if mu_w is not None and mu_b is not None:\n        fd *= (mu_w/mu_b)**0.2\n    return (fd/8.)*Re*Pr/(1 + 900./Re + 12.7*(fd/8.)**0.5*(Pr**(2/3.)-1))\n\n\ndef Nu_Krasnoshchekov(Re: float, Pr: float, rho_w: float | None=None, rho_b: float | None=None, Cp_avg: float | None=None, Cp_b: float | None=None,\n                      T_b: float | None=None, T_w: float | None=None, T_pc: float | None=None) -> float:\n    r\"\"\"Calculates internal convection Nusselt number for turbulent vertical\n    upward flow in a pipe under supercritical conditions according to [1]_.\n\n    .. math::\n        Nu_b = Nu_0\\left(\\frac{\\rho_w}{\\rho_b}\\right)^{0.3}\\left(\n        \\frac{\\bar C_p}{C_{p,b}}\\right)^{n}\n\n    .. math::\n        Nu_0 = \\frac{(f/8)Re_b \\bar Pr_b}{1.07+12.7(f/8)^{1/2}\n        (\\bar Pr_b^{2/3}-1)}\n\n    .. math::\n        f_d = [1.82\\log_{10}(Re_b) - 1.64]^{-2}\n\n    .. math::\n        n = 0.4 \\text{ for } T_b < T_w < T_{pc} \\text{ or }\n        1.2T_{pc} < T_b < T_w\n\n    .. math::\n        n = n_1 = 0.22 + 0.18T_w/T_{pc} \\text{ for } 1 < T_w/T_{pc} < 2.5\n\n    .. math::\n        n = n_1 + (5n_1 - 2)(1 - T_b/T_{pc}) \\text{ for } T_{pc} < T_b <\n        1.2T_{pc} \\text{ and } T_{b} < T_w\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with bulk fluid properties, [-]\n    Pr : float\n        Prandtl number with bulk fluid properties, [-]\n    rho_w : float, optional\n        Density at the wall temperature, [kg/m^3]\n    rho_b : float, optional\n        Density at the bulk temperature, [kg/m^3]\n    Cp_avg : float, optional\n        Average heat capacity between the wall and bulk temperatures, [J/kg/K]\n    Cp_b : float, optional\n        Heat capacity at the bulk temperature, [J/kg/K]\n    T_b : float\n        Bulk temperature, [K]\n    T_w : float\n        Wall temperature, [K]\n    T_pc : float\n        Pseudocritical temperature, i.e. temperature at P where Cp is at a\n        maximum, [K]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with bulk fluid properties, [-]\n\n    Notes\n    -----\n    The range of examined parameters is as follows:\n    P from 23.4 to 29.3 MPa; G from 700-3600 kg/m^2/s;\n    q from 46 to 2600 kW/m^2; Re from 8E4 to 5E5; D from 1.6 to 20 mm.\n\n    If the extra information is not provided, the correlation will be used\n    without the corrections.\n\n    Examples\n    --------\n    >>> Nu_Krasnoshchekov(1E5, 1.2)\n    234.8285518561\n\n    References\n    ----------\n    .. [1] Krasnoshchekov, E.A., Protopopov, V.S., Van Fen, Kuraeva, I.V.,\n       1967. Experimental investigation of heat transfer for carbon dioxide in\n       the supercritical region. In Proceedings of the Second All-Soviet Union\n       Conference on Heat and Mass Transfer, Minsk, Belarus, May.\n    .. [2] Chen, Weiwei, Xiande Fang, Yu Xu, and Xianghui Su. \"An Assessment of\n       Correlations of Forced Convection Heat Transfer to Water at\n       Supercritical Pressure.\" Annals of Nuclear Energy 76 (February 2015):\n       451-60. doi:10.1016/j.anucene.2014.10.027.\n    \"\"\"\n    if T_b is not None and T_w is not None and T_pc is not None:\n        n1 = 0.22 + 0.18*T_w/T_pc\n        if T_b < T_w < T_pc or 1.2*T_pc < T_b < T_w:\n            n = 0.4\n        elif 1.0 < T_w/T_pc < 2.5:\n            n = n1\n        else:\n            n = n1 + (5.0*n1 - 2.0)*(1.0 - T_b/T_pc)\n    else:\n        n = 0.4\n    fd = (1.82*log10(Re) - 1.64)**-2\n    Nu = (fd/8.)*Re*Pr/(1.07 + 12.7*(fd/8.)**0.5*(Pr**(2/3.)-1.0))\n    if rho_w is not None and rho_b is not None:\n        Nu *= (rho_w/rho_b)**0.3\n    if Cp_avg is not None and Cp_b is not None:\n        Nu *= (Cp_avg/Cp_b)**n\n    return Nu\n"
  },
  {
    "path": "ht/conv_tube_bank.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import exp, pi, radians, sin\n\nfrom fluids.numerics import bisplev, horner, implementation_optimize_tck, splev\n\nfrom ht.core import WALL_FACTOR_PRANDTL, wall_factor\n\n__all__: list[str] = [\n    \"ESDU_tube_angle_correction\",\n    \"ESDU_tube_row_correction\",\n    \"Nu_ESDU_73031\",\n    \"Nu_Grimison_tube_bank\",\n    \"Nu_HEDH_tube_bank\",\n    \"Nu_Zukauskas_Bejan\",\n    \"Zukauskas_tube_row_correction\",\n    \"baffle_correction_Bell\",\n    \"baffle_leakage_Bell\",\n    \"bundle_bypassing_Bell\",\n    \"dP_Kern\",\n    \"dP_Zukauskas\",\n    \"laminar_correction_Bell\",\n    \"unequal_baffle_spacing_Bell\",\n]\n\n__numba_additional_funcs__ = [\"Grimison_C1_aligned_interp\", \"Grimison_m_aligned_interp\",\n                              \"Grimson_C1_staggered_interp\", \"Grimson_m_staggered_interp\",\n                              \"Kern_f_Re\", \"Bell_baffle_configuration_obj\", \"Bell_baffle_leakage_obj\",\n                              \"Bell_bundle_bypass_low_obj\", \"Bell_bundle_bypass_high_obj\"]\n\nIS_NUMBA = \"IS_NUMBA\" in globals()\n# Applies for row 1-9.\nGrimson_Nl_aligned = [0.64, 0.8, 0.87, 0.9, 0.92, 0.94, 0.96, 0.98, 0.99]\nGrimson_Nl_staggered = [0.68, 0.75, 0.83, 0.89, 0.92, 0.95, 0.97, 0.98, 0.99]\n\n\nGrimison_SL_aligned = [1.25, 1.5, 2, 3]\nGrimison_ST_aligned = Grimison_SL_aligned\nGrimison_C1_aligned = [[0.348, 0.275, 0.1, 0.0633],\n                                [0.367, 0.25, 0.101, 0.0678],\n                                [0.418, 0.299, 0.229, 0.198],\n                                [0.29, 0.357, 0.374, 0.286]]\nGrimison_m_aligned = [[0.592, 0.608, 0.704, 0.752],\n                               [0.586, 0.62, 0.702, 0.744],\n                               [0.57, 0.602, 0.632, 0.648],\n                               [0.601, 0.584, 0.581, 0.608]]\n\nGrimison_C1_aligned_tck = implementation_optimize_tck([[1.25, 1.25, 1.25, 1.25, 3.0, 3.0, 3.0, 3.0],\n                           [1.25, 1.25, 1.25, 1.25, 3.0, 3.0, 3.0, 3.0],\n                           [0.34800000000000003, 0.20683194444444492, -0.18023055555555617,\n                            0.06330000000000001, 0.3755277777777776, -0.28351037808642043,\n                            0.24365763888889008, -0.0007166666666667326, 0.5481111111111114,\n                            0.2925767746913588, 0.8622214506172828, 0.5207777777777779, 0.29,\n                            0.5062500000000002, 0.26944444444444426, 0.286],\n                            3, 3], force_numpy=IS_NUMBA)\n\nGrimison_C1_aligned_interp = lambda x, y : float(bisplev(x, y, Grimison_C1_aligned_tck))\n\n\nGrimison_m_aligned_tck = implementation_optimize_tck([[1.25, 1.25, 1.25, 1.25, 3.0, 3.0, 3.0, 3.0],\n                          [1.25, 1.25, 1.25, 1.25, 3.0, 3.0, 3.0, 3.0],\n                          [0.5920000000000001, 0.5877777777777775, 0.9133333333333344,\n                           0.752, 0.5828472222222219, 0.7998613040123475,\n                           0.7413584104938251, 0.7841111111111112, 0.5320833333333332,\n                           0.5504147376543196, 0.30315663580247154, 0.4148888888888891,\n                           0.601, 0.5454861111111109, 0.6097500000000002, 0.608],\n                           3, 3], force_numpy=IS_NUMBA)\nGrimison_m_aligned_interp = lambda x, y : float(bisplev(x, y, Grimison_m_aligned_tck))\n\n\nGrimson_SL_staggered = [1.25, 1.5, 2, 3, 1, 1.25, 1.5, 2, 3, 0.9,\n                                 1.125, 1.25, 1.5, 2, 3, 0.6, 0.9, 1.125, 1.25,\n                                 1.5, 2, 3]\n\nGrimson_ST_staggered = [1.25, 1.25, 1.25, 1.25, 1.5, 1.5, 1.5, 1.5,\n                                 1.5, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3]\n\nGrimson_m_staggered = [0.556, 0.568, 0.572, 0.592, 0.558, 0.554,\n                                0.562, 0.568, 0.58, 0.571, 0.565, 0.556, 0.568,\n                                0.556, 0.562, 0.636, 0.581, 0.56, 0.562, 0.568,\n                                0.57, 0.574]\n\nGrimson_C1_staggered = [0.518, 0.451, 0.404, 0.31, 0.497, 0.505, 0.46,\n                                 0.416, 0.356, 0.446, 0.478, 0.519, 0.452,\n                                 0.482, 0.44, 0.213, 0.401, 0.518, 0.522,\n                                 0.488, 0.449, 0.428]\n\n\"\"\"`interp2d` creates warnings when used on these. They are avoided by\npre-generating the splines, and interfacing with fitpack at a lower level.\n\"\"\"\ntck_Grimson_m_staggered = implementation_optimize_tck([[1.25, 1.25, 1.8667584356619125, 2.0, 2.8366905775206916, 3.0, 3.0],\n     [0.6, 0.6, 1.0085084989709654, 1.340729148958038, 1.5154196399508033, 3.0, 3.0],\n     [1.731351706314169, 0.3675823638826614, 0.6267891238439347, 0.5623083927989683, 0.5920000000000982, 1.180171700201992,\n               0.7874995409316767, 0.4622370503994375, 0.562004066622535, 0.5623955950882191, 0.5680620929528815, 0.5720626262793304,\n               0.5510099520872309, 0.5641771077227365, 0.5597975310692721, 0.0, 0.0, 0.0, 0.0, 0.0, 0.6361653765016168,\n               0.5601991640778442, 0.5621224100266599, 0.5684014375982079, 0.573932491076899],\n    1, 1], force_numpy=IS_NUMBA)\n\ntck_Grimson_C1_staggered = implementation_optimize_tck([[1.25, 1.25, 1.936293121624252, 2.0, 2.094408820089069, 3.0, 3.0],\n    [0.6, 0.6, 1.1841422334268308, 1.3897531616318943, 1.6483901017748916, 3.0, 3.0],\n    [0.534042720665836, 0.5446897215451869, 0.4613632028066018, 0.4370513304331604, 0.31000000000000005, 0.3060114256888106,\n              0.4719357486311919, 0.5043332405690643, 0.4371755864391464, 0.4362779343788622, 0.364660449991649, 0.5144234623651529,\n              0.4513822953351327, 0.4852710459180796, 0.4420724694173403, 0.0, 0.0, 0.0, 0.0, 0.0, 0.21898644381978172,\n              0.5500312131715677, 0.4969529176876636, 0.46150347905703587, 0.4270770845430577],\n    1, 1], force_numpy=IS_NUMBA)\n\nGrimson_m_staggered_interp = lambda x, y: float(bisplev(x, y, tck_Grimson_m_staggered))\nGrimson_C1_staggered_interp = lambda x, y: float(bisplev(x, y, tck_Grimson_C1_staggered))\n\n\n\ndef Nu_Grimison_tube_bank(Re: float, Pr: float, Do: float, tube_rows: int, pitch_parallel: float, pitch_normal: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a tube bank\n    of tube rows at a specified `Re`, `Pr`, and `D` using the Grimison\n    methodology as described in [1]_.\n\n    .. math::\n        \\bar{Nu_D} = 1.13C_1Re_{D,max}^m Pr^{1/3}C_2\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to average (bulk) fluid properties and\n        tube outside diameter, [-]\n    Pr : float\n        Prandtl number with respect to average (bulk) fluid properties, [-]\n    Do : float\n        Tube outer diameter, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to tube outside diameter, [-]\n\n    Notes\n    -----\n    Tube row correction factors are applied for tube row counts less than 10,\n    also published in [1]_.\n\n    Examples\n    --------\n    >>> Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=11,\n    ... pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    79.07883866010\n\n    >>> Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=11,\n    ... pitch_normal=.07, pitch_parallel=.05, Do=.025)\n    79.92721078571\n\n    References\n    ----------\n    .. [1] Grimson, E. D. (1937) Correlation and Utilisation of New Data on\n       Flow Resistance and Heat Transfer for Cross Flow of Gases over Tube\n       Banks. Trans. ASME. 59 583-594\n    \"\"\"\n    staggered = abs(1 - pitch_normal/pitch_parallel) > 0.05\n    a = pitch_normal/Do # sT\n    b = pitch_parallel/Do\n    if not staggered:\n        C1 = float(bisplev(b, a, Grimison_C1_aligned_tck))\n        m = float(bisplev(b, a, Grimison_m_aligned_tck))\n    else:\n        C1 = float(bisplev(b, a, tck_Grimson_C1_staggered))\n        m = float(bisplev(b, a, tck_Grimson_m_staggered))\n\n    tube_rows = int(tube_rows)\n    if tube_rows < 10:\n        if tube_rows < 1:\n            tube_rows = 1\n        if staggered:\n            C2 = Grimson_Nl_staggered[tube_rows]\n        else:\n            C2 = Grimson_Nl_aligned[tube_rows]\n    else:\n        C2 = 1.0\n    Nu = 1.13*Re**m*Pr**(1.0/3.0)*C2*C1\n    return Nu\n\n\nZukauskas_Czs_low_Re_staggered = [0.8295, 0.8792, 0.9151, 0.9402, 0.957, 0.9677,\n    0.9745, 0.9785, 0.9808, 0.9823, 0.9838, 0.9855, 0.9873, 0.9891, 0.991,\n    0.9929, 0.9948, 0.9967, 0.9987]\nZukauskas_Czs_high_Re_staggered = [0.6273, 0.7689, 0.8473, 0.8942, 0.9254,\n    0.945, 0.957, 0.9652, 0.9716, 0.9765, 0.9803, 0.9834, 0.9862, 0.989,\n    0.9918, 0.9943, 0.9965, 0.998, 0.9986]\nZukauskas_Czs_inline = [0.6768, 0.8089, 0.8687, 0.9054, 0.9303, 0.9465, 0.9569,\n    0.9647, 0.9712, 0.9766, 0.9811, 0.9847, 0.9877, 0.99, 0.992, 0.9937,\n    0.9953, 0.9969, 0.9986]\n\ndef Zukauskas_tube_row_correction(tube_rows: int, staggered: bool=True, Re: float=1E4) -> float:\n    r\"\"\"Calculates the tube row correction factor according to a graph\n    digitized from [1] for heat transfer across\n    a tube bundle. The correction factors are slightly different for\n    staggered vs. inline configurations; for the staggered configuration,\n    factors are available separately for `Re` larger or smaller than 1000.\n\n    This method is a tabular lookup, with values of 1 when the tube row count\n    is 20 or more.\n\n    Parameters\n    ----------\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    staggered : bool, optional\n        Whether in the in-line or staggered configuration, [-]\n    Re : float, optional\n        The Reynolds number of flow through the tube bank using the bare tube\n        outer diameter and the minimum flow area through the bundle, [-]\n\n    Returns\n    -------\n    F : float\n        Tube row count correction factor, [-]\n\n    Notes\n    -----\n    The basis for this method is that an infinitely long tube bank has a\n    factor of 1; in practice the factor is reached at 20 rows.\n\n    Examples\n    --------\n    >>> Zukauskas_tube_row_correction(4, staggered=True)\n    0.8942\n    >>> Zukauskas_tube_row_correction(6, staggered=False)\n    0.9465\n\n    References\n    ----------\n    .. [1] Zukauskas, A. Heat transfer from tubes in crossflow. In T.F. Irvine,\n       Jr. and J. P. Hartnett, editors, Advances in Heat Transfer, volume 8,\n       pages 93-160. Academic Press, Inc., New York, 1972.\n    \"\"\"\n    tube_rows = int(tube_rows) # sanity for indexing\n    if tube_rows < 1:\n        tube_rows = 1\n    if staggered: # in-line, with a tolerance of 0.05 proximity\n        if tube_rows <= 19:\n            factors = Zukauskas_Czs_low_Re_staggered if Re < 1000 else Zukauskas_Czs_high_Re_staggered\n            correction = factors[tube_rows-1]\n        else:\n            correction = 1.0\n    else:\n        if tube_rows <= 19:\n            correction = Zukauskas_Czs_inline[tube_rows-1]\n        else:\n            correction = 1.0\n    return correction\n\n\ndef Nu_Zukauskas_Bejan(Re: float, Pr: float, tube_rows: int, pitch_parallel: float, pitch_normal: float,\n                       Pr_wall: float | None=None) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a tube bank\n    of tube number n at a specified `Re` according to the method of Zukauskas\n    [1]_. A fit to graphs from [1]_ published in [2]_ is used for the\n    correlation. The tube row correction factor is obtained from digitized\n    graphs from [1]_, and a lookup table was created and is used for speed.\n\n    The formulas are as follows:\n\n    Aligned tube banks:\n\n    .. math::\n        \\bar Nu_D = 0.9 C_nRe_D^{0.4}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 1 < Re < 100\n\n    .. math::\n        \\bar Nu_D = 0.52 C_nRe_D^{0.5}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 100 < Re < 1000\n\n    .. math::\n        \\bar Nu_D = 0.27 C_nRe_D^{0.63}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 1000 < Re < 20000\n\n    .. math::\n        \\bar Nu_D = 0.033 C_nRe_D^{0.8}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 20000 < Re < 200000\n\n    Staggered tube banks:\n\n    .. math::\n        \\bar Nu_D = 1.04C_nRe_D^{0.4}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 1 < Re < 500\n\n    .. math::\n        \\bar Nu_D = 0.71C_nRe_D^{0.5}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\text{ for } 500 < Re < 1000\n\n    .. math::\n        \\bar Nu_D = 0.35 C_nRe_D^{0.6}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\left(\\frac{X_t}{X_l}\\right)^{0.2}\n        \\text{ for } 1000 < Re < 20000\n\n    .. math::\n        \\bar Nu_D = 0.031 C_nRe_D^{0.8}Pr^{0.36}\\left(\\frac{Pr}{Pr_w}\\right)^{0.25}\n        \\left(\\frac{X_t}{X_l}\\right)^{0.2}\n        \\text{ for } 20000 < Re < 200000\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to average (bulk) fluid properties and\n        tube outside diameter, [-]\n    Pr : float\n        Prandtl number with respect to average (bulk) fluid properties, [-]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    Pr_wall : float, optional\n        Prandtl number at the wall temperature; provide if a correction with\n        the defaults parameters is desired; otherwise apply the correction\n        elsewhere, [-]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to tube outside diameter, [-]\n\n    Notes\n    -----\n    If `Pr_wall` is not provided, the Prandtl number correction\n    is not used and left to an outside function.  A Prandtl number exponent of\n    0.25 is recommended in [1]_ for heating and cooling for both liquids and\n    gases.\n\n    Examples\n    --------\n    >>> Nu_Zukauskas_Bejan(Re=1E4, Pr=7., tube_rows=10, pitch_parallel=.05, pitch_normal=.05)\n    175.9202277145248\n\n    References\n    ----------\n    .. [1] Zukauskas, A. Heat transfer from tubes in crossflow. In T.F. Irvine,\n       Jr. and J. P. Hartnett, editors, Advances in Heat Transfer, volume 8,\n       pages 93-160. Academic Press, Inc., New York, 1972.\n    .. [2] Bejan, Adrian. \"Convection Heat Transfer\", 4E. Hoboken,\n       New Jersey: Wiley, 2013.\n    \"\"\"\n    staggered = abs(1 - pitch_normal/pitch_parallel) > 0.05\n\n    f = 1.0\n    if not staggered:\n        if Re < 100:\n            c, m = 0.9, 0.4\n        elif Re < 1000:\n            c, m = 0.52, 0.05\n        elif Re < 2E5:\n            c, m = 0.27, 0.63\n        else:\n            c, m = 0.033, 0.8\n    else:\n        if Re < 500:\n            c, m = 1.04, 0.4\n        elif Re < 1000:\n            c, m = 0.71, 0.5\n        elif Re < 2E5:\n            c, m = 0.35, 0.6\n            f = (pitch_normal/pitch_parallel)**0.2\n        else:\n            c, m = 0.031, 0.8\n            f = (pitch_normal/pitch_parallel)**0.2\n\n    Nu = c*Re**m*Pr**0.36*f\n    if Pr_wall is not None:\n        Nu*= (Pr/Pr_wall)**0.25\n    Cn = Zukauskas_tube_row_correction(tube_rows, staggered=staggered, Re=Re)\n    Nu *= Cn\n    return Nu\n\n\n# For row counts 3 to 9, inclusive. Lower tube counts shouldn't be considered\n# tube banks. 10 is 1.\nESDU_73031_F2_inline = [0.8479, 0.8957, 0.9306, 0.9551, 0.9724, 0.9839, 0.9902]\nESDU_73031_F2_staggered = [0.8593, 0.8984, 0.9268, 0.9482, 0.965, 0.9777, 0.9868]\n\ndef ESDU_tube_row_correction(tube_rows: int, staggered: bool=True, Re: float=3000.0, method: str=\"Hewitt\") -> float:\n    r\"\"\"Calculates the tube row correction factor according to [1]_ as shown in\n    [2]_ for heat transfer across a tube bundle. This is also used for finned\n    bundles. The correction factors are slightly different for staggered vs.\n    inline configurations.\n\n    This method is a tabular lookup, with values of 1 when the tube row count\n    is 10 or more.\n\n    Parameters\n    ----------\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    staggered : bool, optional\n        Whether in the in-line or staggered configuration, [-]\n    Re : float, optional\n        The Reynolds number of flow through the tube bank using the bare tube\n        outer diameter and the minimum flow area through the bundle, [-]\n    method : str, optional\n        'Hewitt'; this may have another option in the future, [-]\n\n    Returns\n    -------\n    F2 : float\n        ESDU tube row count correction factor, [-]\n\n    Notes\n    -----\n    In [1]_, for line data, there are two curves given for different Reynolds\n    number ranges. This is not included in [2]_ and only an average curve is\n    given. This is not implemented here; `Re` is an argument but does not\n    impact the result of this function.\n\n    For tube counts 1-7, [3]_ claims the factors from [1]_ are on average:\n    [0.65, 0.77, 0.84, 0.9, 0.94, 0.97, 0.99].\n\n    Examples\n    --------\n    >>> ESDU_tube_row_correction(4, staggered=True)\n    0.8984\n    >>> ESDU_tube_row_correction(6, staggered=False)\n    0.9551\n\n    References\n    ----------\n    .. [1] \"Convective Heat Transfer During Crossflow of Fluids Over Plain Tube\n       Banks.\" ESDU 73031 (November 1, 1973).\n    .. [2] Hewitt, G. L. Shires, T. Reg Bott G. F., George L. Shires, and T.\n       R. Bott. Process Heat Transfer. 1st edition. Boca Raton: CRC Press,\n       1994.\n    .. [3] Rabas, T. J., and J. Taborek. \"Survey of Turbulent Forced-Convection\n       Heat Transfer and Pressure Drop Characteristics of Low-Finned Tube Banks\n       in Cross Flow.\"  Heat Transfer Engineering 8, no. 2 (January 1987):\n       49-62.\n    \"\"\"\n    if method == \"Hewitt\":\n        if staggered: # in-line, with a tolerance of 0.05 proximity\n            if tube_rows <= 2:\n                correction = ESDU_73031_F2_staggered[0]\n            elif tube_rows >= 10:\n                correction = 1.0\n            else:\n                correction = ESDU_73031_F2_staggered[tube_rows-3]\n        else:\n            if tube_rows <= 2:\n                correction = ESDU_73031_F2_inline[0]\n            elif tube_rows >= 10:\n                correction = 1.0\n            else:\n                correction = ESDU_73031_F2_inline[tube_rows-3]\n        return correction\n\n\ndef ESDU_tube_angle_correction(angle: float) -> float:\n    r\"\"\"Calculates the tube bank inclination correction factor according to\n    [1]_ for heat transfer across a tube bundle.\n\n    .. math::\n        F_3 = \\frac{Nu_{\\theta}}{Nu_{\\theta=90^{\\circ}}} = (\\sin(\\theta))^{0.6}\n\n    Parameters\n    ----------\n    angle : float\n        The angle of inclination of the tuba bank with respect to the\n        longitudinal axis (90° for a straight tube bank)\n\n    Returns\n    -------\n    F3 : float\n        ESDU tube inclination correction factor, [-]\n\n    Notes\n    -----\n    A curve is given in [1]_ but it is so close the function, it is likely the\n    function is all that is used. [1]_ claims this correction is valid for\n    :math:`100 < Re < 10^{6}`.\n\n    For angles less than 10°, the problem should be considered internal\n    flow, not flow across a tube bank.\n\n    Examples\n    --------\n    >>> ESDU_tube_angle_correction(75)\n    0.9794139080247666\n\n    References\n    ----------\n    .. [1] \"Convective Heat Transfer During Crossflow of Fluids Over Plain Tube\n       Banks.\" ESDU 73031 (November 1, 1973).\n    \"\"\"\n    return sin(radians(angle))**0.6\n\n\ndef Nu_ESDU_73031(Re: float, Pr: float, tube_rows: int, pitch_parallel: float, pitch_normal: float,\n                  Pr_wall: float | None=None, angle: float=90.0) -> float:\n    r\"\"\"Calculates the Nusselt number for crossflow across a tube bank\n    with a specified number of tube rows, at a specified `Re` according to\n    [1]_, also shown in [2]_.\n\n    .. math::\n        \\text{Nu} = a \\text{Re}^m\\text{Pr}^{0.34}F_1 F_2\n\n    The constants `a` and `m` come from the following tables:\n\n    In-line tube banks:\n\n    +---------+-------+-------+\n    | Re      | a     | m     |\n    +=========+=======+=======+\n    | 10-300  | 0.742 | 0.431 |\n    +---------+-------+-------+\n    | 300-2E5 | 0.211 | 0.651 |\n    +---------+-------+-------+\n    | 2E5-2E6 | 0.116 | 0.700 |\n    +---------+-------+-------+\n\n    Staggered tube banks:\n\n    +---------+-------+-------+\n    | Re      | a     | m     |\n    +=========+=======+=======+\n    | 10-300  | 1.309 | 0.360 |\n    +---------+-------+-------+\n    | 300-2E5 | 0.273 | 0.635 |\n    +---------+-------+-------+\n    | 2E5-2E6 | 0.124 | 0.700 |\n    +---------+-------+-------+\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to average (bulk) fluid properties and\n        tube outside diameter, [-]\n    Pr : float\n        Prandtl number with respect to average (bulk) fluid properties, [-]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n    Pr_wall : float, optional\n        Prandtl number at the wall temperature; provide if a correction with\n        the defaults parameters is desired; otherwise apply the correction\n        elsewhere, [-]\n    angle : float, optional\n        The angle of inclination of the tuba bank with respect to the\n        longitudinal axis (90° for a straight tube bank)\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to tube outside diameter, [-]\n\n    Notes\n    -----\n    The tube-row count correction factor `F2` can be disabled by setting `tube_rows`\n    to 10. The property correction factor `F1` can be disabled by not specifying\n    `Pr_wall`. A Prandtl number exponent of 0.26 is recommended in [1]_ for\n    heating and cooling for both liquids and gases.\n\n    The pitches are used to determine whhether or not to use data for staggered\n    or inline tube banks.\n\n    The inline coefficients are valid for a normal pitch to tube diameter ratio\n    from 1.2 to 4; and the staggered ones from 1 to 4.\n    The overall accuracy of this method is claimed to be 15%.\n\n    See Also\n    --------\n    ESDU_tube_angle_correction\n    ESDU_tube_row_correction\n\n    Examples\n    --------\n    >>> Nu_ESDU_73031(Re=1.32E4, Pr=0.71, tube_rows=8, pitch_parallel=.09,\n    ... pitch_normal=.05)\n    98.2563319140594\n\n    References\n    ----------\n    .. [1] \"High-Fin Staggered Tube Banks: Heat Transfer and Pressure Drop for\n       Turbulent Single Phase Gas Flow.\" ESDU 86022 (October 1, 1986).\n    .. [2] Hewitt, G. L. Shires, T. Reg Bott G. F., George L. Shires, and T.\n       R. Bott. Process Heat Transfer. 1st edition. Boca Raton: CRC Press,\n       1994.\n    \"\"\"\n    staggered = abs(1 - pitch_normal/pitch_parallel) > 0.05\n    if staggered:\n        if Re <= 300:\n            a, m = 1.309, 0.360\n        elif Re <= 2E5:\n            a, m = 0.273, 0.635\n        else:\n            a, m = 0.124, 0.700\n    else:\n        if Re <= 300:\n            a, m = 0.742, 0.431\n        elif Re <= 2E5:\n            a, m = 0.211, 0.651\n        else:\n            a, m = 0.116, 0.700\n\n    F2 = ESDU_tube_row_correction(tube_rows=tube_rows, staggered=staggered)\n    F3 = ESDU_tube_angle_correction(angle)\n    if Pr_wall is not None:\n        F1 = wall_factor(Pr=Pr, Pr_wall=Pr_wall, Pr_heating_coeff=0.26,\n                         Pr_cooling_coeff=0.26,\n                         property_option=WALL_FACTOR_PRANDTL)\n    else:\n        F1 = 1.0\n    return a*Re**m*Pr**0.34*F1*F2*F3\n\n\ndef Nu_HEDH_tube_bank(Re: float, Pr: float, Do: float, tube_rows: int, pitch_parallel: float, pitch_normal: float) -> float:\n    r\"\"\"Calculates Nusselt number for crossflow across a tube bank\n    of tube rows at a specified `Re`, `Pr`, and `D` using the Heat Exchanger\n    Design Handbook (HEDH) methodology, presented in [1]_.\n\n    .. math::\n        Nu = Nu_m   f_N\n\n    .. math::\n        Nu_m = 0.3 + \\sqrt{Nu_{m,lam}^2 + Nu_{m,turb}^2}\n\n    .. math::\n        Nu_{m,turb} = \\frac{0.037Re^{0.8} Pr}{1 + 2.443Re^{-0.1}(Pr^{2/3} -1)}\n\n    .. math::\n        Nu_{m,lam} = 0.664Re^{0.5} Pr^{1/3}\n\n    .. math::\n        \\psi = 1 - \\frac{\\pi}{4a} \\text{ if b >= 1}\n\n    .. math::\n        \\psi = 1 - \\frac{\\pi}{4ab} \\text{if b < 1}\n\n    .. math::\n        f_A = 1 + \\frac{0.7}{\\psi^{1.5}}\\frac{b/a-0.3}{(b/a) + 0.7)^2} \\text{if inline}\n\n    .. math::\n        f_A = 1 + \\frac{2}{3b} \\text{elif partly staggered}\n\n    .. math::\n        f_N = \\frac{1 + (n-1)f_A}{n}\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number with respect to average (bulk) fluid properties and\n        tube outside diameter, [-]\n    Pr : float\n        Prandtl number with respect to average (bulk) fluid properties, [-]\n    Do : float\n        Tube outer diameter, [m]\n    tube_rows : int\n        Number of tube rows per bundle, [-]\n    pitch_parallel : float\n        Distance between tube center along a line parallel to the flow;\n        has been called `longitudinal` pitch, `pp`, `s2`, `SL`, and `p2`, [m]\n    pitch_normal : float\n        Distance between tube centers in a line 90° to the line of flow;\n        has been called the `transverse` pitch, `pn`, `s1`, `ST`, and `p1`, [m]\n\n    Returns\n    -------\n    Nu : float\n        Nusselt number with respect to tube outside diameter, [-]\n\n    Notes\n    -----\n    Prandtl number correction left to an outside function, although a set\n    of coefficients were specified in [1]_ because they depent on whether\n    heating or cooling is happening, and for gases, use a temperature ratio\n    instaed of Prandtl number.\n\n    The claimed range of validity of these expressions is :math:`10 < Re < 1E5`\n    and :math:`0.6 < Pr < 1000`.\n\n    Examples\n    --------\n    >>> Nu_HEDH_tube_bank(Re=1E4, Pr=7., tube_rows=10, pitch_normal=.05,\n    ... pitch_parallel=.05, Do=.03)\n    382.4636554404698\n\n    Example 3.11 in [2]_:\n\n    >>> Nu_HEDH_tube_bank(Re=10263.37, Pr=.708, tube_rows=11, pitch_normal=.05,\n    ... pitch_parallel=.05, Do=.025)\n    149.18735251017594\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [2] Baehr, Hans Dieter, and Karl Stephan. Heat and Mass Transfer.\n       Springer, 2013.\n    \"\"\"\n    staggered = abs(1 - pitch_normal/pitch_parallel) > 0.05\n    a = pitch_normal/Do\n    b = pitch_parallel/Do\n    if b >= 1:\n        voidage = 1. - pi/(4.0*a)\n    else:\n        voidage = 1. - pi/(4.0*a*b)\n    Re = Re/voidage\n    Nu_laminar = 0.664*Re**0.5*Pr**(1.0/3.)\n    Nu_turbulent = 0.037*Re**0.8*Pr/(1. + 2.443*Re**-0.1*(Pr**(2/3.) - 1.0))\n    Nu = 0.3 + (Nu_laminar*Nu_laminar + Nu_turbulent*Nu_turbulent)**0.5\n    if not staggered:\n        fA = 1.0 + 0.7/voidage**1.5*(b/a - 0.3)/(b/a + 0.7)**2\n    else:\n        fA = 1.0 + 2./(3.0*b)\n        # a further partly staggered tube bank correlation exists, using another pitch\n    if tube_rows < 10:\n        fn = (1.0 + (tube_rows - 1.0)*fA)/tube_rows\n    else:\n        fn = fA\n    Nu = Nu*fn\n    return Nu\n\n\n\"\"\"\nGraph presented in Peters and Timmerhaus uses fanning friction factor.\nThis uses Darcy's friction factor.\nThese coefficients were generated to speed up loading of this module.\nThey are regenerated and checked in the tests.\n\n\"\"\"\nKern_f_Re_tck = implementation_optimize_tck([[9.9524, 9.9524, 9.9524, 9.9524, 17.9105, 27.7862, 47.2083, 83.9573,\n                           281.996, 1122.76, 42999.9, 1012440.0, 1012440.0, 1012440.0, 1012440.0],\n                 [6.040435949178239, 4.64973456285782, 2.95274850806163, 1.9569061885042,\n                           1.1663069946420412, 0.6830549536215098, 0.4588680265447762, 0.22387792331971723,\n                           0.12721190975530583, 0.1395456548881242, 0.12888895743468684, 0.0, 0.0, 0.0, 0.0],\n                 3], force_numpy=IS_NUMBA)\nKern_f_Re = lambda x: float(splev(x, Kern_f_Re_tck))\n\n\ndef dP_Kern(m: float, rho: float, mu: float, DShell: float, LSpacing: float, pitch: float, Do: float, NBaffles: int, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates pressure drop for crossflow across a tube bank\n    according to the equivalent-diameter method developed by Kern [1]_,\n    presented in [2]_.\n\n    .. math::\n        \\Delta P = \\frac{f (m/S_s)^2 D_s(N_B+1)}{2\\rho D_e(\\mu/\\mu_w)^{0.14}}\n\n    .. math::\n        S_S = \\frac{D_S (P_T-D_o) L_B}{P_T}\n\n    .. math::\n        D_e = \\frac{4(P_T^2 - \\pi D_o^2/4)}{\\pi D_o}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate, [kg/s]\n    rho : float\n        Fluid density, [kg/m^3]\n    mu : float\n        Fluid viscosity, [Pa*s]\n    DShell : float\n        Diameter of exchanger shell, [m]\n    LSpacing : float\n        Baffle spacing, [m]\n    pitch : float\n        Tube pitch, [m]\n    Do : float\n        Tube outer diameter, [m]\n    NBaffles : float\n        Baffle count, []\n    mu_w : float\n        Fluid viscosity at wall temperature, [Pa*s]\n\n    Returns\n    -------\n    dP : float\n        Pressure drop across bundle, [Pa]\n\n    Notes\n    -----\n    Adjustment for viscosity left out of this function.\n    Example is from [2]_. Roughly 10% difference due to reading of graph.\n    Graph scanned from [1]_, and interpolation is used to read it.\n\n    Examples\n    --------\n    >>> dP_Kern(m=11., rho=995., mu=0.000803, mu_w=0.000657, DShell=0.584,\n    ... LSpacing=0.1524, pitch=0.0254, Do=.019, NBaffles=22)\n    18980.58768759033\n\n    References\n    ----------\n    .. [1] Kern, Donald Quentin. Process Heat Transfer. McGraw-Hill, 1950.\n    .. [2] Peters, Max, Klaus Timmerhaus, and Ronald West. Plant Design and\n       Economics for Chemical Engineers. 5E. New York: McGraw-Hill, 2002.\n    \"\"\"\n    # Adjustment for viscosity performed if given\n    Ss = DShell*(pitch-Do)*LSpacing/pitch\n    De = 4*(pitch*pitch - pi*Do*Do/4.)/pi/Do\n    Vs = m/Ss/rho\n    Re = rho*De*Vs/mu\n    f = Kern_f_Re(Re)\n    if mu_w:\n        return f*(Vs*rho)**2*DShell*(NBaffles+1)/(2*rho*De*(mu/mu_w)**0.14)\n    else:\n        return f*(Vs*rho)**2*DShell*(NBaffles+1)/(2*rho*De)\n\ndP_staggered_f_tck = implementation_optimize_tck([\n    [1.00000e+01, 1.00000e+01, 1.00000e+01, 1.00000e+01, 1.16733e+01,\n 1.31024e+01, 1.40153e+01, 1.49918e+01, 1.71536e+01, 1.85267e+01,\n 1.98182e+01, 2.07261e+01, 2.22430e+01, 2.37936e+01, 2.67057e+01,\n 3.22732e+01, 3.48580e+01, 3.72879e+01, 4.10554e+01, 4.44722e+01,\n 4.78949e+01, 5.12337e+01, 5.53369e+01, 6.51821e+01, 7.04025e+01,\n 7.60437e+01, 8.21368e+01, 8.87182e+01, 9.51284e+01, 1.03386e+02,\n 1.08398e+02, 1.29188e+02, 1.55444e+02, 1.68914e+02, 1.82793e+02,\n 1.97771e+02, 2.23559e+02, 2.78915e+02, 3.35015e+02, 4.97559e+02,\n 7.31917e+02, 1.11914e+03, 1.74856e+03, 2.30827e+03, 3.36357e+03,\n 4.36703e+03, 4.85424e+03, 6.81715e+03, 9.91409e+03, 1.96837e+04,\n 3.98384e+04, 8.69147e+04, 1.77710e+05, 3.29652e+05, 4.53370e+05,\n 6.17548e+05, 1.38874e+06, 2.75675e+06, 2.75675e+06, 2.75675e+06,\n 2.75675e+06],\n    [1.25, 1.25, 1.25, 1.25, 2.5 , 2.5 , 2.5 , 2.5 ],\n    [ 23.993727564949694 , -10.244567028024317 ,  10.175863843810976 ,\n   1.7999490702171597,  23.522204247227894 , -10.206973826192078 ,\n  10.10518140310304  ,   1.780787357025903 ,  21.056398673217306 ,\n  -8.809585811775245 ,   9.191305635699116 ,   1.7221653902388994,\n  19.30502693908655  ,  -8.454343171481037 ,   8.87084592501417  ,\n   1.6628307168281609,  17.765109289150598 ,  -7.7133771799002115,\n   8.35255872722289  ,   1.6185259877007414,  16.183640933328732 ,\n  -6.833873600289119 ,   7.722187414020649 ,   1.5690827476330849,\n  14.694535763926543 ,  -6.150405226666587 ,   7.22393729697023  ,\n   1.5213836637875222,  13.605573060235757 ,  -5.4221574812289735,\n   6.657567596977061 ,   1.4767279611552022,  13.00457363939894  ,\n  -5.517651045065633 ,   6.649512891288891 ,   1.4466870011383937,\n  11.995125279422092 ,  -4.905206010958158 ,   6.23685497204518  ,\n   1.4176362748134403,  11.320923863947378 ,  -4.3609663889341554,\n   5.823387965136728 ,   1.3889295522585867,  10.55081833434363  ,\n  -4.2246761575331195,   5.6424642699146474,   1.3494878611293746,\n   9.136637777542301 ,  -3.3738486997113624,   4.988770673854508 ,\n   1.2912945512808613,   8.142082809925073 ,  -3.0640564076701335,\n   4.673896497087432 ,   1.2394666235276033,   7.307435480320903 ,\n  -2.4507512853218927,   4.184651311906238 ,   1.197270318810632 ,\n   6.823162531391426 ,  -2.341520042292131 ,   4.031868925359543 ,\n   1.1654503211708163,   6.292609559336966 ,  -2.172105165179806 ,\n   3.851181307698692 ,   1.1342864317994863,   5.7736639984989955,\n  -1.8024125693369684,   3.540068552249239 ,   1.103663937920097 ,\n   5.456996186731616 ,  -1.6944442210715904,   3.394074222435801 ,\n   1.0771356178101834,   5.04760166750843  ,  -1.5241640716734404,\n   3.2252084065116606,   1.051345959799993 ,   4.547228150208529 ,\n  -1.2330993185368226,   2.940049991699233 ,   1.0141134328178203,\n   4.14534270298608  ,  -1.0164114172228296,   2.7045876551545796,\n   0.9793370063645501,   3.771066238885074 ,  -0.8748901176380479,\n   2.528229788862222 ,   0.9470018923394338,   3.578714777343189 ,\n  -0.7900362603927293,   2.4000658218893482,   0.9229840539840486,\n   3.2657684683098536,  -0.5425913450233749,   2.185378113310861 ,\n   0.8999825646391477,   3.1380949473394075,  -0.5491995911762386,\n   2.1192169444451854,   0.8771813561150372,   2.8710190479957056,\n  -0.3178235005664693,   1.9163896313226092,   0.8571821847817371,\n   2.7427220096515885,  -0.350653244945934 ,   1.8829269684603023,\n   0.8348323725060139,   2.4836006182031682,  -0.1352407446908991,\n   1.6647896666111899,   0.8142139723548999,   2.2164004811891416,\n  -0.0371909044098638,   1.492301567301747 ,   0.7533707758356281,\n   1.9945634411125996,   0.1123996806357918,   1.2956302127875685,\n   0.7249191411158085,   1.842686059394845 ,   0.1607181649910975,\n   1.2153169523034464,   0.6897021922030252,   1.7377903418611442,\n   0.289292795896553 ,   1.08344601062934  ,   0.6729372197342073,\n   1.6396914034896823,   0.1989615127535343,   1.0850029234159282,\n   0.6499001080984353,   1.487502515283381 ,   0.3730846731246894,\n   0.9013971733000221,   0.6182632804995061,   1.3522211422419148,\n   0.2911476890926835,   0.8964977394892637,   0.5767990957491218,\n   1.1810712591370587,   0.3394790407828216,   0.7652655011740844,\n   0.5323341532737186,   1.02811191715534  ,   0.2887724828326413,\n   0.7066399775545615,   0.4778931341762794,   0.8895112183187074,\n   0.3210418642443666,   0.6143186197557094,   0.4467010633652874,\n   0.7932715410752142,   0.3211662514007235,   0.5619909984438982,\n   0.4128889836673581,   0.7375513367809549,   0.3144259758348928,\n   0.528973351907581 ,   0.4094681633270362,   0.6972754846297644,\n   0.3205333114809629,   0.4918522964719353,   0.379830474083385 ,\n   0.6641316600566393,   0.281121553527687 ,   0.509197543189297 ,\n   0.3783415752249853,   0.6244559596650743,   0.2837572552667433,\n   0.4993191757674828,   0.3669254758741835,   0.6023735792473888,\n   0.2761933758206954,   0.4987865496444748,   0.364477871468622 ,\n   0.5590674813131451,   0.2621282514144033,   0.4629707633705547,\n   0.344500324531334 ,   0.4782618774782103,   0.2485411042324743,\n   0.3784315811630596,   0.3033924096858183,   0.3937668979943847,\n   0.2127684318169733,   0.3154828002796004,   0.2539053524737366,\n   0.31876438844008  ,   0.158795177701543 ,   0.2564298818590743,\n   0.2026052448806063,   0.2666571057762706,   0.125595092472467 ,\n   0.2213179726704931,   0.1679289011957269,   0.2145850940558933,\n   0.0821608103084532,   0.1746802190336271,   0.1296792214950967,\n   0.226583087040426 ,   0.1193363052691195,   0.1939070597138282,\n   0.1415527224622063,   0.2236870028120291,   0.187323377693516 ,\n   0.1956693312744808,   0.1768800813854576,   0.2267018978658211,\n   0.1724455167753975,   0.1962302349704176,   0.1908917559338361,\n   0.2244440017710325,   0.1881858244890039,   0.2045576574847943,\n   0.1746985249870369,   0.2264047973889584,   0.1728059947546293,\n   0.2044769358453351,   0.1891991544177786,   0.2281141554162358,\n   0.1740746507220272,   0.2115805378214652,   0.1837416784138279],\n    3, 3\n])\n\ndP_staggered_correction_tck = implementation_optimize_tck([\n    [0.4387  , 0.4387  , 0.609319, 0.84214 , 1.22243 , 1.45385 , 2.22751 ,\n 3.54351 , 3.54351 ],\n    [   100.,    100.,    100.,    100., 100000., 100000., 100000., 100000.],\n    [  0.9974058596752864,   2.2479507236683025,  -2.927557461079741 ,\n   1.4506256824457617,   0.9973256008060759,   1.2891120004637224,\n   2.57756043014528  ,   1.308194055102965 ,   0.99328828308559  ,\n   0.9777071534489982,   2.690730180307897 ,   1.1511575741885283,\n   1.0225516740093321,   0.654636148703268 ,   3.5328468308711605,\n   0.9841004806410495,   1.1242321684355248,  -1.285317900605766 ,\n  18.760679189927053 ,   0.9465800254548173,   1.4029517756874132,\n  -6.782908749288587 ,  62.67683464108982  ,   0.9308263957725467,\n   1.6896512655274156, -12.264942447053453 , 107.33977758986381  ,\n   0.9417015493955058],\n    1, 3\n])\n\ndP_inline_f_tck = implementation_optimize_tck([\n    [2.85094e+01, 2.85094e+01, 2.85094e+01, 2.85094e+01, 3.29727e+01,\n 3.53563e+01, 4.12101e+01, 5.26143e+01, 5.91070e+01, 6.37533e+01,\n 8.29896e+01, 1.24713e+02, 1.57106e+02, 2.78938e+02, 5.28457e+02,\n 7.95679e+02, 1.10738e+03, 1.61619e+03, 4.85232e+03, 6.54585e+03,\n 8.11339e+03, 1.45214e+04, 5.39717e+04, 9.84306e+04, 1.69621e+05,\n 6.05857e+05, 1.87104e+06, 1.87104e+06, 1.87104e+06, 1.87104e+06],\n    [1.25, 1.25, 1.25, 1.25, 2.5 , 2.5 , 2.5 , 2.5 ],\n    [ 5.930973938528779 , -1.4817265127271453,  0.455379701866362 ,\n  0.3498836798224479,  5.658593208961423 , -0.864342651441936 ,\n  0.0859302669335574,  0.3461356038232322,  5.313966014275998 ,\n -0.9488816374714495,  0.1958290207282649,  0.3409206025216998,\n  4.7479017538057215, -0.9103110524004313,  0.2580592449510698,\n  0.3323409371000172,  3.985380347891111 , -0.8082048062363013,\n  0.3083826543793066,  0.3209043535273658,  3.386764509595187 ,\n -0.6210063941958163,  0.2773912522639271,  0.3101279173763394,\n  2.997259057262402 , -0.6436424918427293,  0.3541133458508599,\n  0.301791078024438 ,  2.5313481368123476, -0.4636698687516479,\n  0.3080129633362942,  0.291588283194631 ,  1.9067355729954962,\n -0.4062699968822227,  0.3701523002949395,  0.2746968125881167,\n  1.4860009590268453, -0.3047213533591268,  0.3724777524638413,\n  0.2586442595556128,  0.9575648609085928, -0.204166339279796 ,\n  0.3941734724654094,  0.2357333057087107,  0.617062433119386 ,\n -0.1088086799459149,  0.3940863377254021,  0.2089273471639561,\n  0.4722964733105959, -0.0558097050630406,  0.3870405603703184,\n  0.1913524081468901,  0.3995262320386994, -0.025364894783629 ,\n  0.3882892706432594,  0.1722324338381349,  0.4645326824064042,\n  0.00678125270346  ,  0.3521348515608552,  0.1753669353885564,\n  0.5446976745961594,  0.152419457668676 ,  0.2469868959242308,\n  0.176815573751498 ,  0.5104609851427283,  0.1262432245605664,\n  0.2778791531974582,  0.1778458681575732,  0.4747778372905396,\n  0.1841815013323758,  0.2390262532478637,  0.1784924161355043,\n  0.4331707217581522,  0.1966086663135327,  0.2420381252055944,\n  0.1781297356716778,  0.3463614484492485,  0.2262216378962929,\n  0.1657411941914758,  0.1704140168055773,  0.3137425743888637,\n  0.2228368744465938,  0.1287382966547652,  0.1588140647661027,\n  0.2666982751158755,  0.2063058104326992,  0.1587051313760535,\n  0.158741122371858 ,  0.2469799643017819,  0.2074867426640942,\n  0.1619911852835217,  0.1580881696361456,  0.2548927358191072,\n  0.2072520441235713,  0.1588874948041774,  0.1572373415378531,\n  0.2498062734215278,  0.2019373850118195,  0.1635492298499229,\n  0.1573584818834395,  0.2539191494035861,  0.2008897736617199,\n  0.1630751863377278,  0.1570998393113034],\n    3, 3\n])\n\ndP_inline_correction_tck = implementation_optimize_tck([\n    [0.02    , 0.02    , 0.02    , 0.02    , 0.066164, 0.08    , 0.16    ,\n 0.32    , 0.64    , 1.28    , 2.56    , 5.7141  , 5.7141  , 5.7141  ,\n 5.7141  ],\n    [   1000.,    1000.,    1000.,    1000., 1000000., 1000000., 1000000.,\n 1000000.],\n    [ 1.6050000000000011e+01, -9.9185525084848649e+01,  8.0188908903030449e+02,\n  5.3722000000000012e+00,  9.7642684825332609e+00, -5.9212586722045586e+01,\n  4.8681375915163028e+02,  3.8371626170338349e+00,  8.2631729047131390e+00,\n -5.3624502687061614e+01,  4.4328465663719857e+02,  3.3370326010388487e+00,\n  5.0902027741289038e+00, -2.5039923342821140e+01,  2.0959688954308831e+02,\n  2.4638592963292831e+00,  3.3252028425473772e+00, -1.2251528629540998e+01,\n  1.1583792320215544e+02,  2.0227774411216131e+00,  1.7798328575941409e+00,\n  2.7213811631652502e+00, -1.5319618243273222e+01,  1.4299822635240957e+00,\n  1.1740829684913225e+00,  9.4029637834424262e-01,  3.9974603020412691e+00,\n  1.1420933087379526e+00,  6.3974151735102358e-01,  3.5438685909104040e+00,\n -2.2199543860124965e+01,  8.1942218695180635e-01,  4.0902459885654202e-01,\n  1.0486758802627454e+00, -2.1456210505006823e-01,  6.4235546429644219e-01,\n  3.0522194412697784e-01,  2.4239289999078180e+00, -1.3982480984625624e+01,\n  5.5177093110224618e-01,  2.7113000000000009e-01,  1.8811070427272716e+00,\n -9.5202273363636269e+00,  5.1587000000000016e-01],\n    3, 3\n])\n\n\ndef dP_Zukauskas(Re: float, n: int, ST: float, SL: float, D: float, rho: float, Vmax: float) -> float:\n    r\"\"\"Calculates pressure drop for crossflow across a tube bank\n    of tube number n at a specified Re. Method presented in [1]_.\n    Also presented in [2]_.\n\n    .. math::\n        \\Delta P = N_L \\chi \\left(\\frac{\\rho V_{max}^2}{2}\\right)f\n\n    Parameters\n    ----------\n    Re : float\n        Reynolds number, [-]\n    n : float\n        Number of tube rows, [-]\n    ST : float\n        Transverse pitch, used only by some conditions, [m]\n    SL : float\n        Longitudal pitch, used only by some conditions, [m]\n    D : float\n        Tube outer diameter, [m]\n    rho : float\n        Fluid density, [kg/m^3]\n    Vmax : float\n        Maximum velocity, [m/s]\n\n    Returns\n    -------\n    dP : float\n        Pressure drop, [Pa]\n\n    Notes\n    -----\n    Does not account for effects in a heat exchanger.\n    Example 2 is from [2]_. Matches to 0.3%; figures are very approximate.\n    Interpolation used with 4 graphs to obtain friction factor and a\n    correction factor.\n\n    Examples\n    --------\n    >>> dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0343, D=0.0164, rho=1.217, Vmax=12.6)\n    235.2291\n    >>> dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0313, D=0.0164, rho=1.217, Vmax=12.6)\n    161.147\n\n    References\n    ----------\n    .. [1] Zukauskas, A. Heat transfer from tubes in crossflow. In T.F. Irvine,\n       Jr. and J. P. Hartnett, editors, Advances in Heat Transfer, volume 8,\n       pages 93-160. Academic Press, Inc., New York, 1972.\n    .. [2] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    a = ST/D\n    b = SL/D\n    if a == b:\n        parameter = (a-1.)/(b-1.)\n        f = float(bisplev(Re, b, dP_inline_f_tck))\n        x = float(bisplev(parameter, Re, dP_inline_correction_tck))\n\n    else:\n        parameter = a/b\n        f = float(bisplev(Re, a, dP_staggered_f_tck))\n        x = float(bisplev(parameter, Re, dP_staggered_correction_tck))\n    return n*x*f*rho/2*Vmax**2\n\n\n\"\"\"Note: the smoothing factor was tunned to keep only 7 knots/9 coeffs while\ngetting near to requiring more knots. The fitting for a digitized graph is\nlikely to be at the maximum possible accuracy. Any speed increasing fit\nfunction should fit the smoothed function, not the raw data.\n\"\"\"\nBell_baffle_configuration_tck = implementation_optimize_tck([[0.0, 0.0, 0.0, 0.0, 0.517361, 0.802083, 0.866319,\n                                           0.934028, 0.977431, 1.0, 1.0, 1.0, 1.0],\n                                 [0.5328447885827443, 0.6821475548927218, 0.9074424740361304,\n                                           1.0828783604984582, 1.1485665329698214, 1.1612486065399008,\n                                           1.1216591944456349, 1.0762015137576528, 1.0314244120288227,\n                                           0.0, 0.0, 0.0, 0.0],\n                                3], force_numpy=IS_NUMBA)\n\nBell_baffle_configuration_obj = lambda x : float(splev(x, Bell_baffle_configuration_tck))\n\n\"\"\"Derived with:\n\nfit = Chebfun.from_function(lambda x: Bell_baffle_configuration_obj(0.5*(x+1)), domain=[-1,1], N=8)\ncheb2poly(fit.coefficients())[::-1].tolist()\n\nxs = np.linspace(0, 1, 3000)\nf = Bell_baffle_configuration_obj\nprint(max([(f(i)-fit(i*2-1))/f(i) for i in xs]), 'MAX ERR')\nprint(np.mean([abs(f(i)-fit(i*2-1))/f(i) for i in xs]), 'MEAN ERR')\n\"\"\"\nBell_baffle_configuration_coeffs = [-17.267087530974095, -17.341072676377735,\n    60.38380262590988, 60.78202803861199, -83.86556326987701, -84.74024411236306, 58.66461844872558,\n    59.56146082596216, -21.786957547130935, -22.229378707598116, 4.1167302227508, 4.226246012504343,\n    -0.3349723004600481, -0.3685826653263089, -0.0629839069257099, 0.35883309630976157,\n    0.9345478582873352]\n\ndef baffle_correction_Bell(crossflow_tube_fraction: float, method: str=\"spline\") -> float:\n    r\"\"\"Calculate the baffle correction factor `Jc` which accounts for\n    the fact that all tubes are not in crossflow to the fluid - some\n    have fluid flowing parallel to them because they are situated in\n    the \"window\", where the baffle is cut, instead of between the tips\n    of adjacent baffles.\n\n    Equal to 1 for no tubes in the window, increases to 1.15 when the\n    windows are small and velocity there is high; decreases to about 0.52\n    for very large baffle cuts. Well designed exchangers should typically\n    have a value near 1.0.\n\n    Cubic spline interpolation is the default method of retrieving a value\n    from the graph, which was digitized with Engauge-Digitizer.\n\n    The interpolation can be slightly slow, so a Chebyshev polynomial was fit\n    to a maximum error of 0.142%, average error 0.04% - well within the margin\n    of error of the digitization of the graph; this is approximately 10 times\n    faster, accessible via the 'chebyshev' method.\n\n    The Heat Exchanger Design Handbook [4]_, [5]_ provides the linear curve\n    fit, which covers the \"practical\" range of baffle cuts 15-45% but not the\n    last dip in the graph. This method is not recommended, but can be used via\n    the method \"HEDH\".\n\n    .. math::\n        J_c = 0.55 + 0.72Fc\n\n    Parameters\n    ----------\n    crossflow_tube_fraction : float\n        Fraction of tubes which are between baffle tips and not\n        in the window, [-]\n    method : str, optional\n        One of 'chebyshev', 'spline', or 'HEDH'\n\n    Returns\n    -------\n    Jc : float\n        Baffle correction factor in the Bell-Delaware method, [-]\n\n    Notes\n    -----\n    max: ~1.1536 at ~0.9066\n    min: ~0.5328 at 0\n    value at 1: ~1.0314\n\n    For the 'spline' method, this function takes ~13 us per call.\n    The other two methods are approximately 10x faster.\n\n    Examples\n    --------\n    For a HX with four groups of tube bundles; the top and bottom being 9\n    tubes each, in the window, and the two middle bundles having 41 tubes\n    each, for a total of 100 tubes, the fraction between baffle tubes and\n    not in the window is 0.82. The correction factor is then:\n\n    >>> baffle_correction_Bell(0.82)\n    1.1258554691854046\n\n    References\n    ----------\n    .. [1] Bell, Kenneth J. Final Report of the Cooperative Research Program on\n       Shell and Tube Heat Exchangers. University of Delaware, Engineering\n       Experimental Station, 1963.\n    .. [2] Bell, Kenneth J. Delaware Method for Shell-Side Design. In Heat\n       Transfer Equipment Design, by Shah, R.  K., Eleswarapu Chinna Subbarao,\n       and R. A. Mashelkar. CRC Press, 1988.\n    .. [3] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,\n       Eighth Edition. McGraw-Hill Professional, 2007.\n    .. [4] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [5] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    \"\"\"\n    if method == \"spline\":\n        Jc = Bell_baffle_configuration_obj(crossflow_tube_fraction)\n    elif method == \"chebyshev\":\n        return horner(Bell_baffle_configuration_coeffs, 2.0*crossflow_tube_fraction - 1.0)\n    elif method == \"HEDH\":\n        Jc = 0.55 + 0.72*crossflow_tube_fraction\n    return Jc\n\n\n\"\"\"Note: The smoothing factor was hand tuned to not overfit from points which\nwere clearly wrong in the digitization. It will predict values above 1 however\nfor some values; this must be checked!\n\"\"\"\nBell_baffle_leakage_x_max = 0.743614\n\nBell_baffle_leakage_tck = implementation_optimize_tck([[0.0, 0.0, 0.0, 0.0, 0.0213694, 0.0552542, 0.144818,\n                                     0.347109, 0.743614, 0.743614, 0.743614, 0.743614],\n                                    [0.0, 0.0, 0.25, 0.5, 0.75, 1.0, 1.0],\n                                    [1.0001228445490002, 0.9988161050974387, 0.9987070557919563, 0.9979385859402731,\n                                     0.9970983069823832, 0.96602540121758, 0.955136014969614, 0.9476842472211648,\n                                     0.9351143114374392, 0.9059649602818451, 0.9218915266550902, 0.9086000082864022,\n                                     0.8934758292610783, 0.8737960765592091, 0.83185251064324, 0.8664296734965998,\n                                     0.8349705397843921, 0.809133298969704, 0.7752206120745123, 0.7344035693011536,\n                                     0.817047920445813, 0.7694560150930563, 0.7250979336267909, 0.6766754605968431,\n                                     0.629304180420512, 0.7137237030611423, 0.6408238328161417, 0.5772000233279148,\n                                     0.504889627280836, 0.440579886434288, 0.6239736474980684, 0.5273646894226224,\n                                     0.43995388722059986, 0.34359277007615313, 0.26986439252143746, 0.5640689738382749,\n                                     0.4540959882735219, 0.35278120580740957, 0.24364672351604122, 0.1606942128340308],\n                           3, 1], force_numpy=IS_NUMBA)\nBell_baffle_leakage_obj = lambda x, z : float(bisplev(x, z, Bell_baffle_leakage_tck))\n\n\ndef baffle_leakage_Bell(Ssb: float, Stb: float, Sm: float, method: str=\"spline\") -> float:\n    r\"\"\"Calculate the baffle leakage factor `Jl` which accounts for\n    leakage between each baffle.\n    Cubic spline interpolation is the default method of retrieving a value\n    from the graph, which was digitized with Engauge-Digitizer.\n\n    The Heat Exchanger Design Handbook [4]_, [5]_ provides a curve\n    fit as well. This method is not recommended, but can be used via\n    the method \"HEDH\".\n\n    .. math::\n        J_L = 0.44(1-r_s) + [1 - 0.44(1-r_s)]\\exp(-2.2r_{lm})\n\n    .. math::\n        r_s = \\frac{S_{sb}}{S_{sb} + S_{tb}}\n\n    .. math::\n        r_{lm} = \\frac{S_{sb} + S_{tb}}{S_m}\n\n    Parameters\n    ----------\n    Ssb : float\n        Shell to baffle leakage area, [m^2]\n    Stb : float\n        Total baffle leakage area, [m^2]\n    Sm : float\n        Crossflow area, [m^2]\n    method : str, optional\n        One of 'spline', or 'HEDH'\n\n    Returns\n    -------\n    Jl : float\n        Baffle leakage factor in the Bell-Delaware method, [-]\n\n    Notes\n    -----\n    Takes ~5 us per call.\n    If the `x` parameter is larger than 0.743614, it is clipped to it.\n\n    The HEDH curve fits are rather poor and only 6x faster to evaluate.\n    The HEDH example in [6]_'s spreadsheet has an error and uses 0.044 instead\n    of 0.44 in the equation.\n\n    Examples\n    --------\n    >>> baffle_leakage_Bell(1, 3, 8)\n    0.5906621282470\n    >>> baffle_leakage_Bell(1, 3, 8, 'HEDH')\n    0.5530236260777\n\n    References\n    ----------\n    .. [1] Bell, Kenneth J. Final Report of the Cooperative Research Program on\n       Shell and Tube Heat Exchangers. University of Delaware, Engineering\n       Experimental Station, 1963.\n    .. [2] Bell, Kenneth J. Delaware Method for Shell-Side Design. In Heat\n       Transfer Equipment Design, by Shah, R.  K., Eleswarapu Chinna Subbarao,\n       and R. A. Mashelkar. CRC Press, 1988.\n    .. [3] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,\n       Eighth Edition. McGraw-Hill Professional, 2007.\n    .. [4] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [5] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    .. [6] Hall, Stephen. Rules of Thumb for Chemical Engineers, Fifth Edition.\n       5th edition. Oxford ; Waltham , MA: Butterworth-Heinemann, 2012.\n    \"\"\"\n    x = (Ssb + Stb)/Sm\n    if x > Bell_baffle_leakage_x_max:\n        x = Bell_baffle_leakage_x_max\n    z = Ssb/(Ssb + Stb)\n    if z > 1.0 or z < 0.0:\n        raise ValueError(\"Ssb/(Ssb + Stb) must be between 0 and 1\")\n    if method == \"spline\":\n        Jl = Bell_baffle_leakage_obj(x, z)\n        Jl = min(float(Jl), 1.0)\n    elif method == \"HEDH\":\n        # Hemisphere uses 0.44 as coefficient, rules of thumb uses 0.044 in spreadsheet\n        Jl = 0.44*(1.0 - z) + (1.0 - 0.44*(1.0 - z))*exp(-2.2*x)\n    return Jl\n\n\nBell_bundle_bypass_x_max = 0.69532\nBell_bundle_bypass_high_spl = implementation_optimize_tck([[0.0, 0.0, 0.0, 0.0, 0.434967, 0.69532, 0.69532, 0.69532, 0.69532],\n                               [0.0, 0.0, 0.0, 0.0, 0.1, 0.16666666666666666, 0.5, 0.5, 0.5, 0.5],\n                               [0.9992518012440722, 0.9989007625058475, 1.0018411070735471, 0.9941457497302127,\n                                         1.0054152224744488, 1.0000002120327414, 0.8193710201718651, 0.8906557463728106,\n                                         0.9236476444228989, 0.9466472125718047, 1.002564972451326, 1.0000001328221189,\n                                         0.6099796629837915, 0.7779198818216049, 0.8128716798013131, 0.935864247770527,\n                                         0.932707600057425, 0.9999978349038892, 0.46653330555544065, 0.6543895994806808,\n                                         0.7244471950409509, 0.8599376452211228, 0.9622021460141503, 0.9999989177211911,\n                                         0.42206076955873406, 0.6230810793228677, 0.6903177740858685, 0.8544752061829647,\n                                         0.9373953303873518, 0.9999983130568033],\n                               3, 3], force_numpy=IS_NUMBA)\nBell_bundle_bypass_high_obj = lambda x, y: float(bisplev(x, y, Bell_bundle_bypass_high_spl))\n\n\nBell_bundle_bypass_low_spl = implementation_optimize_tck([[0.0, 0.0, 0.0, 0.0, 0.434967, 0.69532, 0.69532, 0.69532, 0.69532],\n                              [0.0, 0.0, 0.0, 0.0, 0.1, 0.16666666666666666, 0.5, 0.5, 0.5, 0.5],\n                              [1.0015970586968514, 0.9976793473578099, 1.0037098839305505, 0.9953304170745584,\n                                        1.0031587186511541, 1.00000028406872, 0.8027498596582175, 0.9050562101782131,\n                                        0.9133675590990569, 0.9611563766991582, 0.9879481797594364, 0.9999988983171519,\n                                        0.5813496854191834, 0.7520908533825839, 0.7927234268976187, 0.9090698658126287,\n                                        0.9857133220039945, 0.9999986096716597, 0.43493461007512263, 0.6478801160783917,\n                                        0.6961255921403956, 0.861432071791341, 0.9243020549338703, 0.999997894037133,\n                                        0.39110224578093694, 0.606829928454368, 0.6600680810505178, 0.8482579667665061,\n                                        0.9223728343461776, 0.9999978298360785],\n                                   3, 3], force_numpy=IS_NUMBA)\nBell_bundle_bypass_low_obj = lambda x, y : float(bisplev(x, y, Bell_bundle_bypass_low_spl))\n\n\ndef bundle_bypassing_Bell(bypass_area_fraction, seal_strips, crossflow_rows,\n                          laminar=False, method=\"spline\"):\n    r\"\"\"Calculate the bundle bypassing effect `Jb` according to the\n    Bell-Delaware method for heat exchanger design.\n    Cubic spline interpolation is the default method of retrieving a value\n    from the graph, which was digitized with Engauge-Digitizer.\n\n    The Heat Exchanger Design Handbook [4]_ provides a curve\n    fit as well. This method is not recommended, but can be used via\n    the method \"HEDH\":\n\n    .. math::\n        J_b = \\exp\\left[-1.25 F_{sbp} (1 -  {2r_{ss}}^{1/3} )\\right]\n\n    For laminar flows, replace 1.25 with 1.35.\n\n    Parameters\n    ----------\n    bypass_area_fraction : float\n        Fraction of the crossflow area which is not blocked by a baffle or\n        anything else and available for bypassing, [-]\n    seal_strips : int\n        Number of seal strips per side of a baffle added to prevent bypassing,\n        [-]\n    crossflow_rows : int\n        The number of tube rows in the crosslfow of the baffle, [-]\n    laminar : bool\n        Whether to use the turbulent correction values or the laminar ones;\n        the Bell-Delaware method uses a Re criteria of 100 for this, [-]\n    method : str, optional\n        One of 'spline', or 'HEDH'\n\n    Returns\n    -------\n    Jb : float\n        Bundle bypassing effect correction factor in the Bell-Delaware method,\n        [-]\n\n    Notes\n    -----\n    Takes ~5 us per call.\n    If the `bypass_area_fraction` parameter is larger than 0.695, it is clipped\n    to it.\n\n    Examples\n    --------\n    >>> bundle_bypassing_Bell(0.5, 5, 25)\n    0.84696117608\n\n    >>> bundle_bypassing_Bell(0.5, 5, 25, method='HEDH')\n    0.84832109705\n\n    References\n    ----------\n    .. [1] Bell, Kenneth J. Final Report of the Cooperative Research Program on\n       Shell and Tube Heat Exchangers. University of Delaware, Engineering\n       Experimental Station, 1963.\n    .. [2] Bell, Kenneth J. Delaware Method for Shell-Side Design. In Heat\n       Transfer Equipment Design, by Shah, R.  K., Eleswarapu Chinna Subbarao,\n       and R. A. Mashelkar. CRC Press, 1988.\n    .. [3] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,\n       Eighth Edition. McGraw-Hill Professional, 2007.\n    .. [4] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    \"\"\"\n    z = seal_strips/crossflow_rows\n    x = bypass_area_fraction\n    if method == \"spline\":\n        if x > Bell_bundle_bypass_x_max:\n            x = Bell_bundle_bypass_x_max\n\n        if laminar:\n            Jb = Bell_bundle_bypass_low_obj(x, z)\n        else:\n            Jb = Bell_bundle_bypass_high_obj(x, z)\n        Jb = min(Jb, 1.0)\n    elif method == \"HEDH\":\n        c = 1.35 if laminar else 1.25\n        Jb = exp(-c*x*(1.0 - (2.0*z)**(1/3.)))\n    return Jb\n\n\ndef unequal_baffle_spacing_Bell(baffles: int, baffle_spacing: float,\n                                baffle_spacing_in: float | None=None,\n                                baffle_spacing_out: float | None=None,\n                                laminar: bool=False) -> float:\n    r\"\"\"Calculate the correction factor for unequal baffle spacing `Js`,\n    which accounts for higher velocity of fluid flow and greater heat transfer\n    coefficients when the in and/or out baffle spacing is less than the\n    standard spacing.\n\n    .. math::\n        J_s = \\frac{(n_b - 1) + (B_{in}/B)^{(1-n_b)} + (B_{out}/B)^{(1-n_b)}}\n        {(n_b - 1) + (B_{in}/B) + (B_{out}/B)}\n\n    Parameters\n    ----------\n    baffles : int\n        Number of baffles, [-]\n    baffle_spacing : float\n        Average spacing between one end of one baffle to the start of\n        the next baffle for non-exit baffles, [m]\n    baffle_spacing_in : float, optional\n        Spacing between entrace to first baffle, [m]\n    baffle_spacing_out : float, optional\n        Spacing between last baffle and exit, [m]\n    laminar : bool, optional\n        Whether to use the turbulent exponent or the laminar one;\n        the Bell-Delaware method uses a Re criteria of 100 for this, [-]\n\n    Returns\n    -------\n    Js : float\n        Unequal baffle spacing correction factor, [-]\n\n    Notes\n    -----\n\n    Examples\n    --------\n    >>> unequal_baffle_spacing_Bell(16, .1, .15, 0.15)\n    0.9640087802805195\n\n    References\n    ----------\n    .. [1] Bell, Kenneth J. Final Report of the Cooperative Research Program on\n       Shell and Tube Heat Exchangers. University of Delaware, Engineering\n       Experimental Station, 1963.\n    .. [2] Bell, Kenneth J. Delaware Method for Shell-Side Design. In Heat\n       Transfer Equipment Design, by Shah, R.  K., Eleswarapu Chinna Subbarao,\n       and R. A. Mashelkar. CRC Press, 1988.\n    .. [3] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [4] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    .. [5] Hall, Stephen. Rules of Thumb for Chemical Engineers, Fifth Edition.\n       5th edition. Oxford ; Waltham , MA: Butterworth-Heinemann, 2012.\n    \"\"\"\n    if baffle_spacing_in is None:\n        baffle_spacing_in = baffle_spacing\n    if baffle_spacing_out is None:\n        baffle_spacing_out = baffle_spacing\n    n = 1.0/3.0 if laminar else 0.6\n    Js = ((baffles - 1.0) + (baffle_spacing_in/baffle_spacing)**(1.0 - n)\n          + (baffle_spacing_out/baffle_spacing)**(1.0 - n))/((baffles - 1.0)\n          + (baffle_spacing_in/baffle_spacing)\n          + (baffle_spacing_out/baffle_spacing))\n    return Js\n\n\ndef laminar_correction_Bell(Re: float, total_row_passes: int) -> float:\n    r\"\"\"Calculate the correction factor for adverse temperature gradient built\n    up in laminar flow `Jr`.\n\n    This correction begins at Re = 100, and is interpolated between the value\n    of the formula until Re = 20, when it is the value of the formula. It is\n    1 for Re >= 100. The value of the formula is not allowed to be less than\n    0.4.\n\n    .. math::\n        Jr^* = \\left(\\frac{10}{N_{row,passes,tot}}\\right)^{0.18}\n\n    Parameters\n    ----------\n    Re : float\n        Shell Reynolds number in the Bell-Delaware method, [-]\n    total_row_passes : int\n        The total number of rows passed by the fluid, including those in\n        windows and counting repeat passes of tube rows, [-]\n\n    Returns\n    -------\n    Jr : float\n        Correction factor for adverse temperature gradient built up in laminar\n        flow, [-]\n\n    Notes\n    -----\n    [5]_ incorrectly uses the number of tube rows per crosslfow section, not\n    total.\n\n    Examples\n    --------\n    >>> laminar_correction_Bell(30, 80)\n    0.7267995454361379\n\n    References\n    ----------\n    .. [1] Bell, Kenneth J. Final Report of the Cooperative Research Program on\n       Shell and Tube Heat Exchangers. University of Delaware, Engineering\n       Experimental Station, 1963.\n    .. [2] Bell, Kenneth J. Delaware Method for Shell-Side Design. In Heat\n       Transfer Equipment Design, by Shah, R.  K., Eleswarapu Chinna Subbarao,\n       and R. A. Mashelkar. CRC Press, 1988.\n    .. [3] Schlünder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1987.\n    .. [4] Serth, R. W., Process Heat Transfer: Principles,\n       Applications and Rules of Thumb. 2E. Amsterdam: Academic Press, 2014.\n    .. [5] Hall, Stephen. Rules of Thumb for Chemical Engineers, Fifth Edition.\n       5th edition. Oxford ; Waltham , MA: Butterworth-Heinemann, 2012.\n    \"\"\"\n    if Re > 100.0:\n        return 1.0\n    Jrr = (10.0/total_row_passes)**0.18\n    if Re < 20.0:\n        Jr = Jrr\n    else:\n        Jr = Jrr + ((20.0-Re)/80.0)*(Jrr - 1.0)\n    if Jr < 0.4:\n        Jr = 0.4\n    return Jr\n"
  },
  {
    "path": "ht/conv_two_phase.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import pi\n\nfrom fluids.core import Prandtl, Reynolds\n\nfrom ht.conv_internal import laminar_entry_Seider_Tate\n\n__all__: list[str] = [\n    \"Aggour\",\n    \"Davis_David\",\n    \"Elamvaluthi_Srinivas\",\n    \"Groothuis_Hendal\",\n    \"Hughmark\",\n    \"Knott\",\n    \"Kudirka_Grosh_McFadden\",\n    \"Martin_Sims\",\n    \"Ravipudi_Godbold\",\n    \"h_two_phase\",\n    \"h_two_phase_methods\",\n]\n\n\ndef Davis_David(m: float, x: float, D: float, rhol: float, rhog: float, Cpl: float, kl: float, mul: float) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        \\frac{h_{TP} D}{k_l} = 0.060\\left(\\frac{\\rho_L}{\\rho_G}\\right)^{0.28}\n        \\left(\\frac{DG_{TP} x}{\\mu_L}\\right)^{0.87}\n        \\left(\\frac{C_{p,L} \\mu_L}{k_L}\\right)^{0.4}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mul : float\n        Viscosity of liquid [Pa*s]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Developed for both vertical and horizontal flow, and flow patters of\n    annular or mist annular flow. Steam-water and air-water were the only\n    considered fluid combinations. Quality ranged from 0.1 to 1 in their data.\n    [1]_ claimed an AAE of 17%.\n\n    Examples\n    --------\n    >>> Davis_David(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300, kl=.6,\n    ... mul=1E-3)\n    1437.3282869955121\n\n    References\n    ----------\n    .. [1] Davis, E. J., and M. M. David. \"Two-Phase Gas-Liquid Convection Heat\n       Transfer. A Correlation.\" Industrial & Engineering Chemistry\n       Fundamentals 3, no. 2 (May 1, 1964): 111-18. doi:10.1021/i160010a005.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    G = m/(pi/4*D**2)\n    Prl = Prandtl(Cp=Cpl, mu=mul, k=kl)\n    Nu_TP = 0.060*(rhol/rhog)**0.28*(D*G*x/mul)**0.87*Prl**0.4\n    return Nu_TP*kl/D\n\n\ndef Elamvaluthi_Srinivas(m: float, x: float, D: float, rhol: float, rhog: float, Cpl: float, kl: float, mug: float, mu_b: float, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        \\frac{h_{TP} D}{k_L} = 0.5\\left(\\frac{\\mu_G}{\\mu_L}\\right)^{0.25}\n        Re_M^{0.7} Pr^{1/3}_L (\\mu_b/\\mu_w)^{0.14}\n\n    .. math::\n        Re_M = \\frac{D V_L \\rho_L}{\\mu_L} + \\frac{D V_g \\rho_g}{\\mu_g}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mug : float\n        Viscosity of gas [Pa*s]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Developed for vertical flow, and flow patters of bubbly and slug.\n    Gas/liquid superficial velocity ratios from 0.3 to 4.6, liquid mass fluxes\n    from 200 to 1600 kg/m^2/s, and the fluids tested were air-water and\n    air-aqueous glycerine solutions. The tube inner diameter was 1 cm, and the\n    L/D ratio was 86.\n\n    Examples\n    --------\n    >>> Elamvaluthi_Srinivas(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300,\n    ... kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    3901.2134471578584\n\n    References\n    ----------\n    .. [1] Elamvaluthi, G., and N. S. Srinivas. \"Two-Phase Heat Transfer in Two\n       Component Vertical Flows.\" International Journal of Multiphase Flow 10,\n       no. 2 (April 1, 1984): 237-42. doi:10.1016/0301-9322(84)90021-1.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vg = m*x/(rhog*pi/4*D**2)\n    Vl = m*(1-x)/(rhol*pi/4*D**2)\n\n    Prl = Prandtl(Cp=Cpl, mu=mu_b, k=kl)\n    ReM = D*Vl*rhol/mu_b + D*Vg*rhog/mug\n    Nu_TP = 0.5*(mug/mu_b)**0.25*ReM**0.7*Prl**(1/3.)\n    if mu_w:\n        Nu_TP *= (mu_b/mu_w)**0.14\n    return Nu_TP*kl/D\n\n\ndef Groothuis_Hendal(m: float, x: float, D: float, rhol: float, rhog: float, Cpl: float, kl: float, mug: float, mu_b: float, mu_w: float | None=None,\n                     water: bool=False) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        Re_M = \\frac{D V_{ls} \\rho_l}{\\mu_l} + \\frac{D V_{gs} \\rho_g}{\\mu_g}\n\n    For the air-water system:\n\n    .. math::\n        \\frac{h_{TP} D}{k_L} = 0.029 Re_M^{0.87}Pr^{1/3}_l (\\mu_b/\\mu_w)^{0.14}\n\n    For gas/air-oil systems (default):\n\n    .. math::\n        \\frac{h_{TP} D}{k_L} = 2.6 Re_M^{0.39}Pr^{1/3}_l (\\mu_b/\\mu_w)^{0.14}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mug : float\n        Viscosity of gas [Pa*s]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    water : bool, optional\n        Whether to use the water-air correlation or the gas/air-oil correlation\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Developed for vertical pipes, with superficial velocity ratios of 0.6-250.\n    Tested fluids were air-water, and gas/air-oil.\n\n    Examples\n    --------\n    >>> Groothuis_Hendal(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300, kl=.6,\n    ... mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    1192.9543445455754\n\n    References\n    ----------\n    .. [1] Groothuis, H., and W. P. Hendal. \"Heat Transfer in Two-Phase Flow.:\n       Chemical Engineering Science 11, no. 3 (November 1, 1959): 212-20.\n       doi:10.1016/0009-2509(59)80089-0.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vg = m*x/(rhog*pi/4*D**2)\n    Vl = m*(1-x)/(rhol*pi/4*D**2)\n\n    Prl = Prandtl(Cp=Cpl, mu=mu_b, k=kl)\n    ReM = D*Vl*rhol/mu_b + D*Vg*rhog/mug\n\n    if water:\n        Nu_TP = 0.029*(ReM)**0.87*(Prl)**(1/3.)\n    else:\n        Nu_TP = 2.6*ReM**0.39*Prl**(1/3.)\n    if mu_w:\n        Nu_TP *= (mu_b/mu_w)**0.14\n    return Nu_TP*kl/D\n\n\ndef Hughmark(m: float, x: float, alpha: float, D: float, L: float, Cpl: float, kl: float, mu_b: float | None=None, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling laminar heat transfer coefficient\n    of a liquid and gas flowing inside a tube of any inclination, as in [1]_\n    and reviewed in [2]_.\n\n    .. math::\n        \\frac{h_{TP} D}{k_l} = 1.75(1-\\alpha)^{-0.5}\\left(\\frac{m_l C_{p,l}}\n        {(1-\\alpha)k_l L}\\right)^{1/3}\\left(\\frac{\\mu_b}{\\mu_w}\\right)^{0.14}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    alpha : float\n        Void fraction in the tube, []\n    D : float\n        Diameter of the tube [m]\n    L : float\n        Length of the tube, [m]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    This model is based on a laminar entry length correlation - for a\n    sufficiently long tube, this will predict unrealistically low heat transfer\n    coefficients.\n\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Developed for horizontal pipes in laminar slug flow. Data consisted of the\n    systems air-water, air-SAE 10 oil, gas-oil, air-diethylene glycol, and\n    air-aqueous glycerine.\n\n    Examples\n    --------\n    >>> Hughmark(m=1, x=.9, alpha=.9, D=.3, L=.5, Cpl=2300, kl=0.6, mu_b=1E-3,\n    ... mu_w=1.2E-3)\n    212.7411636127175\n\n    References\n    ----------\n    .. [1] Hughmark, G. A. \"Holdup and Heat Transfer in Horizontal Slug Gas-\n       Liquid Flow.\" Chemical Engineering Science 20, no. 12 (December 1,\n       1965): 1007-10. doi:10.1016/0009-2509(65)80101-4.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    ml = m*(1-x)\n    RL = 1-alpha\n    Nu_TP = 1.75*(RL)**-0.5*(ml*Cpl/RL/kl/L)**(1/3.)\n    if mu_b and mu_w:\n        Nu_TP *= (mu_b/mu_w)**0.14\n    return Nu_TP*kl/D\n\n\ndef Knott(m: float, x: float, D: float, rhol: int, rhog: float, Cpl: float | None=None, kl: float | None=None, mu_b: float | None=None, mu_w: float | None=None, L: float | None=None,\n          hl: None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    Either a specified `hl` is required, or `Cpl`, `kl`, `mu_b`, `mu_w` and\n    `L` are required to calculate `hl`.\n\n    .. math::\n        \\frac{h_{TP}}{h_l} = \\left(1 + \\frac{V_{gs}}{V_{ls}}\\right)^{1/3}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float, optional\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float, optional\n        Thermal conductivity of liquid [W/m/K]\n    mu_b : float, optional\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    L : float, optional\n        Length of the tube [m]\n    hl : float, optional\n        Liquid-phase heat transfer coefficient as described below, [W/m^2/K]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    The liquid-only heat transfer coefficient will be calculated with the\n    `laminar_entry_Seider_Tate` correlation, should it not be provided as an\n    input. Many of the arguments to this function are optional and are only\n    used if `hl` is not provided.\n\n    `hl` should be calculated with a velocity equal to that determined with\n    a combined volumetric flow of both the liquid and the gas. All other\n    parameters used in calculating the heat transfer coefficient are those\n    of the liquid. If the viscosity at the wall temperature is not given, the\n    liquid viscosity correction in `laminar_entry_Seider_Tate` is not applied.\n\n    Examples\n    --------\n    >>> Knott(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300, kl=.6, mu_b=1E-3,\n    ... mu_w=1.2E-3, L=4)\n    4225.536758045839\n\n    References\n    ----------\n    .. [1] Knott, R. F., R. N. Anderson, Andreas. Acrivos, and E. E. Petersen.\n       \"An Experimental Study of Heat Transfer to Nitrogen-Oil Mixtures.\"\n       Industrial & Engineering Chemistry 51, no. 11 (November 1, 1959):\n       1369-72. doi:10.1021/ie50599a032.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vgs = m*x/(rhog*pi/4*D**2)\n    Vls = m*(1-x)/(rhol*pi/4*D**2)\n    if not hl:\n        V = Vgs + Vls # Net velocity\n        Re = Reynolds(V=V, D=D, rho=rhol, mu=mu_b)\n        Pr = Prandtl(Cp=Cpl, k=kl, mu=mu_b)\n        Nul = laminar_entry_Seider_Tate(Re=Re, Pr=Pr, L=L, Di=D, mu=mu_b, mu_w=mu_w)\n        hl = Nul*kl/D\n    return hl*(1 + Vgs/Vls)**(1/3.)\n\n\ndef Kudirka_Grosh_McFadden(m: float, x: float, D: float, rhol: float, rhog: float, Cpl: float, kl: float, mug: float, mu_b: float, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        Nu = \\frac{h_{TP} D}{k_l} = 125 \\left(\\frac{V_{gs}}{V_{ls}}\n        \\right)^{0.125}\\left(\\frac{\\mu_g}{\\mu_l}\\right)^{0.6} Re_{ls}^{0.25}\n        Pr_l^{1/3}\\left(\\frac{\\mu_b}{\\mu_w}\\right)^{0.14}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mug : float\n        Viscosity of gas [Pa*s]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Developed for air-water and air-ethylene glycol systems with a L/D of 17.6\n    and at low gas-liquid ratios. The flow regimes studied were bubble, slug,\n    and froth flow.\n\n    Examples\n    --------\n    >>> Kudirka_Grosh_McFadden(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300,\n    ... kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    303.9941255903587\n\n    References\n    ----------\n    .. [1] Kudirka, A. A., R. J. Grosh, and P. W. McFadden. \"Heat Transfer in\n       Two-Phase Flow of Gas-Liquid Mixtures.\" Industrial & Engineering\n       Chemistry Fundamentals 4, no. 3 (August 1, 1965): 339-44.\n       doi:10.1021/i160015a018.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vgs = m*x/(rhog*pi/4*D**2)\n    Vls = m*(1-x)/(rhol*pi/4*D**2)\n    Prl = Prandtl(Cp=Cpl, mu=mu_b, k=kl)\n    Rels = D*Vls*rhol/mu_b\n    Nu = 125*(Vgs/Vls)**0.125*(mug/mu_b)**0.6*Rels**0.25*Prl**(1/3.)\n    if mu_w:\n        Nu *= (mu_b/mu_w)**0.14\n    return Nu*kl/D\n\n\ndef Martin_Sims(m: float, x: float, D: float, rhol: float, rhog: float, hl: float | None=None,\n                Cpl: float | None=None, kl: float | None=None, mu_b: float | None=None, mu_w: float | None=None, L: float | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        \\frac{h_{TP}}{h_l} = 1 + 0.64\\sqrt{\\frac{V_{gs}}{V_{ls}}}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval []\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    hl : float, optional\n        Liquid-phase heat transfer coefficient as described below, [W/m^2/K]\n    Cpl : float, optional\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float, optional\n        Thermal conductivity of liquid [W/m/K]\n    mu_b : float, optional\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    L : float, optional\n        Length of the tube [m]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    No specific suggestion for how to calculate the liquid-phase heat transfer\n    coefficient is given in [1]_; [2]_ suggests to use the same procedure as\n    in `Knott`.\n\n    Examples\n    --------\n    >>> Martin_Sims(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, hl=141.2)\n    5563.280000000001\n    >>> Martin_Sims(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300, kl=.6,\n    ... mu_b=1E-3, mu_w=1.2E-3, L=24)\n    5977.505465781747\n\n    References\n    ----------\n    .. [1] Martin, B. W, and G. E Sims. \"Forced Convection Heat Transfer to\n       Water with Air Injection in a Rectangular Duct.\" International Journal\n       of Heat and Mass Transfer 14, no. 8 (August 1, 1971): 1115-34.\n       doi:10.1016/0017-9310(71)90208-0.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vgs = m*x/(rhog*pi/4*D**2)\n    Vls = m*(1-x)/(rhol*pi/4*D**2)\n    if hl is None:\n        V = Vgs + Vls # Net velocity\n        Re = Reynolds(V=V, D=D, rho=rhol, mu=mu_b)\n        Pr = Prandtl(Cp=Cpl, k=kl, mu=mu_b)\n        Nul = laminar_entry_Seider_Tate(Re=Re, Pr=Pr, L=L, Di=D, mu=mu_b, mu_w=mu_w)\n        hl = Nul*kl/D\n    return hl*(1.0 + 0.64*(Vgs/Vls)**0.5)\n\n\ndef Ravipudi_Godbold(m: float, x: float, D: float, rhol: float, rhog: float, Cpl: float, kl: float, mug: float, mu_b: float, mu_w: float | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling heat transfer coefficient of a\n    liquid and gas flowing inside a tube of any inclination, as in [1]_ and\n    reviewed in [2]_.\n\n    .. math::\n        Nu = \\frac{h_{TP} D}{k_l} = 0.56 \\left(\\frac{V_{gs}}{V_{ls}}\n        \\right)^{0.3}\\left(\\frac{\\mu_g}{\\mu_l}\\right)^{0.2} Re_{ls}^{0.6}\n        Pr_l^{1/3}\\left(\\frac{\\mu_b}{\\mu_w}\\right)^{0.14}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    rhog : float\n        Density of the gas [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mug : float\n        Viscosity of gas [Pa*s]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Developed with a vertical pipe, superficial gas/liquid velocity ratios of\n    1-90, in the froth regime, and for fluid mixtures of air and water,\n    toluene, benzene, and methanol.\n\n    Examples\n    --------\n    >>> Ravipudi_Godbold(m=1, x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300, kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    299.3796286459285\n\n    References\n    ----------\n    .. [1] Ravipudi, S., and Godbold, T., The Effect of Mass Transfer on Heat\n       Transfer Rates for Two-Phase Flow in a Vertical Pipe, Proceedings 6th\n       International Heat Transfer Conference, Toronto, V. 1, p. 505-510, 1978.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vgs = m*x/(rhog*pi/4*D**2)\n    Vls = m*(1-x)/(rhol*pi/4*D**2)\n    Prl = Prandtl(Cp=Cpl, mu=mu_b, k=kl)\n    Rels = D*Vls*rhol/mu_b\n    Nu = 0.56*(Vgs/Vls)**0.3*(mug/mu_b)**0.2*Rels**0.6*Prl**(1/3.)\n    if mu_w is not None:\n        Nu *= (mu_b/mu_w)**0.14\n    return Nu*kl/D\n\n\ndef Aggour(m: float, x: float, alpha: float, D: float, rhol: float, Cpl: float, kl: float, mu_b: float, mu_w: float | None=None, L: float | None=None,\n           turbulent: None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling laminar heat transfer coefficient\n    of a liquid and gas flowing inside a tube of any inclination, as in [1]_\n    and reviewed in [2]_.\n\n    Laminar for Rel <= 2000:\n\n    .. math::\n        h_{TP} = 1.615\\frac{k_l}{D}\\left(\\frac{Re_l Pr_l D}{L}\\right)^{1/3}\n        \\left(\\frac{\\mu_b}{\\mu_w}\\right)^{0.14}\n\n    Turbulent for Rel > 2000:\n\n    .. math::\n        h_{TP} = 0.0155\\frac{k_l}{D} Pr_l^{0.5} Re_l^{0.83}\n\n    .. math::\n        Re_l = \\frac{\\rho_l v_l D}{\\mu_l}\n\n    .. math::\n        V_l = \\frac{V_{ls}}{1-\\alpha}\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    alpha : float\n        Void fraction in the tube, [-]\n    D : float\n        Diameter of the tube [m]\n    rhol : float\n        Density of the liquid [kg/m^3]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    mu_b : float\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    L : float, optional\n        Length of the tube, [m]\n    turbulent : bool or None, optional\n        Whether or not to force the correlation to return the turbulent\n        result; will return the laminar regime if False\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    Developed with mixtures of air-water, helium-water, and freon-12-water and\n    vertical tests. Studied flow patterns were bubbly, slug, annular,\n    bubbly-slug, and slug-annular regimes. Superficial velocity ratios ranged\n    from 0.02 to 470.\n\n    A viscosity correction is only suggested for the laminar regime.\n    If the viscosity at the wall temperature is not given, the liquid viscosity\n    correction is not applied.\n\n    Examples\n    --------\n    >>> Aggour(m=1, x=.9, D=.3, alpha=.9, rhol=1000, Cpl=2300, kl=.6, mu_b=1E-3)\n    420.9347146885667\n\n    References\n    ----------\n    .. [1] Aggour, Mohamed A. Hydrodynamics and Heat Transfer in Two-Phase\n       Two-Component Flows, Ph.D. Thesis, University of Manutoba, Canada\n       (1978). http://mspace.lib.umanitoba.ca/xmlui/handle/1993/14171.\n    .. [2] Dongwoo Kim, Venkata K. Ryali, Afshin J. Ghajar, Ronald L.\n       Dougherty. \"Comparison of 20 Two-Phase Heat Transfer Correlations with\n       Seven Sets of Experimental Data, Including Flow Pattern and Tube\n       Inclination Effects.\" Heat Transfer Engineering 20, no. 1 (February 1,\n       1999): 15-40. doi:10.1080/014576399271691.\n    \"\"\"\n    Vls = m*(1-x)/(rhol*pi/4*D**2)\n    Vl = Vls/(1.-alpha)\n\n    Prl = Prandtl(Cp=Cpl, k=kl, mu=mu_b)\n    Rel = Reynolds(V=Vl, D=D, rho=rhol, mu=mu_b)\n\n    if turbulent or (Rel > 2000.0 and turbulent is None):\n        hl = 0.0155*(kl/D)*Rel**0.83*Prl**0.5\n        return hl*(1-alpha)**-0.83\n    else:\n        hl = 1.615*(kl/D)*(Rel*Prl*D/L)**(1/3.)\n        if mu_w:\n            hl *= (mu_b/mu_w)**0.14\n        return hl*(1.0 - alpha)**(-1/3.)\n\n\nconv_two_phase_methods = {\n    \"Davis-David\": (Davis_David, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mul\")),\n    \"Elamvaluthi_Srinivas\": (Elamvaluthi_Srinivas, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mug\", \"mu_b\", \"mu_w\")),\n    \"Groothuis_Hendal\": (Groothuis_Hendal, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mug\", \"mu_b\", \"mu_w\")),\n    \"Hughmark\": (Hughmark, (\"m\", \"x\", \"alpha\", \"D\", \"L\", \"Cpl\", \"kl\", \"mu_b\", \"mu_w\")),\n    \"Knott\": (Knott, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mu_b\", \"mu_w\", \"L\")),\n    \"Kudirka_Grosh_McFadden\": (Kudirka_Grosh_McFadden, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mug\", \"mu_b\", \"mu_w\")),\n    \"Martin_Sims\": (Martin_Sims, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mu_b\", \"mu_w\", \"L\")),\n    \"Ravipudi_Godbold\": (Ravipudi_Godbold, (\"m\", \"x\", \"D\", \"rhol\", \"rhog\", \"Cpl\", \"kl\", \"mug\", \"mu_b\", \"mu_w\")),\n    \"Aggour\": (Aggour, (\"m\", \"x\", \"alpha\", \"D\", \"rhol\", \"Cpl\", \"kl\", \"mu_b\", \"mu_w\", \"L\")),\n}\n\n# Not actually ranked\nconv_two_phase_methods_ranked = [\"Knott\", \"Martin_Sims\", \"Kudirka_Grosh_McFadden\", \"Groothuis_Hendal\",\n                                 \"Aggour\", \"Hughmark\", \"Elamvaluthi_Srinivas\", \"Davis-David\", \"Ravipudi_Godbold\"]\n\nconv_two_phase_bad_method = f\"Correlation name not recognized; the availble methods are {list(conv_two_phase_methods.keys())}.\"\n\"\"\"Generating code:\nfor m in conv_two_phase_methods_ranked:\n    (f_obj, args) = conv_two_phase_methods[m]\n    print('elif method2 == \"%s\":' %(m))\n    t = '    return %s(' %f_obj.__name__\n    for ar in args:\n        t += '%s=%s, ' %(ar, ar)\n    t = t[:-2] + ')'\n    print(t)\n\nfor m in conv_two_phase_methods_ranked:\n    (f_obj, args) = conv_two_phase_methods[m]\n    t = 'if '\n    for ar in args:\n        if ar not in ('m', 'x', 'D', 'Cpl', 'kl'):\n            t += '%s is not None and ' %(ar)\n    t = t[:-5] + ':'\n\n    print(t)\n    print('    methods.append(\"%s\")' %m)\n\"\"\"\n\ndef h_two_phase_methods(m, x, D, Cpl, kl, rhol=None, rhog=None, mul=None,\n                        mu_b=None, mu_w=None, mug=None, L=None, alpha=None,\n                        check_ranges=True):\n    r\"\"\"Returns a list of correlation names for the case of two-phase\n    non-boiling liquid-gas laminar flow heat transfer inside a tube.\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    rhog : float, optional\n        Density of the gas [kg/m^3]\n    mul : float, optional\n        Viscosity of liquid [Pa*s]\n    mu_b : float, optional\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    mug : float, optional\n        Viscosity of gas [Pa*s]\n    L : float, optional\n        Length of the tube, [m]\n    alpha : float, optional\n        Void fraction in the tube, [-]\n    check_ranges : bool, optional\n        Whether or not to return only correlations suitable for the provided\n        data, [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Notes\n    -----\n    A review of the correlations for which has the best performance has not\n    been performed.\n\n    Examples\n    --------\n    >>> h_two_phase_methods(m=1, x=.9, D=.3, alpha=.9, rhol=1000, Cpl=2300, kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=5)[0]\n    'Aggour'\n    \"\"\"\n    methods = []\n    if rhol is not None and rhog is not None and mu_b is not None and mu_w is not None and L is not None:\n        methods.append(\"Knott\")\n    if rhol is not None and rhog is not None and mu_b is not None and mu_w is not None and L is not None:\n        methods.append(\"Martin_Sims\")\n    if rhol is not None and rhog is not None and mug is not None and mu_b is not None and mu_w is not None:\n        methods.append(\"Kudirka_Grosh_McFadden\")\n    if rhol is not None and rhog is not None and mug is not None and mu_b is not None and mu_w is not None:\n        methods.append(\"Groothuis_Hendal\")\n    if alpha is not None and rhol is not None and mu_b is not None and mu_w is not None and L is not None:\n        methods.append(\"Aggour\")\n    if alpha is not None and L is not None and mu_b is not None and mu_w is not None:\n        methods.append(\"Hughmark\")\n    if rhol is not None and rhog is not None and mug is not None and mu_b is not None and mu_w is not None:\n        methods.append(\"Elamvaluthi_Srinivas\")\n    if rhol is not None and rhog is not None and mul is not None:\n        methods.append(\"Davis-David\")\n    if rhol is not None and rhog is not None and mug is not None and mu_b is not None and mu_w is not None:\n        methods.append(\"Ravipudi_Godbold\")\n    return methods\n\n\ndef h_two_phase(m: float, x: float, D: float, Cpl: float, kl: float, rhol: float | None=None, rhog: None=None, mul: None=None,\n                mu_b: float | None=None, mu_w: float | None=None, mug: None=None, L: float | None=None, alpha: float | None=None,\n                method: str | None=None) -> float:\n    r\"\"\"Calculates the two-phase non-boiling laminar heat transfer coefficient\n    of a liquid and gas flowing inside a tube according to the specified\n    method. Nine methods are available.\n\n\n    Parameters\n    ----------\n    m : float\n        Mass flow rate [kg/s]\n    x : float\n        Quality at the specific tube interval [-]\n    D : float\n        Diameter of the tube [m]\n    Cpl : float\n        Constant-pressure heat capacity of liquid [J/kg/K]\n    kl : float\n        Thermal conductivity of liquid [W/m/K]\n    rhol : float, optional\n        Density of the liquid [kg/m^3]\n    rhog : float, optional\n        Density of the gas [kg/m^3]\n    mul : float, optional\n        Viscosity of liquid [Pa*s]\n    mu_b : float, optional\n        Viscosity of liquid at bulk conditions (average of inlet/outlet\n        temperature) [Pa*s]\n    mu_w : float, optional\n        Viscosity of liquid at wall temperature [Pa*s]\n    mug : float, optional\n        Viscosity of gas [Pa*s]\n    L : float, optional\n        Length of the tube, [m]\n    alpha : float, optional\n        Void fraction in the tube, [-]\n\n    Returns\n    -------\n    h : float\n        Heat transfer coefficient [W/m^2/K]\n\n    Other Parameters\n    ----------------\n    method : string, optional\n        A string of the function name to use, as in the dictionary\n        conv_two_phase_methods.\n\n    Notes\n    -----\n    It is difficult to compare correlations.\n\n    Examples\n    --------\n    >>> h_two_phase(m=1, x=.9, D=.3, alpha=.9, rhol=1000, Cpl=2300, kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=5, method='Aggour')\n    420.9347146885667\n    \"\"\"\n    if method is None:\n        method2 = h_two_phase_methods(m=m, x=x, D=D, Cpl=Cpl, kl=kl, rhol=rhol, rhog=rhog, mul=mul, mu_b=mu_b, mu_w=mu_w, mug=mug, L=L, alpha=alpha, check_ranges=True)[0]\n    else:\n        method2 = method\n\n    if method2 == \"Knott\":\n        return Knott(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mu_b=mu_b, mu_w=mu_w, L=L)\n    elif method2 == \"Martin_Sims\":\n        return Martin_Sims(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mu_b=mu_b, mu_w=mu_w, L=L)\n    elif method2 == \"Kudirka_Grosh_McFadden\":\n        return Kudirka_Grosh_McFadden(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mug=mug, mu_b=mu_b, mu_w=mu_w)\n    elif method2 == \"Groothuis_Hendal\":\n        return Groothuis_Hendal(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mug=mug, mu_b=mu_b, mu_w=mu_w)\n    elif method2 == \"Aggour\":\n        return Aggour(m=m, x=x, alpha=alpha, D=D, rhol=rhol, Cpl=Cpl, kl=kl, mu_b=mu_b, mu_w=mu_w, L=L)\n    elif method2 == \"Hughmark\":\n        return Hughmark(m=m, x=x, alpha=alpha, D=D, L=L, Cpl=Cpl, kl=kl, mu_b=mu_b, mu_w=mu_w)\n    elif method2 == \"Elamvaluthi_Srinivas\":\n        return Elamvaluthi_Srinivas(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mug=mug, mu_b=mu_b, mu_w=mu_w)\n    elif method2 == \"Davis-David\":\n        return Davis_David(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mul=mul)\n    elif method2 == \"Ravipudi_Godbold\":\n        return Ravipudi_Godbold(m=m, x=x, D=D, rhol=rhol, rhog=rhog, Cpl=Cpl, kl=kl, mug=mug, mu_b=mu_b, mu_w=mu_w)\n    else:\n        raise ValueError(conv_two_phase_bad_method)\n"
  },
  {
    "path": "ht/core.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nfrom math import log\n\nfrom fluids.numerics import i0, i1, k0, k1\n\n__all__: list[str] = [\n    \"LMTD\",\n    \"Kays_Crawford_laminar_gas_Nu\",\n    \"Kays_Crawford_laminar_gas_fd\",\n    \"Kays_Crawford_laminar_liquid_Nu\",\n    \"Kays_Crawford_laminar_liquid_fd\",\n    \"Kays_Crawford_turbulent_gas_Nu\",\n    \"Kays_Crawford_turbulent_gas_fd\",\n    \"Kays_Crawford_turbulent_liquid_Nu\",\n    \"Kays_Crawford_turbulent_liquid_fd\",\n    \"countercurrent_hx_temperature_check\",\n    \"fin_efficiency_Kern_Kraus\",\n    \"is_heating_property\",\n    \"is_heating_temperature\",\n    \"wall_factor\",\n    \"wall_factor_Nu\",\n    \"wall_factor_fd\",\n]\n\ndef LMTD(Thi: float, Tho: float, Tci: float, Tco: float, counterflow: bool=True) -> float:\n    r\"\"\"Returns the log-mean temperature difference of an ideal counterflow\n    or co-current heat exchanger.\n\n    .. math::\n        \\Delta T_{LMTD}=\\frac{\\Delta T_1-\\Delta T_2}{\\ln(\\Delta T_1/\\Delta T_2)}\n\n    .. math::\n        \\text{For countercurrent:      } \\\\\n        \\Delta T_1=T_{h,i}-T_{c,o}\\\\\n        \\Delta T_2=T_{h,o}-T_{c,i}\n\n    .. math::\n        \\text{Parallel Flow Only:} \\\\\n        {\\Delta T_1=T_{h,i}-T_{c,i}}\\\\\n        {\\Delta T_2=T_{h,o}-T_{c,o}}\n\n    Parameters\n    ----------\n    Thi : float\n        Inlet temperature of hot fluid, [K]\n    Tho : float\n        Outlet temperature of hot fluid, [K]\n    Tci : float\n        Inlet temperature of cold fluid, [K]\n    Tco : float\n        Outlet temperature of cold fluid, [K]\n    counterflow : bool, optional\n        Whether the exchanger is counterflow or co-current\n\n    Returns\n    -------\n    LMTD : float\n        Log-mean temperature difference [K]\n\n    Notes\n    -----\n    Any consistent set of units produces a consistent output.\n\n    For the case where the temperature difference is the same in counterflow,\n    the arithmeric mean difference (either difference in that case) is the\n    correct result following evaluation of the limit.\n\n    For the same problem with the co-current case, the limit evaluates to a\n    temperature difference of zero.\n\n    Examples\n    --------\n    Example 11.1 in [1]_.\n\n    >>> LMTD(100., 60., 30., 40.2)\n    43.200409294131525\n    >>> LMTD(100., 60., 30., 40.2, counterflow=False)\n    39.75251118049003\n    >>> LMTD(100., 60., 20., 60)\n    40.0\n    >>> LMTD(100., 60., 20., 60, counterflow=False)\n    0.0\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    if counterflow:\n        dTF1 = Thi-Tco\n        dTF2 = Tho-Tci\n    else:\n        dTF1 = Thi-Tci\n        dTF2 = Tho-Tco\n\n    ratio = dTF2/dTF1\n    if not counterflow and (ratio <= 0.0 or ratio == 1.0):\n        return 0.0\n    elif counterflow and (ratio <= 0.0 or ratio == 1.0):\n        return dTF1\n    else:\n        return (dTF2 - dTF1)/log(dTF2/dTF1)\n\ndef countercurrent_hx_temperature_check(T0i, T0o, T1i, T1o):\n    r\"\"\"Perform a check on two sets of temperatures that could represent\n    a countercurrent heat exchanger, and return whether they are possible or\n    not.\n\n    Parameters\n    ----------\n    T0i : float\n        Inlet temperature of one fluid, [K]\n    T0o : float\n        Outlet temperature of one fluid, [K]\n    T1i : float\n        Inlet temperature of another fluid, [K]\n    T1o : float\n        Outlet temperature of another fluid, [K]\n\n    Returns\n    -------\n    plausible : bool\n        Whether the exchange is possilble, [-]\n\n    Notes\n    -----\n\n    Examples\n    --------\n\n    \"\"\"\n    if T0i > T1i:\n        Thi, Tho = T0i, T0o\n        Tci, Tco = T1i, T1o\n    else:\n        Thi, Tho = T1i, T1o\n        Tci, Tco = T0i, T0o\n    if Thi < Tho:\n        return False\n    return not Tci > Tco\n\n\ndef is_heating_temperature(T: int, T_wall: int) -> bool:\n    r\"\"\"Checks whether or not a fluid side is being heated or cooled, from\n    the temperature of the wall and the bulk temperature. Returns True for\n    heating the bulk fluid, and False for cooling the bulk fluid.\n\n    Parameters\n    ----------\n    T : float\n        Temperature of flowing fluid away from the heat transfer surface, [K]\n    T_wall : float\n        Temperature of the fluid at the wall, [K]\n\n    Returns\n    -------\n    is_heating : bool\n        Whether or not the flow is being heated up by the wall, [-]\n\n    Examples\n    --------\n    >>> is_heating_temperature(298.15, 350)\n    True\n    \"\"\"\n    return T_wall > T\n\ndef is_heating_property(prop: float, prop_wall: float) -> bool:\n    r\"\"\"Checks whether or not a fluid side is being heated or cooled, from\n    a property of the fluid at the wall and the bulk temperature. Returns True\n    for heating the bulk fluid, and False for cooling the bulk fluid.\n\n    Parameters\n    ----------\n    prop : float\n        Viscosity (or Prandtl number) of flowing fluid away from the heat\n        transfer surface, [Pa*s]\n    prop_wall : float\n        Viscosity (or Prandtl number) of the fluid at the wall, [Pa*s]\n\n    Returns\n    -------\n    is_heating : bool\n        Whether or not the flow is being heated up by the wall, [-]\n\n    Examples\n    --------\n    >>> is_heating_property(1E-3, 1.2E-3)\n    False\n    \"\"\"\n    return prop_wall < prop\n\n\nWALL_FACTOR_VISCOSITY = \"Viscosity\"\nWALL_FACTOR_PRANDTL = \"Prandtl\"\nWALL_FACTOR_TEMPERATURE = \"Temperature\"\nWALL_FACTOR_DEFAULT = \"Default\"\n\n# All powers were originally for (wall/bulk)^power, but have been negated here.\n\n# Results for Deissler\n# -0.11 is also an option from another presented correlation\nKays_Crawford_laminar_liquid_Nu = {\"mu_heating_coeff\": 0.14,\n                                   \"mu_cooling_coeff\": 0.14,\n                                   \"property_option\": WALL_FACTOR_VISCOSITY}\n\nKays_Crawford_laminar_liquid_fd = {\"mu_heating_coeff\": -0.58,\n                                   \"mu_cooling_coeff\": -0.5,\n                                   \"property_option\": WALL_FACTOR_VISCOSITY}\n\n# 1.35 as a result suggested by an experiment byt the analysis is \"preferred\"\nKays_Crawford_laminar_gas_fd = {\"mu_heating_coeff\": -1,\n                                \"mu_cooling_coeff\": -1,\n                                \"property_option\": WALL_FACTOR_VISCOSITY}\n# This is uncertain\nKays_Crawford_laminar_gas_Nu = {\"mu_heating_coeff\": 0.0,\n                                \"mu_cooling_coeff\": 0.0,\n                                \"property_option\": WALL_FACTOR_VISCOSITY}\n\n# These seem fairly well measured\nKays_Crawford_turbulent_liquid_fd = {\"mu_heating_coeff\": -0.25,\n                                     \"mu_cooling_coeff\": -0.25,\n                                     \"property_option\": WALL_FACTOR_VISCOSITY}\n# This is uncertain\nKays_Crawford_turbulent_liquid_Nu = {\"mu_heating_coeff\": 0.11,\n                                     \"mu_cooling_coeff\": 0.25,\n                                     \"property_option\": WALL_FACTOR_VISCOSITY}\n\n# These see pretty accurate\nKays_Crawford_turbulent_gas_fd = {\"mu_heating_coeff\": 0.1,\n                                  \"mu_cooling_coeff\": 0.1,\n                                  \"property_option\": WALL_FACTOR_VISCOSITY}\n\nKays_Crawford_turbulent_gas_Nu = {\"mu_heating_coeff\": 0.5,\n                                  \"mu_cooling_coeff\": 0.0,\n                                  \"property_option\": WALL_FACTOR_VISCOSITY}\n\n\n# is_turbulent, is_liquid\nwall_factor_fd_defaults = {(True, True): Kays_Crawford_turbulent_liquid_fd,\n                           (True, False): Kays_Crawford_turbulent_gas_fd,\n                           (False, True): Kays_Crawford_laminar_liquid_fd,\n                           (False, False): Kays_Crawford_laminar_gas_fd}\n\nwall_factor_Nu_defaults = {(True, True): Kays_Crawford_turbulent_liquid_Nu,\n                           (True, False): Kays_Crawford_turbulent_gas_Nu,\n                           (False, True): Kays_Crawford_laminar_liquid_Nu,\n                           (False, False): Kays_Crawford_laminar_gas_Nu}\n\n\ndef wall_factor_fd(mu, mu_wall, turbulent=True, liquid=False):\n    r\"\"\"Computes the wall correction factor for pressure drop due to friction\n    between a fluid and a wall. These coefficients were derived for internal\n    flow inside a pipe, but can be used elsewhere where appropriate data is\n    missing.\n\n    .. math::\n        \\frac{f_d}{f_{d,\\text{constant properties}}}\n        = \\left(\\frac{\\mu}{\\mu_{wall}}\\right)^n\n\n    Parameters\n    ----------\n    mu : float\n        Viscosity (or Prandtl number) of flowing fluid away from the wall,\n        [Pa*s]\n    mu_wall : float\n        Viscosity (or Prandtl number) of the fluid at the wall, [Pa*s]\n    turbulent : bool\n        Whether or not to use the turbulent coefficient, [-]\n    liquid : bool\n        Whether or not to use the liquid phase coefficient; otherwise the gas\n        coefficient is used, [-]\n\n    Returns\n    -------\n    factor : float\n        Correction factor for pressure loss; to be multiplied by the friction\n        factor, or pressure drop to obtain the actual result, [-]\n\n    Notes\n    -----\n    The exponents are determined as follows:\n\n    +-----------+--------+---------+---------+\n    | Regime    | Phase  | Heating | Cooling |\n    +===========+========+=========+=========+\n    | Turbulent | Liquid | -0.25   | -0.25   |\n    +-----------+--------+---------+---------+\n    | Turbulent | Gas    | 0.1     | 0.1     |\n    +-----------+--------+---------+---------+\n    | Laminar   | Liquid | -0.58   | -0.5    |\n    +-----------+--------+---------+---------+\n    | Laminar   | Gas    | -1      | -1      |\n    +-----------+--------+---------+---------+\n\n    Examples\n    --------\n    >>> wall_factor_fd(mu=8E-4, mu_wall=3E-4, turbulent=True, liquid=True)\n    0.7825422900366437\n\n    References\n    ----------\n    .. [1] Kays, William M., and Michael E. Crawford. Convective Heat and Mass\n       Transfer. 3rd edition. New York: McGraw-Hill Science/Engineering/Math,\n       1993.\n    \"\"\"\n    params = wall_factor_fd_defaults[(turbulent, liquid)]\n    return wall_factor(mu=mu, mu_wall=mu_wall, **params)\n\n\ndef wall_factor_Nu(mu, mu_wall, turbulent=True, liquid=False):\n    r\"\"\"Computes the wall correction factor for heat transfer between a fluid\n    and a wall. These coefficients were derived for internal flow inside a\n    pipe, but can be used elsewhere where appropriate data is missing. It is\n    also useful to compare these results with the coefficients used in various\n    heat transfer coefficients.\n\n    .. math::\n        \\frac{Nu}{Nu_{\\text{constant properties}}}\n        = \\left(\\frac{\\mu}{\\mu_{wall}}\\right)^n\n\n    Parameters\n    ----------\n    mu : float\n        Viscosity (or Prandtl number) of flowing fluid away from the heat\n        transfer surface, [Pa*s]\n    mu_wall : float\n        Viscosity (or Prandtl number) of the fluid at the wall, [Pa*s]\n    turbulent : bool\n        Whether or not to use the turbulent coefficient, [-]\n    liquid : bool\n        Whether or not to use the liquid phase coefficient; otherwise the gas\n        coefficient is used, [-]\n\n    Returns\n    -------\n    factor : float\n        Correction factor for heat transfer; to be multiplied by the Nusselt\n        number, or heat transfer coefficient to obtain the actual result, [-]\n\n    Notes\n    -----\n    The exponents are determined as follows:\n\n    +-----------+--------+---------+---------+\n    | Regime    | Phase  | Heating | Cooling |\n    +===========+========+=========+=========+\n    | Turbulent | Liquid | 0.11    | 0.25    |\n    +-----------+--------+---------+---------+\n    | Turbulent | Gas    | 0.5     | 0       |\n    +-----------+--------+---------+---------+\n    | Laminar   | Liquid | 0.14    | 0.14    |\n    +-----------+--------+---------+---------+\n    | Laminar   | Gas    | 0       | 0       |\n    +-----------+--------+---------+---------+\n\n    Examples\n    --------\n    >>> wall_factor_Nu(mu=8E-4, mu_wall=3E-4, turbulent=True, liquid=True)\n    1.1139265634480144\n\n    >>> wall_factor_Nu(mu=8E-4, mu_wall=3E-4, turbulent=False, liquid=True)\n    1.147190712947014\n\n    >>> wall_factor_Nu(mu=1.5E-5, mu_wall=1.3E-5, turbulent=True, liquid=False)\n    1.0741723110591495\n\n    >>> wall_factor_Nu(mu=1.5E-5, mu_wall=1.3E-5, turbulent=False, liquid=False)\n    1.0\n\n    References\n    ----------\n    .. [1] Kays, William M., and Michael E. Crawford. Convective Heat and Mass\n       Transfer. 3rd edition. New York: McGraw-Hill Science/Engineering/Math,\n       1993.\n    \"\"\"\n    params = wall_factor_Nu_defaults[(turbulent, liquid)]\n    return wall_factor(mu=mu, mu_wall=mu_wall, **params)\n\n\nwall_factor_bad_option_msg = \"Supported options are: \"+ str(\n        [WALL_FACTOR_VISCOSITY, WALL_FACTOR_PRANDTL, WALL_FACTOR_TEMPERATURE,\n         WALL_FACTOR_DEFAULT])\n\ndef wall_factor(mu: int | None=None, mu_wall: int | None=None, Pr: float | None=None, Pr_wall: float | None=None, T: int | None=None,\n                T_wall: int | None=None, mu_heating_coeff: float=0.11, mu_cooling_coeff: float=0.25,\n                Pr_heating_coeff: float=0.11, Pr_cooling_coeff: float=0.25,\n                T_heating_coeff: float=0.11, T_cooling_coeff: float=0.25,\n                property_option: str=WALL_FACTOR_PRANDTL) -> float:\n    r\"\"\"Computes the wall correction factor for heat transfer, mass transfer,\n    or momentum transfer between a fluid and a wall. Utility function; the\n    coefficients for the phenomenon must be provided to this method. The\n    default coefficients are for heat transfer of a turbulent liquid.\n\n    The general formula is as follows; substitute the property desired and\n    the phenomenon desired into the equation for things other than heat\n    transfer.\n\n    .. math::\n        \\frac{Nu}{Nu_{\\text{constant properties}}}\n        = \\left(\\frac{\\mu}{\\mu_{wall}}\\right)^n\n\n    Parameters\n    ----------\n    mu : float, optional\n        Viscosity of flowing fluid away from the surface, [Pa*s]\n    mu_wall : float, optional\n        Viscosity of the fluid at the wall, [Pa*s]\n    Pr : float, optional\n        Prandtl number of flowing fluid away from the surface, [-]\n    Pr_wall : float, optional\n        Prandtl number of the fluid at the wall, [-]\n    T : float, optional\n        Temperature of flowing fluid away from the surface, [K]\n    T_wall : float, optional\n        Temperature of the fluid at the wall, [K]\n    mu_heating_coeff : float, optional\n        Coefficient for viscosity - surface providing heating, [-]\n    mu_cooling_coeff : float, optional\n        Coefficient for viscosity - surface providing cooling, [-]\n    Pr_heating_coeff : float, optional\n        Coefficient for Prandtl number - surface providing heating, [-]\n    Pr_cooling_coeff : float, optional\n        Coefficient for Prandtl number - surface providing cooling, [-]\n    T_heating_coeff : float, optional\n        Coefficient for temperature - surface providing heating, [-]\n    T_cooling_coeff : float, optional\n        Coefficient for temperature - surface providing cooling, [-]\n    property_option : str, optional\n        Which property to use for computing the correction factor; one of\n        'Viscosity', 'Prandtl', or 'Temperature'.\n\n    Returns\n    -------\n    factor : float\n        Correction factor for heat transfer; to be multiplied by the Nusselt\n        number or heat transfer coefficient or friction factor or pressure drop\n        to obtain the actual result, [-]\n\n    Examples\n    --------\n    >>> wall_factor(mu=8E-4, mu_wall=3E-4, Pr=1.2, Pr_wall=1.1, T=300,\n    ... T_wall=350, property_option='Prandtl')\n    1.0096172023817749\n    \"\"\"\n    if property_option == WALL_FACTOR_DEFAULT:\n        property_option = WALL_FACTOR_PRANDTL\n    if property_option == WALL_FACTOR_VISCOSITY:\n        if mu is None or mu_wall is None:\n            raise TypeError(\"Viscosity wall correction specified but both \"\n                            \"viscosity values are not available.\")\n        heating = is_heating_property(mu, mu_wall)\n        if heating:\n            return (mu/mu_wall)**mu_heating_coeff\n        else:\n            return (mu/mu_wall)**mu_cooling_coeff\n    elif property_option == WALL_FACTOR_TEMPERATURE:\n        if T is None or T_wall is None:\n            raise TypeError(\"Temperature wall correction specified but both \"\n                            \"temperature values are not available.\")\n        heating = is_heating_temperature(T, T_wall)\n        if heating:\n            return (T/T_wall)**T_heating_coeff\n        else:\n            return (T/T_wall)**T_cooling_coeff\n    elif property_option == WALL_FACTOR_PRANDTL:\n        if Pr is None or Pr_wall is None:\n            raise TypeError(\"Prandtl number wall correction specified but both\"\n                            \" Prandtl number values are not available.\")\n        heating = is_heating_property(Pr, Pr_wall)\n        if heating:\n            return (Pr/Pr_wall)**Pr_heating_coeff\n        else:\n            return (Pr/Pr_wall)**Pr_cooling_coeff\n    else:\n        raise ValueError(wall_factor_bad_option_msg)\n\n\ndef fin_efficiency_Kern_Kraus(Do: float, D_fin: float, t_fin: float, k_fin: float, h: float) -> float:\n    r\"\"\"Returns the efficiency `eta_f` of a circular fin of constant thickness\n    attached to a circular tube, based on the tube diameter `Do`, fin\n    diameter `D_fin`, fin thickness `t_fin`, fin thermal conductivity `k_fin`,\n    and heat transfer coefficient `h`.\n\n    .. math::\n        \\eta_f = \\frac{2r_o}{m(r_e^2 - r_o^2)}\n        \\left[\\frac{I_1(mr_e)K_1(mr_o) - K_1(mr_e) I_1(mr_o)}\n        {I_0(mr_o) K_1(mr_e) + I_1(mr_e) K_0(mr_o)}\\right]\n\n    .. math::\n        m = \\sqrt{\\frac{2h}{k_{fin} t_{fin}}}\n\n    .. math::\n        r_e = 0.5 D_{fin}\n\n    .. math::\n        r_o = 0.5 D_{o}\n\n    Parameters\n    ----------\n    Do : float\n        Outer diameter of bare pipe (as if there were no fins), [m]\n    D_fin : float\n        Outer diameter of the fin, from the center of the tube to the edge of\n        the fin, [m]\n    t_fin : float\n        Thickness of the fin (for constant thickness fins only), [m]\n    k_fin : float\n        Thermal conductivity of the fin, [W/m/K]\n    h : float\n        Heat transfer coefficient of the finned pipe, [W/K]\n\n    Returns\n    -------\n    eta_fin : float\n        Fin efficiency [-]\n\n    Examples\n    --------\n    >>> fin_efficiency_Kern_Kraus(0.0254, 0.05715, 3.8E-4, 200, 58)\n    0.841258862023\n\n    Notes\n    -----\n    I0, I1, K0 and K1 are modified Bessel functions of order 0 and 1,\n    modified Bessel function of the second kind of order 0 and 1 respectively.\n\n\n    A number of assumptions are made in deriving this set of equations [5]_:\n\n        * 1-D radial conduction\n        * Steady-state operation\n        * No radiative heat transfer\n        * Temperature-independent fin thermal conductivity\n        * Constant heat transfer coefficient across the whole fin\n        * The fin base temperature is a constant value\n        * There is no constant resistance between the tube material and the added fin\n        * The surrounding fluid is at a constant temperature\n\n    References\n    ----------\n    .. [1] Kern, Donald Quentin, and Allan D. Kraus. Extended Surface Heat\n       Transfer. McGraw-Hill, 1972.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    .. [4] Kraus, Allan D., Abdul Aziz, and James Welty. Extended Surface Heat\n       Transfer. 1st edition. New York: Wiley-Interscience, 2001.\n    .. [5] Perrotin, Thomas, and Denis Clodic. \"Fin Efficiency Calculation in\n       Enhanced Fin-and-Tube Heat Exchangers in Dry Conditions.\" In Proc. Int.\n       Congress of Refrigeration 2003, 2003.\n    \"\"\"\n    re = 0.5*D_fin\n    ro = 0.5*Do\n    m = (2.0*h/(k_fin*t_fin))**0.5\n\n    mre = m*re\n    mro = m*ro\n    x0 = i1(mre)\n    x1 = k1(mre)\n    num = x0*k1(mro) - x1*i1(mro)\n    den = i0(mro)*x1 + x0*k0(mro)\n    return float(2.0*ro/(m*(re*re - ro*ro))*num/den)\n\n\n\n"
  },
  {
    "path": "ht/hx.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nimport os\nfrom math import exp, floor, log, sqrt, tanh  # tanh= 1/coth\nfrom typing import Callable\n\nfrom fluids.constants import Btu, degree_Fahrenheit, foot, hour, inch\nfrom fluids.numerics import bisect, brenth, factorial, gamma, horner, iv, quad, secant\nfrom fluids.numerics import numpy as np\nfrom fluids.piping import BWG_SI, BWG_gauges\n\n__all__: list[str] = [\n    \"DBundle_for_Ntubes_HEDH\",\n    \"DBundle_for_Ntubes_Phadkeb\",\n    \"DBundle_min\",\n    \"D_baffle_holes\",\n    \"D_for_Ntubes_VDI\",\n    \"F_LMTD_Fakheri\",\n    \"L_unsupported_max\",\n    \"NTU_from_P_E\",\n    \"NTU_from_P_G\",\n    \"NTU_from_P_H\",\n    \"NTU_from_P_J\",\n    \"NTU_from_P_basic\",\n    \"NTU_from_P_plate\",\n    \"NTU_from_UA\",\n    \"NTU_from_effectiveness\",\n    \"Ntubes\",\n    \"Ntubes_HEDH\",\n    \"Ntubes_Perrys\",\n    \"Ntubes_Phadkeb\",\n    \"Ntubes_VDI\",\n    \"P_NTU_Pc\",\n    \"P_NTU_Pp\",\n    \"P_NTU_method\",\n    \"R_value\",\n    \"TEMA_heads\",\n    \"TEMA_rears\",\n    \"TEMA_services\",\n    \"TEMA_shells\",\n    \"UA_from_NTU\",\n    \"baffle_thickness\",\n    \"baffle_types\",\n    \"calc_Cmax\",\n    \"calc_Cmin\",\n    \"calc_Cr\",\n    \"effectiveness_NTU_method\",\n    \"effectiveness_from_NTU\",\n    \"shell_clearance\",\n    \"size_bundle_from_tubecount\",\n    \"square_C1s\",\n    \"square_Ns\",\n    \"temperature_effectiveness_TEMA_E\",\n    \"temperature_effectiveness_TEMA_G\",\n    \"temperature_effectiveness_TEMA_H\",\n    \"temperature_effectiveness_TEMA_J\",\n    \"temperature_effectiveness_air_cooler\",\n    \"temperature_effectiveness_basic\",\n    \"temperature_effectiveness_plate\",\n    \"triangular_C1s\",\n    \"triangular_Ns\",\n]\n\nR_value = foot*foot*degree_Fahrenheit*hour/Btu\n\n__numba_additional_funcs__ = [\"crossflow_effectiveness_to_int\", \"to_solve_Ntubes_Phadkeb\",\n                              \"_tubecount_objf_Perry\", \"_NTU_max_for_P_solver\",\n                              \"_NTU_from_P_solver\", \"_NTU_from_P_objective\", \"_NTU_from_P_erf\"]\nIS_NUMBA = \"IS_NUMBA\" in globals()\nif IS_NUMBA:\n    __numba_additional_funcs__.append(\"factorial\")\n    def factorial(n):\n        return gamma(n + 1.0)\n\ndef crossflow_effectiveness_to_int(v: float, NTU: float, t0: float) -> float:\n    x0 = v*v*t0\n    return (1. + NTU - x0)*exp(-x0)*v*float(iv(0.0, v))\n\ndef effectiveness_from_NTU(NTU, Cr, subtype=\"counterflow\", n_shell_tube=None):\n    r\"\"\"Returns the effectiveness of a heat exchanger at a specified heat\n    capacity rate, number of transfer units, and configuration. The following\n    configurations are supported:\n\n        * Counterflow (ex. double-pipe)\n        * Parallel (ex. double pipe inefficient configuration)\n        * Shell and tube exchangers with even numbers of tube passes,\n          one or more shells in series\n        * Crossflow, single pass, fluids unmixed\n        * Crossflow, single pass, Cmax mixed, Cmin unmixed\n        * Crossflow, single pass, Cmin mixed, Cmax unmixed\n        * Boiler or condenser\n\n    These situations are normally not those which occur in real heat exchangers,\n    but are useful for academic purposes. More complicated expressions are\n    available for other methods. These equations are confirmed in [1]_,\n    [2]_, and [3]_.\n\n    For parallel flow heat exchangers:\n\n    .. math::\n        \\epsilon = \\frac{1 - \\exp[-NTU(1+C_r)]}{1+C_r}\n\n    For counterflow heat exchangers:\n\n    .. math::\n        \\epsilon = \\frac{1 - \\exp[-NTU(1-C_r)]}{1-C_r\\exp[-NTU(1-C_r)]},\\; C_r < 1\n\n    .. math::\n        \\epsilon = \\frac{NTU}{1+NTU},\\; C_r = 1\n\n    For TEMA E shell-and-tube heat exchangers with one shell pass, 2n tube\n    passes:\n\n    .. math::\n        \\epsilon_1 = 2\\left\\{1 + C_r + \\sqrt{1+C_r^2}\\times\\frac{1+\\exp\n        [-(NTU)_1\\sqrt{1+C_r^2}]}{1-\\exp[-(NTU)_1\\sqrt{1+C_r^2}]}\\right\\}^{-1}\n\n    For TEMA E shell-and-tube heat exchangers with more than one shell pass, 2n\n    tube passes (this model assumes each exchanger has an equal share of the\n    overall NTU or said more plainly, the same UA):\n\n    .. math::\n        \\epsilon = \\left[\\left(\\frac{1-\\epsilon_1 C_r}{1-\\epsilon_1}\\right)^2\n        -1\\right]\\left[\\left(\\frac{1-\\epsilon_1 C_r}{1-\\epsilon_1}\\right)^n\n        - C_r\\right]^{-1}\n\n    For cross-flow (single-pass) heat exchangers with both fluids unmixed, there\n    is an approximate and an exact formula. The approximate one is:\n\n    .. math::\n        \\epsilon = 1 - \\exp\\left[\\left(\\frac{1}{C_r}\\right)\n        (NTU)^{0.22}\\left\\{\\exp\\left[C_r(NTU)^{0.78}\\right]-1\\right\\}\\right]\n\n    The exact solution for crossflow (fluids unmixed) uses SciPy's quad\n    to perform an integral (there is no analytical integral solution available).\n    :math:`I_0(v)` is the modified Bessel function of the first kind. This formula\n    was developed in [4]_.\n\n    .. math::\n        \\epsilon = \\frac{1}{C_r} - \\frac{\\exp(-C_r \\cdot NTU)}{2(C_r NTU)^2}\n        \\int_0^{2 NTU\\sqrt{C_r}} \\left(1 + NTU - \\frac{v^2}{4C_r NTU}\\right)\n        \\exp\\left(-\\frac{v^2}{4C_r NTU}\\right)v I_0(v) dv\n\n    For cross-flow (single-pass) heat exchangers with Cmax mixed, Cmin unmixed:\n\n    .. math::\n        \\epsilon = \\left(\\frac{1}{C_r}\\right)(1 - \\exp\\left\\{-C_r[1-\\exp(-NTU)]\\right\\})\n\n    For cross-flow (single-pass) heat exchangers with Cmin mixed, Cmax unmixed:\n\n    .. math::\n        \\epsilon = 1 - \\exp(-C_r^{-1}\\{1 - \\exp[-C_r(NTU)]\\})\n\n    For cases where `Cr` = 0, as in an exchanger with latent heat exchange,\n    flow arrangement does not matter:\n\n    .. math::\n        \\epsilon = 1 - \\exp(-NTU)\n\n    Parameters\n    ----------\n    NTU : float\n        Thermal Number of Transfer Units [-]\n    Cr : float\n        The heat capacity rate ratio, of the smaller fluid to the larger\n        fluid, [-]\n    subtype : str, optional\n        The subtype of exchanger; one of 'counterflow', 'parallel', 'crossflow'\n        'crossflow approximate', 'crossflow, mixed Cmin',\n        'crossflow, mixed Cmax', 'boiler', 'condenser', 'S&T'\n    n_shell_tube : None or int, optional\n        The number of shell and tube exchangers in a row, [-]\n\n    Returns\n    -------\n    effectiveness : float\n        The thermal effectiveness of the heat exchanger, [-]\n\n    Notes\n    -----\n    Once the effectiveness of the exchanger has been calculated, the total\n    heat transferred can be calculated according to the following formulas,\n    depending on which stream temperatures are known:\n\n    If the inlet temperatures for both sides are known:\n\n    .. math::\n        Q=\\epsilon C_{min}(T_{h,i}-T_{c,i})\n\n    If the outlet temperatures for both sides are known:\n\n    .. math::\n        Q = \\frac{\\epsilon C_{min}C_{hot}C_{cold}(T_{c,o}-T_{h,o})}\n        {\\epsilon  C_{min}(C_{hot} +C_{cold}) - (C_{hot}C_{cold}) }\n\n    If the hot inlet and cold outlet are known:\n\n    .. math::\n        Q = \\frac{\\epsilon C_{min}C_c(T_{co}-T_{hi})}{\\epsilon C_{min}-C_c}\n\n    If the hot outlet stream and cold inlet stream are known:\n\n    .. math::\n        Q = \\frac{\\epsilon C_{min}C_h(T_{ci}-T_{ho})}{\\epsilon C_{min}-C_h}\n\n\n    If the inlet and outlet conditions for a single side are known, the\n    effectiveness wasn't needed for it to be calculated. For completeness,\n    the formulas are as follows:\n\n    .. math::\n        Q = C_c(T_{c,o} - T_{c,i}) = C_h(T_{h,i} - T_{h,o})\n\n    There is also a term called :math:`Q_{max}`, which is the heat which would\n    have been transferred if the effectiveness was 1. It is calculated as\n    follows:\n\n    .. math::\n        Q_{max} = \\frac{Q}{\\text{effectiveness}}\n\n    Examples\n    --------\n    Worst case, parallel flow:\n\n    >>> effectiveness_from_NTU(NTU=5, Cr=0.7, subtype='parallel')\n    0.5881156068417585\n\n    Crossflow, somewhat higher effectiveness:\n\n    >>> effectiveness_from_NTU(NTU=5, Cr=0.7, subtype='crossflow')\n    0.84448217997\n\n    Counterflow, better than either crossflow or parallel flow:\n\n    >>> effectiveness_from_NTU(NTU=5, Cr=0.7, subtype='counterflow')\n    0.920670368605\n\n    One shell and tube heat exchanger gives worse performance than counterflow,\n    but they are designed to be economical and compact which a counterflow\n    exchanger would not be. As the number of shells approaches infinity,\n    the counterflow result is obtained exactly.\n\n    >>> effectiveness_from_NTU(NTU=5, Cr=0.7, subtype='S&T')\n    0.683497704431\n    >>> effectiveness_from_NTU(NTU=5, Cr=0.7, subtype='S&T', n_shell_tube=50)\n    0.920505870278\n\n\n    Overall case of rating an existing heat exchanger where a known flowrate\n    of steam and oil are contacted in crossflow, with the steam side mixed\n    (example 10-9 in [3]_):\n\n    >>> U = 275 # W/m^2/K\n    >>> A = 10.82 # m^2\n    >>> Cp_oil = 1900 # J/kg/K\n    >>> Cp_steam = 1860 # J/kg/K\n    >>> m_steam = 5.2 # kg/s\n    >>> m_oil = 0.725 # kg/s\n    >>> Thi = 130 # °C\n    >>> Tci = 15 # °C\n    >>> Cmin = calc_Cmin(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> Cmax = calc_Cmax(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> Cr = calc_Cr(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> NTU = NTU_from_UA(UA=U*A, Cmin=Cmin)\n    >>> eff = effectiveness_from_NTU(NTU=NTU, Cr=Cr, subtype='crossflow, mixed Cmax')\n    >>> Q = eff*Cmin*(Thi - Tci)\n    >>> Tco = Tci + Q/(m_oil*Cp_oil)\n    >>> Tho = Thi - Q/(m_steam*Cp_steam)\n    >>> Cmin, Cmax, Cr\n    (1377.5, 9672.0, 0.1424214226633)\n    >>> NTU, eff, Q\n    (2.16007259528, 0.831218036142, 131675.3271504)\n    >>> Tco, Tho\n    (110.5900741563, 116.3859256461)\n\n    Alternatively, if only the outlet temperatures had been known:\n\n    >>> Tco = 110.59007415639887\n    >>> Tho = 116.38592564614977\n    >>> Cc, Ch = Cmin, Cmax # In this case but not always\n    >>> Q = eff*Cmin*Cc*Ch*(Tco - Tho)/(eff*Cmin*(Cc+Ch) - Ch*Cc)\n    >>> Thi = Tho + Q/Ch\n    >>> Tci = Tco - Q/Cc\n    >>> Q, Tci, Thi\n    (131675.3271504, 14.99999999999, 130.0000000000)\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    .. [2] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [3] Holman, Jack. Heat Transfer. 10th edition. Boston: McGraw-Hill\n       Education, 2009.\n    .. [4] Triboix, Alain. \"Exact and Approximate Formulas for Cross Flow Heat\n       Exchangers with Unmixed Fluids.\" International Communications in Heat\n       and Mass Transfer 36, no. 2 (February 1, 2009): 121-24.\n       doi:10.1016/j.icheatmasstransfer.2008.10.012.\n    \"\"\"\n    if Cr > 1:\n        raise ValueError(\"Heat capacity rate must be less than 1 by definition.\")\n\n    if subtype == \"counterflow\":\n        if Cr < 1:\n            return (1. - exp(-NTU*(1. - Cr)))/(1. - Cr*exp(-NTU*(1. - Cr)))\n        elif Cr == 1:\n            return NTU/(1. + NTU)\n    elif subtype == \"parallel\":\n            return (1. - exp(-NTU*(1. + Cr)))/(1. + Cr)\n    elif \"S&T\" == subtype:\n        # str_shells = subtype.split('S&T')[0]\n        shells = n_shell_tube if n_shell_tube is not None else 1\n        NTU = NTU/shells\n\n        x0 = sqrt(1. + Cr*Cr)\n        x1 = exp(-NTU*x0)\n        top = 1. + x1\n        bottom = 1. - x1\n        effectiveness = 2./(1. + Cr + x0*top/bottom)\n        if shells > 1:\n            # this applies to crossflow also according to Efficiency and Effectiveness of Heat Exchanger Series equation 21\n            term = ((1. - effectiveness*Cr)/(1. - effectiveness))**shells\n            effectiveness = (term - 1.)/(term - Cr)\n        return effectiveness\n    elif subtype == \"crossflow\":\n        t0 = 1.0/(4.*Cr*NTU)\n        res, err = quad(crossflow_effectiveness_to_int, 0, 2.*NTU*sqrt(Cr), args=(NTU, t0,))\n        int_term = res\n        CrNTU = Cr*NTU\n        return 1./Cr - exp(-CrNTU)/(2.*CrNTU*CrNTU)*int_term\n    elif subtype == \"crossflow approximate\":\n        return 1. - exp(1./Cr*NTU**0.22*(exp(-Cr*NTU**0.78) - 1.))\n    elif subtype == \"crossflow, mixed Cmin\":\n        return 1. -exp(-1.0/Cr*(1. - exp(-Cr*NTU)))\n    elif subtype ==  \"crossflow, mixed Cmax\":\n        return (1./Cr)*(1. - exp(-Cr*(1. - exp(-NTU))))\n    elif subtype in (\"boiler\", \"condenser\"):\n        return  1. - exp(-NTU)\n    else:\n        raise ValueError(\"Input heat exchanger type not recognized\")\n\n\ndef NTU_from_effectiveness(effectiveness, Cr, subtype=\"counterflow\", n_shell_tube=None):\n    r\"\"\"Returns the Number of Transfer Units of a heat exchanger at a specified\n    heat capacity rate, effectiveness, and configuration. The following\n    configurations are supported:\n\n        * Counterflow (ex. double-pipe)\n        * Parallel (ex. double pipe inefficient configuration)\n        * Shell and tube exchangers with even numbers of tube passes,\n          one or more shells in series (TEMA E (one pass shell) only)\n        * Crossflow, single pass, fluids unmixed\n        * Crossflow, single pass, Cmax mixed, Cmin unmixed\n        * Crossflow, single pass, Cmin mixed, Cmax unmixed\n        * Boiler or condenser\n\n    These situations are normally not those which occur in real heat exchangers,\n    but are useful for academic purposes. More complicated expressions are\n    available for other methods. These equations are confirmed in [1]_, [2]_,\n    and [3]_.\n\n    For parallel flow heat exchangers:\n\n    .. math::\n        NTU = -\\frac{\\ln[1 - \\epsilon(1+C_r)]}{1+C_r}\n\n    For counterflow heat exchangers:\n\n    .. math::\n        NTU = \\frac{1}{C_r-1}\\ln\\left(\\frac{\\epsilon-1}{\\epsilon C_r-1}\\right)\n\n    .. math::\n        NTU = \\frac{\\epsilon}{1-\\epsilon} \\text{ if } C_r = 1\n\n    For TEMA E shell-and-tube heat exchangers with one shell pass, 2n tube\n    passes:\n\n    .. math::\n        (NTU)_1 = -(1 + C_r^2)^{-0.5}\\ln\\left(\\frac{E-1}{E+1}\\right)\n\n    .. math::\n        E = \\frac{2/\\epsilon_1 - (1 + C_r)}{(1 + C_r^2)^{0.5}}\n\n    For TEMA E shell-and-tube heat exchangers with more than one shell pass, 2n\n    tube passes (this model assumes each exchanger has an equal share of the\n    overall NTU or said more plainly, the same UA):\n\n    .. math::\n        \\epsilon_1 = \\frac{F-1}{F-C_r}\n\n    .. math::\n        F = \\left(\\frac{\\epsilon C_r-1}{\\epsilon-1}\\right)^{1/n}\n\n    .. math::\n        NTU = n(NTU)_1\n\n    For cross-flow (single-pass) heat exchangers with both fluids unmixed,\n    there is no analytical solution. However, the function is monotonically\n    increasing, and a closed-form solver is implemented as 'crossflow approximate',\n    guaranteed to solve for :math:`10^{-7} < NTU < 10^5`. The exact solution\n    for 'crossflow' uses the approximate solution's initial guess as a starting\n    point for Newton's method. Some issues are noted at effectivenesses higher\n    than 0.9 and very high NTUs, because the numerical integral term approaches\n    1 too quickly.\n\n    For cross-flow (single-pass) heat exchangers with Cmax mixed, Cmin unmixed:\n\n    .. math::\n        NTU = -\\ln\\left[1 + \\frac{1}{C_r}\\ln(1 - \\epsilon C_r)\\right]\n\n    For cross-flow (single-pass) heat exchangers with Cmin mixed, Cmax unmixed:\n\n    .. math::\n        NTU = -\\frac{1}{C_r}\\ln[C_r\\ln(1-\\epsilon)+1]\n\n    For cases where `Cr` = 0, as in an exchanger with latent heat exchange,\n    flow arrangement does not matter:\n\n    .. math::\n        NTU = -\\ln(1-\\epsilon)\n\n    Parameters\n    ----------\n    effectiveness : float\n        The thermal effectiveness of the heat exchanger, [-]\n    Cr : float\n        The heat capacity rate ratio, of the smaller fluid to the larger\n        fluid, [-]\n    subtype : str, optional\n        The subtype of exchanger; one of 'counterflow', 'parallel', 'crossflow'\n        'crossflow approximate', 'crossflow, mixed Cmin',\n        'crossflow, mixed Cmax', 'boiler', 'condenser', 'S&T'.\n    n_shell_tube : None or int, optional\n        The number of shell and tube exchangers in a row, [-]\n\n\n    Returns\n    -------\n    NTU : float\n        Thermal Number of Transfer Units [-]\n\n    Notes\n    -----\n    Unlike :obj:`ht.hx.effectiveness_from_NTU`, not all inputs can\n    calculate the NTU - many exchanger types have effectiveness limits\n    below 1 which depend on `Cr` and the number of shells in the case of\n    heat exchangers. If an impossible input is given, an error will be raised\n    and the maximum possible effectiveness will be printed.\n\n    >>> NTU_from_effectiveness(.99, Cr=.7, subtype='5S&T') # doctest: +SKIP\n    Traceback (most recent call last):\n    Exception: The specified effectiveness is not physically possible for this configuration; the maximum effectiveness possible is 0.974122977755.\n\n    Examples\n    --------\n    Worst case, parallel flow:\n\n    >>> NTU_from_effectiveness(effectiveness=0.5881156068417585, Cr=0.7, subtype='parallel')\n    5.000000000000\n\n    Crossflow, somewhat higher effectiveness:\n\n    >>> NTU_from_effectiveness(effectiveness=0.8444821799748551, Cr=0.7, subtype='crossflow')\n    5.000000000000\n\n    Counterflow, better than either crossflow or parallel flow:\n\n    >>> NTU_from_effectiveness(effectiveness=0.9206703686051108, Cr=0.7, subtype='counterflow')\n    5.0\n\n    Shell and tube exchangers:\n\n    >>> NTU_from_effectiveness(effectiveness=0.6834977044311439, Cr=0.7, subtype='S&T')\n    5.000000000000\n    >>> NTU_from_effectiveness(effectiveness=0.9205058702789254, Cr=0.7, n_shell_tube=50, subtype='S&T')\n    4.999999999999\n\n\n    Overall case of rating an existing heat exchanger where a known flowrate\n    of steam and oil are contacted in crossflow, with the steam side mixed,\n    known inlet and outlet temperatures, and unknown UA\n    (based on example 10-8 in [3]_):\n\n    >>> Cp_oil = 1900 # J/kg/K\n    >>> Cp_steam = 1860 # J/kg/K\n    >>> m_steam = 5.2 # kg/s\n    >>> m_oil = 1.45 # kg/s\n    >>> Thi = 130 # °C\n    >>> Tci = 15 # °C\n    >>> Tco = 85 # °C # Design specification\n    >>> Q = Cp_oil*m_oil*(Tci-Tco)\n    >>> dTh = Q/(m_steam*Cp_steam)\n    >>> Tho = Thi + dTh\n    >>> Cmin = calc_Cmin(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> Cmax = calc_Cmax(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> Cr = calc_Cr(mh=m_steam, mc=m_oil, Cph=Cp_steam, Cpc=Cp_oil)\n    >>> effectiveness = -Q/Cmin/(Thi-Tci)\n    >>> NTU = NTU_from_effectiveness(effectiveness, Cr, subtype='crossflow, mixed Cmax')\n    >>> UA = UA_from_NTU(NTU, Cmin)\n    >>> U = 200 # Assume this was calculated; would actually need to be obtained iteratively as U depends on the exchanger geometry\n    >>> A = UA/U\n    >>> Tho, Cmin, Cmax, Cr\n    (110.06100082712986, 2755.0, 9672.0, 0.2848428453267163)\n    >>> effectiveness, NTU, UA, A\n    (0.608695652173, 1.1040839095, 3041.75117083, 15.2087558541)\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    .. [2] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [3] Holman, Jack. Heat Transfer. 10th edition. Boston: McGraw-Hill\n       Education, 2009.\n    \"\"\"\n    if Cr > 1:\n        raise ValueError(\"Heat capacity rate must be less than 1 by definition.\")\n\n    if subtype == \"counterflow\":\n        # [2]_ gives the expression 1./(1-Cr)*log((1-Cr*eff)/(1-eff)), but\n        # this is just the same equation rearranged differently.\n        if Cr < 1:\n            return 1./(Cr - 1.)*log((effectiveness - 1.)/(effectiveness*Cr - 1.))\n        elif Cr == 1:\n            return effectiveness/(1. - effectiveness)\n    elif subtype == \"parallel\":\n        if effectiveness*(1. + Cr) > 1:\n            raise ValueError(\"The specified effectiveness is not physically \"\n                             \"possible for this configuration; the maximum effectiveness \"\n                             \"possible is %s.\" % (1./(Cr + 1.))) # numba: delete\n#                             ) # numba: uncomment\n        return -log(1. - effectiveness*(1. + Cr))/(1. + Cr)\n    elif \"S&T\" == subtype:\n        # [2]_ gives the expression\n        # D = (1+Cr**2)**0.5\n        # 1/D*log((2-eff*(1+Cr-D))/(2-eff*(1+Cr + D)))\n        # This is confirmed numerically to be the same equation rearranged\n        # differently\n        shells = n_shell_tube if n_shell_tube is not None else 1\n\n        F = ((effectiveness*Cr - 1.)/(effectiveness - 1.))**(1./shells)\n        e1 = (F - 1.)/(F - Cr)\n        E = (2./e1 - (1. + Cr))/(1. + Cr**2)**0.5\n\n        if (E - 1.)/(E + 1.) <= 0:\n            # Derived with SymPy\n            max_effectiveness = (-((-Cr + sqrt(Cr**2 + 1) + 1)/(Cr + sqrt(Cr**2 + 1) - 1))**shells + 1)/(Cr - ((-Cr + sqrt(Cr**2 + 1) + 1)/(Cr + sqrt(Cr**2 + 1) - 1))**shells)\n            raise ValueError(\"The specified effectiveness is not physically \" # numba: delete\nf\"possible for this configuration; the maximum effectiveness possible is {max_effectiveness}.\") # numba: delete\n#            raise ValueError(\"Fail\") # numba: uncomment\n\n        NTU = -(1. + Cr*Cr)**-0.5*log((E - 1.)/(E + 1.))\n        return shells*NTU\n    elif subtype == \"crossflow\":\n        # Can't use a bisect solver here because at high NTU there's a derivative of 0\n        # due to the integral term not changing when it's very near one\n        guess = NTU_from_effectiveness(effectiveness, Cr, \"crossflow approximate\")\n        def to_solve(NTU, Cr, effectiveness):\n            return effectiveness_from_NTU(NTU, Cr, subtype=\"crossflow\") - effectiveness\n        return secant(to_solve, guess, args=(Cr, effectiveness))\n    elif subtype == \"crossflow approximate\":\n        # This will fail if NTU is more than 10,000 or less than 1E-7, but\n        # this is extremely unlikely to occur in normal usage.\n        # Maple and SymPy and Wolfram Alpha all failed to obtain an exact\n        # analytical expression even with coefficients for 0.22 and 0.78 or\n        # with an explicit value for Cr. The function has been plotted,\n        # and appears to be monotonic - there is only one solution.\n        def to_solve(NTU, Cr, effectiveness):\n            return (1. - exp(1./Cr*NTU**0.22*(exp(-Cr*NTU**0.78) - 1.))) - effectiveness\n        return secant(to_solve, x0=2.5, low=1e-7, high=1e5, bisection=True, require_eval=True, args=(Cr, effectiveness))\n\n    elif subtype == \"crossflow, mixed Cmin\":\n        if Cr*log(1. - effectiveness) < -1:\n            raise ValueError(\"The specified effectiveness is not physically \\\npossible for this configuration; the maximum effectiveness possible is %s.\" % (1. - exp(-1./Cr)))\n        return -1./Cr*log(Cr*log(1. - effectiveness) + 1.)\n\n    elif subtype ==  \"crossflow, mixed Cmax\":\n        if 1./Cr*log(1. - effectiveness*Cr) < -1:\n            raise ValueError(\"The specified effectiveness is not physically \\\npossible for this configuration; the maximum effectiveness possible is %s.\" % ((exp(Cr) - 1.0)*exp(-Cr)/Cr))\n        return -log(1. + 1./Cr*log(1. - effectiveness*Cr))\n\n    elif subtype in [\"boiler\", \"condenser\"]:\n        return -log(1. - effectiveness)\n    else:\n        raise ValueError(\"Input heat exchanger type not recognized\")\n\n\ndef calc_Cmin(mh: float, mc: float, Cph: float, Cpc: int) -> float:\n    r\"\"\"Returns the heat capacity rate for the minimum stream\n    having flows `mh` and `mc`, with averaged heat capacities `Cph` and `Cpc`.\n\n    .. math::\n        C_c = m_cC_{p,c}\n\n        C_h = m_h C_{p,h}\n\n        C_{min} = \\min(C_c, C_h)\n\n    Parameters\n    ----------\n    mh : float\n        Mass flow rate of hot stream, [kg/s]\n    mc : float\n        Mass flow rate of cold stream, [kg/s]\n    Cph : float\n        Averaged heat capacity of hot stream, [J/kg/K]\n    Cpc : float\n        Averaged heat capacity of cold stream, [J/kg/K]\n\n    Returns\n    -------\n    Cmin : float\n        The heat capacity rate of the smaller fluid, [W/K]\n\n    Notes\n    -----\n    Used with the effectiveness method for heat exchanger design.\n    Technically, it doesn't matter if the hot and cold streams are in the right\n    order for the input, but it is easiest to use this function when the order\n    is specified.\n\n    Examples\n    --------\n    >>> calc_Cmin(mh=22., mc=5.5, Cph=2200, Cpc=4400.)\n    24200.0\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    Ch = mh*Cph\n    Cc = mc*Cpc\n    return min(Ch, Cc)\n\n\ndef calc_Cmax(mh: float, mc: float, Cph: float, Cpc: int) -> float:\n    r\"\"\"Returns the heat capacity rate for the maximum stream\n    having flows `mh` and `mc`, with averaged heat capacities `Cph` and `Cpc`.\n\n    .. math::\n        C_c = m_cC_{p,c}\n\n    .. math::\n        C_h = m_h C_{p,h}\n\n    .. math::\n        C_{max} = \\max(C_c, C_h)\n\n    Parameters\n    ----------\n    mh : float\n        Mass flow rate of hot stream, [kg/s]\n    mc : float\n        Mass flow rate of cold stream, [kg/s]\n    Cph : float\n        Averaged heat capacity of hot stream, [J/kg/K]\n    Cpc : float\n        Averaged heat capacity of cold stream, [J/kg/K]\n\n    Returns\n    -------\n    Cmax : float\n        The heat capacity rate of the larger fluid, [W/K]\n\n    Notes\n    -----\n    Used with the effectiveness method for heat exchanger design.\n    Technically, it doesn't matter if the hot and cold streams are in the right\n    order for the input, but it is easiest to use this function when the order\n    is specified.\n\n    Examples\n    --------\n    >>> calc_Cmax(mh=22., mc=5.5, Cph=2200, Cpc=4400.)\n    48400.0\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    Ch = mh*Cph\n    Cc = mc*Cpc\n    return max(Ch, Cc)\n\n\ndef calc_Cr(mh: float, mc: float, Cph: float, Cpc: int) -> float:\n    r\"\"\"Returns the heat capacity rate ratio for a heat exchanger\n    having flows `mh` and `mc`, with averaged heat capacities `Cph` and `Cpc`.\n\n    .. math::\n        C_r=C^*=\\frac{C_{min}}{C_{max}}\n\n    Parameters\n    ----------\n    mh : float\n        Mass flow rate of hot stream, [kg/s]\n    mc : float\n        Mass flow rate of cold stream, [kg/s]\n    Cph : float\n        Averaged heat capacity of hot stream, [J/kg/K]\n    Cpc : float\n        Averaged heat capacity of cold stream, [J/kg/K]\n\n    Returns\n    -------\n    Cr : float\n        The heat capacity rate ratio, of the smaller fluid to the larger\n        fluid, [-]\n\n    Notes\n    -----\n    Used with the effectiveness method for heat exchanger design.\n    Technically, it doesn't matter if the hot and cold streams are in the right\n    order for the input, but it is easiest to use this function when the order\n    is specified.\n\n    Examples\n    --------\n    >>> calc_Cr(mh=22., mc=5.5, Cph=2200, Cpc=4400.)\n    0.5\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    Ch = mh*Cph\n    Cc = mc*Cpc\n    Cmin = min(Ch, Cc)\n    Cmax = max(Ch, Cc)\n    return Cmin/Cmax\n\n\ndef NTU_from_UA(UA: float, Cmin: float) -> float:\n    r\"\"\"Returns the Number of Transfer Units for a heat exchanger having\n    `UA`, and with `Cmin` heat capacity rate.\n\n    .. math::\n        NTU = \\frac{UA}{C_{min}}\n\n    Parameters\n    ----------\n    UA : float\n        Combined Area-heat transfer coefficient term, [W/K]\n    Cmin : float\n        The heat capacity rate of the smaller fluid, [W/K]\n\n    Returns\n    -------\n    NTU : float\n        Thermal Number of Transfer Units [-]\n\n    Notes\n    -----\n    Used with the effectiveness method for heat exchanger design.\n\n    Examples\n    --------\n    >>> NTU_from_UA(4400., 22.)\n    200.0\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return UA/Cmin\n\n\ndef UA_from_NTU(NTU: float, Cmin: float) -> float:\n    r\"\"\"Returns the combined area-heat transfer term for a heat exchanger\n    having a specified `NTU`, and with `Cmin` heat capacity rate.\n\n    .. math::\n        UA = NTU C_{min}\n\n    Parameters\n    ----------\n    NTU : float\n        Thermal Number of Transfer Units [-]\n    Cmin : float\n        The heat capacity rate of the smaller fluid, [W/K]\n\n    Returns\n    -------\n    UA : float\n        Combined area-heat transfer coefficient term, [W/K]\n\n    Notes\n    -----\n    Used with the effectiveness method for heat exchanger design.\n\n    Examples\n    --------\n    >>> UA_from_NTU(200., 22.)\n    4400.0\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    return NTU*Cmin\n\n\ndef P_NTU_Pp(x, y):\n    r\"\"\"Basic helper calculator which accepts a transformed R1 and NTU1 as\n    inputs for a common term used in the calculation of the P-NTU method for\n    plate exchangers.\n\n    Returns a value which is normally used in other calculations before the\n    actual P1 is calculated.\n\n    .. math::\n        P_p(x, y) = \\frac{1 - \\exp[-x(1 + y)]}{1 + y}\n\n    Parameters\n    ----------\n    x : float\n        A modification of NTU1, the Thermal Number of Transfer Units [-]\n    y : float\n        A modification of R1, the thermal effectiveness [-]\n\n    Returns\n    -------\n    z : float\n        Just another term in the calculation, [-]\n\n    Notes\n    -----\n    Used with the P-NTU plate method for heat exchanger design. At y = -1,\n    this function has a ZeroDivisionError but can be evaluated at the limit\n    to be z = x\n\n    Examples\n    --------\n    >>> P_NTU_Pp(5, .4)\n    0.713634370024\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    if y == -1.0:\n        return x\n    return (1. - exp(-x*(1. + y)))/(1. + y)\n\n\ndef P_NTU_Pc(x, y):\n    r\"\"\"Basic helper calculator which accepts a transformed R1 and NTU1 as\n    inputs for a common term used in the calculation of the P-NTU method for\n    plate exchangers.\n\n    Returns a value which is normally used in other calculations before the\n    actual P1 is calculated. Nominally used in counterflow calculations\n\n    .. math::\n        P_c(x, y) = \\frac{1 - \\exp[-x(1 - y)]}{1 - y\\exp[-x(1 - y)]}\n\n    Parameters\n    ----------\n    x : float\n        A modification of NTU1, the Thermal Number of Transfer Units [-]\n    y : float\n        A modification of R1, the thermal effectiveness [-]\n\n    Returns\n    -------\n    z : float\n        Just another term in the calculation, [-]\n\n    Notes\n    -----\n    Used with the P-NTU plate method for heat exchanger design. At y =-1,\n    this function has a ZeroDivisionError but can be evaluated at the limit\n    to be :math:`z = \\frac{x}{1+x}`.\n\n    Examples\n    --------\n    >>> P_NTU_Pc(5, .7)\n    0.920670368605\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    term = exp(-x*(1. - y))\n    if (1. - y*term) == 0.0:\n        return x/(1. + x)\n    return (1. - term)/(1. - y*term)\n\n\ndef effectiveness_NTU_method(mh, mc, Cph, Cpc, subtype=\"counterflow\", Thi=None,\n                             Tho=None, Tci=None, Tco=None, UA=None,\n                             n_shell_tube=None):\n    r\"\"\"Wrapper for the various effectiveness-NTU method function calls,\n    which can solve a heat exchanger. The heat capacities and mass flows\n    of each stream and the type of the heat exchanger are always required.\n    As additional inputs, one combination of the following inputs is required:\n\n    * Three of the four inlet and outlet stream temperatures.\n    * Temperatures for the cold outlet and hot inlet and UA\n    * Temperatures for the cold outlet and hot outlet and UA\n    * Temperatures for the cold inlet and hot inlet and UA\n    * Temperatures for the cold inlet and hot outlet and UA\n\n    Parameters\n    ----------\n    mh : float\n        Mass flow rate of hot stream, [kg/s]\n    mc : float\n        Mass flow rate of cold stream, [kg/s]\n    Cph : float\n        Averaged heat capacity of hot stream, [J/kg/K]\n    Cpc : float\n        Averaged heat capacity of cold stream, [J/kg/K]\n    subtype : str, optional\n        The subtype of exchanger; one of 'counterflow', 'parallel', 'crossflow'\n        'crossflow, mixed Cmin', 'crossflow, mixed Cmax', 'boiler', 'condenser',\n        'S&T', or 'nS&T' where n is the number of shell and tube exchangers in\n        a row\n    Thi : float, optional\n        Inlet temperature of hot fluid, [K]\n    Tho : float, optional\n        Outlet temperature of hot fluid, [K]\n    Tci : float, optional\n        Inlet temperature of cold fluid, [K]\n    Tco : float, optional\n        Outlet temperature of cold fluid, [K]\n    UA : float, optional\n        Combined Area-heat transfer coefficient term, [W/K]\n    n_shell_tube : None or int, optional\n        The number of shell and tube exchangers in a row, [-]\n\n    Returns\n    -------\n    results : dict\n        * Q : Heat exchanged in the heat exchanger, [W]\n        * UA : Combined area-heat transfer coefficient term, [W/K]\n        * Cr : The heat capacity rate ratio, of the smaller fluid to the larger\n          fluid, [-]\n        * Cmin : The heat capacity rate of the smaller fluid, [W/K]\n        * Cmax : The heat capacity rate of the larger fluid, [W/K]\n        * effectiveness : The thermal effectiveness of the heat exchanger, [-]\n        * NTU : Thermal Number of Transfer Units [-]\n        * Thi : Inlet temperature of hot fluid, [K]\n        * Tho : Outlet temperature of hot fluid, [K]\n        * Tci : Inlet temperature of cold fluid, [K]\n        * Tco : Outlet temperature of cold fluid, [K]\n\n    See Also\n    --------\n    effectiveness_from_NTU\n    NTU_from_effectiveness\n\n    Examples\n    --------\n    Solve a heat exchanger to determine UA and effectiveness given the\n    configuration, flows, subtype, the cold inlet/outlet temperatures, and the\n    hot stream inlet temperature.\n\n    >>> from pprint import pprint\n    >>> pprint(effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900,\n    ... subtype='crossflow, mixed Cmax', Tci=15, Tco=85, Thi=130))\n    {'Cmax': 9672.0,\n     'Cmin': 2755.0,\n     'Cr': 0.284842845326,\n     'NTU': 1.104083909,\n     'Q': 192850.0,\n     'Tci': 15,\n     'Tco': 85,\n     'Thi': 130,\n     'Tho': 110.0610008271,\n     'UA': 3041.75117083,\n     'effectiveness': 0.608695652173}\n\n    Solve the same heat exchanger with the UA specified, and known inlet\n    temperatures:\n\n    >>> pprint(effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900,\n    ... subtype='crossflow, mixed Cmax', Tci=15, Thi=130, UA=3041.75))\n    {'Cmax': 9672.0,\n     'Cmin': 2755.0,\n     'Cr': 0.284842845326,\n     'NTU': 1.104083484573,\n     'Q': 192849.9631022,\n     'Tci': 15,\n     'Tco': 84.9999866069,\n     'Thi': 130,\n     'Tho': 110.0610046420,\n     'UA': 3041.75,\n     'effectiveness': 0.608695535712}\n    \"\"\"\n    Cmin = calc_Cmin(mh=mh, mc=mc, Cph=Cph, Cpc=Cpc)\n    Cmax = calc_Cmax(mh=mh, mc=mc, Cph=Cph, Cpc=Cpc)\n    Cr = calc_Cr(mh=mh, mc=mc, Cph=Cph, Cpc=Cpc)\n    Cc = mc*Cpc\n    Ch = mh*Cph\n    if UA is not None:\n        NTU = NTU_from_UA(UA=UA, Cmin=Cmin)\n        effectiveness = eff = effectiveness_from_NTU(NTU=NTU, Cr=Cr, n_shell_tube=n_shell_tube, subtype=subtype)\n\n        possible_inputs = [(Tci, Thi), (Tci, Tho), (Tco, Thi), (Tco, Tho)]\n        if not any(i for i in possible_inputs if None not in i):\n            raise ValueError(\"One set of (Tci, Thi), (Tci, Tho), (Tco, Thi), or (Tco, Tho) are required along with UA.\")\n\n        if Thi is not None and Tci is not None:\n            Q = eff*Cmin*(Thi - Tci)\n        elif Tho is not None and Tco is not None:\n            Q = eff*Cmin*Cc*Ch*(Tco - Tho)/(eff*Cmin*(Cc+Ch) - Ch*Cc)\n        elif Thi is not None and Tco is not None:\n            Q = Cmin*Cc*eff*(Tco-Thi)/(eff*Cmin - Cc)\n        elif Tho is not None and Tci is not None:\n            Q = Cmin*Ch*eff*(Tci-Tho)/(eff*Cmin - Ch)\n        # The following is not used as it was decided to require complete temperature information\n#        elif Tci and Tco:\n#            Q = Cc*(Tco - Tci)\n#        elif Tho and Thi:\n#            Q = Ch*(Thi-Tho)\n        # Compute the remaining temperatures with the fewest lines of code\n        if Tci is not None and Tco is None:\n            Tco = Tci + Q/(Cc)\n        else:\n            Tci = Tco - Q/(Cc)\n        if Thi is not None and Tho is None:\n            Tho = Thi - Q/(Ch)\n        else:\n            Thi = Tho + Q/(Ch)\n\n    elif UA is None:\n        # Case where we're solving for UA\n        # Three temperatures are required\n        # Ensures all four temperatures are set and Q is calculated\n        if Thi is not None and Tho is not None:\n            Q = mh*Cph*(Thi-Tho)\n            if Tci is not None and Tco is None:\n                Tco = Tci + Q/(mc*Cpc)\n            elif Tco is not None and Tci is None:\n                Tci = Tco - Q/(mc*Cpc)\n            elif Tco is not None and Tci is not None:\n                Q2 = mc*Cpc*(Tco-Tci)\n                if abs((Q-Q2)/Q) > 0.01:\n                    raise ValueError(\"The specified heat capacities, mass flows, and temperatures are inconsistent\")\n            else:\n                raise ValueError(\"At least one temperature is required to be specified on the cold side.\")\n\n        elif Tci is not None and Tco is not None:\n            Q = mc*Cpc*(Tco-Tci)\n            if Thi is not None and Tho is None:\n                Tho = Thi - Q/(mh*Cph)\n            elif Tho is not None and Thi is None:\n                Thi = Tho + Q/(mh*Cph)\n            else:\n                raise ValueError(\"At least one temperature is required to be specified on the cold side.\")\n        else:\n            raise ValueError(\"Three temperatures are required to be specified \"\n                            \"when solving for UA\")\n\n        effectiveness = Q/Cmin/(Thi-Tci)\n        NTU = NTU_from_effectiveness(effectiveness, Cr, n_shell_tube=n_shell_tube, subtype=subtype)\n        UA = UA_from_NTU(NTU, Cmin)\n    return {\"Q\": Q, \"UA\": UA, \"Cr\":Cr, \"Cmin\": Cmin, \"Cmax\":Cmax,\n            \"effectiveness\": effectiveness, \"NTU\": NTU, \"Thi\": Thi, \"Tho\": Tho,\n            \"Tci\": Tci, \"Tco\": Tco}\n\n\ndef temperature_effectiveness_air_cooler(R1: float, NTU1: float, rows: int, passes: int, coerce: bool=True) -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of an air cooler with\n    a specified heat capacity ratio, number of transfer units `NTU1`,\n    number of rows `rows`, and number of passes `passes`. The supported cases\n    are as follows:\n\n    * N rows 1 pass\n    * N row N pass (up to N = 5)\n    * 4 rows 2 passes\n\n    For N rows 1 passes ([2]_, shown in [1]_ and [3]_):\n\n    .. math::\n        P = \\frac{1}{R} \\left\\{1 - \\left[\\frac{N\\exp(NKR)}\n        {1 + \\sum_{i=1}^{N-1}\\sum_{j=0}^i  {{i}\\choose{j}}K^j \\exp(-(i-j)NTU/N)\n        \\sum_{k=0}^j \\frac{(NKR)^k}{k!}}\\right]^{-1}\\right\\}\n\n    For 2 rows 2 passes (cited as from [4]_ in [1]_):\n\n    .. math::\n        P_1 = \\frac{1}{R}\\left(1 -\\frac{1}{\\xi}\\right)\n\n    .. math::\n        \\xi = \\frac{K}{2} + \\left(1 - \\frac{K}{2}\\right)\\exp(2KR)\n\n    .. math::\n        K = 1 - \\exp\\left(\\frac{-NTU}{2}\\right)\n\n    For 3 rows / 3 passes (cited as from [4]_ in [1]_):\n\n    .. math::\n        \\xi = K\\left[1 - \\frac{K}{4} - RK\\left(1 - \\frac{K}{2}\\right)\\right]\n        \\exp(KR) + \\exp(3KR)\\left(1 - \\frac{K}{2}\\right)^2\n\n    .. math::\n        K = 1 - \\exp\\left(\\frac{-NTU}{3}\\right)\n\n    For 4 rows / 4 passes (cited as from [4]_ in [1]_):\n\n    .. math::\n        \\xi = \\frac{K}{2}\\left(1 - \\frac{K}{2} + \\frac{K^2}{4}\\right)\n        + K\\left(1 - \\frac{K}{2}\\right)\n        \\left[1 - \\frac{R}{8}K\\left(1 - \\frac{K}{2}\\right)\\exp(2KR)\\right]\n        + \\exp(4KR)\\left(1 - \\frac{K}{2}\\right)^3\n\n    .. math::\n        K = 1 - \\exp\\left(\\frac{-NTU}{4}\\right)\n\n    For 5 rows / 5 passes (cited as from [4]_ in [1]_):\n\n    .. math::\n        \\xi = \\left\\{K \\left(1 - \\frac{3}{4}K + \\frac{K^2}{2}- \\frac{K^3}{8}\n        \\right) - RK^2\\left[1 -K + \\frac{3}{4}K^2 - \\frac{1}{4}K^3\n        - \\frac{R}{2}K^2\\left(1 - \\frac{K}{2}\\right)^2\\right]\\right\\}\\exp(KR)\n        + \\left[K\\left(1 - \\frac{3}{4}K + \\frac{1}{16}K^3\\right) - 3RK^2\\left(1\n        - \\frac{K}{2}\\right)^3\\right]\\exp(3KR)+ \\left(1 - \\frac{K}{2}\\right)^4\n        \\exp(5KR)\n\n    For 4 rows / 2 passes (cited as from [4]_ in [1]_):\n\n    .. math::\n        P_1 = \\frac{1}{R}\\left(1 -\\frac{1}{\\xi}\\right)\n\n    .. math::\n        \\xi = \\left\\{\\frac{R}{2}K^3[4 - K + 2RK^2] + \\exp(4KR)\n        + K\\left[1 - \\frac{K}{2} + \\frac{K^2}{8}\\right]\n        \\left[1 - \\exp(4KR)\\right]\n        \\right\\}\\frac{1}{(1+RK^2)^2}\n\n    .. math::\n        K = 1 - \\exp\\left(\\frac{-NTU}{4}\\right)\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (process fluid side) [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (process fluid side) [-]\n    rows : int\n        Number of rows of tubes in the air cooler [-]\n    passes : int\n        Number of passes the process fluid undergoes [-]\n    coerce : bool\n        If True, the number of passes or rows, if otherwise unsupported, will\n        be replaced with a similar number to allow the calculation to proceed,\n        [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (process fluid side) [-]\n\n    Notes\n    -----\n    For the 1-pass case, the exact formula used can take a while to compute for\n    large numbers of tube rows; 100 us for 20 rows, 1 ms for 50 rows.\n    Floating point rounding behavior can also be an issue for large numbers of\n    tube passes, leading to thermal effectivenesses larger than one being\n    returned:\n\n    >>> temperature_effectiveness_air_cooler(1e-10, 100, rows=150, passes=1.0)\n    1.000026728092962\n\n    Furthermore, as a factorial of the number of tube counts is used, there\n    comes a point where standard floats are not able to hold the intermediate\n    calculations values and an error will occur:\n\n    >>> temperature_effectiveness_air_cooler(.5, 1.1, rows=200, passes=1.0)\n    Traceback (most recent call last):\n    ...\n    OverflowError: int too large to convert to float\n\n\n    Examples\n    --------\n    >>> temperature_effectiveness_air_cooler(.5, 2, rows=2, passes=2)\n    0.7523072855817072\n\n    References\n    ----------\n    .. [1] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [2] Schedwill, H., \"Thermische Auslegung von Kreuzstromwarmeaustauschern,\n       Fortschr-Ber.\" VDI Reihe 6 19, VDI, Germany, 1968.\n    .. [3] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1983.\n    .. [4]  Nicole, F. J. L.. \"Mean temperature difference for heat exchanger\n       design.\" Council for Scientific and Industrial Research, Special Report\n       Chem. 223, Pretoria, South Africa (1972).\n    \"\"\"\n    if passes == 1:\n        N = rows\n        K = 1. - exp(-NTU1/N)\n        NKR1 = N*K*R1\n        NTU1_N = NTU1/N\n        top = N*exp(N*K*R1)\n        # TODO speed this up\n        # Precalculate integer factorials up to N\n        # Factorial fits in 64 bit int only up to N = 20\n        # https://stackoverflow.com/questions/62056035/how-to-call-math-factorial-from-numba-with-nopython-mode\n        Np1 = N+1\n        factorials = [factorial(i) for i in range(N)]\n        K_powers = [K**j for j in range(N+1)]\n        NKR1_powers = [NKR1**k for k in range(N+1)]\n        exp_terms = [exp(i*NTU1_N) for i in range(-N+1, 1)] # Only need to compute one exp, then multiply\n        NKR1_powers_over_factorials = [NKR1_powers[k]/factorials[k]\n                                       for k in range(N)]\n\n        # Precompute even more...\n        NKR1_pows_div_factorials = [0]\n        for k in NKR1_powers_over_factorials:\n            NKR1_pows_div_factorials.append(NKR1_pows_div_factorials[-1]+k)\n        NKR1_pows_div_factorials.pop(0)\n\n        final_speed = [0.0]*N\n        for i in range(N):\n            final_speed[i] = K_powers[i]*NKR1_pows_div_factorials[i]\n#        final_speed = [i*j for i, j in zip(K_powers, NKR1_pows_div_factorials)]\n\n        tot = 0.\n        for i in range(1, N):\n            for j in range(i+1):\n                # can't optimize the factorial\n                prod = factorials[i]/(factorials[i-j]*factorials[j])\n                tot1 = prod*exp_terms[j-i-1]\n                tot += tot1*final_speed[j]\n\n        return 1./R1*(1. - 1./(top/(1.+tot)))\n    elif rows == passes == 2:\n        K = 1. - exp(-0.5*NTU1)\n        xi = 0.5*K + (1. - 0.5*K)*exp(2.*K*R1)\n        return 1./R1*(1. - 1./xi)\n    elif rows == passes == 3:\n        K = 1. - exp(-NTU1/3.)\n        xi = (K*(1. - 0.25*K - R1*K*(1. - 0.5*K))*exp(K*R1)\n              + exp(3.*K*R1)*(1. - 0.5*K)**2)\n        return 1./R1*(1. - 1./xi)\n    elif rows == passes == 4:\n        K = 1. - exp(-0.25*NTU1)\n        xi = (0.5*K*(1. - 0.5*K + 0.25*K**2)\n              + K*(1. - 0.5*K)*(1. - 0.125*R1*K*(1. - 0.5*K)*exp(2.*K*R1))\n              + exp(4.*K*R1)*(1. - 0.5*K)**3)\n        return 1./R1*(1. - 1./xi)\n    elif rows == passes == 5:\n        K = 1. - exp(-0.2*NTU1)\n        K2 = K*K\n        K3 = K2*K\n        xi = (K*(1. - .75*K + .5*K2 - .125*K3)\n              - R1*K2*(1. - K + .75*K2 - .25*K3\n              - .5*R1*K2*(1. - .5*K)**2))*exp(K*R1)\n        xi += ((K*(1. - .75*K + 1/16.*K3) - 3*R1*K2*(1. - .5*K)**3)\n              *exp(3*K*R1) + (1. - .5*K)**4*exp(5*K*R1))\n        return 1./R1*(1. - 1./xi)\n    elif rows == 4 and passes == 2:\n        K = 1. - exp(-0.25*NTU1)\n        xi = (0.5*R1*K**3*(4. - K + 2.*R1*K**2) + exp(4.*K*R1) + K*(1. - 0.5*K\n              + 0.125*K**2)*(1 - exp(4.*K*R1)))*(1. + R1*K**2)**-2\n        return 1./R1*(1. - 1./xi)\n    else:\n        if coerce:\n            if passes > rows:\n                passes = rows # bad user input - replace with an exception?\n            new_passes, new_rows = passes, rows\n            # Domain reduction\n            if passes > 5:\n                new_passes = passes = 5\n            if rows > 5:\n                new_rows = rows = 5\n            if rows -1 == passes:\n                new_rows, new_passes = rows -1, passes\n            elif (passes in (2, 3, 5)) and rows >= 4:\n                new_rows, new_passes = 4, 2\n\n            return temperature_effectiveness_air_cooler(R1=R1, NTU1=NTU1, rows=new_rows, passes=new_passes)\n\n        else:\n            raise ValueError(\"Number of passes and rows not supported.\")\n\n\ndef temperature_effectiveness_basic(R1: float, NTU1: float, subtype: str=\"crossflow\") -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of a heat exchanger with\n    a specified heat capacity ratio, number of transfer units `NTU1`,\n    and of type `subtype`. This function performs the calculations for the\n    basic cases, not actual shell-and-tube exchangers. The supported cases\n    are as follows:\n\n    * Counterflow (ex. double-pipe)\n    * Parallel (ex. double pipe inefficient configuration)\n    * Crossflow, single pass, fluids unmixed\n    * Crossflow, single pass, fluid 1 mixed, fluid 2 unmixed\n    * Crossflow, single pass, fluid 2 mixed, fluid 1 unmixed\n    * Crossflow, single pass, both fluids mixed\n\n    For parallel flow heat exchangers (this configuration is symmetric):\n\n    .. math::\n        P_1 = \\frac{1 - \\exp[-NTU_1(1+R_1)]}{1 + R_1}\n\n    For counterflow heat exchangers (this configuration is symmetric):\n\n    .. math::\n        P_1 = \\frac{1 - \\exp[-NTU_1(1-R_1)]}{1 - R_1 \\exp[-NTU_1(1-R_1)]}\n\n    For cross-flow (single-pass) heat exchangers with both fluids unmixed\n    (this configuration is symmetric), there are two solutions available;\n    a frequently cited approximation and an exact solution which uses\n    a numerical integration developed in [4]_. The approximate solution is:\n\n    .. math::\n        P_1 \\approx 1 - \\exp\\left[\\frac{NTU_1^{0.22}}{R_1}\n        (\\exp(-R_1 NTU_1^{0.78})-1)\\right]\n\n    The exact solution for crossflow (single pass, fluids unmixed) is:\n\n    .. math::\n        \\epsilon = \\frac{1}{R_1} - \\frac{\\exp(-R_1 \\cdot NTU_1)}{2(R_1 NTU_1)^2}\n        \\int_0^{2 NTU_1\\sqrt{R_1}} \\left(1 + NTU_1 - \\frac{v^2}{4R_1 NTU_1}\n        \\right)\\exp\\left(-\\frac{v^2}{4R_1 NTU_1}\\right)v I_0(v) dv\n\n    For cross-flow (single-pass) heat exchangers with fluid 1 mixed, fluid 2\n    unmixed:\n\n    .. math::\n        P_1 = 1 - \\exp\\left(-\\frac{K}{R_1}\\right)\n\n    .. math::\n        K = 1 - \\exp(-R_1 NTU_1)\n\n    For cross-flow (single-pass) heat exchangers with fluid 2 mixed, fluid 1\n    unmixed:\n\n    .. math::\n        P_1 = \\frac{1 - \\exp(-K R_1)}{R_1}\n\n    .. math::\n        K = 1 - \\exp(-NTU_1)\n\n    For cross-flow (single-pass) heat exchangers with both fluids mixed\n    (this configuration is symmetric):\n\n    .. math::\n        P_1 = \\left(\\frac{1}{K_1} + \\frac{R_1}{K_2} - \\frac{1}{NTU_1}\\right)^{-1}\n\n    .. math::\n        K_1 = 1 - \\exp(-NTU_1)\n\n    .. math::\n        K_2 = 1 - \\exp(-R_1 NTU_1)\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 [-]\n    subtype : float\n        The type of heat exchanger; one of 'counterflow', 'parallel',\n        'crossflow', 'crossflow approximate', 'crossflow, mixed 1',\n        'crossflow, mixed 2', 'crossflow, mixed 1&2'.\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    The crossflow case is an approximation only. There is an actual\n    solution involving an infinite sum. This was implemented, but found to\n    differ substantially so the approximation is used instead.\n\n    Examples\n    --------\n    >>> temperature_effectiveness_basic(R1=.1, NTU1=4, subtype='counterflow')\n    0.9753412729761263\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [4] Triboix, Alain. \"Exact and Approximate Formulas for Cross Flow Heat\n       Exchangers with Unmixed Fluids.\" International Communications in Heat\n       and Mass Transfer 36, no. 2 (February 1, 2009): 121-24.\n       doi:10.1016/j.icheatmasstransfer.2008.10.012.\n    \"\"\"\n    if subtype == \"counterflow\":\n        # Same as TEMA 1 pass\n        if R1 == 1.0:\n            \"\"\"from sympy import *\n            R1, NTU1 = symbols('R1, NTU1')\n            P1 = (1 - exp(-NTU1*(1 - R1)))/(1 - R1*exp(-NTU1*(1-R1)))\n            limit(P1, R1, 1)\n            \"\"\"\n            P1 = -NTU1/(-NTU1 - 1.0)\n        else:\n            P1 = (1.0 - exp(-NTU1*(1 - R1)))/(1.0 - R1*exp(-NTU1*(1-R1)))\n    elif subtype == \"parallel\":\n        P1 = (1.0 - exp(-NTU1*(1 + R1)))/(1.0 + R1)\n    elif subtype == \"crossflow approximate\":\n        # This isn't technically accurate, an infinite sum is required\n        # It has been computed from two different sources\n        # but is found not to be within the 1% claimed of this equation\n        P1 = 1.0 - exp(NTU1**0.22/R1*(exp(-R1*NTU1**0.78) - 1.))\n    elif subtype == \"crossflow\":\n        # TODO attempt chebyshev approximation of P1 as a function of R1, NTU1 (for stability)\n        R1_NTU1_4_inv = 1.0/(4.*R1*NTU1)\n        int_term = quad(crossflow_effectiveness_to_int, 0.0, 2.*NTU1*R1**0.5, args=(NTU1, R1_NTU1_4_inv))[0]\n        P1 = 1./R1 - exp(-R1*NTU1)/(2.*(R1*NTU1)**2)*int_term\n    elif subtype == \"crossflow, mixed 1\":\n        # Not symmetric\n        K = 1 - exp(-R1*NTU1)\n        P1 = 1 - exp(-K/R1)\n    elif subtype == \"crossflow, mixed 2\":\n        # Not symmetric\n        K = 1 - exp(-NTU1)\n        P1 = (1 - exp(-K*R1))/R1\n    elif subtype == \"crossflow, mixed 1&2\":\n        K1 = 1. - exp(-NTU1)\n        K2 = 1. - exp(-R1*NTU1)\n        P1 = (1./K1 + R1/K2 - 1./NTU1)**-1\n    else:\n        raise ValueError(\"Subtype not recognized.\")\n    return P1\n\n\ndef temperature_effectiveness_TEMA_J(R1: float, NTU1: float, Ntp: int) -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of a TEMA J type heat exchanger\n    with a specified heat capacity ratio, number of transfer units `NTU1`,\n    and of number of tube passes `Ntp`. The supported cases are as follows:\n\n    * One tube pass (shell fluid mixed)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes)\n    * Four tube passes (shell fluid mixed, tube pass mixed between passes)\n\n    For 1-1 TEMA J shell and tube exchangers, shell and tube fluids mixed:\n\n    .. math::\n        P_1 = \\frac{1}{R_1}\\left[1- \\frac{(2-R_1)(2E + R_1 B)}{(2+R_1)\n        (2E - R_1/B)}\\right]\n\n    For 1-2 TEMA J, shell and tube fluids mixed. There are two possible\n    arrangements for the flow and the number of tube passes, but the equation\n    is the same in both:\n\n    .. math::\n        P_1 = \\left[1 + \\frac{R_1}{2} + \\lambda B - 2\\lambda C D\\right]^{-1}\n\n    .. math::\n        B = \\frac{(A^\\lambda +1)}{A^\\lambda -1}\n\n    .. math::\n        C = \\frac{A^{(1 + \\lambda)/2}}{\\lambda - 1 + (1 + \\lambda)A^\\lambda}\n\n    .. math::\n        D = 1 + \\frac{\\lambda A^{(\\lambda-1)/2}}{A^\\lambda -1}\n\n    .. math::\n        A = \\exp(NTU_1)\n\n    .. math::\n        \\lambda = (1 + R_1^2/4)^{0.5}\n\n    For 1-4 TEMA J, shell and tube exchanger with both sides mixed:\n\n    .. math::\n        P_1 = \\left[1 + \\frac{R_1}{4}\\left(\\frac{1+3E}{1+E}\\right) + \\lambda B\n        - 2 \\lambda C D\\right]^{-1}\n\n    .. math::\n        B = \\frac{A^\\lambda +1}{A^\\lambda -1}\n\n    .. math::\n        C = \\frac{A^{(1+\\lambda)/2}}{\\lambda - 1 + (1 + \\lambda)A^\\lambda}\n\n    .. math::\n        D = 1 + \\frac{\\lambda A^{(\\lambda-1)/2}}{A^\\lambda -1}\n\n    .. math::\n        A = \\exp(NTU_1)\n\n    .. math::\n        E = \\exp(R_1 NTU_1/2)\n\n    .. math::\n        \\lambda = (1 + R_1^2/16)^{0.5}\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, 2, or 4, [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    For numbers of tube passes that are not 1, 2, or 4, an exception is raised.\n    The convention for the formulas in [1]_ and [3]_ are with the shell side\n    as side 1, and the tube side as side 2. [2]_ has formulas with the\n    opposite convention.\n\n    Examples\n    --------\n    >>> temperature_effectiveness_TEMA_J(R1=1/3., NTU1=1., Ntp=1)\n    0.5699085193651295\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    if Ntp == 1:\n        A = exp(NTU1)\n        B = exp(-NTU1*R1/2.)\n        if R1 != 2:\n            P1 = 1./R1*(1. - (2. - R1)*(2.*A + R1*B)/(2. + R1)/(2.*A - R1/B))\n        else:\n            P1 = 0.5*(1. - (1. + A**-2)/2./(1. + NTU1))\n    elif Ntp == 2:\n        lambda1 = (1. + R1*R1/4.)**0.5\n        A = exp(NTU1)\n        D = 1. + lambda1*A**((lambda1 - 1.)/2.)/(A**lambda1 - 1.)\n        C = A**((1+lambda1)/2.)/(lambda1 - 1. + (1. + lambda1)*A**lambda1)\n        B = (A**lambda1 + 1.)/(A**lambda1 - 1.)\n        P1 = 1./(1. + R1/2. + lambda1*B - 2.*lambda1*C*D)\n    elif Ntp == 4:\n        lambda1 = (1. + R1**2/16.)**0.5\n        E = exp(R1*NTU1/2.)\n        A = exp(NTU1)\n        D = 1. + lambda1*A**((lambda1-1)/2.)/(A**lambda1-1.)\n        C = A**((1+lambda1)/2.)/(lambda1 - 1. + (1. + lambda1)*A**lambda1)\n        B = (A**lambda1 + 1.)/(A**lambda1-1)\n        P1 = 1./(1. + R1/4.*(1. + 3.*E)/(1. + E) + lambda1*B - 2.*lambda1*C*D)\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1, 2, and 4.\")\n    return P1\n\n\ndef temperature_effectiveness_TEMA_H(R1: float, NTU1: float, Ntp: int, optimal: bool=True) -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of a TEMA H type heat exchanger\n    with a specified heat capacity ratio, number of transfer units `NTU1`,\n    and of number of tube passes `Ntp`. For the two tube pass case, there are\n    two possible orientations, one inefficient and one efficient controlled\n    by the `optimal` option. The supported cases are as follows:\n\n    * One tube pass (tube fluid split into two streams individually mixed,\n      shell fluid mixed)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes, inlet\n      tube side next to inlet shell-side)\n\n    1-1 TEMA H, tube fluid split into two streams individually mixed, shell\n    fluid mixed:\n\n    .. math::\n        P_1 = E[1 + (1 - BR_1/2)(1 - A R_1/2 + ABR_1)] - AB(1 - BR_1/2)\n\n    .. math::\n        A = \\frac{1}{1 + R_1/2}\\{1 - \\exp[-NTU_1(1 + R_1/2)/2]\\}\n\n    .. math::\n        B = \\frac{1-D}{1-R_1 D/2}\n\n    .. math::\n        D = \\exp[-NTU_1(1-R_1/2)/2]\n\n    .. math::\n        E = (A + B - ABR_1/2)/2\n\n    1-2 TEMA H, shell and tube fluids mixed in each pass at the cross section:\n\n    .. math::\n        P_1 = \\frac{1}{R_1}\\left[1 - \\frac{(1-D)^4}{B - 4G/R_1}\\right]\n\n    .. math::\n        B = (1+H)(1+E)^2\n\n    .. math::\n        G = (1-D)^2(D^2 + E^2) + D^2(1 + E)^2\n\n    .. math::\n        H = [1 - \\exp(-2\\beta)]/(4/R_1 -1)\n\n    .. math::\n        E = [1 - \\exp(-\\beta)]/(4/R_1 - 1)\n\n    .. math::\n        D = [1 - \\exp(-\\alpha)]/(4/R_1 + 1)\n\n    .. math::\n        \\alpha = NTU_1(4 + R_1)/8\n\n    .. math::\n        \\beta = NTU_1(4-R_1)/8\n\n    1-2 TEMA H, shell and tube fluids mixed in each pass at the cross section\n    but with the inlet tube stream coming in next to the shell fluid inlet\n    in an inefficient way (this is only shown in [2]_, and the stream 1/2\n    convention in it is different but converted here; P1 is still returned):\n\n    .. math::\n        P_2 = \\left[1 - \\frac{B + 4GR_2}{(1-D)^4}\\right]\n\n    .. math::\n        B = (1 + H)(1 + E)^2\n\n    .. math::\n        G = (1-D)^2(D^2 + E^2) + D^2(1 + E)^2\n\n    .. math::\n        D = \\frac{1 - \\exp(-\\alpha)}{1 - 4R_2}\n\n    .. math::\n        E = \\frac{\\exp(-\\beta) - 1}{4R_2 +1}\n\n    .. math::\n        H = \\frac{\\exp(-2\\beta) - 1}{4R_2 +1}\n\n    .. math::\n        \\alpha = \\frac{NTU_2}{8}(4R_2 -1)\n\n    .. math::\n        \\beta = \\frac{NTU_2}{8}(4R_2 +1)\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, or 2, [-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case, [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    For numbers of tube passes greater than 1 or 2, an exception is raised.\n    The convention for the formulas in [1]_ and [3]_ are with the shell side\n    as side 1, and the tube side as side 2. [2]_ has formulas with the\n    opposite convention.\n\n    Examples\n    --------\n    >>> temperature_effectiveness_TEMA_H(R1=1/3., NTU1=1., Ntp=1)\n    0.5730728284905833\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    if Ntp == 1:\n        A = 1./(1 + R1/2.)*(1. - exp(-NTU1*(1. + R1/2.)/2.))\n        D = exp(-NTU1*(1. - R1/2.)/2.)\n        if R1 != 2:\n            B = (1. - D)/(1. - R1*D/2.)\n        else:\n            B = NTU1/(2. + NTU1)\n        E = (A + B - A*B*R1/2.)/2.\n        P1 = E*(1. + (1. - B*R1/2.)*(1. - A*R1/2. + A*B*R1)) - A*B*(1. - B*R1/2.)\n    elif Ntp == 2 and optimal:\n        alpha = NTU1*(4. + R1)/8.\n        beta = NTU1*(4. - R1)/8.\n        D = (1. - exp(-alpha))/(4./R1 + 1)\n        if R1 != 4:\n            E = (1. - exp(-beta))/(4./R1 - 1.)\n            H = (1. - exp(-2.*beta))/(4./R1 - 1.)\n        else:\n            E = NTU1/2.\n            H = NTU1\n        G = (1-D)**2*(D**2 + E**2) + D**2*(1+E)**2\n        B = (1. + H)*(1. + E)**2\n        P1 = 1./R1*(1. - (1. - D)**4/(B - 4.*G/R1))\n    elif Ntp == 2 and not optimal:\n        R1_orig = R1\n        #NTU2 = NTU1*R1_orig but we want to treat it as NTU1 in this case\n        NTU1 = NTU1*R1_orig # switch 1\n        # R2 = 1/R1 but we want to treat it as R1 in this case\n        R1 = 1./R1_orig # switch 2\n\n        beta = NTU1*(4.*R1 + 1)/8.\n        alpha = NTU1/8.*(4.*R1 - 1.)\n        H = (exp(-2.*beta) - 1.)/(4.*R1 + 1.)\n        E = (exp(-beta) - 1.)/(4.*R1 + 1.)\n        B = (1. + H)*(1. + E)**2\n        if R1 != 0.25:\n            D = (1. - exp(-alpha))/(1. - 4.*R1)\n            G = (1. - D)**2*(D**2 + E**2) + D**2*(1. + E)**2\n            P1 = (1. - (B + 4.*G*R1)/(1. - D)**4)\n        else:\n            D = -NTU1/8.\n            G = (1. - D)**2*(D**2 + E**2) + D**2*(1. + E)**2\n            P1 = (1. - (B + 4.*G*R1)/(1. - D)**4)\n        P1 = P1/R1_orig # switch 3, confirmed\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1 and 2.\")\n    return P1\n\n\ndef temperature_effectiveness_TEMA_G(R1: float, NTU1: float, Ntp: int, optimal: bool=True) -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of a TEMA G type heat exchanger\n    with a specified heat capacity ratio, number of transfer units `NTU1`,\n    and of number of tube passes `Ntp`. For the two tube pass case, there are\n    two possible orientations, one inefficient and one efficient controlled\n    by the `optimal` option. The supported cases are as follows:\n\n    * One tube pass (tube fluid split into two streams individually mixed,\n      shell fluid mixed)\n    * Two tube passes (shell and tube exchanger with shell and tube fluids\n      mixed in each pass at the cross section), counterflow arrangement\n    * Two tube passes (shell and tube exchanger with shell and tube fluids\n      mixed in each pass at the cross section), parallelflow arrangement\n\n    1-1 TEMA G, tube fluid split into two streams individually mixed, shell\n    fluid mixed (this configuration is symmetric):\n\n    .. math::\n        P_1 = A + B - AB(1 + R_1) + R_1 AB^2\n\n    .. math::\n        A = \\frac{1}{1 + R_1}\\{1 - \\exp(-NTU_1(1+R_1)/2)\\}\n\n    .. math::\n        B = \\frac{1 - D}{1 - R_1 D}\n\n    .. math::\n        D = \\exp[-NTU_1(1-R_1)/2]\n\n    1-2 TEMA G, shell and tube exchanger with shell and tube fluids mixed in\n    each pass at the cross section:\n\n    .. math::\n        P_1 = (B - \\alpha^2)/(A + 2 + R_1 B)\n\n    .. math::\n        A = -2 R_1(1-\\alpha)^2/(2 + R_1)\n\n    .. math::\n        B = [4 - \\beta(2+R_1)]/(2 - R_1)\n\n    .. math::\n        \\alpha = \\exp[-NTU_1(2+R_1)/4]\n\n    .. math::\n        \\beta = \\exp[-NTU_1(2 - R_1)/2]\n\n    1-2 TEMA G, shell and tube exchanger in overall parallelflow arrangement\n    with shell and tube fluids mixed in each pass at the cross section\n    (this is only shown in [2]_, and the stream convention in it is different\n    but converted here; P1 is still returned):\n\n    .. math::\n        P_2 = \\frac{(B-\\alpha^2)}{R_2(A - \\alpha^2/R_2 + 2)}\n\n    .. math::\n        A = \\frac{(1-\\alpha)^2}{(R_2-0.5)}\n\n    .. math::\n        B = \\frac{4R_2 - \\beta(2R_2 - 1)}{2R_2 + 1}\n\n    .. math::\n        \\alpha = \\exp\\left(\\frac{-NTU_2(2R_2-1)}{4}\\right)\n\n    .. math::\n        \\beta = \\exp\\left(\\frac{-NTU_2(2R_2+1)}{2}\\right)\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n    Ntp : int\n        Number of tube passes, 1 or 2, [-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case (only applies for two passes), [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    For numbers of tube passes greater than 1 or 2, an exception is raised.\n    The convention for the formulas in [1]_ and [3]_ are with the shell side\n    as side 1, and the tube side as side 2. [2]_ has formulas with the\n    opposite convention.\n\n    Examples\n    --------\n    >>> temperature_effectiveness_TEMA_G(R1=1/3., NTU1=1., Ntp=1)\n    0.5730149350867675\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    if Ntp == 1:\n        D = exp(-NTU1*(1. - R1)/2.)\n        if R1 != 1:\n            B = (1. - D)/(1. - R1*D)\n        else:\n            B = NTU1/(2. + NTU1)\n        A = 1./(1. + R1)*(1. - exp(-NTU1*(1. + R1)/2.))\n        P1 = A + B - A*B*(1. + R1) + R1*A*B**2\n    elif Ntp == 2 and optimal:\n        if R1 != 2:\n            beta = exp(-NTU1*(2. - R1)/2.)\n            alpha = exp(-NTU1*(2. + R1)/4.)\n            B = (4. - beta*(2. + R1))/(2. - R1)\n            A = -2.*R1*(1-alpha)**2/(2. + R1)\n            P1 = (B - alpha**2)/(A + 2. + R1*B)\n        else:\n            alpha = exp(-NTU1)\n            P1 = (1. + 2.*NTU1 - alpha**2)/(4. + 4.*NTU1 - (1. - alpha)**2)\n    elif Ntp == 2 and not optimal:\n        R1_orig = R1\n        #NTU2 = NTU1*R1_orig but we want to treat it as NTU1 in this case\n        NTU1 = NTU1*R1_orig # switch 1\n        # R2 = 1/R1 but we want to treat it as R1 in this case\n        R1 = 1./R1_orig # switch 2\n        if R1 != 0.5:\n            beta = exp(-NTU1*(2.*R1 + 1.)/2.)\n            alpha = exp(-NTU1*(2.*R1 - 1.)/4.)\n            B = (4.*R1 - beta*(2.*R1 - 1.))/(2.*R1 + 1.)\n            A = (1. - alpha)**2/(R1 - 0.5)\n            P1 = (B - alpha**2)/(R1*(A - alpha**2/R1 + 2.))\n        else:\n            beta = exp(-2.*R1*NTU1)\n            P1 = (1. + 2.*R1*NTU1 - beta)/R1/(4. + 4.*R1*NTU1 + R1**2*NTU1**2)\n        P1 = P1/R1_orig # switch 3, confirmed\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1 and 2.\")\n    return P1\n\n\ndef temperature_effectiveness_TEMA_E(R1: float, NTU1: float, Ntp: int=1, optimal: bool=True) -> float:\n    r\"\"\"Returns temperature effectiveness `P1` of a TEMA E type heat exchanger\n    with a specified heat capacity ratio, number of transfer units `NTU1`,\n    number of tube passes `Ntp`, and whether or not it is arranged in a more\n    countercurrent (optimal configuration) way or a more parallel (optimal=False)\n    case. The supported cases are as follows:\n\n    * 1-1 TEMA E, shell fluid mixed\n    * 1-2 TEMA E, shell fluid mixed (this configuration is symmetric)\n    * 1-2 TEMA E, shell fluid split into two steams individually mixed\n    * 1-3 TEMA E, shell and tube fluids mixed, one parallel pass and two\n      counterflow passes (efficient)\n    * 1-3 TEMA E, shell and tube fluids mixed, two parallel passes and one\n      counteflow pass (inefficient)\n    * 1-N TEMA E, shall and tube fluids mixed, efficient counterflow orientation,\n      N an even number\n\n    1-1 TEMA E, shell fluid mixed:\n\n    .. math::\n        P_1 = \\frac{1 - \\exp[-NTU_1(1-R_1)]}{1 - R_1 \\exp[-NTU_1(1-R_1)]}\n\n    1-2 TEMA E, shell fluid mixed (this configuration is symmetric):\n\n    .. math::\n        P_1 = \\frac{2}{1 + R_1 + E\\coth(E\\cdot NTU_1/2)}\n\n    .. math::\n        E = [1 + R_1^2]^{1/2}\n\n    1-2 TEMA E, shell fluid split into two steams individually mixed:\n\n    .. math::\n        P_1 = \\frac{1}{R_1}\\left[1 - \\frac{(2-R_1)(2E+R_1B)}{(2+R_1)(2E-R_1/B)}\n        \\right]\n\n    .. math::\n        E = \\exp(NTU_1)\n\n    .. math::\n        B = \\exp(-NTU_1 R_1/2)\n\n    1-3 TEMA E, shell and tube fluids mixed, one parallel pass and two\n    counterflow passes (efficient):\n\n    .. math::\n        P_1 = \\frac{1}{R_1} \\left[1 - \\frac{C}{AC + B^2}\\right]\n\n    .. math::\n        A = X_1(R_1 + \\lambda_1)(R_1 - \\lambda_2)/(2\\lambda_1) - X_3 \\delta\n        - X_2(R_1 + \\lambda_2)(R_1-\\lambda_1)/(2\\lambda_2) + 1/(1-R_1)\n\n    .. math::\n        B = X_1(R_1-\\lambda_2) - X_2(R_1-\\lambda_1) + X_3\\delta\n\n    .. math::\n        C = X_2(3R_1 + \\lambda_1) - X_1(3R_1 + \\lambda_2) + X_3 \\delta\n\n    .. math::\n        X_i = \\exp(\\lambda_i NTU_1/3)/(2\\delta),\\;\\; i = 1,2,3\n\n    .. math::\n        \\delta = \\lambda_1 - \\lambda_2\n\n    .. math::\n        \\lambda_1 = -\\frac{3}{2} + \\left[\\frac{9}{4} + R_1(R_1-1)\\right]^{1/2}\n\n    .. math::\n        \\lambda_2 = -\\frac{3}{2} - \\left[\\frac{9}{4} + R_1(R_1-1)\\right]^{1/2}\n\n    .. math::\n        \\lambda_3 = R_1\n\n    1-3 TEMA E, shell and tube fluids mixed, two parallel passes and one\n    counteflow pass (inefficient):\n\n    .. math::\n        P_2 = \\left[1 - \\frac{C}{(AC + B^2)}\\right]\n\n    .. math::\n        A = \\chi_1(1 + R_2 \\lambda_1)(1 - R_2\\lambda_2)/(2R_2^2\\lambda_1) - E\n        -\\chi_2(1 + R_2\\lambda_2)(1 - R_2\\lambda_1)/(2R^2\\lambda_2) + R/(R-1)\n\n    .. math::\n        B = \\chi_1(1 - R_2\\lambda_2)/R_2 - \\chi_2(1 - R_2 \\lambda_1)/R_2 + E\n\n    .. math::\n        C = -\\chi_1(3 + R_2\\lambda_2)/R_2 + \\chi_2(3 + R_2\\lambda_1)/R_2 + E\n\n    .. math::\n        E = 0.5\\exp(NTU_2/3)\n\n    .. math::\n        \\lambda_1 = (-3 + \\delta)/2\n\n    .. math::\n        \\lambda_2 = (-3 - \\delta)/2\n\n    .. math::\n        \\delta = \\frac{[9R_2^2 + 4(1-R_2))]^{0.5}}{R_2}\n\n    .. math::\n        \\chi_1 = \\frac{\\exp(\\lambda_1 R_2 NTU_2/3)}{2\\delta}\n\n    .. math::\n        \\chi_2 = \\frac{\\exp(\\lambda_2 R_2 NTU_2/3)}{2\\delta}\n\n    1-N TEMA E, shall and tube fluids mixed, efficient counterflow orientation,\n    N an even number:\n\n    .. math::\n        P_2 = \\frac{2}{A + B + C}\n\n    .. math::\n        A = 1 + R_2 + \\coth(NTU_2/2)\n\n    .. math::\n        B = \\frac{-1}{N_1}\\coth\\left(\\frac{NTU_2}{2N_1}\\right)\n\n    .. math::\n        C = \\frac{1}{N_1}\\sqrt{1 + N_1^2 R_2^2}\n        \\coth\\left(\\frac{NTU_2}{2N_1}\\sqrt{1 + N_1^2 R_2^2}\\right)\n\n    .. math::\n        N_1 = \\frac{N_{tp}}{2}\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, 2, 3, 4, or an even number[-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case, [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    For odd numbers of tube passes greater than 3, an exception is raised.\n    [2]_ actually has a formula for 5 tube passes, but it is an entire page\n    long.\n    The convention for the formulas in [1]_ and [3]_ are with the shell side\n    as side 1, and the tube side as side 2. [2]_ has formulas with the\n    opposite convention.\n\n    Examples\n    --------\n    >>> temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=1)\n    0.5870500654031314\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    if Ntp == 1:\n        # Just the basic counterflow case\n        if R1 != 1:\n            P1 = (1-exp(-NTU1*(1-R1))) / (1 - R1*exp(-NTU1*(1-R1)))\n        else:\n            P1 = NTU1/(1. + NTU1)\n    elif Ntp == 2 and optimal:\n        if R1 != 1:\n            E = (1. + R1**2)**0.5\n            P1 = 2./(1 + R1 + E/tanh(E*NTU1/2.))\n        else:\n            P1 = 1/(1 + 1/tanh(NTU1*2**-0.5)*2**-0.5)\n    elif Ntp == 2 and not optimal:\n        # Shah, reverse flow but with divider; without divider would be parallel.\n        # Same as J-1, but E = A and B = B.\n        A = exp(NTU1)\n        B = exp(-NTU1*R1/2.)\n        if R1 != 2:\n            P1 = 1/R1*(1 - (2-R1)*(2*A + R1*B)/(2+R1)/(2*A - R1/B))\n        else:\n            P1 = 0.5*(1 - (1 + A**-2)/2./(1+NTU1))\n    elif Ntp == 3 and optimal:\n        # This gives slightly different results than in Thulukkanam!\n        lambda3 = R1 # in Rosehnhow, this is minus. makes a small diff though\n        lambda2 = -1.5 - (2.25 + R1*(R1-1))**0.5\n        lambda1 = -1.5 + (2.25 + R1*(R1-1))**0.5\n        delta = lambda1 - lambda2\n        X1 = exp(lambda1*NTU1/3.)/2/delta\n        X2 = exp(lambda2*NTU1/3.)/2/delta\n        X3 = exp(lambda3*NTU1/3.)/2/delta\n        C = X2*(3*R1 + lambda1) - X1*(3*R1 + lambda2) + X3*delta\n        B = X1*(R1 - lambda2) - X2*(R1 - lambda1) + X3*delta\n        if R1 != 1:\n            A = X1*(R1 + lambda1)*(R1 - lambda2)/2/lambda1 - X3*delta - X2*(R1 + lambda2)*(R1 - lambda1)/2/lambda2 + 1./(1-R1)\n        else:\n            A = -exp(-NTU1)/18 - exp(NTU1/3.)/2 + (NTU1 + 5)/9.\n        P1 = 1./R1*(1. - C/(A*C + B*B))\n    elif Ntp == 3 and not optimal:\n        # Thulukkanam, Parallel instead of direct.\n        R1_orig = R1\n        #NTU2 = NTU1*R1_orig but we want to treat it as NTU1 in this case\n        NTU1 = NTU1*R1_orig # switch 1\n        # R2 = 1/R1 but we want to treat it as R1 in this case\n        R1 = 1./R1_orig # switch 2\n\n        delta = (9*R1**2 + 4*(1 - R1))**0.5/R1\n        l1 = (-3 + delta)/2.\n        l2 = (-3 - delta)/2.\n        chi1 = exp(l1*R1*NTU1/3.)/2/delta\n        chi2 = exp(l2*R1*NTU1/3.)/2/delta\n        E = 0.5*exp(NTU1/3.)\n        C = -chi1*(3 + R1*l2)/R1 + chi2*(3 + R1*l1)/R1 + E\n        B = chi1*(1 - R1*l2)/R1 - chi2*(1 - R1*l1)/R1 + E\n#        if R1 != 1:\n        A = (chi1*(1 + R1*l1)*(1 - R1*l2)/(2*R1**2*l1) - E\n             - chi2*(1 + R1*l2)*(1 - R1*l1)/(2*R1**2*l2) + R1*(R1 -1))\n        # The below change is NOT CONSISTENT with the main expression and is disabled\n#        else:\n#            A = -exp(-NTU1)/18. - exp(NTU1/3)/2. + (5 + NTU1)/9.\n        P1 = (1 - C/(A*C + B**2))\n\n        P1 = P1/R1_orig # switch 3, confirmed\n\n    elif Ntp == 4 or Ntp %2 == 0:\n        # The 4 pass case is present in all three sources, and is confirmed to\n        # give the same results for all three for Ntp = 4. However,\n        # what is awesome about the Thulukkanam version is that it supports\n        # n tube passes so long as n is even.\n        R1_orig = R1\n        #NTU2 = NTU1*R1_orig but we want to treat it as NTU1 in this case\n        NTU1 = NTU1*R1_orig # switch 1\n        # R2 = 1/R1 but we want to treat it as R1 in this case\n        R1 = 1./R1_orig # switch 2\n\n        N1 = Ntp/2.\n        C = 1/N1*(1 + N1**2*R1**2)**0.5/tanh(NTU1/(2*N1)*(1 + N1**2*R1**2)**0.5)\n        B = -1/N1/tanh(NTU1/(2*N1))\n        A = 1 + R1 + 1/tanh(NTU1/2.)\n        P1 = 2/(A + B + C)\n\n        P1 = P1/R1_orig # switch 3, confirmed\n    else:\n        raise ValueError(\"For TEMA E shells with an odd number of tube passes more than 3, no solution is implemented.\")\n    return P1\n\n\ndef temperature_effectiveness_plate(R1: float, NTU1: float, Np1: int, Np2: int, counterflow: bool=True,\n                                    passes_counterflow: bool=True, reverse: bool=False) -> float:\n    r\"\"\"Returns the temperature effectiveness `P1` of side 1 of a plate heat\n    exchanger with a specified side 1 heat capacity ratio `R1`, side 1 number\n    of transfer units `NTU1`, number of passes on sides 1 and 2 (respectively\n    `Np1` and `Np2`).\n\n    For all cases, the function also takes as arguments whether the exchanger\n    is setup in an overall counter or parallel orientation `counterflow`, and\n    whether or not individual stream passes are themselves counterflow or\n    parallel.\n\n    The 20 supported cases are as follows. (the first number of sides listed\n    refers to side 1, and the second number refers to side 2):\n\n    * 1 pass/1 pass parallelflow\n    * 1 pass/1 pass counterflow\n    * 1 pass/2 pass\n    * 1 pass/3 pass or 3 pass/1 pass (with the two end passes in parallel)\n    * 1 pass/3 pass or 3 pass/1 pass (with the two end passes in counterflow)\n    * 1 pass/4 pass\n    * 2 pass/2 pass, overall parallelflow, individual passes in parallel\n    * 2 pass/2 pass, overall parallelflow, individual passes counterflow\n    * 2 pass/2 pass, overall counterflow, individual passes parallelflow\n    * 2 pass/2 pass, overall counterflow, individual passes counterflow\n    * 2 pass/3 pass or 3 pass/2 pass, overall parallelflow\n    * 2 pass/3 pass or 3 pass/2 pass, overall counterflow\n    * 2 pass/4 pass or 4 pass/2 pass, overall parallel flow\n    * 2 pass/4 pass or 4 pass/2 pass, overall counterflow flow\n\n    For all plate heat exchangers, there are two common formulas used by most\n    of the expressions.\n\n    .. math::\n        P_p(x, y) = \\frac{1 - \\exp[-x(1 + y)]}{1 + y}\n\n        P_c(x, y) = \\frac{1 - \\exp[-x(1 - y)]}{1 - y\\exp[-x(1 - y)]}\n\n    The main formulas used are as follows. Note that for some cases such as\n    4 pass/2 pass, the formula is not shown because it is that of 2 pass/4\n    pass, but with R1, NTU1, and P1 conversions.\n\n    For 1 pass/1 pass paralleflow (streams symmetric):\n\n    .. math::\n        P_1 = P_p(NTU_1, R_1)\n\n    For 1 pass/1 pass counterflow (streams symmetric):\n\n    .. math::\n        P_1 = P_c(NTU_1, R_1)\n\n    For 1 pass/2 pass (any of the four possible configurations):\n\n    .. math::\n        P_1 = 0.5(A + B - 0.5ABR_1)\n\n    .. math::\n        A = P_p(NTU_1, 0.5R_1)\n\n    .. math::\n        B = P_c(NTU_1, 0.5R_1)\n\n    For 1 pass/3 pass (with the two end passes in parallel):\n\n    .. math::\n        P_1 = \\frac{1}{3}\\left[B + A\\left(1 - \\frac{R_1 B}{3}\\right)\\left(2\n        - \\frac{R_1 A}{3}\\right)\\right]\n\n    .. math::\n        A = P_p\\left(NTU_1, \\frac{R_1}{3}\\right)\n\n    .. math::\n        B = P_c\\left(NTU_1, \\frac{R_1}{3}\\right)\n\n    For 1 pass/3 pass (with the two end passes in counterflow):\n\n    .. math::\n        P_1 = \\frac{1}{3}\\left[A + B\\left(1 - \\frac{R_1 A}{3}\\right)\\left(2\n        - \\frac{R_1 B}{3}\\right)\\right]\n\n    .. math::\n        A = P_p\\left(NTU_1, \\frac{R_1}{3}\\right)\n\n    .. math::\n        B = P_c\\left(NTU_1, \\frac{R_1}{3}\\right)\n\n    For 1 pass/4 pass (any of the four possible configurations):\n\n    .. math::\n        P_1 = \\frac{1-Q}{R_1}\n\n    .. math::\n        Q = \\left(1 - \\frac{AR_1}{4}\\right)^2\\left(1 - \\frac{BR_1}{4}\\right)^2\n\n    .. math::\n        A = P_p\\left(NTU_1, \\frac{R_1}{4}\\right)\n\n    .. math::\n        B = P_c\\left(NTU_1, \\frac{R_1}{4}\\right)\n\n    For 2 pass/2 pass, overall parallelflow, individual passes in parallel\n    (stream symmetric):\n\n    .. math::\n        P_1 = P_p(NTU_1, R_1)\n\n    For 2 pass/2 pass, overall parallelflow, individual passes counterflow\n    (stream symmetric):\n\n    .. math::\n        P_1 = B[2 - B(1 + R_1)]\n\n    .. math::\n        B = P_c\\left(\\frac{NTU_1}{2}, R_1\\right)\n\n    For 2 pass/2 pass, overall counterflow, individual passes parallelflow\n    (stream symmetric):\n\n    .. math::\n        P_1 = \\frac{2A - A^2(1 + R_1)}{1 - R_1 A^2}\n\n    .. math::\n        A = P_p\\left(\\frac{NTU_1}{2}, R_1\\right)\n\n    For 2 pass/2 pass, overall counterflow and individual passes counterflow\n    (stream symmetric):\n\n    .. math::\n        P_1 = P_c(NTU_1, R_1)\n\n    For 2 pass/3 pass, overall parallelflow:\n\n    .. math::\n        P_1 = A + B - \\left(\\frac{2}{9} + \\frac{D}{3}\\right)\n        (A^2 + B^2) - \\left(\\frac{5}{9} + \\frac{4D}{3}\\right)AB\n        + \\frac{D(1+D)AB(A+B)}{3} - \\frac{D^2A^2B^2}{9}\n\n    .. math::\n        A = P_p\\left(\\frac{NTU_1}{2}, D\\right)\n\n    .. math::\n        B = P_c\\left(\\frac{NTU_1}{2}, D\\right)\n\n    .. math::\n        D = \\frac{2R_1}{3}\n\n    For 2 pass/3 pass, overall counterflow:\n\n    .. math::\n        P_1 = \\frac{A + 0.5B + 0.5C + D}{R_1}\n\n    .. math::\n        A = \\frac{2R_1 EF^2 - 2EF + F - F^2}\n        {2R_1 E^2 F^2 - E^2 - F^2 - 2EF + E + F}\n\n    .. math::\n        B = \\frac{A(E-1)}{F}\n\n    .. math::\n        C = \\frac{1 - A}{E}\n\n    .. math::\n        D = R_1 E^2 C - R_1 E + R_1 - \\frac{C}{2}\n\n    .. math::\n        E = \\frac{3}{2R_1 G}\n\n    .. math::\n        F = \\frac{3}{2R_1 H}\n\n    .. math::\n        G = P_c\\left(\\frac{NTU_1}{2}, \\frac{2R_1}{3}\\right)\n\n    .. math::\n        H = P_p\\left(\\frac{NTU_1}{2}, \\frac{2R_1}{3}\\right)\n\n    For 2 pass/4 pass, overall parallel flow:\n\n    .. math::\n        P_1 = 2D - (1 + R_1)D^2\n\n    .. math::\n        D = \\frac{A + B - 0.5ABR_1}{2}\n\n    .. math::\n        A = P_p\\left(\\frac{NTU_1}{2}, \\frac{R_1}{2}\\right)\n\n    .. math::\n        B = P_c\\left(\\frac{NTU_1}{2}, \\frac{R_1}{2}\\right)\n\n    For 2 pass/4 pass, overall counterflow flow:\n\n    .. math::\n        P_1 = \\frac{2D - (1+R_1)D^2}{1 - D^2 R_1}\n\n    .. math::\n        D = \\frac{A + B - 0.5ABR_1}{2}\n\n    .. math::\n        A = P_p\\left(\\frac{NTU_1}{2}, \\frac{R_1}{2}\\right)\n\n    .. math::\n        B = P_c\\left(\\frac{NTU_1}{2}, \\frac{R_1}{2}\\right)\n\n    Parameters\n    ----------\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 [-]\n    Np1 : int\n        Number of passes on side 1 [-]\n    Np2 : int\n        Number of passes on side 2 [-]\n    counterflow : bool\n        Whether or not the overall flow through the heat exchanger is in\n        counterflow or parallel flow, [-]\n    passes_counterflow : bool\n        In addition to the overall flow direction, in some cases individual\n        passes may be in counter or parallel flow; this controls that [-]\n    reverse : bool\n        Used **internally only** to allow cases like the 1-4 formula to work\n        for the 4-1 flow case, without having to duplicate the code [-]\n\n    Returns\n    -------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    For diagrams of these heat exchangers, see [3]_.\n    In all cases, each pass is assumed to be made up of an infinite number\n    of plates. The fluid velocities must be uniform across the plate channels,\n    and the flow must be uniformly distributed between the channels. The heat\n    transfer coefficient is also assumed constant.\n\n    The defaults of counterflow=True and passes_counterflow=True will always\n    result in the most efficient heat exchanger option, normally what is\n    desired.\n\n    If a number of passes which is not supported is provided, an exception is\n    raised.\n\n    Examples\n    --------\n    Three passes on side 1; one pass on side 2; two end passes in counterflow\n    orientation.\n\n    >>> temperature_effectiveness_plate(R1=1/3., NTU1=1., Np1=3, Np2=1)\n    0.5743514352720835\n\n    If the same heat exchanger (in terms of NTU1 and R1) were operating with\n    sides 1 and 2 switched, a slightly less efficient design results.\n\n    >>> temperature_effectiveness_plate(R1=1/3., NTU1=1., Np1=1, Np2=3)\n    0.5718726757657066\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    .. [3] Kandlikar, S. G., and R. K. Shah. \"Asymptotic Effectiveness-NTU\n       Formulas for Multipass Plate Heat Exchangers.\" Journal of Heat Transfer\n       111, no. 2 (May 1, 1989): 314-21. doi:10.1115/1.3250679.\n    .. [4] Kandlikar, S. G., and R. K. Shah. \"Multipass Plate Heat Exchangers\n       Effectiveness-NTU Results and Guidelines for Selecting Pass\n       Arrangements.\" Journal of Heat Transfer 111, no. 2 (May 1, 1989):\n       300-313. doi:10.1115/1.3250678.\n    \"\"\"\n    if Np1 == 1 and Np2 == 1 and counterflow:\n        return P_NTU_Pc(NTU1, R1)\n    elif Np1 == 1 and Np2 == 1 and not counterflow:\n        return P_NTU_Pp(NTU1, R1)\n    elif Np1 == 1 and Np2 == 2:\n        # There are four configurations but all have the same formula\n        # They do behave different depending on the number of available plates\n        # but this model assues infinity\n        # There are four more arrangements that are equivalent as well\n        A = P_NTU_Pp(NTU1, 0.5*R1)\n        B = P_NTU_Pc(NTU1, 0.5*R1)\n        return 0.5*(A + B - 0.5*A*B*R1)\n    elif Np1 == 1 and Np2 == 3 and counterflow:\n        # There are six configurations, two formulas\n        # Each behaves differently though as a function of number of plates\n        A = P_NTU_Pp(NTU1, R1/3.)\n        B = P_NTU_Pc(NTU1, R1/3.)\n        return 1/3.*(A + B*(1. - R1*A/3.)*(2. - R1*B/3.))\n    elif Np1 == 1 and Np2 == 3 and not counterflow:\n        A = P_NTU_Pp(NTU1, R1/3.)\n        B = P_NTU_Pc(NTU1, R1/3.)\n        return 1/3.*(B + A*(1. - R1*B/3.)*(2. - R1*A/3.))\n    elif Np1 == 1 and Np2 == 4:\n        # four configurations\n        # Again a function of number of plates, but because expressions assume\n        # infinity it gets ignored and they're the same\n        A = P_NTU_Pp(NTU1, 0.25*R1)\n        B = P_NTU_Pc(NTU1, 0.25*R1)\n        t1 = (1. - 0.25*A*R1)\n        t2 = (1. - 0.25*B*R1)\n        t3 = t1*t2 # minor optimization\n        return (1. - t3*t3)/R1\n    elif Np1 == 2 and Np2 == 2:\n        if counterflow and passes_counterflow:\n            return P_NTU_Pc(NTU1, R1)\n        elif counterflow and not passes_counterflow:\n            A = P_NTU_Pp(0.5*NTU1, R1)\n            return (2.*A - A*A*(1. + R1))/(1. - R1*A*A)\n        elif not counterflow and passes_counterflow:\n            B = P_NTU_Pc(0.5*NTU1, R1)\n            return B*(2. - B*(1. + R1))\n        elif not counterflow and not passes_counterflow:\n            return temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=1,\n                                                   passes_counterflow=True,\n                                                   counterflow=False,\n                                                   reverse=False)\n    elif Np1 == 2 and Np2 == 3:\n        # One place says there are four configurations; no other discussion is\n        # presented\n        if counterflow:\n            H = P_NTU_Pp(0.5*NTU1, 2./3.*R1)\n            G = P_NTU_Pc(0.5*NTU1, 2./3.*R1)\n            E = 1./(2./3.*R1*G)\n            F = 1./(2./3.*R1*H)\n            E2 = E*E\n            F2 = F*F\n            A = (2.*R1*E*F2 - 2.*E*F + F - F2)/(2.*R1*E2*F2 - E2 - F2 - 2.*E*F + E + F)\n            C = (1. - A)/E\n            D = R1*E*E*C - R1*E + R1 - 0.5*C\n            B = A*(E - 1.)/F\n            return (A + 0.5*B + 0.5*C + D)/R1\n        elif not counterflow:\n            D = 2*R1/3.\n            A = P_NTU_Pp(NTU1/2, D)\n            B = P_NTU_Pc(NTU1/2, D)\n            return (A + B - (2/9. + D/3.)*(A*A + B*B)\n                    -(5./9. + 4./3.*D)*A*B\n                    + D*(1. + D)*A*B*(A + B)/3.\n                    - D*D*A*A*B*B/9.)\n    elif Np1 == 2 and Np2 == 4:\n        # Both cases are correct for passes_counterflow=True or False\n        if counterflow:\n            A = P_NTU_Pp(0.5*NTU1, 0.5*R1)\n            B = P_NTU_Pc(0.5*NTU1, 0.5*R1)\n            D = 0.5*(A + B - 0.5*A*B*R1)\n            return (2.*D - (1. + R1)*D*D)/(1. - D*D*R1)\n        elif not counterflow:\n            A = P_NTU_Pp(0.5*NTU1, 0.5*R1)\n            B = P_NTU_Pc(0.5*NTU1, 0.5*R1)\n            D = 0.5*(A + B - 0.5*A*B*R1)\n            return 2.*D - ((1. + R1)*D*D)\n    if not reverse:\n        # only the asymmetric cases will be able to solve by flipping things\n        # Note that asymmetric performs differently depending on the arguments\n        # The user still needs to input R1, NTU1 for side 1\n        # so if they want to do a 3-1 instead of a 1-3 as is implemented here\n        # They give R1 and NTU1 for \"3 pass\" side instead of the \"1 pass\" side\n        # and will get back P1 for the \"3 pass\" side.\n\n        # numba is dying on this recursion when caching is on, disable caching for now\n        R2 = 1./R1\n        NTU2 = NTU1*R1\n        P2 = temperature_effectiveness_plate(R1=R2, NTU1=NTU2, Np1=Np2, Np2=Np1,\n                                             counterflow=counterflow,\n                                             passes_counterflow=passes_counterflow,\n                                             reverse=True)\n        P1 = P2*R2\n        return P1\n\n    raise ValueError(\"Supported number of passes does not have a formula available\")\n\n\nNTU_from_plate_2_3_parallel_offset = [7.5e-09, 1.4249999999999999e-08, 2.7074999999999996e-08, 5.144249999999999e-08, 9.774074999999998e-08, 1.8570742499999996e-07,\n        3.528441074999999e-07, 6.704038042499998e-07, 1.2737672280749996e-06, 2.420157733342499e-06, 4.598299693350748e-06, 8.73676941736642e-06,\n        1.6599861892996197e-05, 3.153973759669277e-05, 5.9925501433716265e-05, 0.0001138584527240609, 0.0002163310601757157, 0.0004110290143338598,\n        0.0007809551272343336, 0.0014838147417452338, 0.002819248009315944, 0.005356571217700294, 0.010177485313630557, 0.019337222095898058,\n        0.036740721982206306, 0.06980737176619198, 0.13263400635576475, 0.25200461207595304, 0.47880876294431074, 0.9097366495941903,\n        1.7284996342289616, 3.2841493050350268, 6.23988367956655, 11.855778991176445, 22.525980083235243, 42.79936215814696, 81.31878810047922,\n        154.5056973909105, 293.56082504272996, 557.7655675811869\n    ]\nNTU_from_plate_2_3_parallel_p = [\n        [6.462119185839311e+42, -7.89735987601022e+35, -9.087083856062007e+27, 1.7050113422248866e+19, -1688535720.902906, 39.613950137696285],\n        [2.318252075647079e+40, 4.220218073315233e+33, 1.8285573384676073e+26, 3.084411438713216e+18, 21021750157.222004, 38.330242461631514],\n        [-2.725246602458712e+39, 2.3068644128776514e+32, 4.627829472767517e+25, 1.1310001900283219e+18, 966837452.7610933, 37.046534751334335],\n        [1.2235529142820281e+37, 8.353473028988188e+30, 1.1577363564247304e+24, 5.26111342386283e+16, 1261185446.350375, 35.762826989453515],\n        [-2.268909561806343e+38, -1.3039314202429206e+32, -1.0060952358606218e+25, 2.825039921898014e+17, -4479452951.060747, 34.47911926523136],\n        [3.1317729161848482e+35, 1.2588127743217981e+30, 3.276383218600776e+23, 5869028606256265.0, 1575663397.1343608, 33.19541167935255],\n        [1.269695711103147e+34, 4.290756179192165e+28, 2.9775379948312816e+22, 5786034109781830.0, 164435306.647866, 31.911704317934102],\n        [2.3505913930420825e+33, 1.1812928249795345e+28, 9.295788631785714e+21, 646240998532863.4, 152570202.7077346, 30.627996765657006],\n        [9.372652014253886e+30, 1.3865784239035505e+26, 4.189500257555692e+20, 382474529586341.4, 87229551.47782452, 29.34428979550431],\n        [2.4394239228002745e+29, 8.48439767361896e+24, 5.6565841650672206e+19, 104617438878045.67, 31457806.46330641, 28.060583495837115],\n        [1.1756565638642434e+28, 8.043965680172975e+23, 9.83892031482124e+18, 28459853223759.457, -9973441.564916672, 26.776878200784502],\n        [-7.434125480121518e+25, -9.162097000642035e+21, -1.8461512379952253e+17, -265723153860.95157, 9996257.22456268, 25.493174743647415],\n        [2.0776904219507715e+25, 5.321566516109094e+21, 2.830031172775278e+17, 5145809833029.548, 30832206.351568446, 24.20947444204136],\n        [-2.0513335420466532e+24, -2.289228286826745e+20, -929209616723210.4, 76660920130.18863, -1702371.8751699005, 22.925779468541926],\n        [1.0921158668621774e+22, 1.0481031815969962e+19, 1918841223032205.0, 108793646298.43532, 1871101.8043717288, 21.642093202587958],\n        [4.225007197010862e+20, 1.0174799962646577e+18, 418193922144622.8, 50623892747.72083, 1687944.9487507509, 20.35842139409845],\n        [5.3571938699724366e+19, 1.9585365429957734e+17, 127061183144718.2, 22936953503.569767, 702355.1752422716, 19.074772810895016],\n        [-4.732337226080112e+19, -1.1230910989054965e+17, -30110540624204.457, 6413264110.352206, -490016.8688730465, 17.791160116387005],\n        [7.152554048415291e+17, 4327530795294686.5, 3402335929741.3604, -374943769.5945296, 826.0224931539136, 16.507601903407284],\n        [984051013256121.4, 24396685224717.965, 97948169286.30563, 109018337.85835141, 26368.75705403507, 15.22412348284966],\n        [50680993613887.11, 879940841713.1937, 3547863447.171348, 8460582.67871622, 12799.65592799938, 13.940760190166468],\n        [-875507484434.7006, 25808107236.834812, 1010170510.2032485, 5345388.737994069, 4433.937793425797, 12.65756872526503],\n        [-2545609349.155158, 1744025195.285, 104920108.05542274, 1393742.0881427797, 5165.737303799409, 11.374674386567444],\n        [-44107270179.70516, -9966996021.270891, -227618846.07818735, 221021.67601654973, -3146.660020222547, 10.092433966069105],\n        [-17223688.786470495, -23864400.404286776, -3058744.705574641, -92465.34160573207, 79.26693119855088, 8.811928082820112],\n        [207089.07738276388, 1227730.4574734285, 66877.00675493496, -61.49057944248921, -50.69640655670642, 7.536263692403265],\n        [-119095.47949526514, -896903.6380506152, -426050.23346265673, -50907.75212691221, -869.3604740196895, 6.27351591893888],\n        [938.3304032079799, 15625.662817632307, 14723.43865453997, 3567.9928498984227, 173.109130231987, 5.042051163423371],\n        [10.211511823367426, 282.8051136783963, 451.2780669544769, 189.16900463066924, 20.74121725239963, 3.8767657222797793],\n        [1.1464843558305287, 40.27461672000967, 59.16225274077587, 10.379056077245352, 5.7929254308893565, 2.829369860323157],\n        [-0.01276147756024723, -0.48777843281385097, 0.6032501474532808, 4.559017517350226, 1.8620463339982214, 1.9541776601728913],\n        [-0.00014226514748006712, -0.023808643483844285, -0.289121674152071, -1.114005659180411, -1.1972235528397606, 1.2832212535010843],\n        [-2.581120907700105e-05, -0.00418426633038938, 0.009339781397016987, 0.45600757529303554, -0.4034481381751588, 0.8099512337803161],\n        [9.273821864840757e-07, 0.0007547318108085425, 0.03245749164236026, 0.2965758497751961, -0.27934160268782265, 0.4972383631571961],\n        [-6.233458586767228e-06, -0.015884785719281296, -0.7538527292952916, 0.3269735695585127, -1.7829706967875358, 0.2994738457522529],\n        [-5.781637596658974e-06, -0.0035915273327539812, -0.01157399390997103, 0.029559240961787817, 0.07388163435077193, 0.17786369186050757],\n        [3.961559826678127e-10, 1.4543254012176232e-06, 0.0001957616811595701, 0.0005362176178959326, 0.013938290268178794, 0.10448348895756158],\n        [-3.2803452031636568e-09, -5.9441710409871e-06, -2.9118957190454924e-05, 0.0009942748181445327, -0.004462241345741868, 0.06081951964311699],\n        [-4.279563643962056e-12, -6.561380309179023e-08, -3.081429869708402e-05, 0.0006859774272069931, -0.005747071000328576, 0.035126028098573805],\n        [-2.8686462733352614e-14, -7.790696462481343e-10, -6.653666019778786e-07, 1.23027958890778e-05, -0.0010604984777168322, 0.020147982521643307]\n    ]\n\nNTU_from_plate_2_3_parallel_q = [\n        [1.3683227596264214e+41, -2.165884158620195e+34, -2.2644202669570306e+26, 4.297163948003187e+17, -35893193.88590451, 1.0],\n        [7.421678196787487e+38, 1.2085634160881847e+32, 5.007192734165482e+24, 8.236249667102427e+16, 552099325.8742635, 1.0],\n        [-7.873002863853876e+37, 7.713934423114926e+30, 1.3099803429483467e+24, 3.054836281163621e+16, 28091870.519562516, 1.0],\n        [4.291647340124204e+35, 2.5740797788209477e+29, 3.375618651322059e+22, 1500065233601050.2, 36352377.943491936, 1.0],\n        [-7.882176775266176e+36, -3.9793411938031736e+30, -2.8656985978364168e+23, 8113694498408136.0, -129324377.97821534, 1.0],\n        [1.41563514882479e+34, 4.110117035735913e+28, 9.893491716866435e+21, 191433581840910.7, 47790732.509775005, 1.0],\n        [4.999607502786247e+32, 1.4716031312619367e+27, 9.64517819667706e+20, 182008960314679.44, 5330443.45680183, 1.0],\n        [9.614824718113606e+31, 4.141511196223844e+26, 3.0530586050969154e+20, 21521729107166.945, 5078800.175545379, 1.0],\n        [4.1734091264684445e+29, 5.27412019351319e+24, 1.4929447878932255e+19, 13174953396585.623, 3026132.05876614, 1.0],\n        [1.1769712254415933e+28, 3.433836747260235e+23, 2.1211399654690634e+18, 3756068921305.945, 1150517.6889615546, 1.0],\n        [6.078422345745446e+26, 3.430506170699249e+22, 3.854675824830577e+17, 1055299400508.5115, -356221.4839331609, 1.0],\n        [-4.089621096755519e+24, -4.1038010771907025e+20, -7474524051100801.0, -7335562207.356166, 401094.5632574399, 1.0],\n        [1.2324411281606296e+24, 2.5711536866148785e+20, 1.2592856537866202e+16, 218766477060.82593, 1278536.155959092, 1.0],\n        [-1.1176764700506538e+23, -1.0287618349794472e+19, -27891844673339.754, 3102282562.5889225, -71489.86007645915, 1.0],\n        [7.664428901664619e+20, 5.762787874997372e+17, 95614758117398.92, 5149781499.376999, 87998.69012738229, 1.0],\n        [3.4119512881216352e+19, 6.137984726024919e+16, 22450868109060.75, 2555122134.822306, 83774.17840871602, 1.0],\n        [4.6001726715440077e+18, 1.251467305711515e+16, 7213875441880.186, 1219435827.5993042, 37305.80357283532, 1.0],\n        [-3.7939650022637384e+18, -6879494995144079.0, -1586382848606.9028, 352684674.27383363, -27269.243916658892, 1.0],\n        [6.7216868954665256e+16, 295784765041063.1, 202637936045.26175, -22780898.93638217, 205.15524877583223, 1.0],\n        [123022914844252.03, 2025598600989.9355, 7038321451.723578, 7292211.533895971, 1820.5540872255187, 1.0],\n        [5798659105371.397, 73063980599.12009, 280808963.08350337, 647166.1744273758, 969.0169714952737, 1.0],\n        [-78112612992.76324, 3642113943.605489, 91804780.43020414, 430751.9137746645, 379.78281402152874, 1.0],\n        [386280523.6835199, 257220540.02040184, 11120485.271634161, 129819.12602039713, 471.40597550979186, 1.0],\n        [-10693211009.303871, -1223510009.089181, -22274545.978089698, 18549.30307838344, -301.55242573732323, 1.0],\n        [-9964085.923738554, -4365150.737138249, -411386.6438696054, -10484.174450932624, 15.149670076979616, 1.0],\n        [541842.864264581, 193482.276072197, 9029.947067528488, -46.62458209582185, -2.9624038642089237, 1.0],\n        [-220621.23296789522, -274557.9340203262, -86401.22446411186, -8443.070539356306, -136.23322675049926, 1.0],\n        [3251.5504349303765, 6784.343990577191, 3934.5214064481625, 757.415724007334, 35.811562912463835, 1.0],\n        [53.522734456906555, 170.40437538950374, 161.01012955496134, 53.54537645357537, 6.286762810448105, 1.0],\n        [7.431444192909625, 26.301988720695135, 22.960637706381636, 4.801125750057049, 2.6341536761332267, 1.0],\n        [-0.09119759477325269, -0.1801061475533146, 1.1300524605333688, 2.654994783545935, 1.3104918958676977, 1.0],\n        [-0.003219836192304881, -0.06183937303877033, -0.40176496853684673, -1.0694441157327017, -0.7230743001450916, 1.0],\n        [-0.0006010237525033756, -0.004761184653841278, 0.0793179816483663, 0.5022239858108873, -0.3793171422255701, 1.0],\n        [8.145183997513813e-05, 0.005514321701324045, 0.10462537982334606, 0.5591837393502016, -0.4962661882194018, 1.0],\n        [-0.0015949168754582125, -0.14279546004455532, -2.4776545238210446, 0.8797754471386745, -5.918081385718453, 1.0],\n        [-0.0004175562163856941, -0.021446016127794405, -0.06189815758682979, 0.1741242853443794, 0.4345628604094691, 1.0],\n        [1.3086618344372457e-07, 3.314955362016943e-05, 0.0019252809212552016, 0.00649537976330168, 0.14368642580610227, 1.0],\n        [-5.903426856053935e-07, -0.00010040636378527861, -0.00038871197761919683, 0.015942278794350923, -0.06787066591282914, 1.0],\n        [-5.058158205238362e-09, -4.452304825119217e-06, -0.0008198822672829164, 0.01904864306291245, -0.16068039934665684, 1.0],\n        [-5.653709672617434e-11, -9.033364681018711e-08, -3.206216480769893e-05, 0.0005282786596535016, -0.05107404858407456, 1.0]\n    ]\n\nNTU_from_plate_2_4_parallel_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184, 80.5306368\n    ]\n\nNTU_from_plate_2_4_parallel_p = [\n        [9.311147683727706e+30, 4.5399729910913565e+24, 3.1701820445412416e+17, -3255667075.4059496, 34.19784973443562],\n        [-8.462341214355869e+28, -1.0512639657566505e+23, -2.397873666023334e+16, -1034750601.3220837, 32.81155554496288],\n        [-3.6927863016874774e+26, -5.302214079709395e+20, 234857662396561.97, 234020488.33100477, 31.425261515365865],\n        [1.4107278670661704e+28, 1.0940739712642787e+22, -9489860868172880.0, -687734269.4135523, 30.03896731810403],\n        [1.1202073850258956e+26, 9.003750344938989e+20, 1018203877208583.4, -168299066.7668561, 28.65267341622791],\n        [1.8786218497132513e+24, 2.175783072978128e+19, -23527291714453.8, -214131092.84929407, 27.266380416202626],\n        [1.594257427685343e+23, 2.5690709590606633e+18, 5268834190667.634, -5146824.418519467, 25.880088256899946],\n        [-1.288122210563083e+24, -2.519981017465274e+19, 71292241683275.88, 50019381.18860227, 24.493798790383742],\n        [4.550486151425468e+20, 6.198563773137455e+16, 1012994755481.759, -6103023.336117795, 23.107514134304758],\n        [1.4422649047868342e+19, 4076064182439184.0, 179797171632.60355, 949172.8606007934, 21.721238910630372],\n        [-1.9069286759409193e+19, -1.2582415698734126e+16, -1417288085609.7737, -31351459.7223076, 20.334983003863815],\n        [1.7928329210392084e+18, 381796280677969.25, -92227167011.14949, -1569077.3721812628, 18.94876593787189],\n        [760697593557199.6, 2716878092435.118, 1858731756.7367892, 384593.9690124189, 17.562626424902703],\n        [-2980345873795.288, 16009202094.020222, 90691363.25017029, 80729.4890879997, 16.17664340548921],\n        [131451648291400.28, 725493611523.8276, 609748841.6264181, 108426.56091552545, 14.790977175191966],\n        [-6486852327.346251, -700388548.9015493, -5924391.104567888, -7146.787711492918, 13.40595533578488],\n        [3015535151.0983796, 286704001.5011526, 4236710.766282784, 17437.87545106799, 12.022255562960611],\n        [-10942972.229197213, -1899779.4140737972, -10761.968304033877, 1039.3968445688706, 10.641289014994197],\n        [8220953.631429097, 2918560.727065227, 148692.00451266085, 2287.789927663398, 9.266006978920416],\n        [-1464338.9963959353, 124017.62034205094, 30117.83144319644, 483.6759667244992, 7.902526411526671],\n        [66462.98718285977, 130896.08947621491, 17250.88254238583, 284.03597528444567, 6.5631079987885395],\n        [10553.524946159525, 11986.93762850903, 1221.0626417135122, -30.985812105731874, 5.270578375104107],\n        [10.082588418517084, 303.14370012586807, 202.6175740387262, 25.89698508509613, 4.062131572817784],\n        [0.5499329874641293, 17.521023550239388, 43.72139301663008, 27.37645885999178, 2.986658250212071],\n        [-0.010913878122056958, 0.45840298571677157, 2.2251798856421043, 2.423889635140142, 2.090206859688884],\n        [0.0006495212907688513, 0.32658889500269045, 4.465059447323286, 11.849683742435108, 1.3958641696720409],\n        [-0.00010585785411094622, -0.036741246609915734, -0.7420406683674805, -3.1387647586257446, 0.8947297519985067],\n        [0.0002762890128259569, 0.07593463651942846, 1.0334886344644887, -1.3947478189369613, 0.5543111790837415],\n        [5.081221447274532e-06, 0.017547763053272165, 0.7422027775716376, -0.4571910134917369, 0.3340446930199166],\n        [-2.616743919341764e-08, 0.00020934843129808607, 0.020386785890459298, -0.02006239152998345, 0.19683902757373653],\n        [-3.101568430040571e-08, 0.00033734949109025253, 0.06821623160637866, -0.15878348849333124, 0.1138774497175727]\n    ]\nNTU_from_plate_2_4_parallel_q = [\n        [3.291974284016541e+29, 1.4046022258329841e+23, 9191295776559532.0, -94421155.58205885, 1.0],\n        [-3.193039887202064e+27, -3.4584178939213135e+21, -744806062875625.5, -31129803.142464183, 1.0],\n        [-1.4381734658615522e+25, -1.693967837916621e+19, 8744771440563.748, 7659034.457524104, 1.0],\n        [5.334771832140096e+26, 3.310748737686997e+20, -318539018055488.6, -22783770.25004286, 1.0],\n        [4.926301588203296e+24, 3.3624134280590442e+19, 35173571760931.96, -5815597.159534814, 1.0],\n        [8.649595607153984e+22, 8.156774026772406e+17, -1108318826792.9722, -7822738.38075017, 1.0],\n        [7.404592532060123e+21, 1.0301055990958646e+17, 198966807158.52313, -182772.06662951043, 1.0],\n        [-6.23738327477897e+22, -1.0048009493765537e+18, 2927622159692.4263, 2050629.9961337105, 1.0],\n        [2.6592386481247224e+19, 2908854062634457.0, 42550661625.26152, -259606.3621141768, 1.0],\n        [9.134101063562578e+17, 206794469159654.2, 8356789568.550677, 46095.68024652044, 1.0],\n        [-1.3457090730356344e+18, -697630890940867.9, -71678079579.3958, -1540469.3978697397, 1.0],\n        [1.1648162142676827e+17, 16957170961125.854, -4925846474.02719, -82119.20066004853, 1.0],\n        [69235668361192.89, 184631921507.40326, 113484951.21664792, 22269.071053282812, 1.0],\n        [-214631136673.61963, 1622101574.6971405, 6486940.571456372, 5191.662978533358, 1.0],\n        [13037201476178.576, 53359497555.82677, 41997862.035921745, 7440.558062890958, 1.0],\n        [-1510382156.1036587, -72336552.91298369, -482917.9480942061, -472.4787451295257, 1.0],\n        [601613270.3192981, 32675351.48453366, 399065.14389228437, 1484.22312195332, 1.0],\n        [-2806385.722630836, -221612.42147962135, 234.94182591367698, 116.6915537324147, 1.0],\n        [2708621.889882308, 453979.7463113455, 18565.770503192096, 257.75689787361085, 1.0],\n        [-222744.307636411, 37667.70409365177, 4153.602682046006, 67.49251582259824, 1.0],\n        [57484.8140277244, 29249.909883546512, 2777.238094492285, 46.96976971793605, 1.0],\n        [6211.193365476433, 2807.633263716254, 215.9750919403814, -3.689822852474681, 1.0],\n        [68.48406976517343, 136.01076483156524, 57.439094496787085, 7.674214233620933, 1.0],\n        [3.138051268210192, 15.474492941908835, 21.438163552556862, 9.928142597214924, 1.0],\n        [0.052309953216059274, 0.647521303684222, 1.5240912769957224, 1.5965807136033143, 1.0],\n        [0.03724768734929924, 0.9146363469974856, 5.2570155120528295, 8.733003177321063, 1.0],\n        [-0.004061747315746429, -0.14038236184631592, -1.29781295599634, -3.375368854837777, 1.0],\n        [0.008747917519380184, 0.2707496260037431, 1.685727780371999, -2.445440187207637, 1.0],\n        [0.0015720431608568725, 0.1353192513128876, 2.1708447802007065, -1.3315013189823655, 1.0],\n        [1.6024647013909014e-05, 0.0030671976634641853, 0.10156204670681959, -0.08262254790017286, 1.0],\n        [2.3229283659683647e-05, 0.008935849190909461, 0.5851500679118268, -1.384387683729736, 1.0]\n    ]\n\nNTU_from_plate_2_2_parallel_counterflow_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184, 80.5306368\n    ]\nNTU_from_plate_2_2_parallel_counterflow_p = [\n        [-1.3540947044203507e+30, -8.410868237241077e+23, -9.592458969288491e+16, -2069815723.7830818, 32.81155785582896],\n        [-5.909190345903646e+27, -4.24286158072528e+21, 939084401227737.4, 468010968.1889994, 31.42526592915459],\n        [2.2580839013543478e+29, 8.759887723905137e+22, -3.795586069473787e+16, -1376170474.1965516, 30.03897572979474],\n        [1.792810256083172e+27, 7.204726957462461e+21, 4073730638465264.0, -336704176.572998, 28.652689407724193],\n        [3.0136351918641795e+25, 1.7449506492771002e+20, -94436408765550.34, -429497368.9344826, 27.2664107356295],\n        [2.5503663600480286e+24, 2.0547278237477323e+19, 21065007797896.387, -10291984.296030033, 25.8801455685103],\n        [-2.068959886273596e+25, -2.0275177343647046e+20, 283363617196754.2, 99817061.51082629, 24.493906760153582],\n        [7.316250745095077e+21, 4.981073282863969e+17, 4071178832783.351, -12246412.243451085, 23.10771675633743],\n        [2.303093386026652e+20, 3.2523232692334844e+16, 716985370983.0242, 1890719.1416514283, 21.72161752401211],\n        [-4.4715545423999264e+20, -1.4745520169872864e+17, -8317355851715.972, -92722811.75950827, 20.335686947153395],\n        [3.048309794645512e+19, 3461917411846938.0, -362599062006.45734, -3395666.6901195566, 18.95006719428506],\n        [1.0840830998464214e+16, 18649593079388.15, 6191089972.499226, 639683.9318348671, 17.565015462728365],\n        [-56829165736312.85, 70564590547.99759, 306929905.61277986, 148301.85724583076, 16.18099391544868],\n        [310867835909252.25, 2199488772836.398, 1846929222.0995405, 116534.16034655277, 14.79882120114736],\n        [-334740697066.67944, -11566416197.512352, -46807636.94628418, -36055.36084122248, 13.41992479832999],\n        [26840001873.396393, 1176747347.4470434, 8813678.971174415, 20286.661696956173, 12.046746116490432],\n        [331913333.4983728, 40516050.23123385, 806397.6785176995, 5236.358697987059, 10.683356504174844],\n        [44564097.249639705, 3136095.9802567307, 13197.27737274941, 472.46470130684173, 9.336331182644951],\n        [17994131.336623687, 4944651.796285454, 176426.70513709838, 1635.990096945895, 8.015855071773482],\n        [1175197.7515924468, -5987292.526887681, -1249674.1787671829, -47443.87985192143, 6.736866971917378],\n        [32169.38393625651, 35667.678007831906, 3281.4651865653304, 10.308412025244055, 5.519759829746941],\n        [726.6676328162513, 2656.6374294136144, 938.8331291251928, 91.97929785764381, 4.389835242348104],\n        [19.69824258336419, 111.99161644970393, 66.99538082454526, 16.542529871221728, 3.3746537841440527],\n        [0.14533082879935388, 4.621483129606414, 13.046154764778136, 10.666553990710677, 2.4990539191450107],\n        [0.002263983168833709, 0.012748221620148423, 0.08650686829071288, 1.2031142177285348, 1.779035515465167],\n        [-9.830589986253666e-05, -0.0029990944273936377, 0.07473329578861215, 0.6680604884342561, 1.2170809731605838],\n        [-0.00023383933828264596, -0.055094751033442003, -0.9014330674014724, -3.2873931899225397, 0.8013800839068237],\n        [-4.59305763926361e-06, -0.0023384643471826417, -0.075298488101913, -0.519264025248997, 0.5094004416089638],\n        [8.296798367082449e-06, 0.005019553134541902, 0.14520784160424574, -0.1480560699285633, 0.3138448562017667],\n        [-0.00010404498951688742, -0.042625544741268964, 0.07039958323658324, -0.19160439461435394, 0.18823178739081262],\n        [1.9257874863594892e-08, 5.065044581803412e-05, 0.005970986973437208, 0.007799255403717845, 0.11036344917508734]\n    ]\n\nNTU_from_plate_2_2_parallel_counterflow_q = [\n        [-5.109312737272847e+28, -2.7669837286303267e+22, -2979525666165644.0, -62269188.45954034, 1.0],\n        [-2.3013695133305585e+26, -1.3555563147438998e+20, 34967643100737.21, 15317110.975382129, 1.0],\n        [8.539176311283978e+27, 2.651062211838455e+21, -1274041588071886.2, -45590896.094170064, 1.0],\n        [7.884125680680726e+25, 2.690570806322227e+20, 140725727389471.77, -11634889.668290695, 1.0],\n        [1.3875230679709336e+24, 6.541525966824309e+18, -4448026600910.923, -15690760.761365911, 1.0],\n        [1.1845109172174247e+23, 8.238643367203461e+17, 795468754178.3317, -365479.85193633026, 1.0],\n        [-1.0019142582756757e+24, -8.086708001888148e+18, 11636573241044.895, 4092189.8130896357, 1.0],\n        [4.274893801197289e+20, 2.337481097686945e+16, 171016757014.2874, -520955.8420503665, 1.0],\n        [1.4582333948892862e+19, 1649920265439080.0, 33323373506.59859, 91837.83231499583, 1.0],\n        [-3.154069768612261e+19, -8175627871376203.0, -420703621074.17615, -4557050.2207395835, 1.0],\n        [1.9847893757166674e+18, 157724843212160.53, -19387590413.827114, -177816.88499161773, 1.0],\n        [978720427117839.0, 1262120134355.849, 377566806.9648005, 37158.4755696676, 1.0],\n        [-4513922446287.058, 8413417806.407876, 22154634.809136182, 9566.661311724654, 1.0],\n        [38070523736321.266, 175066430198.3794, 126396868.72314765, 8093.653907458961, 1.0],\n        [-61489371269.06048, -1171842872.8663423, -3846269.020383889, -2566.272998013682, 1.0],\n        [5045193301.256966, 133092026.4251891, 834715.8381330054, 1750.712772778083, 1.0],\n        [87384327.07596397, 5685052.186587454, 91282.50331715525, 527.4122879147639, 1.0],\n        [10190075.423735108, 370265.87179662683, 1818.871879286359, 71.60265020472393, 1.0],\n        [6596827.383166512, 848613.961529598, 24268.6940300083, 216.01923171376424, 1.0],\n        [-1866586.5008091372, -1826397.6735039286, -233559.34184976644, -7035.606933227122, 1.0],\n        [23329.113452411028, 8850.625264022498, 589.593396865346, 5.78276680823048, 1.0],\n        [1025.6980944478596, 1030.4061217224696, 257.83080542412074, 23.20339328125292, 1.0],\n        [36.169804435094974, 56.11202269478698, 25.35072952019013, 6.191692301948293, 1.0],\n        [0.870223837663587, 4.952736276431698, 8.141700513572173, 5.001805420623979, 1.0],\n        [0.0053042419079786796, 0.012398428202822248, 0.27504711840752394, 1.0888403188024758, 1.0],\n        [-0.0006872648984212443, 0.006963112330393481, 0.17402749161779235, 0.7777215103341757, 1.0],\n        [-0.006590838477539741, -0.19611938648031352, -1.640780687507329, -3.97716372393897, 1.0],\n        [-0.00024349857853046174, -0.013728589278679348, -0.21715653326322837, -0.9520846696079065, 1.0],\n        [0.0005124101312746552, 0.03261073652701299, 0.4456416681314436, -0.4360265030003868, 1.0],\n        [-0.004815365117901423, -0.219395737344097, 0.35487804621679386, -0.9991702722289716, 1.0],\n        [4.108812052585529e-06, 0.000985483311381511, 0.05478155149325794, 0.0804130994573366, 1.0]\n    ]\n\nNTU_from_H_2_unoptimal_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184, 80.5306368\n    ]\nNTU_from_H_2_unoptimal_p = [\n        [9.311090177068194e+30, 4.5399475564038554e+24, 3.1701651864920506e+17, -3255644601.8905473, 34.19784939508176],\n        [-8.462125737049189e+28, -1.051236894580789e+23, -2.39780488292632e+16, -1034705971.0814927, 32.81155489224577],\n        [-3.69265415130165e+26, -5.301822567178955e+20, 234882398081691.12, 234024752.99665904, 31.425260261916403],\n        [1.410560599685134e+28, 1.093808467030952e+22, -9490122636110636.0, -687633577.4144348, 30.038964915173185],\n        [1.1201146547787187e+26, 9.003076575091149e+20, 1018131781915969.1, -168283241.34922192, 28.652668818329857],\n        [1.877203115154918e+24, 2.174212412689376e+19, -23504286677434.996, -213953804.07995003, 27.266371636249264],\n        [1.5943258764466105e+23, 2.5692522022742523e+18, 5269608999836.621, -5146997.019028249, 25.88007152864389],\n        [-1.2864224116384471e+24, -2.5151093731537924e+19, 71437838753037.27, 50054408.15140979, 24.49376699655128],\n        [4.543942596226072e+20, 6.190381882242281e+16, 1011578832812.2455, -6097146.227414874, 23.107453874576674],\n        [1.443032893602968e+19, 4079127223298191.0, 179961190587.62994, 950472.5517376459, 21.72112504269345],\n        [-1.728525301221655e+19, -1.1407375350719094e+16, -1284373100357.226, -28343072.8472184, 20.334768568331974],\n        [1.758725436886904e+18, 365882402028983.06, -92828439127.84097, -1530591.291875413, 18.948363656972532],\n        [792036415908859.2, 2862760755487.6484, 1976373644.0058162, 409085.29888017545, 17.561875017574707],\n        [-2786989433439.3467, 18416834507.402943, 95324460.57822925, 82900.5916379863, 16.175246819451317],\n        [128921676834374.16, 719301630875.2167, 615567114.8357931, 110348.07378592492, 14.788396313036571],\n        [-2794040572.6818414, -507746769.4624018, -4437994.568915218, -4358.585576142468, 13.401217944728895],\n        [3853463713.3106866, 379360075.81886023, 5594276.687695783, 22313.0443512979, 12.013630281672944],\n        [66137990.08414679, 19025214.66224554, 664515.59380578, 6201.159018478011, 10.625745240108772],\n        [9822129.89007198, 3897096.80061018, 202285.06707868786, 2999.612381935198, 9.238376729914885],\n        [-948514.706520815, 374713.5998567277, 41481.55233261393, 494.59805780216936, 7.8543751267742525],\n        [-11980.837950093153, -20667.491465511925, -2068.4413590656304, 80.22238868415197, 6.481745527422999],\n        [-838.008545833977, -6831.181943934252, -3093.5280521633795, -306.91642288399237, 5.139846224565047],\n        [19.032578110906325, 391.13780322667174, 466.3339913926907, 133.0562843703077, 3.8685445515879007],\n        [-0.6990369659716387, 25.392942977606992, 27.402588487800582, 0.6420111258460738, 2.733344882284591],\n        [0.09338324529681567, 2.865351487389797, 5.114582382139363, 1.469511752917645, 1.8084168254866542],\n        [-0.0007321936823915426, -0.11675608789113232, -1.0568175987314021, -1.748890445704759, 1.13225374983665],\n        [0.0011779746288648211, 0.32293841158631104, 2.913257638698029, -2.4643506838886613, 0.6823222255523778],\n        [5.3274221084394595e-06, 0.0014584108461436326, 0.00018851507626193995, -0.3401471788904687, 0.4011229006580691],\n        [1.8271761689352308e-07, 0.0007480503587161893, 0.02957290171761351, -0.11994510120785795, 0.23177982864651042],\n        [6.8784748559726126e-09, 1.0482965040695156e-05, 0.0002687892019338303, -0.025003862996259105, 0.13213333004089212],\n        [8.763989208567784e-11, 3.591705984063844e-07, 4.921736181910166e-05, 0.0005333054403615145, 0.07446942413083177]\n    ]\nNTU_from_H_2_unoptimal_q = [\n        [3.291954404217546e+29, 1.4045943998953848e+23, 9191247072077158.0, -94420499.23235528, 1.0],\n        [-3.1929593654948206e+27, -3.458328656247019e+21, -744784566006064.1, -31128443.437835522, 1.0],\n        [-1.4381207928261743e+25, -1.693830694462608e+19, 8745588741895.983, 7659170.596221632, 1.0],\n        [5.334127451972166e+26, 3.309852357106662e+20, -318547388902977.1, -22780419.901297953, 1.0],\n        [4.925904942982619e+24, 3.3621635012359696e+19, 35171092574049.785, -5815045.64860498, 1.0],\n        [8.643102749014142e+22, 8.150919305905134e+17, -1107277799713.401, -7816238.671263142, 1.0],\n        [7.404943670579725e+21, 1.0301814770628384e+17, 198996743041.04614, -182778.72900289771, 1.0],\n        [-6.228991027766363e+22, -1.0027628939625004e+18, 2933582652790.756, 2052062.8183752794, 1.0],\n        [2.6555314925123396e+19, 2905025729565769.5, 42490608344.3377, -259352.57588899546, 1.0],\n        [9.139672887482086e+17, 206954301896627.38, 8364534478.701708, 46155.88226561543, 1.0],\n        [-1.219999405456035e+18, -632482998158155.4, -64953233304.81653, -1392542.5072398013, 1.0],\n        [1.1417868279414859e+17, 16091601606423.625, -4956298785.520264, -80089.7158649981, 1.0],\n        [72281648309673.0, 194796621486.79834, 120708758.31747963, 23664.722681493673, 1.0],\n        [-191688538350.4686, 1813128315.751175, 6801704.817635524, 5326.460112015771, 1.0],\n        [12819548881301.445, 52995232684.17356, 42414015.75348217, 7571.915653206027, 1.0],\n        [-902051651.0068148, -53121439.77681727, -359594.87348877365, -264.4646423506963, 1.0],\n        [789302837.8910002, 43370445.43163683, 526337.3354614506, 1891.217157665758, 1.0],\n        [20890921.591943897, 2670229.183391574, 73117.13860794589, 602.7662205426564, 1.0],\n        [3563425.2597333514, 615785.8657853191, 25312.120646154457, 335.70276322683435, 1.0],\n        [-5281.921891333585, 79753.7409802169, 5646.05302573743, 69.41887774964894, 1.0],\n        [-10534.39102576053, -4471.762975806752, -281.81541885802784, 16.231070841093203, 1.0],\n        [-2357.310740142227, -2582.904848108706, -744.555607310463, -57.3657004239234, 1.0],\n        [113.868855200266, 255.96866595663204, 169.54873521825837, 35.836022237199735, 1.0],\n        [6.394734078690184, 18.116469980060796, 10.094374048899589, 1.1083023536795746, 1.0],\n        [0.7587189251723472, 3.0042361512189037, 3.205115156278497, 1.3209192849079732, 1.0],\n        [-0.022869248133995868, -0.34815770989249484, -1.3774996352160318, -1.2636425293046998, 1.0],\n        [0.060036246550538616, 1.1203157641107213, 3.7280232186165474, -3.462501131451635, 1.0],\n        [0.00026946774515168733, 0.004270492842455563, -0.06591637316270788, -0.7704935865841344, 1.0],\n        [0.0001068179798574021, 0.008394972657004668, 0.10682274388388532, -0.4776775454943614, 1.0],\n        [1.506979766231119e-06, 0.00012838571550289634, -0.001854978747745747, -0.16888199753883318, 1.0],\n        [4.521472806270594e-08, 1.1656542235467652e-05, 0.0007261231042891383, 0.01752787098221555, 1.0]\n    ]\n\nNTU_from_G_2_unoptimal_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184\n    ]\nNTU_from_G_2_unoptimal_p = [\n        [9.3109303298284e+30, 4.5398767600969564e+24, 3.170118237710197e+17, -3255582028.524916, 34.197848452021496],\n        [-8.46153002817336e+28, -1.0511619908571051e+23, -2.3976144993098692e+16, -1034582403.5113205, 32.811553084100204],\n        [-3.692290021887378e+26, -5.30074247026417e+20, 234950665825511.66, 234036525.3056526, 31.425256801589224],\n        [1.4101005965316078e+28, 1.0930781123070384e+22, -9490843606104960.0, -687356679.2161583, 30.038958306458262],\n        [1.1198607183619476e+26, 9.001227755812281e+20, 1017933807262523.2, -168239785.08146304, 28.652656224909716],\n        [1.8733467374857413e+24, 2.16994206245589e+19, -23441677453694.316, -213471555.46532023, 27.26634769739391],\n        [1.594512099343422e+23, 2.569743318791424e+18, 5271709548496.723, -5147454.137281263, 25.88002614751128],\n        [-1.2818229253935495e+24, -2.5019202614319935e+19, 71832292062919.38, 50148771.068874955, 24.4936812282376],\n        [4.526495011307341e+20, 6.168512896379921e+16, 1007792749560.6382, -6081385.246719949, 23.107292341412784],\n        [1.4451218664677962e+19, 4087331357766796.5, 180399075525.08047, 953934.9722401868, 21.720822001301844],\n        [-1.3869417526718001e+19, -9157013351748946.0, -1029788858691.2903, -22579365.615234394, 20.33420262961592],\n        [1.6729941515616177e+18, 324820952603289.25, -94618051655.88188, -1432919.5602435556, 18.947312380207574],\n        [881377079365588.4, 3273908659562.771, 2305553502.530553, 477247.7586482068, 17.5599347216217],\n        [-2294712887420.415, 24687543307.214867, 107469238.04231983, 88609.84525340016, 16.171694155750217],\n        [122305930099635.03, 705130609607.45, 635856450.1020223, 115721.47051671412, 14.78195757555553],\n        [4611767764.284328, -109441848.88329092, -1372356.3121382846, 1370.2740105504195, 13.389707907074477],\n        [10777953775.11337, 1102063066.2696054, 16002550.06022829, 59325.3942992436, 11.993442742792807],\n        [177557128.393412, 49828237.759808525, 1637511.0220782922, 13518.269190691442, 10.591302235163992],\n        [-11319417.192115635, -4781582.158127945, -231145.86260741882, -2382.4032164871915, 9.181987939464335],\n        [4453125.420063021, 3506923.02340456, 273936.10624431854, 4847.528594239127, 7.7676966035380675],\n        [13382.567476165745, 21430.76649959107, 2674.227284505346, 103.35356016929184, 6.3607932986774065],\n        [543.272216259408, 4094.6104229588664, 2371.7677593267967, 332.1165814161398, 4.994049687616688],\n        [1019.6252971158917, 7258.186980145784, 2649.616182665721, -234.08989484797726, 3.726702452635227],\n        [-0.16061952890054718, 26.475103623327957, 43.95078747890926, 10.898179144782612, 2.631460758603036],\n        [0.09149784249886796, 4.507115402896758, 15.671800736565093, 13.267529540880941, 1.761750359230347],\n        [-0.00015770925539570476, -0.022822040552860745, -0.16411319759532497, 0.0669124755747916, 1.126534416642668],\n        [0.00017204089843551025, 0.016550563961219227, -0.11929008580672096, -1.7458596555122052, 0.6944621419501356],\n        [-7.685285829457997e-05, 0.0018127599213621482, 0.2174778970361136, -0.33456541736023027, 0.41625508736123845],\n        [9.408372464685374e-05, 0.02102006446772354, 0.00912807079932442, -0.1551911187056057, 0.24418730333772493],\n        [5.544070897390911e-08, 9.56760771830238e-05, 0.006378971832410667, -0.003131142559408388, 0.1408475496320552]\n    ]\nNTU_from_G_2_unoptimal_q = [\n        [3.291899133189346e+29, 1.4045726158959873e+23, 9191111431994574.0, -94418671.74467972, 1.0],\n        [-3.192736723751476e+27, -3.4580817365485486e+21, -744725064710364.8, -31124678.831225593, 1.0],\n        [-1.4379756315457668e+25, -1.6934523380520071e+19, 8747844401754.986, 7659546.39574443, 1.0],\n        [5.332355293465041e+26, 3.307386549899383e+20, -318570445606863.2, -22771206.601799294, 1.0],\n        [4.924818318184813e+24, 3.361477658856301e+19, 35164284666572.586, -5813531.206756055, 1.0],\n        [8.625452913515019e+22, 8.135001664691246e+17, -1104444855152.0972, -7798558.608923992, 1.0],\n        [7.405897764320868e+21, 1.0303870840706498e+17, 199077908074.35632, -182796.37614918998, 1.0],\n        [-6.206279982934437e+22, -9.972450845965889e+17, 2949730732036.1255, 2055922.8784550051, 1.0],\n        [2.6456407174731583e+19, 2894792447086410.5, 42330038939.27757, -258671.97913873894, 1.0],\n        [9.154740126119596e+17, 207382210576832.97, 8385210219.820697, 46316.26048683696, 1.0],\n        [-9.792909081377169e+17, -507714298948915.3, -52072419949.23038, -1109132.0457241398, 1.0],\n        [1.0837682471753584e+17, 13849549366085.156, -5047510075.563598, -74938.92605805417, 1.0],\n        [80947665751539.0, 223424288658.0732, 140917314.1477617, 27549.357113325757, 1.0],\n        [-132644052917.59738, 2311595719.622853, 7627291.298373281, 5680.979777532329, 1.0],\n        [12251665633349.52, 52214132651.39238, 43847873.4458912, 7939.025429824954, 1.0],\n        [357856427.292005, -13251164.49142286, -104886.64220397608, 163.45236732230813, 1.0],\n        [2296389972.242021, 126515566.06074195, 1501329.2443050412, 4980.7209489861, 1.0],\n        [57930714.72719192, 6980962.132745493, 178865.45887007687, 1295.833190332679, 1.0],\n        [-4491299.168210062, -759374.3426606245, -28261.14356909038, -248.17491581939632, 1.0],\n        [2506378.5603899686, 662130.496745444, 39393.242284047185, 630.7413500970226, 1.0],\n        [11844.477007158022, 4964.567889890172, 475.3789207352269, 20.27033156384447, 1.0],\n        [1416.4504720022767, 1813.2683066018321, 634.6090169991996, 68.9432285360459, 1.0],\n        [2588.630195894044, 3034.5274746385926, 618.0900263390289, -61.3460322498087, 1.0],\n        [6.112796092986507, 23.856734715976987, 20.0956829765361, 5.00250593541833, 1.0],\n        [1.0163551310040695, 6.580584763171997, 12.526779989536907, 8.018967861683878, 1.0],\n        [-0.00425071771516727, -0.057961324447462347, -0.14113094148720395, 0.3271266362038584, 1.0],\n        [0.003503234523706573, 0.006625141755068311, -0.5342364646029686, -2.37092136161077, 1.0],\n        [-0.00024692055494272906, 0.04414352357324488, 0.4614638247959701, -0.7287208247762657, 1.0],\n        [0.00372150090621385, 0.08764328509210832, 0.012510039071747442, -0.5966700220138256, 1.0],\n        [1.214635258673814e-05, 0.0015853341009969197, 0.0448060202483571, -0.0022540017940275857, 1.0]\n    ]\n\nNTU_from_P_J_2_offset = [7.5e-08, 2.25e-07, 6.75e-07, 2.025e-06, 6.075e-06, 1.8225000000000003e-05, 5.467500000000001e-05, 0.00016402500000000002, 0.000492075,\n        0.001476225, 0.004428675, 0.013286025, 0.039858075, 0.119574225, 0.358722675, 1.0761680249999999, 3.2285040749999996, 9.685512224999998,\n        29.056536674999997, 87.169610025]\nNTU_from_P_J_2_p = [\n        [1.379293737184234e+44, 5.439023353733237e+37, 4.2006081013865867e+30, 1.5600236133130092e+23, 1.0691012154169038e+16, 607948038.8625113, 35.584143946088],\n        [3.977011844664325e+41, 4.3621401764830945e+35, 5.394318809746255e+28, 6.18977231622784e+20, 2371944977808139.5, -13729570.055684585, 33.386919579479546],\n        [5.503399680509165e+39, 1.817486676934107e+34, 2.4835200809625483e+27, -4.94507688364635e+21, 1710942974186981.0, -323425148.685019, 31.189694983023596],\n        [-5.688303341798886e+34, 1.9802128520243527e+30, 3.873601341667205e+25, 1.3266955228207854e+20, 32936950212583.0, -192901487.91097888, 28.99247043733991],\n        [2.6577822797427475e+31, 3.677744229595766e+27, 9.720475078230118e+22, 7.630266992579775e+17, 1079206988084.657, -713421.4769980257, 26.795245857337733],\n        [2.535644640454403e+31, 3.3854769442469036e+27, 7.414350002779228e+22, 2.7270860191982288e+17, 2032720913118.922, 2586699.473660061, 24.598021286804627],\n        [-3.670558764178667e+26, -2.907829370394574e+23, -3.832557120797078e+19, -972481647974356.9, 8754962146.297441, -578040.0935389815, 22.40079670572366],\n        [1.4567732266714603e+24, 2.0002302464098957e+21, 5.807908884342328e+17, 86872945369936.56, 11954307761.34507, 805855.0329613951, 20.203572198563034],\n        [-1.8717456698528226e+20, -1.2176465524651423e+18, -778715222269321.5, 869869235169.809, 701696300.6903126, 123267.94767870879, 18.00634747585284],\n        [-1.2720358195046216e+18, -2.994023342276172e+16, -115432726426873.97, -103528958523.52058, 5714026.505779477, -15843.156326800376, 15.809121639609089],\n        [-693868088372775.0, -14665128532110.385, -40097140813.94941, -12207173.118260076, 874474.9845013419, 4765.386828156788, 13.611888987763974],\n        [608526214919.5482, 213144699162.69724, 10494925952.93119, 161216968.40265524, 912961.118340575, 3645.556442288636, 11.414614080037193],\n        [12400266.233880278, 55616915.46934441, 15009980.829033542, 1319417.6118004804, 48979.82322881266, 885.3320092533332, 9.217129450305661],\n        [-2175425.2487209123, -50112748.10174761, -19806780.207386833, -1499087.9941959996, 37429.79938076639, -732.1927840030977, 7.019288428844824],\n        [180.38230298958038, -6877.271284301687, -7818.717128329305, -1317.358943766587, 230.73216317292162, -43.76812039187138, 4.830718891488284],\n        [-0.17395706235381111, -16.6766544106866, 17.378017727113797, 28.091561354012356, -3.3753097336005804, 9.746402232018756, 2.7734138119975618],\n        [-0.08170110767689108, -1.9622386891531531, 31.973619141306784, -18.994072067345428, 18.01530939582972, -10.00277120433454, 1.2830169212938194],\n        [-1.8673203116193894e-06, -0.0006729694269362634, -0.0038298059267577044, 0.17481160261931097, 0.5595504373144352, 1.1890765321959993, 0.5336606579343032],\n        [-4.126347971671396e-07, -0.00010383779245126719, 0.0004941341620841793, -0.0036143614373294695, 0.03215823233734107, -0.13594349795793487, 0.2153400299994889],\n        [1.1352761642923954e-12, 4.466300862534921e-09, 4.980466105756786e-07, -1.747924038757887e-05, 0.0005662659607976993, -0.0008124803373884537, 0.08545603782210896]\n    ]\nNTU_from_P_J_2_q = [\n        [4.591167043547481e+42, 1.606114843399718e+36, 1.2027419595813414e+29, 4.5709455933251277e+21, 308809321150730.1, 17834210.46773281, 1.0],\n        [1.4176611491239528e+40, 1.3607402099050933e+34, 1.5783578828462145e+27, 3.912507110657984e+19, 70413898494599.84, -144987.26733659825, 1.0],\n        [2.1375766831490205e+38, 6.038431370476358e+32, 6.054805550705697e+25, -1.5264408314370513e+20, 53809598724793.99, -10274617.610954134, 1.0],\n        [-2.141040713656621e+33, 8.876323674907398e+28, 1.4680506954801534e+24, 4.665180136962245e+18, 902143492964.3142, -6619437.068866051, 1.0],\n        [1.432164429610735e+30, 1.6247132650490878e+26, 3.9301808580131244e+21, 2.9081928379120252e+16, 39088664097.274124, -14338.490436435039, 1.0],\n        [1.3632572533340117e+30, 1.5022149283687727e+26, 3.0554280135011666e+21, 1.1447971515162446e+16, 83004234706.80063, 109620.15224286402, 1.0],\n        [-2.429838319244439e+25, -1.5116925717630222e+22, -1.7919330403274191e+18, -42320389648484.82, 336427956.90190256, -24171.475216249233, 1.0],\n        [1.029014370536014e+23, 1.1241714145850822e+20, 3.066377639010162e+16, 4603604903923.01, 614289753.7531514, 40490.27848023662, 1.0],\n        [-1.7047361017944777e+19, -7.913845937988589e+16, -38110753754005.18, 56102625195.25173, 40336224.323338695, 7071.527033415434, 1.0],\n        [-1.466460222837932e+17, -2368131962476749.0, -7883636266218.59, -6487219371.973534, 253874.3242902243, -916.4549397393939, 1.0],\n        [-80727057098668.84, -1158659586259.3425, -3079314024.2938294, 658517.4797846868, 73213.81902982714, 383.2675505551966, 1.0],\n        [154696420804.57706, 27182107403.606, 1083690882.8286123, 15089725.838928567, 83871.50963458995, 332.564715920644, 1.0],\n        [14186109.875687288, 11604436.970824337, 2246816.302173693, 168932.58014667718, 5798.38653812484, 101.49810005349056, 1.0],\n        [-10506354.591316702, -12816984.672097836, -3355998.4791482566, -200389.50800387145, 5079.542670150122, -101.92851768910828, 1.0],\n        [-1306.7658976560958, -3118.914532403747, -1953.578672005278, -214.44697466919783, 37.10146877200857, -7.922586619768505, 1.0],\n        [-3.4777812458808555, -2.66496086895917, 12.06040187108384, 9.382513303976543, 0.7618565915752666, 4.082394043941239, 1.0],\n        [-0.5478521985532157, 4.4820443343765985, 21.325292193447055, -11.421627483324068, 12.178810914368531, -7.5579809400927775, 1.0],\n        [-9.742102821144731e-05, -0.002065573589076824, 0.019790600076312437, 0.41450177639499663, 1.235749069760604, 2.312490295019506, 1.0],\n        [-1.5856176703649368e-05, -0.00041496261982164757, 0.0018006879594633617, -0.012449317525219798, 0.13114216762570655, -0.6025944343758391, 1.0],\n        [4.690094899391156e-10, 1.1078843951667822e-07, 3.7862270042457132e-06, -0.0001399289022755603, 0.006526270606084676, 0.00022681636474048618, 1.0]\n    ]\nNTU_from_P_J_4_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184\n    ]\nNTU_from_P_J_4_p = [\n        [1.1137179009139922e+22, 7276370402964671.0, 982286593.77106, 35.36100061385685],\n        [3.9520974777651436e+20, 817675826063219.9, 326507731.5694956, 33.97470625485492],\n        [-6.841863118463395e+19, -40856958897824.58, 81315681.91084157, 32.588411778703986],\n        [-1.226994790378735e+20, -467148543840559.25, -248085221.6635263, 31.20211748691618],\n        [6.48597266541994e+17, 11019359745896.43, 35584715.41588573, 29.8158232003719],\n        [2.1079329317454016e+18, 35398661212068.19, 99510270.06019339, 28.429528868794645],\n        [8935402325113268.0, 618377307638.4402, 8039429.253688355, 27.043234454056968],\n        [5560958051752470.0, 452304392321.3483, 6957555.9298604345, 25.656940184631672],\n        [126235735091357.48, 34964623767.870056, 1810157.0390347333, 24.270645740470233],\n        [103033182132830.16, 36058139909.400696, 2072264.0804883514, 22.884351392471412],\n        [-103982270484.21591, 838356119.2129722, 306578.86931115517, 21.498057055394064],\n        [-7251975283452.386, -8287862367.975066, -1294281.061275808, 20.111763168535326],\n        [-158106070969.9289, -328902231.04025, -61097.005884115875, 18.725469990458958],\n        [-17294918972.910526, -76296368.6262589, -29707.458670753877, 17.339179506802296],\n        [256922268.69636458, 5269647.432513786, 18204.805713360474, 15.952898438512468],\n        [58898464.41169616, 1813429.6541062293, 10011.43433572321, 14.566648122016973],\n        [446520.17751930194, 153233.62152383465, 3090.2164859982668, 13.180497004021207],\n        [192422.14842327707, 48315.74348976142, 1547.3573889245085, 11.794657577802244],\n        [22663.130317209336, 11333.59117949032, 700.5385580157777, 10.409766262101133],\n        [1967.4393020460104, 2327.830281611502, 297.97297093031005, 9.027639452147119],\n        [-318.3313733466705, 16.786387998216867, 82.34942017917173, 7.653122592980561],\n        [11.458463050331853, 90.2649720625161, 49.98898169401306, 6.297942670584156],\n        [0.1370275766836422, 13.527475822643838, 18.083157099365827, 4.9866549707448655],\n        [-0.08811753949415488, 0.7580719231984764, 5.1618411905678885, 3.7607700748102135],\n        [-0.026715037890536985, -7.268631456244228, -11.596324791801184, 2.6722136470814455],\n        [0.0007400741868303971, 0.1167759145386527, 0.8860970545163467, 1.7671234621614083],\n        [0.004830310767271772, 1.079863001801655, 6.078126424454076, 1.0804293879908267],\n        [-0.0014226263147185095, -0.33627027530350345, -0.060678051246797524, 0.6204891876781652],\n        [1.2996495928311868e-08, 7.487428756304456e-05, 0.01170061756683815, 0.34410237764731944],\n        [-2.781758163682452e-07, -0.0008169026844673782, -0.06269490294979985, 0.18770099027480536]\n    ]\nNTU_from_P_J_4_q = [\n        [3.838083335177554e+20, 222263807511839.7, 28532938.656622943, 1.0],\n        [1.4833618909488933e+19, 26684604852189.977, 10002766.828354824, 1.0],\n        [-2.475411036306694e+18, -1042375335783.4248, 2699804.4727502298, 1.0],\n        [-4.833610251211771e+18, -15898701744151.383, -7844079.587894955, 1.0],\n        [2.8854497720401664e+16, 416128712820.01227, 1249382.9866715993, 1.0],\n        [9.364002670645787e+16, 1342489459568.0027, 3529555.587532283, 1.0],\n        [453285058958963.44, 26079026061.61398, 312688.0379653563, 1.0],\n        [286149498334759.3, 19473946611.856277, 279296.371346023, 1.0],\n        [7422551752650.021, 1667363729.5110798, 78874.03269449141, 1.0],\n        [6265733267256.983, 1757307727.953103, 92829.6964275974, 1.0],\n        [1999652867.803483, 49852548.82714711, 15472.119794909637, 1.0],\n        [-512013153282.79803, -455443511.83280444, -63707.00543582891, 1.0],\n        [-12222218188.63782, -19143850.59303709, -2915.0995349095583, 1.0],\n        [-1506979769.7819808, -4839415.404125513, -1525.5783956902367, 1.0],\n        [29423132.775343254, 415645.0522902444, 1243.1836879724854, 1.0],\n        [7318822.988441785, 154640.7646059886, 743.1491517287512, 1.0],\n        [141201.0534254414, 16674.388169779257, 265.3197588068411, 1.0],\n        [45153.80125997977, 5777.697281822111, 148.43127372342246, 1.0],\n        [6966.966337389611, 1591.6903920455154, 77.05203947040957, 1.0],\n        [917.2988119948286, 402.52765640680553, 38.61336284687747, 1.0],\n        [-71.87668749611038, 26.972070330473336, 14.038555292975968, 1.0],\n        [18.036042518702104, 27.128549126117615, 9.887065213985007, 1.0],\n        [1.9767237853128081, 6.305760321878647, 4.800623897964247, 1.0],\n        [0.04809865838967166, 1.0212459815948616, 2.083454689699847, 1.0],\n        [-1.0298310153064745, -4.619556300508356, -3.90904614301033, 1.0],\n        [0.016605629497247247, 0.1917630272238318, 0.7612198916261416, 1.0],\n        [0.15032334712603257, 1.849779948438833, 5.776977591182038, 1.0],\n        [-0.04700684698139208, -0.5503640789830394, -0.015203083681555351, 1.0],\n        [7.574689191705429e-06, 0.0015757631170495458, 0.07698932879125621, 1.0],\n        [-8.744918585890159e-05, -0.011691953640170439, -0.31212155570753924, 1.0]\n    ]\n\nNTU_from_P_basic_crossflow_mixed_12_offset = [7.5e-08, 1.5e-07, 3e-07, 6e-07, 1.2e-06, 2.4e-06, 4.8e-06, 9.6e-06, 1.92e-05, 3.84e-05, 7.68e-05, 0.0001536, 0.0003072, 0.0006144, 0.0012288,\n        0.0024576, 0.0049152, 0.0098304, 0.0196608, 0.0393216, 0.0786432, 0.1572864, 0.3145728, 0.6291456, 1.2582912, 2.5165824, 5.0331648, 10.0663296,\n        20.1326592, 40.2653184, 80.5306368, 161.0612736, 322.1225472, 644.2450944, 1288.4901888\n    ]\nNTU_from_P_basic_crossflow_mixed_12_p = [\n        [1.0648657843926371e+28, 1.953857955950789e+22, 7266974622321844.0, 901310037.367627, 35.29646216590824],\n        [-2.725970106134222e+28, -5.668910625458952e+22, -2.214546614947417e+16, -2075136770.0413792, 33.91016772641483],\n        [3.317334215900722e+36, 1.83532794193258e+30, 1.3685590706146844e+21, 363848581451.6158, 32.52387319458047],\n        [2.287548017339333e+25, 2.235626801942006e+20, 421302243477568.8, 237921355.15637708, 31.1375789140508],\n        [3.7397053636559112e+25, 3.711246345042558e+20, 677728033156592.5, 293850388.0168432, 29.75128463980416],\n        [1.0868350552139688e+30, 1.8455968608452927e+25, 4.7684805369296495e+19, 73543771834.092, 28.36499027336039],\n        [-5.68877408709714e+22, -1.58579560884536e+18, -4299134851761.376, 23968028.669715144, 26.978695929717148],\n        [1.6747242923170734e+22, 1.255438889589369e+18, 15434191675148.246, 27075146.549738526, 25.592401393795864],\n        [1.0569269667427512e+22, 1.2502500074264484e+18, 18964792281222.582, -130738981.69876468, 24.2061071320861],\n        [-2.5803066379744737e+18, 372261157232874.94, 28264835013.28186, -17050.367595574695, 22.819812804805323],\n        [-9.755620022787496e+17, -725650029723333.5, -41926633472.52738, 3113611.357517518, 21.433518761319352],\n        [-4.5273524706659283e+17, -909679128993800.9, -318106354724.0829, -28491925.038955502, 20.047224673431018],\n        [9262291183292458.0, 19527324488391.098, 4613123691.341467, -663030.266969785, 18.660931382962406],\n        [-1268775247799946.5, -14687587336923.14, -27389900433.704067, -12603645.373545203, 17.274641094810104],\n        [3158577553978.4697, 71185736277.97443, 261619313.33159643, 249174.90223218722, 15.888360350134677],\n        [152798849901.24323, 5254166915.823552, 29780970.83267744, 47672.85047654532, 14.502111276022058],\n        [292692355448.6804, 11747722863.857492, 50327505.150009006, -93575.49190852011, 13.115964119634741],\n        [1106317355.2031553, 127940907.99872206, 2104897.7308680704, 8042.20078053657, 11.7301387421864],\n        [2197193.2553803152, 1285706.599464342, 94469.9714858117, 1982.9696716666438, 10.345295129780379],\n        [628759.7709569605, 367127.78202066384, 28069.761808265386, 683.706593111148, 8.963325126986435],\n        [528.078676943018, 2632.4181877354436, 1230.1904049453256, 174.67508689366082, 7.589305501960269],\n        [-1494.2855542418577, -6088.743359266542, -2320.2207257673876, -183.19106697358848, 6.2356286720949745],\n        [0.8507108729411813, 22.302501634010234, 45.4763530114471, 27.27372898572285, 4.928616927537855],\n        [-1.2077329580227858, -36.62873095860811, -74.72114158071923, -30.567927983101946, 3.713928731013624],\n        [0.8647680033690556, 31.52269638492401, 55.565702550395976, -4.780723933354412, 2.6509731108629784],\n        [0.2985244757802897, 47.382849336432166, 448.40056689075203, 934.1164294026304, 1.7905411822239048],\n        [-0.00021659913188603507, -0.031019118273585895, -0.06734409089895292, 1.4954198465032587, 1.1499737101680396],\n        [2.1622908509544346e-05, 0.008770641444302658, 0.16604173854981807, 0.382168453132166, 0.7082821192347464],\n        [4.196344927837933e-06, 0.0037795723343284817, 0.13015088360211113, 0.025875640008383147, 0.42214432523510087],\n        [6.341115075750826e-09, 0.00019953280608039998, 0.01857524533658307, 0.00019535277989255078, 0.24534755148670773],\n        [4.642762949093271e-06, 0.005095731601409439, -0.04639395438641826, 0.03610487934676299, 0.1398621181683815],\n        [1.2306148922906546e-08, 4.004868303268181e-05, 0.003670103859870603, -0.030187701704396393, 0.07853403174401082],\n        [4.3797422412183115e-12, 8.829865413669967e-08, 5.3467304702596584e-05, 0.0016073164432044349, 0.0435699623017177],\n        [-7.062736110507592e-09, -7.668007088536754e-05, 0.0023318927789922703, -0.041990582834008715, 0.023936688503263276],\n        [1.2508061870706862e-14, 2.573853599556939e-09, 7.24838458529996e-06, -0.00012330891215276327, 0.013044234435602044]\n    ]\n\nNTU_from_P_basic_crossflow_mixed_12_q = [\n        [3.973671938704683e+26, 6.326552638003598e+20, 220710170167753.03, 26290926.9768005, 1.0],\n        [-1.026756192847948e+27, -1.8529253231359474e+21, -678280420727251.2, -60801923.8992356, 1.0],\n        [1.135562772430311e+35, 5.643879638731395e+28, 4.208089303288672e+19, 11187328400.684576, 1.0],\n        [9.744383540727682e+23, 8.115450878596962e+18, 14270577510742.908, 7748023.36603521, 1.0],\n        [1.5931786175761789e+24, 1.3561342279548963e+19, 23312891578604.902, 9932917.423178872, 1.0],\n        [4.859688211478509e+28, 7.000358779926185e+23, 1.6811909822046449e+18, 2592795007.454948, 1.0],\n        [-2.666944038287914e+21, -6.228033882597861e+16, -147002301520.06125, 903850.04214734, 1.0],\n        [8.607232894250505e+20, 5.360902575722586e+16, 611331531040.4706, 1066077.3271792284, 1.0],\n        [5.6923263643194255e+20, 5.5529930521810664e+16, 760135235703.9015, -5396770.908948376, 1.0],\n        [-1.1447343385186822e+17, 19557170326968.332, 1212359780.557646, 1535.249044757823, 1.0],\n        [-6.7087362640990504e+16, -37115893206839.71, -1786055637.3556702, 146483.33188585352, 1.0],\n        [-3.4756109279027156e+16, -53271233725098.945, -16792652327.870298, -1420590.8612348323, 1.0],\n        [717903881236155.8, 1149403566251.7737, 234365669.11825627, -35181.515793654195, 1.0],\n        [-131068069929832.05, -1062923626979.946, -1723158048.0735118, -729415.4542761801, 1.0],\n        [373138123021.75226, 5693132516.134963, 18041434.36138755, 15785.296488339987, 1.0],\n        [19866365968.41335, 452347302.11955184, 2229754.0098727057, 3343.417286909013, 1.0],\n        [39770464992.804535, 1030615797.581643, 3613628.7482191008, -7103.45523067367, 1.0],\n        [200128825.45281503, 13652967.796242092, 190746.07900072972, 702.9359016386885, 1.0],\n        [734053.0142461995, 188917.2993281958, 10859.229501012394, 201.49437641508658, 1.0],\n        [209302.76040083222, 56139.34393204773, 3521.801145946451, 81.92398920910554, 1.0],\n        [598.8866174601792, 715.9466859667624, 227.62193299094852, 26.319829515259006, 1.0],\n        [-1479.3910297195062, -1619.331929198887, -432.5244387771081, -27.41252766738836, 1.0],\n        [3.2574469229510354, 12.8571035438057, 15.091263524092597, 6.715596193986065, 1.0],\n        [-5.223964240539322, -22.61021951185674, -26.126504739428494, -7.521201583422795, 1.0],\n        [4.384367871411823, 20.758534092876616, 20.16342961309194, -1.3847296429245695, 1.0],\n        [4.891865775589256, 81.08707101822866, 375.67471782459376, 521.9351243262005, 1.0],\n        [-0.003354856095171886, -0.037975637276086216, 0.11222885303757815, 1.4337579152114632, 1.0],\n        [0.0007839864026962514, 0.02894459533320549, 0.272639521725721, 0.611588697885286, 1.0],\n        [0.0003025722525591445, 0.020683093661872085, 0.3104855870447247, 0.09936172614571803, 1.0],\n        [1.3308588756670941e-05, 0.002314200802093514, 0.0756883464283556, 0.020616151735835784, 1.0],\n        [0.0004083029953833101, 0.03304346443946263, -0.32908410954386225, 0.2683607066488552, 1.0],\n        [2.7228204913745714e-06, 0.000755047941743242, 0.0447212276770666, -0.37916271374424443, 1.0],\n        [4.914765639846191e-09, 5.27587799649255e-06, 0.001324873372051413, 0.03955253112545274, 1.0],\n        [-4.6335857071244e-06, -0.0030716430602319663, 0.0950492776042504, -1.7528843558197416, 1.0],\n        [1.2061450998792682e-10, 5.775284765597841e-07, 0.0005491863749069216, -0.008769384960859137, 1.0]\n    ]\n\n\n\ndef _NTU_from_P_objective(NTU1, R1, P1, function, *args):\n    \"\"\"Private function to hold the common objective function used by\n    all backwards solvers for the P-NTU method.\n    These methods are really hard on on floating points (overflows and divide\n    by zeroes due to numbers really close to 1), so if the function fails,\n    mpmath is imported and tried.\n    \"\"\"\n    P1_calc = function(R1, NTU1, *args)\n    # Handled a larger range, not worth it\n#    try:\n#        P1_calc = function(R1, NTU1, **kwargs)\n#    except :\n#        try:\n#            import mpmath\n#        except ImportError:  # pragma: no cover\n#            raise ValueError('For some reverse P-NTU numerical solutions, the \\\n#intermediary results are ill-conditioned and do not fit in a float; mpmath must \\\n#be installed for this calculation to proceed.')\n#        globals()['exp'] = mpmath.exp\n#        P1_calc = float(function(R1, NTU1, **kwargs))\n#        globals()['exp'] = math.exp\n    return P1_calc - P1\n\n\ndef _NTU_from_P_erf(NTU1: float, *args) -> float:\n    \"\"\"Private function to hold the common objective function used by\n    all backwards solvers for the P-NTU method.\n    These methods are really hard on on floating points (overflows and divide\n    by zeroes due to numbers really close to 1), so if the function fails,\n    mpmath is imported and tried.\n    \"\"\"\n    R1, P1, function = args[0], args[1], args[2]\n    return function(R1, NTU1, *args[3:]) - P1\n\ndef _NTU_from_P_solver(P1: float, R1: float, NTU_min: float | None, NTU_max: float | None, function: Callable, guess: float | None, *args) -> int | float:\n    \"\"\"Private function to solve the P-NTU method backwards, given the\n    function to use, the upper and lower NTU bounds for consideration,\n    and the desired P1 and R1 values.\n    \"\"\"\n    args2 = (R1, P1, function) + args\n    try:\n        if guess is not None:\n            guess2 = guess\n        elif NTU_min < 2.0 < NTU_max:\n            guess2 = 2.0\n        else:\n            guess2 = NTU_min + 0.001*NTU_max\n        if (NTU_min is not None and NTU_max is not None) and (guess2 < NTU_min or guess2 > NTU_max):\n            guess2 = 0.5*(NTU_min + NTU_max)\n        return secant(_NTU_from_P_erf, guess2, low=NTU_min, high=NTU_max, bisection=False, xtol=1e-13, args=args2)\n    except:\n        # secant failed. For some reason, the bisection in secant is going to wrong wrong value\n        # floating point really sucks\n        pass\n\n    # Better for numerical stability if we don't need to evaluate these\n    P1_max = _NTU_from_P_erf(NTU_max, *(R1, 0.0, function) + args)\n    P1_min = _NTU_from_P_erf(NTU_min, *(R1, 0.0, function) + args)\n    if P1 > P1_max:\n        raise ValueError(f\"No solution possible gives such a high P1; maximum P1={P1_max:f} at NTU1={NTU_max:f}\") # numba: delete\n        # raise ValueError(\"No solution\") # numba: uncomment\n    if P1 < P1_min:\n        # raise ValueError(\"No solution\") # numba: uncomment\n        raise ValueError(f\"No solution possible gives such a low P1; minimum P1={P1_min:f} at NTU1={NTU_min:f}\") # numba: delete\n    # Construct the function as a lambda expression as solvers don't support kwargs\n    return brenth(_NTU_from_P_erf, NTU_min, NTU_max, args=args2)\n\n\ndef _NTU_max_for_P_solver(ps: list[list[float]], qs: list[list[float]], offsets: list[float], R1: float) -> float:\n    \"\"\"Private function to calculate the upper bound on the NTU1 value in the\n    P-NTU method. This value is calculated via a pade approximation obtained\n    on the result of a global minimizer which calculated the maximum P1\n    at a given R1 from ~1E-7 to approximately 100. This should suffice for\n    engineering applications. This value is needed to bound the solver.\n    \"\"\"\n    offset_max = offsets[-1]\n    for offset, p, q in zip(offsets, ps, qs):\n        if R1 < offset or offset == offset_max:\n            x = R1 - offset\n            return horner(p, x)/horner(q, x)\n\n\ndef NTU_from_P_basic(P1: float, R1: float, subtype: str=\"crossflow\") -> float:\n    r\"\"\"Returns the number of transfer units of a basic heat exchanger type\n    with a specified (for side 1) thermal effectiveness `P1`, and heat capacity\n    ratio `R1`. The supported cases are as follows:\n\n    * Counterflow (ex. double-pipe) [analytical]\n    * Parallel (ex. double pipe inefficient configuration) [analytical]\n    * Crossflow, single pass, fluids unmixed [numerical]\n    * Crossflow, single pass, fluid 1 mixed, fluid 2 unmixed [analytical]\n    * Crossflow, single pass, fluid 2 mixed, fluid 1 unmixed [analytical]\n    * Crossflow, single pass, both fluids mixed [numerical]\n\n    The analytical solutions, for those cases they are available, are as\n    follows:\n\n    Counterflow:\n\n    .. math::\n        NTU_1 = - \\frac{1}{R_{1} - 1} \\ln{\\left (\\frac{P_{1} R_{1} - 1}{P_{1}\n        - 1} \\right )}\n\n    Parallel:\n\n    .. math::\n        NTU_1 = \\frac{1}{R_{1} + 1} \\ln{\\left (- \\frac{1}{P_{1} \\left(R_{1}\n        + 1\\right) - 1} \\right )}\n\n    Crossflow, single pass, fluid 1 mixed, fluid 2 unmixed:\n\n    .. math::\n        NTU_1 = - \\frac{1}{R_{1}} \\ln{\\left (R_{1} \\ln{\\left (- \\left(P_{1}\n        - 1\\right) e^{\\frac{1}{R_{1}}} \\right )} \\right )}\n\n    Crossflow, single pass, fluid 2 mixed, fluid 1 unmixed\n\n    .. math::\n        NTU_1 = - \\ln{\\left (\\frac{1}{R_{1}} \\ln{\\left (- \\left(P_{1} R_{1}\n        - 1\\right) e^{R_{1}} \\right )} \\right )}\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    subtype : float\n        The type of heat exchanger; one of 'counterflow', 'parallel',\n        'crossflow', 'crossflow approximate', 'crossflow, mixed 1',\n        'crossflow, mixed 2', 'crossflow, mixed 1&2'.\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    Although this function allows the thermal effectiveness desired to be\n    specified, it does not mean such a high value can be obtained. An exception\n    is raised when this occurs, although not always a helpful one.\n\n    >>> NTU_from_P_basic(P1=.99, R1=.1, subtype='parallel')\n    Traceback (most recent call last):\n    ValueError: math domain error\n\n    For the 'crossflow approximate' solution the function is monotonic, and a\n    bounded solver is used within the range of NTU1 from 1E-11 to 1E5.\n\n    For the full correct 'crossflow' solution, the initial guess for newton's\n    method is obtained by the 'crossflow approximate' solution; the function\n    may not converge because of inaccuracy performing the numerical integral\n    involved.\n\n    For the 'crossflow, mixed 1&2' solution, a bounded solver is first use, but\n    the upper bound on P1 and the upper NTU1 limit is calculated from a pade\n    approximation performed with mpmath.\n\n    Examples\n    --------\n    >>> NTU_from_P_basic(P1=.975, R1=.1, subtype='counterflow')\n    3.984769850376482\n    \"\"\"\n    NTU_min = 1E-11\n    guess = None\n    if subtype == \"counterflow\":\n        return -log((P1*R1 - 1.)/(P1 - 1.))/(R1 - 1.)\n    elif subtype == \"parallel\":\n        return log(-1./(P1*(R1 + 1.) - 1.))/(R1 + 1.)\n    elif subtype == \"crossflow, mixed 1\":\n        return -log(R1*log(-(P1 - 1.)*exp(1./R1)))/R1\n    elif subtype == \"crossflow, mixed 2\":\n        return -log(log(-(P1*R1 - 1.)*exp(R1))/R1)\n    elif subtype == \"crossflow, mixed 1&2\":\n        NTU_max = _NTU_max_for_P_solver(NTU_from_P_basic_crossflow_mixed_12_p,\n                                        NTU_from_P_basic_crossflow_mixed_12_q,\n                                        NTU_from_P_basic_crossflow_mixed_12_offset, R1)\n    elif subtype == \"crossflow approximate\":\n        # These are tricky but also easy because P1 can always be 1\n        NTU_max = 1E5\n    elif subtype == \"crossflow\":\n        guess = NTU_from_P_basic(P1, R1, subtype=\"crossflow approximate\")\n        return secant(_NTU_from_P_objective, guess, args=(R1, P1, temperature_effectiveness_basic, \"crossflow\"))\n    else:\n        raise ValueError(\"Subtype not recognized.\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, temperature_effectiveness_basic, guess, subtype)\n\n\ndef NTU_from_P_G(P1: float, R1: float, Ntp: int, optimal: bool=True) -> float:\n    r\"\"\"Returns the number of transfer units of a TEMA G type heat exchanger\n    with a specified (for side 1) thermal effectiveness `P1`, heat capacity\n    ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case\n    whether or not the inlets are arranged optimally. The supported cases are\n    as follows:\n\n    * One tube pass (tube fluid split into two streams individually mixed,\n      shell fluid mixed)\n    * Two tube passes (shell and tube exchanger with shell and tube fluids\n      mixed in each pass at the cross section), counterflow arrangement\n    * Two tube passes (shell and tube exchanger with shell and tube fluids\n      mixed in each pass at the cross section), parallelflow arrangement\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    Ntp : int\n        Number of tube passes, 1 or 2 [-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case (only applies for two passes), [-]\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n\n    Notes\n    -----\n    For numbers of tube passes greater than 1 or 2, an exception is raised.\n\n    Although this function allows the thermal effectiveness desired to be\n    specified, it does not mean such a high value can be obtained. An exception\n    is raised which shows the maximum possible effectiveness obtainable at the\n    specified `R1` and configuration.\n\n    >>> NTU_from_P_G(P1=1, R1=1/3., Ntp=2)\n    Traceback (most recent call last):\n    ValueError: No solution possible gives such a high P1; maximum P1=0.954545 at NTU1=10000.000000\n\n    Of the three configurations, 1 pass and the optimal 2 pass have monotonic\n    functions which allow for a bounded solver to work smoothly. In both cases\n    a solution is searched for between NTU1 values of 1E-11 and 1E-4.\n\n    For the 2 pass unoptimal solution, a bounded solver is first use, but\n    the upper bound on P1 and the upper NTU1 limit is calculated from a pade\n    approximation performed with mpmath.\n\n    Examples\n    --------\n    >>> NTU_from_P_G(P1=.573, R1=1/3., Ntp=1)\n    0.9999513707759524\n    \"\"\"\n    NTU_min = 1E-11\n    function = temperature_effectiveness_TEMA_G\n    if Ntp == 1 or (Ntp == 2 and optimal):\n        NTU_max = 1E4\n        # We could fit a curve to determine the NTU where the floating point\n        # does not allow NTU to increase though, but that would be another\n        # binary bisection process, different from the current pipeline\n    elif Ntp == 2 and not optimal:\n        NTU_max = _NTU_max_for_P_solver(NTU_from_G_2_unoptimal_p, NTU_from_G_2_unoptimal_q,\n                                        NTU_from_G_2_unoptimal_offset, R1)\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1 or 2.\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, None, Ntp, optimal)\n\n\ndef NTU_from_P_J(P1: float, R1: float, Ntp: int) -> float:\n    r\"\"\"Returns the number of transfer units of a TEMA J type heat exchanger\n    with a specified (for side 1) thermal effectiveness `P1`, heat capacity\n    ratio `R1`, and the number of tube passes `Ntp`. The supported cases are\n    as follows:\n\n    * One tube pass (shell fluid mixed)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes)\n    * Four tube passes (shell fluid mixed, tube pass mixed between passes)\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, 2, or 4, [-]\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n\n    Notes\n    -----\n    For numbers of tube passes that are not 1, 2, or 4, an exception is raised.\n\n    For the 1 tube pass case, a bounded solver is used to solve the equation\n    numerically, with NTU1 ranging from 1E-11 to 1E3. NTU1 grows extremely\n    quickly near its upper limit (NTU1 diverges to infinity at this maximum,\n    but because the solver is bounded it will only increase up to 1000 before\n    an exception is raised).\n\n    >>> NTU_from_P_J(P1=.995024, R1=.01, Ntp=1)\n    13.940758768266656\n    >>> NTU_from_P_J(P1=.99502487562189, R1=.01, Ntp=1)  # doctest: +SKIP\n    Traceback (most recent call last):\n    ValueError: No solution possible gives such a high P1; maximum P1=0.995025 at NTU1=1000.000000\n\n    For the 2 pass and 4 pass solution, a bounded solver is first use, but\n    the upper bound on P1 and the upper NTU1 limit is calculated from a pade\n    approximation performed with mpmath. These normally do not allow NTU1 to\n    rise above 100.\n\n    Examples\n    --------\n    >>> NTU_from_P_J(P1=.57, R1=1/3., Ntp=1)\n    1.0003070138879664\n    \"\"\"\n    NTU_min = 1E-11\n    function = temperature_effectiveness_TEMA_J\n    if Ntp == 1:\n        # Very often failes because at NTU=1000, there is no variation in P1\n        # for instance at NTU=40, P1 already peaked and does not decline with\n        # higher NTU\n        NTU_max = 1E3\n        # We could fit a curve to determine the NTU where the floating point\n        # does not allow NTU to increase though, but that would be another\n        # binary bisection process, different from the current pipeline\n    elif Ntp == 2:\n        NTU_max = _NTU_max_for_P_solver(NTU_from_P_J_2_p, NTU_from_P_J_2_q, NTU_from_P_J_2_offset, R1)\n    elif Ntp == 4:\n        NTU_max = _NTU_max_for_P_solver(NTU_from_P_J_4_p, NTU_from_P_J_4_q, NTU_from_P_J_4_offset, R1)\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1, 2, and 4.\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, None, Ntp)\n\n\ndef NTU_from_P_E(P1: float, R1: float, Ntp: int, optimal: bool=True) -> float:\n    r\"\"\"Returns the number of transfer units of a TEMA E type heat exchanger\n    with a specified (for side 1) thermal effectiveness `P1`, heat capacity\n    ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case\n    whether or not the inlets are arranged optimally. The supported cases are\n    as follows:\n\n    * 1-1 TEMA E, shell fluid mixed\n    * 1-2 TEMA E, shell fluid mixed (this configuration is symmetric)\n    * 1-2 TEMA E, shell fluid split into two steams individually mixed\n    * 1-3 TEMA E, shell and tube fluids mixed, one parallel pass and two\n      counterflow passes (efficient)\n    * 1-3 TEMA E, shell and tube fluids mixed, two parallel passes and one\n      counteflow pass (inefficient)\n    * 1-N TEMA E, shall and tube fluids mixed, efficient counterflow\n      orientation, N an even number\n\n    Two of these cases have analytical solutions; the rest use numerical\n    solvers of varying quality.\n\n    The analytical solution to 1-1 TEMA E, shell fluid mixed (the same as pure\n    counterflow):\n\n    .. math::\n        NTU_1 = - \\frac{1}{R_{1} - 1} \\ln{\\left (\\frac{P_{1} R_{1} - 1}{P_{1}\n        - 1} \\right )}\n\n    1-2 TEMA E, shell fluid mixed:\n\n    .. math::\n        NTU_1 = \\frac{2}{\\sqrt{R_{1}^{2} + 1}} \\ln{\\left (\\sqrt{\\frac{P_{1}\n        R_{1} - P_{1} \\sqrt{R_{1}^{2} + 1} + P_{1} - 2}{P_{1} R_{1} + P_{1}\n        \\sqrt{R_{1}^{2} + 1} + P_{1} - 2}} \\right )}\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, 2, 3, 4, or an even number [-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case, [-]\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n\n    Notes\n    -----\n    For odd numbers of tube passes greater than 3, an exception is raised.\n\n    For the 2 pass, unoptimal case, a bounded solver is used with NTU1 between\n    1E-11 and 100; the solution to any feasible P1 was found to lie in there.\n    For the 4 or a higher even number of pass case, the upper limit on NTU1\n    is 1000; this solver works pretty well, but as NTU1 reaches its limit the\n    change in P1 is so small a smaller but also correct solution is often\n    returned.\n\n    For both the optimal and unoptimal 3 tube pass case, a solution is only\n    returned if NTU1 is between 1E-11 and 10. These functions are extremely\n    mathematically frustrating, and as NTU1 rises above 10 catastrophic\n    cancellation quickly results in this expression finding a ZeroDivisionError.\n    The use of arbitrary prevision helps little - quickly 1000 digits are needed,\n    and then 1000000 digits, and so one. Using SymPy's rational number support\n    works better but is extremely slow for these complicated solutions.\n    Nevertheless, so long as a solution is between 1E-11 and 10, the solver is\n    quite robust.\n\n    Examples\n    --------\n    >>> NTU_from_P_E(P1=.58, R1=1/3., Ntp=2)\n    1.0381979240816719\n\n    \"\"\"\n    NTU_min = 1E-11\n    function = temperature_effectiveness_TEMA_E\n    if Ntp == 1:\n        return NTU_from_P_basic(P1, R1, subtype=\"counterflow\")\n    elif Ntp == 2 and optimal:\n        # Nice analytical solution is available\n        # There are actually two roots but one of them is complex\n        x1 = R1*R1 + 1.\n        return 2.*log(((P1*R1 - P1*x1**0.5 + P1 - 2.)/(P1*R1 + P1*x1**0.5 + P1 - 2.))**0.5)*(x1)**-.5\n    elif Ntp == 2 and not optimal:\n        NTU_max = 1E2\n        # Can't find anywhere it needs to go above 70 to reach the maximum\n    elif Ntp == 3 and optimal:\n        # no pade could be found, just about the worst-conditioned problem\n        # I've ever found\n        # Higher starting values result in errors\n        NTU_max = 10\n    elif Ntp == 3 and not optimal:\n        # no pade could be found, just about the worst-conditioned problem\n        # I've ever found\n        NTU_max = 10\n    elif Ntp == 4 or Ntp %2 == 0:\n        NTU_max = 1E3\n    else:\n        raise ValueError(\"For TEMA E shells with an odd number of tube passes more than 3, no solution is implemented.\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, function, None, Ntp, optimal)\n\n\ndef NTU_from_P_H(P1: float, R1: float, Ntp: int, optimal: bool=True) -> float:\n    r\"\"\"Returns the number of transfer units of a TEMA H type heat exchanger\n    with a specified (for side 1) thermal effectiveness `P1`, heat capacity\n    ratio `R1`, the number of tube passes `Ntp`, and for the two-pass case\n    whether or not the inlets are arranged optimally. The supported cases are\n    as follows:\n\n    * One tube pass (tube fluid split into two streams individually mixed,\n      shell fluid mixed)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes)\n    * Two tube passes (shell fluid mixed, tube pass mixed between passes, inlet\n      tube side next to inlet shell-side)\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 (shell side = 1, tube side = 2) [-]\n    Ntp : int\n        Number of tube passes, 1, or 2, [-]\n    optimal : bool, optional\n        Whether or not the arrangement is configured to give more of a\n        countercurrent and efficient (True) case or an inefficient parallel\n        case, [-]\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 (shell side = 1, tube side\n        = 2) [-]\n\n    Notes\n    -----\n    For numbers of tube passes greater than 1 or 2, an exception is raised.\n\n    Only numerical solutions are available for this function. For the case of\n    1 tube pass or the optimal 2 tube pass, the function is monotonic and a\n    bounded solver is used with NTU1 between 1E-11 and 100; it will find the\n    solution anywhere in that range.\n\n    For the non-optimal 2 pass case, the function is not monotonic and a pade\n    approximation was used to obtain a curve of NTU1s which give the maximum\n    P1s which is used as the upper bound in the bounded solver. The lower\n    bound is still 1E-11. These solvers are all robust.\n\n    Examples\n    --------\n    >>> NTU_from_P_H(P1=0.573, R1=1/3., Ntp=1)\n    0.9997628696891168\n    \"\"\"\n    NTU_min = 1E-11\n    if Ntp == 1:\n        NTU_max = 100\n    elif Ntp == 2 and optimal:\n        NTU_max = 100\n    elif Ntp == 2 and not optimal:\n        NTU_max = _NTU_max_for_P_solver(NTU_from_H_2_unoptimal_p, NTU_from_H_2_unoptimal_q,\n                                        NTU_from_H_2_unoptimal_offset, R1)\n    else:\n        raise ValueError(\"Supported numbers of tube passes are 1 and 2.\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, temperature_effectiveness_TEMA_H,\n                              None, Ntp, optimal)\n\n\ndef NTU_from_P_plate(P1: float, R1: float, Np1: int, Np2: int, counterflow: bool=True,\n                     passes_counterflow: bool=True, reverse: bool=False) -> float:\n    r\"\"\"Returns the number of transfer units of a plate heat exchanger\n    with a specified side 1 heat capacity ratio `R1`, side 1 number\n    of transfer units `NTU1`, number of passes on sides 1 and 2 (respectively\n    `Np1` and `Np2`).\n\n    For all cases, the function also takes as arguments whether the exchanger\n    is setup in an overall counter or parallel orientation `counterflow`, and\n    whether or not individual stream passes are themselves counterflow or\n    parallel.\n\n    The 20 supported cases are as follows. (the first number of sides listed\n    refers to side 1, and the second number refers to side 2):\n\n    * 1 pass/1 pass parallelflow\n    * 1 pass/1 pass counterflow\n    * 1 pass/2 pass\n    * 1 pass/3 pass or 3 pass/1 pass (with the two end passes in parallel)\n    * 1 pass/3 pass or 3 pass/1 pass (with the two end passes in counterflow)\n    * 1 pass/4 pass\n    * 2 pass/2 pass, overall parallelflow, individual passes in parallel\n    * 2 pass/2 pass, overall parallelflow, individual passes counterflow\n    * 2 pass/2 pass, overall counterflow, individual passes parallelflow\n    * 2 pass/2 pass, overall counterflow, individual passes counterflow\n    * 2 pass/3 pass or 3 pass/2 pass, overall parallelflow\n    * 2 pass/3 pass or 3 pass/2 pass, overall counterflow\n    * 2 pass/4 pass or 4 pass/2 pass, overall parallel flow\n    * 2 pass/4 pass or 4 pass/2 pass, overall counterflow flow\n\n    For all except the simplest cases numerical solutions are used.\n\n    1 pass/1 pass counterflow (also 2/2 fully counterflow):\n\n    .. math::\n        NTU_1 = - \\frac{1}{R_{1} - 1} \\ln{\\left (\\frac{P_{1} R_{1} - 1}{P_{1}\n        - 1} \\right )}\n\n    1 pass/1 pass parallel flow (also 2/2 fully parallelflow):\n\n    .. math::\n        NTU_1 = \\frac{1}{R_{1} + 1} \\ln{\\left (- \\frac{1}{P_{1} \\left(R_{1}\n        + 1\\right) - 1} \\right )}\n\n    Parameters\n    ----------\n    P1 : float\n        Thermal effectiveness of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    R1 : float\n        Heat capacity ratio of the heat exchanger in the P-NTU method,\n        calculated with respect to stream 1 [-]\n    Np1 : int\n        Number of passes on side 1 [-]\n    Np2 : int\n        Number of passes on side 2 [-]\n    counterflow : bool\n        Whether or not the overall flow through the heat exchanger is in\n        counterflow or parallel flow, [-]\n    passes_counterflow : bool\n        In addition to the overall flow direction, in some cases individual\n        passes may be in counter or parallel flow; this controls that [-]\n    reverse : bool\n        Used **internally only** to allow cases like the 1-4 formula to work\n        for the 4-1 flow case, without having to duplicate the code [-]\n\n    Returns\n    -------\n    NTU1 : float\n        Thermal number of transfer units of the heat exchanger in the P-NTU\n        method, calculated with respect to stream 1 [-]\n\n    Notes\n    -----\n    The defaults of counterflow=True and passes_counterflow=True will always\n    result in the most efficient heat exchanger option, normally what is\n    desired.\n\n    If a number of passes which is not supported is provided, an exception is\n    raised.\n\n    For more details, see :obj:`temperature_effectiveness_plate`.\n\n    Examples\n    --------\n    Three passes on side 1; one pass on side 2; two end passes in counterflow\n    orientation.\n\n    >>> NTU_from_P_plate(P1=0.5743, R1=1/3., Np1=3, Np2=1)\n    0.9998336056090733\n    \"\"\"\n    NTU_min = 1E-11\n    if Np1 == 1 and Np2 == 1 and counterflow:\n        try:\n            return -log((P1*R1 - 1.)/(P1 - 1.))/(R1 - 1.)\n        except:\n#            raise ValueError(\"impossible\") # numba: uncomment\n            raise ValueError(\"The maximum P1 obtainable at the specified R1 is %f at the limit of NTU1=inf.\" %(1./R1)) # numba: delete\n\n    elif Np1 == 1 and Np2 == 1 and not counterflow:\n        try:\n            return log(-1./(P1*(R1 + 1.) - 1.))/(R1 + 1.)\n        except:\n#            raise ValueError(\"impossible\") # numba: uncomment\n            raise ValueError(f\"The maximum P1 obtainable at the specified R1 is {P_NTU_Pp(1E10, R1):f} at the limit of NTU1=inf.\") # numba: delete\n    elif Np1 == 1 and Np2 == 2:\n        NTU_max = 100.\n    elif Np1 == 1 and Np2 == 3 and counterflow:\n        NTU_max = 100.\n    elif Np1 == 1 and Np2 == 3 and not counterflow:\n        NTU_max = 100.\n    elif Np1 == 1 and Np2 == 4:\n        NTU_max = 100.\n    elif Np1 == 2 and Np2 == 2:\n        if counterflow and passes_counterflow:\n            return NTU_from_P_plate(P1, R1, Np1=1, Np2=1, counterflow=True,\n                                    passes_counterflow=True)\n        elif counterflow and not passes_counterflow:\n            NTU_max = 100.0\n        elif not counterflow and passes_counterflow:\n            NTU_max = _NTU_max_for_P_solver(NTU_from_plate_2_2_parallel_counterflow_p,\n                                            NTU_from_plate_2_2_parallel_counterflow_q,\n                                            NTU_from_plate_2_2_parallel_counterflow_offset, R1)\n        elif not counterflow and not passes_counterflow:\n            return NTU_from_P_plate(P1, R1, Np1=1, Np2=1, counterflow=False,\n                                    passes_counterflow=False)\n    elif Np1 == 2 and Np2 == 3:\n        if counterflow:\n            NTU_max = 100.0\n        elif not counterflow:\n            NTU_max = _NTU_max_for_P_solver(NTU_from_plate_2_3_parallel_p,\n                                            NTU_from_plate_2_3_parallel_q,\n                                            NTU_from_plate_2_3_parallel_offset, R1)\n    elif Np1 == 2 and Np2 == 4:\n        if counterflow:\n            NTU_max = 100.0\n        elif not counterflow:\n            NTU_max = _NTU_max_for_P_solver(NTU_from_plate_2_4_parallel_p,\n                                            NTU_from_plate_2_4_parallel_q,\n                                            NTU_from_plate_2_4_parallel_offset, R1)\n    elif not reverse:\n        # Proved to work by example\n        P2 = P1*R1\n        R2 = 1./R1\n        NTU2 = NTU_from_P_plate(R1=R2, P1=P2, Np1=Np2, Np2=Np1,\n                                counterflow=counterflow,\n                                passes_counterflow=passes_counterflow,\n                                reverse=True)\n        NTU1 = NTU2/R1\n        return NTU1\n    else:\n        raise ValueError(\"Supported number of passes does not have a formula available\")\n    return _NTU_from_P_solver(P1, R1, NTU_min, NTU_max, temperature_effectiveness_plate, None, Np1,\n                              Np2, counterflow, passes_counterflow)\n\n\ndef P_NTU_method(m1: float, m2: float, Cp1: float, Cp2: float, UA: float | None=None, T1i: int | None=None, T1o: float | None=None,\n                 T2i: int | None=None, T2o: int | None=None, subtype: str=\"crossflow\", Ntp: int=1, optimal: bool=True) -> dict[str, float]:\n    r\"\"\"Wrapper for the various P-NTU method function calls,\n    which can solve a heat exchanger. The heat capacities and mass flows\n    of each stream and the type of the heat exchanger are always required.\n    As additional inputs, one combination of the following inputs is required:\n\n    * Three of the four inlet and outlet stream temperatures.\n    * Temperatures for the side 1 outlet and side 2 inlet and UA\n    * Temperatures for the side 1 outlet side 2 outlet and UA\n    * Temperatures for the side 1 inlet and side 2 inlet and UA\n    * Temperatures for the side 1 inlet and side 2 outlet and UA\n\n    Computes the total heat exchanged as well as both temperatures of both\n    streams.\n\n    Parameters\n    ----------\n    m1 : float\n        Mass flow rate of stream 1 (shell side = 1, tube side = 2), [kg/s]\n    m2 : float\n        Mass flow rate of stream 2 (shell side = 1, tube side = 2), [kg/s]\n    Cp1 : float\n        Averaged heat capacity of stream 1 (shell side), [J/kg/K]\n    Cp2 : float\n        Averaged heat capacity of stream 2 (tube side), [J/kg/K]\n    UA : float, optional\n        Combined Area-heat transfer coefficient term, [W/K]\n    T1i : float, optional\n        Inlet temperature of stream 1 (shell side), [K]\n    T1o : float, optional\n        Outlet temperature of stream 1 (shell side), [K]\n    T2i : float, optional\n        Inlet temperature of stream 2 (tube side), [K]\n    T2o : float, optional\n        Outlet temperature of stream 2 (tube-side), [K]\n    subtype : str, optional\n        The subtype of exchanger; one of 'E', 'G', 'H', 'J', 'counterflow',\n        'parallel', 'crossflow', 'crossflow, mixed 1', 'crossflow, mixed 2',\n        or 'crossflow, mixed 1&2'. For plate exchangers 'Np1/Np2' where `Np1`\n        is the number of side 1 passes and `Np2` is the number of side 2 passes\n    Ntp : int, optional\n        For real heat exchangers (types 'E', 'G', 'H', and 'J'), the number of\n        tube passes needss to be specified as well. Not all types support\n        any number of tube passes.\n    optimal : bool, optional\n        For real heat exchangers (types 'E', 'G', 'H', and 'J'), there is often\n        a more countercurrent (optimal) way to arrange the tube passes and a\n        more parallel (optimal=False) way to arrange them. This controls that.\n\n    Returns\n    -------\n    results : dict\n        * Q : Heat exchanged in the heat exchanger, [W]\n        * UA : Combined area-heat transfer coefficient term, [W/K]\n        * T1i : Inlet temperature of stream 1, [K]\n        * T1o : Outlet temperature of stream 1, [K]\n        * T2i : Inlet temperature of stream 2, [K]\n        * T2o : Outlet temperature of stream 2, [K]\n        * P1 : Thermal effectiveness with respect to stream 1, [-]\n        * P2 : Thermal effectiveness with respect to stream 2, [-]\n        * R1 : Heat capacity ratio with respect to stream 1, [-]\n        * R2 : Heat capacity ratio with respect to stream 2, [-]\n        * C1 : The heat capacity rate of fluid 1, [W/K]\n        * C2 : The heat capacity rate of fluid 2, [W/K]\n        * NTU1 : Thermal Number of Transfer Units with respect to stream 1 [-]\n        * NTU2 : Thermal Number of Transfer Units with respect to stream 2 [-]\n\n    Notes\n    -----\n    The main equations used in this method are as follows. For the individual\n    expressions used to calculate `P1`, see the `See Also` section.\n\n    .. math::\n        Q = P_1 C_1 \\Delta T_{max} = P_2 C_2 \\Delta T_{max}\n\n    .. math::\n        \\Delta T_{max} = T_{h,i} - T_{c,i} = |T_{2,i} - T_{1,i}|\n\n    .. math::\n        R_1 = \\frac{C_1}{C_2} = \\frac{T_{2,i} - T_{2,o}}{T_{1,o} - T_{1, i}}\n\n    .. math::\n        R_2 = \\frac{C_2}{C_1} = \\frac{T_{1,o} - T_{1, i}}{T_{2,i} - T_{2,o}}\n\n    .. math::\n        R_1 = \\frac{1}{R_2}\n\n    .. math::\n        NTU_1 = \\frac{UA}{C_1}\n\n    .. math::\n        NTU_2 = \\frac{UA}{C_2}\n\n    .. math::\n        NTU_1 = NTU_2 R_2\n\n    .. math::\n        NTU_2 = NTU_1 R_1\n\n    .. math::\n        P_1 = \\frac{T_{1,o} - T_{1,i}}{T_{2,i} - T_{1,i}}\n\n    .. math::\n        P_2 = \\frac{T_{2,i} - T_{2,o}}{T_{2,i} - T_{1,i}}\n\n    .. math::\n        P_1 = P_2 R_2\n\n    .. math::\n        P_2 = P_1 R_1\n\n    .. math::\n        C_1 = m_1 Cp_1\n\n    .. math::\n        C_2 = m_2 Cp_2\n\n    Once `P1` has been calculated, there are six different cases for calculating\n    the other stream temperatures depending on the two temperatures provided.\n    They were derived with SymPy.\n\n    Two known inlet temperatures:\n\n    .. math::\n        T_{1,o} = - P_{1} T_{1,i} + P_{1} T_{2,i} + T_{1,i}\n\n    .. math::\n        T_{2,o} = P_{1} R_{1} T_{1,i} - P_{1} R_{1} T_{2,i} + T_{2,i}\n\n    Two known outlet temperatures:\n\n    .. math::\n        T_{1,i} = \\frac{P_{1} R_{1} T_{1,o} + P_{1} T_{2,o}\n        - T_{1,o}}{P_{1} R_{1} + P_{1} - 1}\n\n    .. math::\n        T_{2,i} = \\frac{P_{1} R_{1} T_{1,o} + P_{1} T_{2,o}\n        - T_{2,o}}{P_{1} R_{1} + P_{1} - 1}\n\n    Inlet 1 known, outlet 2 known:\n\n    .. math::\n        T_{1,o} = \\frac{1}{P_{1} R_{1} - 1} \\left(P_{1} R_{1} T_{1,i}\n        + P_{1} T_{1,i} - P_{1} T_{2,o} - T_{1,i}\\right)\n\n    .. math::\n        T_{2,i} = \\frac{P_{1} R_{1} T_{1,i} - T_{2,o}}{P_{1} R_{1} - 1}\n\n    Outlet 1 known, inlet 2 known:\n\n    .. math::\n        T_{1,i} = \\frac{P_{1} T_{2,i} - T_{1,o}}{P_{1} - 1}\n\n    .. math::\n        T_{2,o}  = \\frac{1}{P_{1} - 1} \\left(R_{1} \\left(P_{1} T_{2,i}\n        - T_{1,o}\\right) - \\left(P_{1} - 1\\right) \\left(R_{1} T_{1,o}\n        - T_{2,i}\\right)\\right)\n\n    Input and output of 2 known:\n\n    .. math::\n        T_{1,i} = \\frac{1}{P_{1} R_{1}} \\left(P_{1} R_{1} T_{2,i}\n        - T_{2,i} + T_{2,o}\\right)\n\n    .. math::\n        T_{1,o} = \\frac{1}{P_{1} R_{1}} \\left(P_{1} R_{1} T_{2,i}\n        + \\left(P_{1} - 1\\right) \\left(T_{2,i} - T_{2,o}\\right)\\right)\n\n    Input and output of 1 known:\n\n    .. math::\n        T_{2,i} = \\frac{1}{P_{1}} \\left(P_{1} T_{1,i} - T_{1,i}\n        + T_{1,o}\\right)\n\n    .. math::\n        T_{2,o} = \\frac{1}{P_{1}} \\left(P_{1} R_{1} \\left(T_{1,i}\n        - T_{1,o}\\right) + P_{1} T_{1,i} - T_{1,i} + T_{1,o}\\right)\n\n    See Also\n    --------\n    temperature_effectiveness_basic\n    temperature_effectiveness_plate\n    temperature_effectiveness_TEMA_E\n    temperature_effectiveness_TEMA_G\n    temperature_effectiveness_TEMA_H\n    temperature_effectiveness_TEMA_J\n    NTU_from_P_basic\n    NTU_from_P_plate\n    NTU_from_P_E\n    NTU_from_P_G\n    NTU_from_P_H\n    NTU_from_P_J\n\n    Examples\n    --------\n    Solve a heat exchanger with the UA specified, and known inlet temperatures:\n\n    >>> from pprint import pprint\n    >>> pprint(P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900,\n    ... subtype='E', Ntp=4, T2i=15, T1i=130, UA=3041.75))\n    {'C1': 9672.0,\n     'C2': 2755.0,\n     'NTU1': 0.314490281224,\n     'NTU2': 1.104083484573,\n     'P1': 0.173081161436,\n     'P2': 0.60763738417,\n     'Q': 192514.714242,\n     'R1': 3.5107078039,\n     'R2': 0.28484284532,\n     'T1i': 130,\n     'T1o': 110.095666434,\n     'T2i': 15,\n     'T2o': 84.878299180,\n     'UA': 3041.75}\n\n    Solve the same heat exchanger as if T1i, T2i, and T2o were known but UA was\n    not:\n\n    >>> pprint(P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900, subtype='E',\n    ... Ntp=4, T1i=130, T2i=15, T2o=84.87829918042112))\n    {'C1': 9672.0,\n     'C2': 2755.0,\n     'NTU1': 0.31449028122,\n     'NTU2': 1.10408348457,\n     'P1': 0.173081161436,\n     'P2': 0.60763738417,\n     'Q': 192514.714242,\n     'R1': 3.5107078039,\n     'R2': 0.2848428453,\n     'T1i': 130,\n     'T1o': 110.095666434,\n     'T2i': 15,\n     'T2o': 84.878299180,\n     'UA': 3041.7499999}\n\n    Solve a 2 pass/2 pass plate heat exchanger with overall parallel flow and\n    its individual passes operating in parallel and known outlet temperatures.\n    Note the overall parallel part is trigered with `optimal=False`, and the\n    individual pass parallel is triggered by appending 'p' to the subtype. The\n    subpass counterflow can be specified by appending 'c' instead to the\n    subtype, but this is never necessary as it is the default.\n\n    >>> pprint(P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300,\n    ... T1o=126.7, T2o=26.7, subtype='2/2p', optimal=False))\n    {'C1': 9672.0,\n     'C2': 2755.0,\n     'NTU1': 0.0310173697270,\n     'NTU2': 0.10889292196,\n     'P1': 0.0289452959747,\n     'P2': 0.101618476467,\n     'Q': 32200.0503078,\n     'R1': 3.5107078039,\n     'R2': 0.28484284532,\n     'T1i': 130.029202885,\n     'T1o': 126.7,\n     'T2i': 15.0121414490,\n     'T2o': 26.7,\n     'UA': 300}\n\n    References\n    ----------\n    .. [1] Shah, Ramesh K., and Dusan P. Sekulic. Fundamentals of Heat\n       Exchanger Design. 1st edition. Hoboken, NJ: Wiley, 2002.\n    .. [2] Thulukkanam, Kuppan. Heat Exchanger Design Handbook, Second Edition.\n       CRC Press, 2013.\n    .. [3] Rohsenow, Warren and James Hartnett and Young Cho. Handbook of Heat\n       Transfer, 3E. New York: McGraw-Hill, 1998.\n    \"\"\"\n    # Shellside: 1\n    # Tubeside: 2\n    C1 = m1*Cp1\n    C2 = m2*Cp2\n    R1 = C1/C2\n    R2 = C2/C1\n\n    if UA is not None:\n        NTU1 = UA/C1\n        NTU2 = UA/C2\n\n        if subtype in (\"counterflow\", \"parallel\", \"crossflow\", \"crossflow, mixed 1\", \"crossflow, mixed 2\", \"crossflow, mixed 1&2\"):\n            P1 = temperature_effectiveness_basic(R1, NTU1, subtype=subtype)\n        elif subtype == \"E\":\n            P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"G\":\n            P1 = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"H\":\n            P1 = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"J\":\n            P1 = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1, Ntp=Ntp)\n        elif \"/\" in subtype:\n            passes_counterflow = True\n            Np1, end = subtype.split(\"/\")\n            if end[-1] in [\"c\",\"p\"]:\n                passes_counterflow = end[-1] == \"c\"\n                end = end[0:-1]\n            Np1, Np2 = int(Np1), int(end)\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=Np1, Np2=Np2, counterflow=optimal, passes_counterflow=passes_counterflow)\n        else:\n            raise ValueError(\"Supported types are 'E', 'G', 'H', 'J', 'counterflow',\\\n    'parallel', 'crossflow', 'crossflow, mixed 1', 'crossflow, mixed 2', \\\n    'crossflow, mixed 1&2', or 'Np1/Np2' for plate exchangers\")\n\n        possible_inputs = [(T1i, T2i), (T1o, T2o), (T1i, T2o), (T1o, T2i), (T1i, T1o), (T2i, T2o)]\n        if not any(i for i in possible_inputs if None not in i):\n            raise ValueError(\"One set of (T1i, T2i), (T1o, T2o), (T1i, T2o), (T1o, T2i), (T1i, T1o), or (T2i, T2o) is required along with UA.\")\n\n        # Deal with different temperature inputs, generated with SymPy\n        if T1i and T2i:\n            T2o = P1*R1*T1i - P1*R1*T2i + T2i\n            T1o = -P1*T1i + P1*T2i + T1i\n        elif T1o and T2o:\n            T2i = (P1*R1*T1o + P1*T2o - T2o)/(P1*R1 + P1 - 1.)\n            T1i = (P1*R1*T1o + P1*T2o - T1o)/(P1*R1 + P1 - 1.)\n        elif T1o and T2i:\n            T2o = (R1*(P1*T2i - T1o) - (P1 - 1.)*(R1*T1o - T2i))/(P1 - 1.)\n            T1i = (P1*T2i - T1o)/(P1 - 1.)\n        elif T1i and T2o:\n            T1o = (P1*R1*T1i + P1*T1i - P1*T2o - T1i)/(P1*R1 - 1.)\n            T2i = (P1*R1*T1i - T2o)/(P1*R1 - 1.)\n        elif T2i and T2o:\n            T1o = (P1*R1*T2i + (P1 - 1.)*(T2i - T2o))/(P1*R1)\n            T1i = (P1*R1*T2i - T2i + T2o)/(P1*R1)\n        elif T1i and T1o:\n            T2o = (P1*R1*(T1i - T1o) + P1*T1i - T1i + T1o)/P1\n            T2i = (P1*T1i - T1i + T1o)/P1\n    else:\n        # Case where we're solving for UA\n        # Three temperatures are required\n        # Ensures all four temperatures are set and Q is calculated\n        if T1i is not None and T1o is not None:\n            Q = m1*Cp1*(T1i-T1o)\n            if T2i is not None and T2o is None:\n                T2o = T2i + Q/(m2*Cp2)\n            elif T2o is not None and T2i is None:\n                T2i = T2o - Q/(m2*Cp2)\n            elif T2o is not None and T2i is not None:\n                Q2 = m2*Cp2*(T2o-T2i)\n                if abs((Q-Q2)/Q) > 0.01:\n                    raise ValueError(\"The specified heat capacities, mass flows,\"\n                                    \" and temperatures are inconsistent\")\n            else:\n                raise ValueError(\"At least one temperature is required to be \"\n                                \"specified on side 2.\")\n\n        elif T2i is not None and T2o is not None:\n            Q = m2*Cp2*(T2o-T2i)\n            if T1i is not None and T1o is None:\n                T1o = T1i - Q/(m1*Cp1)\n            elif T1o is not None and T1i is None:\n                T1i = T1o + Q/(m1*Cp1)\n            else:\n                raise ValueError(\"At least one temperature is required to be \"\n                                \"specified on side 2.\")\n        else:\n            raise ValueError(\"Three temperatures are required to be specified \"\n                            \"when solving for UA\")\n\n        P1 = Q/(C1*abs(T2i-T1i))\n        if subtype in (\"counterflow\", \"parallel\", \"crossflow\", \"crossflow, mixed 1\", \"crossflow, mixed 2\", \"crossflow, mixed 1&2\"):\n            NTU1 = NTU_from_P_basic(P1=P1, R1=R1, subtype=subtype)\n        elif subtype == \"E\":\n            NTU1 = NTU_from_P_E(P1=P1, R1=R1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"G\":\n            NTU1 = NTU_from_P_G(P1=P1, R1=R1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"H\":\n            NTU1 = NTU_from_P_H(P1=P1, R1=R1, Ntp=Ntp, optimal=optimal)\n        elif subtype == \"J\":\n            NTU1 = NTU_from_P_J(P1=P1, R1=R1, Ntp=Ntp)\n        elif \"/\" in subtype:\n            passes_counterflow = True\n            Np1, end = subtype.split(\"/\")\n            if end[-1] in [\"c\",\"p\"]:\n                passes_counterflow = end[-1] == \"c\"\n                end = end[0:-1]\n            Np1, Np2 = int(Np1), int(end)\n            NTU1 = NTU_from_P_plate(P1=P1, R1=R1, Np1=Np1, Np2=Np2, counterflow=optimal, passes_counterflow=passes_counterflow)\n        else:\n            raise ValueError(\"Supported types are 'E', 'G', 'H', 'J', 'counterflow',\\\n    'parallel', 'crossflow', 'crossflow, mixed 1', 'crossflow, mixed 2', \\\n    'crossflow, mixed 1&2', or 'Np1/Np2' for plate exchangers\")\n        UA = NTU1*C1\n        NTU2 = UA/C2\n\n    Q = abs(T1i-T2i)*P1*C1\n    # extra:\n    P2 = P1*R1\n#    effectiveness = max(C1, C2)/min(C1, C2)\n    results = {\"Q\": Q, \"T1i\": T1i, \"T1o\": T1o, \"T2i\": T2i, \"T2o\": T2o,\n          \"C1\": C1, \"C2\": C2, \"R1\": R1, \"R2\": R2, \"P1\": P1, \"P2\": P2, \"NTU1\": NTU1, \"NTU2\": NTU2, \"UA\": UA}\n    return results\n\n\ndef F_LMTD_Fakheri(Thi: int, Tho: float, Tci: int, Tco: float, shells: int=1) -> float:\n    r\"\"\"Calculates the log-mean temperature difference correction factor `Ft`\n    for a shell-and-tube heat exchanger with one or an even number of tube\n    passes, and a given number of shell passes, with the expression given in\n    [1]_ and also shown in [2]_.\n\n    .. math::\n        F_t=\\frac{S\\ln W}{\\ln \\frac{1+W-S+SW}{1+W+S-SW}}\n\n    .. math::\n        S = \\frac{\\sqrt{R^2+1}}{R-1}\n\n    .. math::\n        W = \\left(\\frac{1-PR}{1-P}\\right)^{1/N}\n\n    .. math::\n        R = \\frac{T_{in}-T_{out}}{t_{out}-t_{in}}\n\n    .. math::\n        P = \\frac{t_{out}-t_{in}}{T_{in}-t_{in}}\n\n    If R = 1 and logarithms cannot be evaluated:\n\n    .. math::\n        W' = \\frac{N-NP}{N-NP+P}\n\n    .. math::\n        F_t = \\frac{\\sqrt{2}\\frac{1-W'}{W'}}{\\ln\\frac{\\frac{W'}{1-W'}+\\frac{1}\n        {\\sqrt{2}}}{\\frac{W'}{1-W'}-\\frac{1}{\\sqrt{2}}}}\n\n    Parameters\n    ----------\n    Thi : float\n        Inlet temperature of hot fluid, [K]\n    Tho : float\n        Outlet temperature of hot fluid, [K]\n    Tci : float\n        Inlet temperature of cold fluid, [K]\n    Tco : float\n        Outlet temperature of cold fluid, [K]\n    shells : int, optional\n        Number of shell-side passes, [-]\n\n    Returns\n    -------\n    Ft : float\n        Log-mean temperature difference correction factor, [-]\n\n    Notes\n    -----\n    This expression is symmetric - the same result is calculated if the cold\n    side values are swapped with the hot side values. It also does not\n    depend on the units of the temperature given.\n\n    Examples\n    --------\n    >>> F_LMTD_Fakheri(Tci=15, Tco=85, Thi=130, Tho=110, shells=1)\n    0.9438358829645933\n\n    References\n    ----------\n    .. [1] Fakheri, Ahmad. \"A General Expression for the Determination of the\n       Log Mean Temperature Correction Factor for Shell and Tube Heat\n       Exchangers.\" Journal of Heat Transfer 125, no. 3 (May 20, 2003): 527-30.\n       doi:10.1115/1.1571078.\n    .. [2] Hall, Stephen. Rules of Thumb for Chemical Engineers, Fifth Edition.\n       Oxford; Waltham, MA: Butterworth-Heinemann, 2012.\n    \"\"\"\n    R = (Thi - Tho)/(Tco - Tci)\n    P = (Tco - Tci)/(Thi - Tci)\n    if R == 1.0:\n        W2 = (shells - shells*P)/(shells - shells*P + P)\n        return (2**0.5*(1. - W2)/W2)/log((W2/(1. - W2) + 2**-0.5)/(W2/(1. - W2) - 2**-0.5))\n    else:\n        W = ((1. - P*R)/(1. - P))**(1./shells)\n        S = (R*R + 1.)**0.5/(R - 1.)\n        return S*log(W)/log((1. + W - S + S*W)/(1. + W + S - S*W))\n\n### Tubes\n\n# TEMA tubes from http://www.engineeringpage.com/technology/thermal/tubesize.html\n# NPSs in inches, which convert to outer diameter exactly.\n_NPSs = [0.25, 0.25, 0.375, 0.375, 0.375, 0.5, 0.5, 0.625, 0.625, 0.625, 0.75, 0.75, 0.75, 0.75, 0.75, 0.875, 0.875, 0.875, 0.875, 1, 1, 1, 1, 1.25, 1.25, 1.25, 1.25, 2, 2]\n_Dos = [0.00635, 0.00635, 0.009525, 0.009525, 0.009525, 0.0127, 0.0127, 0.015875, 0.015875, 0.015875, 0.01905, 0.01905, 0.01905, 0.01905, 0.01905, 0.022225, 0.022225, 0.022225, 0.022225, 0.0254, 0.0254, 0.0254, 0.0254, 0.03175, 0.03175, 0.03175, 0.03175, 0.0508, 0.0508]\n_BWGs = [22, 24, 18, 20, 22, 18, 20, 16, 18, 20, 12, 14, 16, 18, 20, 14, 16, 18, 20, 12, 14, 16, 18, 10, 12, 14, 16, 12, 14]\n_ts = [0.000711, 0.000559, 0.001245, 0.000889, 0.000711, 0.001245, 0.000889, 0.001651, 0.001245, 0.000889, 0.002769, 0.002108, 0.001651, 0.001245, 0.000889, 0.002108, 0.001651, 0.001245, 0.000889, 0.002769, 0.002108, 0.001651, 0.001245, 0.003404, 0.002769, 0.002108, 0.001651, 0.002769, 0.002108]\n_Dis = [0.004928, 0.005232, 0.007035, 0.007747, 0.008103, 0.01021, 0.010922, 0.012573, 0.013385, 0.014097, 0.013512, 0.014834, 0.015748, 0.01656, 0.017272, 0.018009, 0.018923, 0.019735, 0.020447, 0.019862, 0.021184, 0.022098, 0.02291, 0.024942, 0.026212, 0.027534, 0.028448, 0.045262, 0.046584]\n\n# Structure: Look up NPS, get BWGs. BWGs listed in increasing order --> decreasing thickness\nTEMA_tubing = {0.25: (22, 24), 0.375: (18, 20, 22), 0.5: (18, 20),\n0.625: (16, 18, 20), 0.75: (12, 14, 16, 18, 20),\n0.875: (14, 16, 18, 20), 1.: (12, 14, 16, 18),\n1.25: (10, 12, 14, 16), 2.: (12, 14)}\n\n#\n#for tup in TEMA_Full_Tubing:\n#    Do, BWG = tup[0]/1000., tup[1]\n#    t = BWG_SI[BWG_gauges.index(BWG)]\n#    Di = Do-2*t\n#    print t*1000, Di*1000\n#\ndef check_tubing_TEMA(NPS=None, BWG=None):\n    \"\"\"Check if tubing NPS and BWG combination is valid per TEMA standards.\n    >>> check_tubing_TEMA(2, 22)\n    False\n    >>> check_tubing_TEMA(0.375, 22)\n    True\n    \"\"\"\n    if NPS in TEMA_tubing:\n        if BWG in TEMA_tubing[NPS]:\n            return True\n    return False\n\n\ndef get_tube_TEMA(NPS=None, BWG=None, Do=None, Di=None, tmin=None):\n    # Tube defined by a thickness and an outer diameter only, no pipe.\n    # If Di or Do are specified, they must be exactly correct.\n    if NPS and BWG:\n        # Fully defined, guaranteed\n        if not check_tubing_TEMA(NPS, BWG):\n            raise ValueError(\"NPS and BWG Specified are not listed in TEMA\")\n        Do = 0.0254*NPS\n        t = BWG_SI[BWG_gauges.index(BWG)]\n        Di = Do-2*t\n    elif Do and BWG:\n        NPS = Do/.0254\n        if not check_tubing_TEMA(NPS, BWG):\n            raise ValueError(\"NPS and BWG Specified are not listed in TEMA\")\n        t = BWG_SI[BWG_gauges.index(BWG)]\n        Di = Do-2*t\n    elif BWG and Di:\n        t = BWG_SI[BWG_gauges.index(BWG)] # Will fail if BWG not int\n        Do = t*2 + Di\n        NPS = Do/.0254\n        if not check_tubing_TEMA(NPS, BWG):\n            raise ValueError(\"NPS and BWG Specified are not listed in TEMA\")\n    elif NPS and Di:\n        Do = 0.0254*NPS\n        t = (Do - Di)/2\n        BWG = [BWG_gauges[BWG_SI.index(t)]]\n        if not check_tubing_TEMA(NPS, BWG):\n            raise ValueError(\"NPS and BWG Specified are not listed in TEMA\")\n    elif Di and Do:\n        NPS = Do/.0254\n        t = (Do - Di)/2\n        BWG = [BWG_gauges[BWG_SI.index(t)]]\n        if not check_tubing_TEMA(NPS, BWG):\n            raise ValueError(\"NPS and BWG Specified are not listed in TEMA\")\n    # Begin Fuzzy matching\n    elif NPS and tmin:\n        Do = 0.0254*NPS\n        ts = [BWG_SI[BWG_gauges.index(BWG)] for BWG in TEMA_tubing[NPS]]\n        ts.reverse() # Small to large\n        if tmin > ts[-1]:\n            raise ValueError(\"Specified minimum thickness is larger than available in TEMA\")\n        for t in ts: # Runs if at least 1 of the thicknesses are the right size.\n            if tmin <= t:\n                break\n        BWG = [BWG_gauges[BWG_SI.index(t)]]\n        Di = Do-2*t\n    elif Do and tmin:\n        NPS = Do/.0254\n        NPS, BWG, Do, Di, t = get_tube_TEMA(NPS=NPS, tmin=tmin)\n    elif Di and tmin:\n        raise ValueError(\"Not funny defined input for TEMA Schedule; multiple solutions\")\n    elif NPS:\n        BWG = TEMA_tubing[NPS][0] # Pick the first listed size\n        Do = 0.0254*NPS\n        t = BWG_SI[BWG_gauges.index(BWG)]\n        Di = Do-2*t\n    else:\n        raise ValueError(\"Insufficient information provided\")\n    return NPS, BWG, Do, Di, t\n\nTEMA_Ls_imperial = [96., 120., 144., 192., 240.] # inches\nTEMA_Ls = [2.438, 3.048, 3.658, 4.877, 6.096]\nHTRI_Ls_imperial = [6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60] # ft\nHTRI_Ls = [1.829, 2.438, 3.048, 3.658, 4.267, 4.877, 5.486, 6.096, 6.706, 7.315, 8.534, 9.754, 10.973, 12.192, 13.411, 14.63, 15.85, 17.069, 18.288]\n\n\n# Shells up to 120 inch in diameter.\n# This is for plate shells, not pipe (up to 12 inches, pipe is used)\nHEDH_shells_imperial = [12., 13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 24., 26., 28., 30., 32., 34., 36., 38., 40., 42., 44., 46., 48., 50., 52., 54., 56., 58., 60., 63., 66., 69., 72., 75., 78., 81., 84., 87., 90., 93., 96., 99., 102., 105., 108., 111., 114., 117., 120.]\nHEDH_shells = [0.3048, 0.3302, 0.3556, 0.381, 0.4064, 0.4318, 0.4572, 0.4826, 0.508, 0.5334, 0.5588, 0.6096, 0.6604, 0.7112, 0.762, 0.8128, 0.8636, 0.9144, 0.9652, 1.016, 1.0668, 1.1176, 1.1684, 1.2192, 1.27, 1.3208, 1.3716, 1.4224, 1.4732, 1.524, 1.6002, 1.6764, 1.7526, 1.8288, 1.905, 1.9812, 2.0574, 2.1336, 2.2098, 2.286, 2.3622, 2.4384, 2.5146, 2.5908, 2.667, 2.7432, 2.8194, 2.8956, 2.9718, 3.048]\n\n\nHEDH_pitches = {0.25: (1.25, 1.5), 0.375: (1.330, 1.420),\n0.5: (1.250, 1.310, 1.380), 0.625: (1.250, 1.300, 1.400),\n0.75: (1.250, 1.330, 1.420, 1.500), 1.: (1.250, 1.312, 1.375),\n1.25: (1.250,), 1.5: (1.250,), 2.: (1.250,)}\n\ndef DBundle_min(Do: float) -> float:\n    r\"\"\"Very roughly, determines a good choice of shell diameter for a given\n    tube outer diameter, according to figure 1, section 3.3.5 in [1]_.\n\n    Parameters\n    ----------\n    Do : float\n        Tube outer diameter, [m]\n\n    Returns\n    -------\n    DShell : float\n        Shell inner diameter, optional, [m]\n\n    Notes\n    -----\n    This function should be used if a tube diameter is specified but not a\n    shell size. DShell will have to be adjusted later, once the area\n    requirement is known.\n    This function is essentially a lookup table.\n\n    Examples\n    --------\n    >>> DBundle_min(0.0254)\n    1.0\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1983.\n    \"\"\"\n    data = ((0.006, 0.1), (0.01, 0.1), (.014, 0.3), (0.02, 0.5), (0.03, 1.0))\n    for Do_tabulated, DBundle in data:\n        if Do <= Do_tabulated:\n            return DBundle\n    return 1.5\n\n\ndef shell_clearance(DBundle: float | None=None, DShell: float | None=None) -> float:\n    r\"\"\"Looks up the recommended clearance between a shell and tube bundle in\n    a TEMA HX [1]. Either the bundle diameter or the shell diameter are needed\n    provided.\n\n    Parameters\n    ----------\n    DBundle : float, optional\n        Outer diameter of tube bundle, [m]\n    DShell : float, optional\n        Shell inner diameter, [m]\n\n    Returns\n    -------\n    c : float\n        Shell-tube bundle clearance, [m]\n\n    Notes\n    -----\n    Lower limits are extended up to the next limit where intermediate limits\n    are not provided.\n\n    Examples\n    --------\n    >>> shell_clearance(DBundle=1.245)\n    0.0064\n\n    References\n    ----------\n    .. [1] Standards of the Tubular Exchanger Manufacturers Association,\n       Ninth edition, 2007, TEMA, New York.\n    \"\"\"\n    DShell_data = [(0.457, 0.0032), (1.016, 0.0048), (1.397, 0.0064),\n                   (1.778, 0.0079), (2.159, 0.0095)]\n    DBundle_data = [(0.457 - 0.0048, 0.0032), (1.016 - 0.0064, 0.0048),\n                    (1.397 - 0.0079, 0.0064), (1.778 - 0.0095, 0.0079),\n                    (2.159 - 0.011, 0.0095)]\n    if DShell:\n        for DShell_tabulated, c in DShell_data:\n            if DShell < DShell_tabulated:\n                return c\n        return 0.011\n    elif DBundle:\n        for DBundle_tabulated, c in DBundle_data:\n            if DBundle < DBundle_tabulated:\n                return c\n        return 0.011\n    else:\n        raise ValueError(\"Either DShell or DBundle must be specified\")\n\n\n_TEMA_baffles_refinery = [[0.0032, 0.0048, 0.0064, 0.0095, 0.0095],\n[0.0048, 0.0064, 0.0095, 0.0095, 0.0127],\n[0.0064, 0.0075, 0.0095, 0.0127, 0.0159],\n[0.0064, 0.0095, 0.0127, 0.0159, 0.0159],\n[0.0095, 0.0127, 0.0159, 0.0191, 0.0191]]\n\n_TEMA_baffles_other = [[0.0016, 0.0032, 0.0048, 0.0064, 0.0095, 0.0095],\n[0.0032, 0.0048, 0.0064, 0.0095, 0.0095, 0.0127],\n[0.0048, 0.0064, 0.0075, 0.0095, 0.0127, 0.0159],\n[0.0064, 0.0064, 0.0095, 0.0127, 0.0159, 0.0159],\n[0.0064, 0.0095, 0.0127, 0.0127, 0.0191, 0.0191]]\n\ndef baffle_thickness(Dshell, L_unsupported, service=\"C\"):\n    r\"\"\"Determines the thickness of baffles and support plates in TEMA HX\n    [1]_. Applies to latitudinal baffles along the diameter of the HX, but\n    not longitudinal baffles parallel to the tubes.\n\n    Parameters\n    ----------\n    Dshell : float\n        Shell inner diameter, [m]\n    L_unsupported : float\n        Distance between tube supports, [m]\n    service : str\n        Service type, C, R or B, [-]\n\n    Returns\n    -------\n    t : float\n        Baffle or support plate thickness, [m]\n\n    Notes\n    -----\n    No checks are implemented to ensure the given shell size is TEMA compatible.\n    The baffles do not need to be strongas the pressure is almost the same on\n    both of their sides. `L_unsupported` is a design choice; the more baffles\n    in a given length, the higher the pressure drop.\n\n    Examples\n    --------\n    >>> baffle_thickness(Dshell=.3, L_unsupported=50, service='R')\n    0.0095\n\n    References\n    ----------\n    .. [1] Standards of the Tubular Exchanger Manufacturers Association,\n       Ninth edition, 2007, TEMA, New York.\n    \"\"\"\n    if Dshell < 0.381:\n        j = 0\n    elif 0.381 <= Dshell < 0.737:\n        j = 1\n    elif 0.737 <= Dshell < 0.991:\n        j = 2\n    elif 0.991 <= Dshell  < 1.524:\n        j = 3\n    else:\n        j = 4\n\n    if service == \"R\":\n        if L_unsupported <= 0.61:\n            i = 0\n        elif 0.61 < L_unsupported <= 0.914:\n            i = 1\n        elif 0.914 < L_unsupported <= 1.219:\n            i = 2\n        elif 1.219 < L_unsupported <= 1.524:\n            i = 3\n        else:\n            i = 4\n        t = _TEMA_baffles_refinery[j][i]\n\n    elif service in (\"C\", \"B\"):\n        if L_unsupported <= 0.305:\n            i = 0\n        elif 0.305 < L_unsupported <= 0.610:\n            i = 1\n        elif 0.61 < L_unsupported <= 0.914:\n            i = 2\n        elif 0.914 < L_unsupported <= 1.219:\n            i = 3\n        elif 1.219 < L_unsupported <= 1.524:\n            i = 4\n        else:\n            i = 5\n        t = _TEMA_baffles_other[j][i]\n    return t\n\n\n\ndef D_baffle_holes(Do, L_unsupported):\n    r\"\"\"Determines the diameter of holes in baffles for tubes according to\n    TEMA [1]_. Applies for all geometries.\n\n    Parameters\n    ----------\n    Do : float\n        Tube outer diameter, [m]\n    L_unsupported : float\n        Distance between tube supports, [m]\n\n    Returns\n    -------\n    dB : float\n        Baffle hole diameter, [m]\n\n    Notes\n    -----\n\n    Examples\n    --------\n    >>> D_baffle_holes(Do=.0508, L_unsupported=0.75)\n    0.0516\n    >>> D_baffle_holes(Do=0.01905, L_unsupported=0.3)\n    0.01985\n    >>> D_baffle_holes(Do=0.01905, L_unsupported=1.5)\n    0.019450000000000002\n\n    References\n    ----------\n    .. [1] Standards of the Tubular Exchanger Manufacturers Association,\n       Ninth edition, 2007, TEMA, New York.\n    \"\"\"\n    if Do > 0.0318 or L_unsupported <= 0.914: # 1-1/4 inches and 36 inches\n        extra = 0.0008\n    else:\n        extra = 0.0004\n    d = Do + extra\n    return d\n\n\n\n_L_unsupported_Do =   [0.25,  0.375, 0.5,  0.628,  0.75,  0.875, 1.,   1.25,  1.5,  2.,    2.5,   3.]\n_L_unsupported_steel = [0.66, 0.889, 1.118, 1.321, 1.524, 1.753, 1.88, 2.235, 2.54, 3.175, 3.175, 3.175]\n_L_unsupported_aluminium = [0.559, 0.762, 0.965, 1.143, 1.321, 1.524, 1.626,\n                            1.93, 2.21, 2.794, 2.794, 2.794]\n\n\ndef L_unsupported_max(Do: float, material: str=\"CS\") -> float:\n    r\"\"\"Determines the maximum length of a heat exchanger tube can go without\n    a support, according to TEMA [1]_. The limits provided apply for the\n    worst-case temperature allowed for the material to be used at.\n\n    Parameters\n    ----------\n    Do : float\n        Outer tube diameter, [m]\n    material : str\n        Material type, either 'CS' or 'aluminium', [-]\n\n    Returns\n    -------\n    L_unsupported : float\n        Maximum length of unsupported tube, [m]\n\n    Notes\n    -----\n    The 'CS' results is also listed as representing high alloy steel, low\n    alloy steel, nickel-copper, nickel, and nickel-chromium-iron alloys.\n    The 'aluminium' results are those of copper and copper alloys and\n    also titanium alloys.\n\n    The maximum and minimum tube outer diameter tabulated are 3 inch and 1/4\n    inch respectively. The result is returned for the nearest tube diameter\n    equal or smaller than the provided diameter, which helps ensures the\n    returned tube length will not be optimistic. However, if the diameter is\n    under 0.25 inches, the result will be optimistic!\n\n\n    Examples\n    --------\n    >>> L_unsupported_max(Do=.0254, material='CS')\n    1.88\n\n    References\n    ----------\n    .. [1] Standards of the Tubular Exchanger Manufacturers Association,\n       Ninth edition, 2007, TEMA, New York, p 5.4-5.\n    \"\"\"\n    Do = Do/inch # convert diameter to inches\n    for i in range(12):\n        if _L_unsupported_Do[i] == Do:\n            break # perfect\n        elif _L_unsupported_Do[i] > Do:\n            i -= 1 # too big, go down a length\n            break\n    i = min(11, i)\n    i = 0 if i == -1 else i\n    if material == \"CS\":\n        return _L_unsupported_steel[i]\n    elif material == \"aluminium\":\n        return _L_unsupported_aluminium[i]\n    else:\n        raise ValueError('Material argument should be one of \"CS\" or \"aluminium\"')\n\n\n### Tube bundle count functions\n\nsquare_C1s = square_Ns = triangular_C1s = triangular_Ns = None\n\ndef _load_coeffs_Phadkeb() -> None:\n    global square_C1s, square_Ns, triangular_C1s, triangular_Ns\n    hx_data_folder = os.path.join(os.path.dirname(__file__), \"data\")\n    triangular_Ns = np.load(os.path.join(hx_data_folder, \"triangular_Ns_Phadkeb.npy\"))\n    triangular_C1s = np.load(os.path.join(hx_data_folder, \"triangular_C1s_Phadkeb.npy\"))\n    square_Ns = np.load(os.path.join(hx_data_folder, \"square_Ns_Phadkeb.npy\"))\n    square_C1s = np.load(os.path.join(hx_data_folder, \"square_C1s_Phadkeb.npy\"))\n\ndef Ntubes_Phadkeb(DBundle: float, Do: float, pitch: float, Ntp: int, angle: float=30) -> int:\n    r\"\"\"Using tabulated values and correction factors for number of passes,\n    the highly accurate method of [1]_ is used to obtain the tube count\n    of a given tube bundle outer diameter for a given tube size and pitch.\n\n    Parameters\n    ----------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    Ntp : int\n        Number of tube passes, [-]\n    angle : float, optional\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    Nt : int\n        Total number of tubes that fit in the heat exchanger, [-]\n\n    Notes\n    -----\n    For single-pass cases, the result is exact, and no tubes need to be removed\n    for any reason. For 4, 6, 8 pass arrangements, a number of tubes must be\n    removed to accommodate pass partition plates. The following assumptions\n    are involved with that:\n\n    * The pass partition plate is where a row of tubes would have been.\n      Only one or two rows are assumed affected.\n    * The thickness of partition plate is < 70% of the tube outer diameter.\n    * The distance between the centerline of the partition plate and the\n      centerline of the nearest row of tubes is equal to the pitch.\n\n    This function will fail when there are more than 100,000 tubes.\n    [1]_ tabulated values up to approximately 3,000 tubes derived with\n    number theory. The sequesnces of integers were identified in the\n    On-Line Encyclopedia of Integer Sequences (OEIS), and formulas listed in\n    it were used to generate more coefficient to allow up to 100,000 tubes.\n    The integer sequences are A003136, A038590, A001481, and A057961. The\n    generation of coefficients for A038590 is very slow, but the rest are\n    reasonably fast.\n\n    The number of tubes that fit generally does not increase one-by-one, but by\n    several.\n\n    >>> Ntubes_Phadkeb(DBundle=1.007, Do=.028, pitch=.036, Ntp=2, angle=45.)\n    558\n    >>> Ntubes_Phadkeb(DBundle=1.008, Do=.028, pitch=.036, Ntp=2, angle=45.)\n    574\n\n    Because a pass partition needs to be installed in multiple tube pass\n    shells, more tubes fit in an exchanger the fewer passes are used.\n\n    >>> Ntubes_Phadkeb(DBundle=1.008, Do=.028, pitch=.036, Ntp=1, angle=45.)\n    593\n\n    Examples\n    --------\n    >>> Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=2, angle=45.)\n    782\n\n    References\n    ----------\n    .. [1] Phadke, P. S., Determining tube counts for shell and tube\n       exchangers, Chem. Eng., September, 91, 65-68 (1984).\n    \"\"\"\n    if square_C1s is None: # numba: delete\n         _load_coeffs_Phadkeb() # numba: delete\n    if DBundle <= Do*Ntp:\n        return 0\n\n    if Ntp == 6:\n        e = 0.265\n    elif Ntp == 8:\n        e = 0.404\n    else:\n        e = 0.\n\n    r = 0.5*(DBundle - Do)/pitch\n    s = r*r\n    Ns, Nr = floor(s), floor(r)\n    # If Ns is between two numbers, take the smaller one\n    # C1 is the number of tubes for a single pass arrangement.\n    if angle in (30, 60):\n        i = np.searchsorted(triangular_Ns, Ns, side=\"right\")\n        C1 = int(triangular_C1s[i-1])\n    elif angle in (45, 90):\n        i = np.searchsorted(square_Ns, Ns, side=\"right\")\n        C1 = int(square_C1s[i-1])\n\n    Cx = 2*Nr + 1.\n\n    # triangular and rotated triangular\n    if (angle in (30, 60)):\n        w = 2*r/3**0.5\n        Nw = floor(w)\n        if Nw % 2 == 0:\n            Cy = 3*Nw\n        else:\n            Cy = 3*Nw + 1\n        if Ntp == 2:\n            if angle == 30 :\n                C2 = C1 - Cx\n            else:\n                C2 = C1 - Cy - 1\n        else: # 4 passes, or 8; this value is needed\n            C4 = C1 - Cx - Cy\n\n    if (angle in (30, 60)) and (Ntp in (6, 8)):\n        if angle == 30: # triangular\n            v = 2*e*r/3**0.5 + 0.5\n            Nv = floor(v)\n            u = 3**0.5*Nv/2.\n            if Nv % 2 == 0:\n                z = (s-u*u)**0.5\n            else:\n                z = (s-u*u)**0.5 - 0.5\n            Nz = floor(z)\n            if Ntp == 6:\n                C6 = C1 - Cy - 4*Nz - 1\n            else:\n                C8 = C4 - 4*Nz\n        else: # rotated triangular\n            v = 2.*e*r\n            Nv = floor(v)\n            u1 = 0.5*Nv\n            z = (s - u1*u1)**0.5\n            w1 = 2*z/2**0.5\n#            w1 = 2**2**0.5 # WRONG\n            u2 = 0.5*(Nv + 1)\n            zs = (s-u2*u2)**0.5\n            w2 = 2.*zs/3**0.5\n            if Nv%2 == 0:\n                z1 = 0.5*w1\n                z2 = 0.5*(w2+1)\n            else:\n                z1 = 0.5*(w1+1)\n                z2 = 0.5*w2\n            Nz1 = floor(z1)\n            Nz2 = floor(z2)\n            if Ntp == 6:\n                C6 = C1 - Cx - 4.*(Nz1 + Nz2)\n            else: # 8\n                C8 = C4 - 4.*(Nz1 + Nz2)\n\n    if (angle in (45, 90)):\n        if angle == 90:\n            Cy = Cx - 1.\n            # eq 6 or 8 for c2 or c4\n            if Ntp == 2:\n                C2 = C1 - Cx\n            else: # 4 passes, or 8; this value is needed\n                C4 = C1 - Cx - Cy\n        else: # rotated square\n            w = r/2**0.5\n            Nw = floor(w)\n            Cx = 2.*Nw + 1\n            Cy = Cx - 1\n            if Ntp == 2:\n                C2 = C1 - Cx\n            else: # 4 passes, or 8; this value is needed\n                C4 = C1 - Cx - Cy\n\n    if (angle in (45, 90)) and (Ntp in (6, 8)):\n        if angle == 90:\n            v = e*r + 0.5\n            Nv = floor(v)\n            z = (s - Nv*Nv)**0.5\n            Nz = floor(z)\n            if Ntp == 6:\n                C6 = C1 - Cy - 4*Nz - 1\n            else:\n                C8 = C4 - 4*Nz\n        else:\n            w = r/2**0.5\n            Nw = floor(w)\n            Cx = 2*Nw + 1\n\n            v = 2**0.5*e*r\n            Nv = floor(v)\n            u1 = Nv/2**0.5\n            z = (s-u1*u1)**0.5\n            w1 = 2**0.5*z\n            u2 = (Nv + 1)/2**0.5\n            zs = (s-u2*u2)**0.5\n            w2 = 2**0.5*zs\n            # if Nv is odd, 21a and 22a. If even, 21b and 22b. Nz1, Nz2\n            if Nv %2 == 0:\n                z1 = 0.5*w1\n                z2 = 0.5*(w2 + 1)\n            else:\n                z1 = 0.5*(w1 + 1)\n                z2 = 0.5*w2\n            Nz1 = floor(z1)\n            Nz2 = floor(z2)\n            if Ntp == 6:\n                C6 = C1 - Cx - 4*(Nz1 + Nz2)\n            else: # 8\n                C8 = C4 - 4*(Nz1 + Nz2)\n\n    if Ntp == 1:\n        ans = C1\n    elif Ntp == 2:\n        ans = C2\n    elif Ntp == 4:\n        ans = C4\n    elif Ntp == 6:\n        ans = C6\n    elif Ntp == 8:\n        ans = C8\n    else:\n        raise ValueError(\"Only 1, 2, 4, 6, or 8 tube passes are supported\")\n    ans = int(ans)\n    # In some cases, a negative number would be returned by these formulas\n    if ans < 0:\n        ans = 0 # pragma: no cover\n    return ans\n\ndef to_solve_Ntubes_Phadkeb(DBundle: int, Do: float, pitch: float, Ntp: int, angle: int, Ntubes: int) -> int:\n    ans = Ntubes_Phadkeb(DBundle=DBundle, Do=Do, pitch=pitch, Ntp=Ntp, angle=angle) - Ntubes\n    return ans\n\ndef DBundle_for_Ntubes_Phadkeb(Ntubes: int, Do: float, pitch: float, Ntp: int, angle: int=30) -> float:\n    r\"\"\"Determine the bundle diameter required to fit a specified number of\n    tubes in a heat exchanger. Uses the highly accurate method of [1]_,\n    which takes into account pitch, number of tube passes, angle,\n    and tube diameter. The method is analytically correct when used in the\n    other direction (calculating number of tubes from bundle diameter); in\n    reverse, it is solved by bisection.\n\n    Parameters\n    ----------\n    Ntubes : int\n        Total number of tubes that fit in the heat exchanger, [-]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    Ntp : int\n        Number of tube passes, [-]\n    angle : float, optional\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n\n    Notes\n    -----\n    This function will fail when there are more than 100,000 tubes. There are\n    a range of correct diameters for which there can be the given number of\n    tubes; a number within that range is returned as found by bisection.\n\n    Examples\n    --------\n    >>> DBundle_for_Ntubes_Phadkeb(Ntubes=782, Do=.028, pitch=.036, Ntp=2, angle=45.)\n    1.1879392959379533\n\n    References\n    ----------\n    .. [1] Phadke, P. S., Determining tube counts for shell and tube\n       exchangers, Chem. Eng., September, 91, 65-68 (1984).\n    \"\"\"\n    if square_C1s is None: # numba: delete\n        _load_coeffs_Phadkeb() # numba: delete\n    if angle in (30, 60):\n        Ns = triangular_Ns[-1]\n    elif angle in (45, 90):\n        Ns = square_Ns[-1]\n    s = Ns + 1\n    r = s**0.5\n    DBundle_max = (Do + 2.*pitch*r)*(1. - 1E-8) # Cannot be exact or floor(s) will give an int too high\n    return float(bisect(to_solve_Ntubes_Phadkeb, 0, DBundle_max, args=(Do, pitch, Ntp, angle, Ntubes)))\n\n\ndef Ntubes_Perrys(DBundle: float, Do: float, Ntp: int, angle: int=30) -> int:\n    r\"\"\"A rough equation presented in Perry's Handbook [1]_ for estimating\n    the number of tubes in a tube bundle of differing geometries and tube\n    sizes. Claimed accuracy of 24 tubes.\n\n    Parameters\n    ----------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n    Do : int\n        Tube outer diameter, [m]\n    Ntp : float\n        Number of tube passes, [-]\n    angle : float\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    Nt : int\n        Number of tubes, [-]\n\n    Notes\n    -----\n    Perry's equation 11-74.\n    Pitch equal to 1.25 times the tube outside diameter\n    No other source for this equation is given.\n    Experience suggests this is accurate to 40 tubes, but is often around 20\n    tubes off.\n\n    Examples\n    --------\n    >>> Ntubes_Perrys(DBundle=1.184, Do=.028, Ntp=2, angle=45)\n    803\n\n    References\n    ----------\n    .. [1] Green, Don, and Robert Perry. Perry's Chemical Engineers' Handbook,\n       Eighth Edition. New York: McGraw-Hill Education, 2007.\n    \"\"\"\n    if angle in (30, 60):\n        C = 0.75 * DBundle / Do - 36.\n        if Ntp == 1:\n            Nt = (((-0.0006 * C - 0.0078) * C + 1.283) * C + 74.86) * C + 1298.\n        elif Ntp == 2:\n            Nt = (((-0.0005 * C - 0.0071) * C + 1.234) * C + 73.58) * C + 1266.\n        elif Ntp == 4:\n            Nt = (((-0.0004 * C - 0.0059) * C + 1.180) * C + 70.79) * C + 1196.\n        elif Ntp == 6:\n            Nt = (((-0.0006 * C - 0.0074) * C + 1.269) * C + 70.72) * C + 1166.\n        else:\n            raise ValueError(\"N passes not 1, 2, 4 or 6\")\n    elif angle in (45, 90):\n        C = DBundle / Do - 36.\n        if Ntp == 1:\n            Nt = (((0.0001 * C - 0.0012) * C + 0.3782) * C + 33.52) * C + 593.6\n        elif Ntp == 2:\n            Nt = (((0.0001 * C - 0.0013) * C + 0.3847) * C + 33.36) * C + 578.8\n        elif Ntp == 4:\n            Nt = (((0.0002 * C - 0.0016) * C + 0.3661) * C + 33.04) * C + 562.0\n        elif Ntp == 6:\n            Nt = (((0.0001 * C - 0.0013) * C + 0.3873) * C + 32.49) * C + 550.4\n        else:\n            raise ValueError(\"N passes not 1, 2, 4 or 6\")\n    return int(Nt)\n\ndef Ntubes_VDI(DBundle: float | None=None, Ntp: int | None=None, Do: float | None=None, pitch: float | None=None, angle: int=30.) -> int:\n    r\"\"\"A rough equation presented in the VDI Heat Atlas for estimating\n    the number of tubes in a tube bundle of differing geometries and tube\n    sizes. No accuracy estimation given.\n\n    Parameters\n    ----------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n    Ntp : float\n        Number of tube passes, [-]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    angle : float\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    N : float\n        Number of tubes, [-]\n\n    Notes\n    -----\n    No coefficients for this method with Ntp=6 are available in [1]_. For\n    consistency, estimated values were added to support 6 tube passes, f2 = 90..\n    This equation is a rearranged form of that presented in [1]_.\n    The calculated tube count is rounded down to an integer.\n\n    Examples\n    --------\n    >>> Ntubes_VDI(DBundle=1.184, Ntp=2, Do=.028, pitch=.036, angle=30)\n    966\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if Ntp == 1:\n        f2 = 0.\n    elif Ntp == 2:\n        f2 = 22.\n    elif Ntp == 4:\n        f2 = 70.\n    elif Ntp == 8:\n        f2 = 105.\n    elif Ntp == 6:\n        f2 = 90. # Estimated!\n    else:\n        raise ValueError(\"Only 1, 2, 4 and 8 passes are supported\")\n    if angle in (30, 60):\n        f1 = 1.1\n    elif angle in (45, 90):\n        f1 = 1.3\n    else:\n        raise ValueError(\"Only 30, 60, 45 and 90 degree layouts are supported\")\n\n    DBundle, Do, pitch = DBundle*1000, Do*1000, pitch*1000 # convert to mm, equation is dimensional.\n    t = pitch\n    Ntubes = (-(-4*f1*t**4*f2**2*Do + 4*f1*t**4*f2**2*DBundle**2 + t**4*f2**4)**0.5\n    - 2*f1*t**2*Do + 2*f1*t**2*DBundle**2 + t**2*f2**2) / (2*f1**2*t**4)\n    return int(Ntubes)\n\n\ndef D_for_Ntubes_VDI(N: int, Ntp: float, Do: float, pitch: float, angle: float=30) -> float:\n    r\"\"\"A rough equation presented in the VDI Heat Atlas for estimating\n    the size of a tube bundle from a given number of tubes, number of tube\n    passes, outer tube diameter, pitch, and arrangement.\n    No accuracy estimation given.\n\n    .. math::\n        OTL = \\sqrt{f_1 z t^2 + f_2 t \\sqrt{z} - d_o}\n\n    Parameters\n    ----------\n    N : float\n        Number of tubes, [-]\n    Ntp : float\n        Number of tube passes, [-]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    angle : float\n        The angle the tubes are positioned; 30, 45, 60 or 90\n\n    Returns\n    -------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n\n    Notes\n    -----\n    f1 = 1.1 for triangular, 1.3 for square patterns\n    f2 is as follows: 1 pass, 0; 2 passes, 22; 4 passes, 70; 8 passes, 105.\n    6 tube passes is not officially supported, only 1, 2, 4 and 8.\n    However, an estimated constant has been added to support it.\n    f2 = 90.\n\n    Examples\n    --------\n    >>> D_for_Ntubes_VDI(N=970, Ntp=2., Do=0.00735, pitch=0.015, angle=30.)\n    0.5003600119829544\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if Ntp == 1:\n        f2 = 0.\n    elif Ntp == 2:\n        f2 = 22.\n    elif Ntp == 4:\n        f2 = 70.\n    elif Ntp == 6:\n        f2 = 90.\n    elif Ntp == 8:\n        f2 = 105.\n    else:\n        raise ValueError(\"Only 1, 2, 4 and 8 passes are supported\")\n    if angle in (30, 60):\n        f1 = 1.1\n    elif angle in (45, 90):\n        f1 = 1.3\n    else:\n        raise ValueError(\"Only 30, 60, 45 and 90 degree layouts are supported\")\n    Do, pitch = Do*1000, pitch*1000 # convert to mm, equation is dimensional.\n    Dshell = (f1*N*pitch**2 + f2*N**0.5*pitch +Do)**0.5\n    return Dshell/1000.\n\n\ndef Ntubes_HEDH(DBundle: float | None=None, Do: float | None=None, pitch: float | None=None, angle: int=30) -> int:\n    r\"\"\"A rough equation presented in the HEDH for estimating\n    the number of tubes in a tube bundle of differing geometries and tube\n    sizes. No accuracy estimation given. Only 1 pass is supported.\n\n    .. math::\n        N = \\frac{0.78(D_{bundle} - D_o)^2}{C_1(\\text{pitch})^2}\n\n    C1 = 0.866 for 30° and 60° layouts, and 1 for 45 and 90° layouts.\n\n    Parameters\n    ----------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    angle : float\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    N : float\n        Number of tubes, [-]\n\n    Notes\n    -----\n    Seems reasonably accurate.\n\n    Examples\n    --------\n    >>> Ntubes_HEDH(DBundle=1.184, Do=.028, pitch=.036, angle=30)\n    928\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1983.\n    \"\"\"\n    if angle in (30, 60):\n        C1 = 13/15.\n    elif angle in (45, 90):\n        C1 = 1.\n    else:\n        raise ValueError(\"Only 30, 60, 45 and 90 degree layouts are supported\")\n    Dctl = DBundle - Do\n    N = 0.78*Dctl*Dctl/(C1*pitch*pitch)\n    return int(N)\n\n\ndef DBundle_for_Ntubes_HEDH(N: int, Do: float, pitch: float, angle: int=30) -> float:\n    r\"\"\"A rough equation presented in the HEDH for estimating the tube bundle\n    diameter necessary to fit a given number of tubes.\n    No accuracy estimation given. Only 1 pass is supported.\n\n    .. math::\n        D_{bundle} = (D_o + (\\text{pitch})\\sqrt{\\frac{1}{0.78}}\\cdot\n        \\sqrt{C_1\\cdot N})\n\n\n    C1 = 0.866 for 30° and 60° layouts, and 1 for 45 and 90° layouts.\n\n    Parameters\n    ----------\n    N : float\n        Number of tubes, [-]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    angle : float\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n\n    Notes\n    -----\n    Easily reversed from the main formulation.\n\n    Examples\n    --------\n    >>> DBundle_for_Ntubes_HEDH(N=928, Do=.028, pitch=.036, angle=30)\n    1.183993079564\n\n    References\n    ----------\n    .. [1] Schlunder, Ernst U, and International Center for Heat and Mass\n       Transfer. Heat Exchanger Design Handbook. Washington:\n       Hemisphere Pub. Corp., 1983.\n    \"\"\"\n    if angle in (30, 60):\n        C1 = 13/15.\n    elif angle in (45, 90):\n        C1 = 1.\n    else:\n        raise ValueError(\"Only 30, 60, 45 and 90 degree layouts are supported\")\n    return (Do + (1./.78)**0.5*pitch*(C1*N)**0.5)\n\n\ndef Ntubes(DBundle: float, Do: float, pitch: float, Ntp: int=1, angle: int=30, Method: str | None=None) -> int:\n    r\"\"\"Calculates the number of tubes which can fit in a heat exchanger.\n    The tube count is effected by the pitch, number of tube passes, and angle.\n\n    The result is an exact number of tubes and is calculated by a very accurate\n    method using number theory by default. This method is available only up to\n    100,000 tubes.\n\n    Parameters\n    ----------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    Ntp : int, optional\n        Number of tube passes, [-]\n    angle : float, optional\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    N : int\n        Total number of tubes that fit in the heat exchanger, [-]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        One of 'Phadkeb', 'HEDH', 'VDI' or 'Perry'\n\n    See Also\n    --------\n    Ntubes_Phadkeb\n    Ntubes_Perrys\n    Ntubes_VDI\n    Ntubes_HEDH\n    size_bundle_from_tubecount\n\n    Examples\n    --------\n    >>> Ntubes(DBundle=1.2, Do=0.025, pitch=0.03125)\n    1285\n\n    The approximations are pretty good too:\n\n    >>> Ntubes(DBundle=1.2, Do=0.025, pitch=0.03125, Method='Perry')\n    1297\n    >>> Ntubes(DBundle=1.2, Do=0.025, pitch=0.03125, Method='VDI')\n    1340\n    >>> Ntubes(DBundle=1.2, Do=0.025, pitch=0.03125, Method='HEDH')\n    1272\n    \"\"\"\n    if Method is None:\n        Method = \"Phadkeb\"\n\n    if Method == \"Phadkeb\":\n        return Ntubes_Phadkeb(DBundle=DBundle, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)\n    elif Method == \"HEDH\":\n        return Ntubes_HEDH(DBundle=DBundle, Do=Do, pitch=pitch, angle=angle)\n    elif Method == \"VDI\":\n        return Ntubes_VDI(DBundle=DBundle, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)\n    elif Method == \"Perry\":\n        return Ntubes_Perrys(DBundle=DBundle, Do=Do, Ntp=Ntp, angle=angle)\n    else:\n        raise ValueError('Method not recognized; allowable methods are '\n                        '\"Phadkeb\", \"HEDH\", \"VDI\", and \"Perry\"')\n\ndef _tubecount_objf_Perry(D: float, Do: float, Ntp: int, angle: int, N: int) -> int:\n    return Ntubes_Perrys(DBundle=D, Do=Do, Ntp=Ntp, angle=angle) - N\n\ndef size_bundle_from_tubecount(N: int, Do: float, pitch: float, Ntp: int=1, angle: int=30, Method: str | None=None) -> float:\n    r\"\"\"Calculates the outer diameter of a tube bundle containing a specified\n    number of tubes.\n    The tube count is effected by the pitch, number of tube passes, and angle.\n\n    The result is an exact number of tubes and is calculated by a very accurate\n    method using number theory by default. This method is available only up to\n    100,000 tubes.\n\n    Parameters\n    ----------\n    N : int\n        Total number of tubes that fit in the heat exchanger, [-]\n    Do : float\n        Tube outer diameter, [m]\n    pitch : float\n        Pitch; distance between two orthogonal tube centers, [m]\n    Ntp : int, optional\n        Number of tube passes, [-]\n    angle : float, optional\n        The angle the tubes are positioned; 30, 45, 60 or 90, [degrees]\n\n    Returns\n    -------\n    DBundle : float\n        Outer diameter of tube bundle, [m]\n\n    Other Parameters\n    ----------------\n    Method : string, optional\n        One of 'Phadkeb', 'HEDH', 'VDI' or 'Perry'\n\n    See Also\n    --------\n    Ntubes\n    DBundle_for_Ntubes_Phadkeb\n    D_for_Ntubes_VDI\n    DBundle_for_Ntubes_HEDH\n\n    Notes\n    -----\n    The 'Perry' method is solved with a numerical solver and is very unreliable.\n\n    Examples\n    --------\n    >>> size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125)\n    1.1985676402390355\n    \"\"\"\n    if Method is None:\n        Method2 = \"Phadkeb\"\n    else:\n        Method2 = Method\n    if Method2 == \"Phadkeb\":\n        return DBundle_for_Ntubes_Phadkeb(Ntubes=N, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)\n    elif Method2 == \"VDI\":\n        return D_for_Ntubes_VDI(N=N, Ntp=Ntp, Do=Do, pitch=pitch, angle=angle)\n    elif Method2 == \"HEDH\":\n        return DBundle_for_Ntubes_HEDH(N=N, Do=Do, pitch=pitch, angle=angle)\n    elif Method2 == \"Perry\":\n        return brenth(_tubecount_objf_Perry, Do*5, 1000*Do, args=(Do, Ntp, angle, N))\n    else:\n        raise ValueError('Method not recognized; allowable methods are '\n                        '\"Phadkeb\", \"HEDH\", \"VDI\", and \"Perry\"')\n\n\n\n\nTEMA_heads = {\"A\": \"Removable Channel and Cover\",\n              \"B\": \"Bonnet (Integral Cover)\",\n              \"C\": \"Integral With Tubesheet Removable Cover\",\n              \"N\": \"Channel Integral With Tubesheet and Removable Cover\",\n              \"D\": \"Special High-Pressure Closures\"}\nTEMA_shells = {\"E\": \"One-Pass Shell\",\n               \"F\": \"Two-Pass Shell with Longitudinal Baffle\",\n               \"G\": \"Split Flow\", \"H\": \"Double Split Flow\",\n               \"J\": \"Divided Flow\",\n               \"K\": \"Kettle-Type Reboiler\",\n               \"X\": \"Cross Flow\"}\nTEMA_rears = {\"L\": 'Fixed Tube Sheet; Like \"A\" Stationary Head',\n              \"M\": 'Fixed Tube Sheet; Like \"B\" Stationary Head',\n              \"N\": 'Fixed Tube Sheet; Like \"C\" Stationary Head',\n              \"P\": \"Outside Packed Floating Head\",\n              \"S\": \"Floating Head with Backing Device\",\n              \"T\": \"Pull-Through Floating Head\",\n              \"U\": \"U-Tube Bundle\",\n              \"W\": \"Externally Sealed Floating Tubesheet\"}\nTEMA_services = {\"B\": \"Chemical\",\n                 \"R\": \"Refinery\",\n                 \"C\": \"General\"}\nbaffle_types = [\"segmental\", \"double segmental\", \"triple segmental\",\n                \"disk and doughnut\", \"no tubes in window\", \"orifice\", \"rod\"]\n"
  },
  {
    "path": "ht/insulation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import interp\n\nfrom ht.conduction import R_to_k\n\n__all__ = [\n    \"ASHRAE\",\n    \"ASHRAE_k\",\n    \"Cp_material\",\n    \"building_materials\",\n    \"k_material\",\n    \"materials_dict\",\n    \"nearest_material\",\n    \"refractories\",\n    \"refractory_VDI_Cp\",\n    \"refractory_VDI_k\",\n    \"rho_material\",\n]\n\n# building_materials in VDI Heat Atlas; full table in DIN EN 12524-2000 which\n# is used here\n# Format: density, thermal conductivity, heat capacity\n# Units: kg/m^3, W/m/K, and J/kg/K\n# A roughly room-teperature value is attached to all values\n\n\nbuilding_materials = {\"Asphalt\": (2100.0, 0.7, 1000.0),\n\"Bitumen, pure\": (1050.0, 0.17, 1000.0),\n\"Bitumen, felt or sheet\": (1100.0, 0.23, 1000.0),\n\"Concrete, medium density 1800 kg/m^3\": (1800.0, 1.15, 1000.0),\n\"Concrete, medium density 2000 kg/m^3\": (2000.0, 1.35, 1000.0),\n\"Concrete, medium density 2200 kg/m^3\": (2200.0, 1.65, 1000.0),\n\"Concrete, high density\": (2400.0, 2.0, 1000.0),\n\"Concrete, reinforced with 1% steel\": (2300.0, 2.3, 1000.0),\n\"Concrete, reinforced with 2% steel\": (2400.0, 2.5, 1000.0),\n\"Floor covering, rubber\": (1200.0, 0.17, 1400.0),\n\"Floor covering, plastic\": (1700.0, 0.25, 1400.0),\n\"Floor covering, underlay, cellular or plastic\": (270.0, 0.1, 1400.0),\n\"Floor covering, underlay, felt\": (120.0, 0.05, 1300.0),\n\"Floor covering, underlay, wool\": (200.0, 0.06, 1300.0),\n\"Floor covering, underlay, cork\": (200.0, 0.05, 1500.0),\n\"Floor covering, tiles, cork\": (400.0, 65.0, 1500.0),\n\"Floor covering, carpet / textile flooring\": (200.0, 0.06, 1300.0),\n\"Floor covering, Linoleum\": (1200.0, 0.17, 1400.0),\n\"Gases, air\": (1.23, 0.025, 1008.0),\n\"Gases, carbon dioxide\": (1.95, .014, 820.0),\n\"Gases, argon\": (1.7, .017, 519.0),\n\"Gases, sulphur hexafluoride\": (6.36, .013, 614.0),\n\"Gases, krypton\": (3.56, 0.009, 245.0),\n\"Gases, xenon\": (5.68, 0.0054, 160.0),\n\"Glass, soda lime\": (2500.0, 1.0, 750.0),\n\"Glass, quartz\": (2200.0, 1.4, 750.0),\n\"Glass, glass mosaic\": (2000.0, 1.2, 750.0),\n\"Water, ice at -10 °C\": (920.0, 2.3, 2000.0),\n\"Water, ice at 0 °C\": (900.0, 2.2, 2000.0),\n\"Water, snow, freshly fallen (<30 mm)\": (100.0, 0.05, 2000.0),\n\"Water, snow, soft (30 mm to 70 mm)\": (200.0, 0.12, 2000.0),\n\"Water, snow, slightly compacted (70 mm to 100 mm)\": (300.0, 0.23, 2000.0),\n\"Water, snow, compacted (<200 mm)\": (500.0, 0.6, 2000.0),\n\"Water at 10°C\": (1000.0, 0.6, 4190.0),\n\"Water at 40°C\": (990.0, 0.63, 4190.0),\n\"Water at 80°C\": (970.0, 0.67, 4190.0),\n\"Metals, aluminium alloys\": (2800.0, 160.0, 880.0),\n\"Metals, bronze\": (8700.0, 65.0, 380.0),\n\"Metals, brass\": (8400.0, 120.0, 380.0),\n\"Metals, copper\": (8900.0, 380.0, 380.0),\n\"Metals, iron, cast\": (7500.0, 50.0, 450.0),\n\"Metals, lead\": (11300.0, 35.0, 130.0),\n\"Metals, steel\": (7800.0, 50.0, 450.0),\n\"Metals, stainless steel\": (7900.0, 17.0, 460.0),\n\"Metals, zinc\": (7200.0, 110.0, 380.0),\n\"Plastics, acrylic\": (1050.0, 0.2, 1500.0),\n\"Plastics, polycarbonates\": (1200.0, 0.2, 1200.0),\n\"Plastics, polytetrafluoroethylene (PTFE)\": (2200.0, 0.25, 1000.0),\n\"Plastics, Polyvinylchloride (PVC)\": (1390.0, 0.17, 900.0),\n\"Plastics, polymethylmethacrylate (PMMA)\": (1180.0, 0.18, 1500.0),\n\"Plastics, polyacetate\": (1410.0, 0.3, 1400.0),\n\"Plastics, polyamide (nylon)\": (1150.0, 0.25, 1600.0),\n\"Plastics, polyamide 6.6 with 25% glass fibre\": (1450.0, 0.3, 1600.0),\n\"Plastics, polyethylene / polythene, high density\": (980.0, 0.5, 1800.0),\n\"Plastics, polyethylene / polythene, low density\": (920.0, 0.33, 2200.0),\n\"Plastics, polystyrene\": (1050.0, 0.16, 1300.0),\n\"Plastics, polypropylene\": (910.0, 0.22, 1800.0),\n\"Plastics, polypropylene with 25% glass fibre\": (1200.0, 0.25, 1800.0),\n\"Plastics, polyurethane (PU)\": (1200.0, 0.25, 1800.0),\n\"Plastics, epoxy resin\": (1200.0, 0.2, 1400.0),\n\"Plastics, phenolic resin\": (1300.0, 0.3, 1700.0),\n\"Plastics, polyester resin\": (1400.0, 0.19, 1200.0),\n\"Rubber, natural\": (910.0, 0.13, 1100.0),\n\"Rubber, neoprene (polychloroprene)\": (1240.0, 0.23, 2140.0),\n\"Rubber, butyl (isobutene), solid melt\": (1200.0, 0.24, 1400.0),\n\"Rubber, foam rubber\": (70.0, 0.06, 1500.0),\n\"Rubber, hard rubber (ebonite), solid\": (1200.0, 0.17, 1400.0),\n\"Rubber, ethylene propylene diene monomer (EPDM)\": (1150.0, 0.25, 1000.0),\n\"Rubber, polyisobutylene\": (930.0, 0.2, 1100.0),\n\"Rubber, polysulfide\": (1700.0, 0.4, 1000.0),\n\"Rubber, butadiene\": (980.0, 0.25, 1000.0),\n\"Sealant, silica gel (dessicant)\": (720.0, 0.13, 1000.0),\n\"Sealant, silicone, pure\": (1200.0, 0.35, 1000.0),\n\"Sealant, silicone, filled\": (1450.0, 0.5, 1000.0),\n\"Sealant, silicone foam\": (750.0, 0.12, 1000.0),\n\"Sealant, urethane / polyurethane (thermal break)\": (1300.0, 0.21, 1800.0),\n\"Sealant, polyvinylchloride (PVC) flexible, with 40% softner\": (1200.0, 0.14, 1000.0),\n\"Sealant, elastomeric foam, flexible\": (70.0, 0.05, 1500.0),\n\"Sealant, polyurethane (PU) foam\": (70.0, 0.05, 1500.0),\n\"Sealant, polyethylene foam\": (70.0, 0.05, 2300.0),\n\"Gypsum, 600 kg/m^3\": (600.0, 0.18, 1000.0),\n\"Gypsum, 900 kg/m^3\": (900.0, 0.3, 1000.0),\n\"Gypsum, 1200 kg/m^3\": (1200.0, 0.43, 1000.0),\n\"Gypsum, 1500 kg/m^3\": (1500.0, 0.56, 1000.0),\n\"Gypsum, plasterboard\": (900.0, 0.25, 1000.0),\n\"Plasters and renders, gypsum insulating plaster\": (600.0, 0.18, 1000.0),\n\"Plasters and renders, gypsum plastering, 1000 kg/m^3\": (1000.0, 0.4, 1000.0),\n\"Plasters and renders, gypsum plastering, 1300 kg/m^3\": (1300.0, 0.57, 1000.0),\n\"Plasters and renders, lime sand\": (1600.0, 0.8, 1000.0),\n\"Plasters and renders, cement sand\": (1600.0, 0.8, 1000.0),\n\"Plasters and renders, gypsum sand\": (1800.0, 1.0, 1000.0),\n\"Solids, clay or silt\": (1500.0, 1.5, 2085.0),\n\"Solids, sand and gravel\": (1950.0, 2.0, 1045.0),\n\"Stone, natural, crystalline rock\": (2800.0, 3.5, 1000.0),\n\"Stone, natural, sedimentary rock\": (2600.0, 2.3, 1000.0),\n\"Stone, natural, sedimentary rock, light\": (1500.0, 0.85, 1000.0),\n\"Stone, natural, porous\": (1600.0, 0.55, 1000.0),\n\"Stone, basalt\": (2850.0, 3.5, 1000.0),\n\"Stone, gneiss\": (2550.0, 3.5, 1000.0),\n\"Stone, granite\": (2600.0, 2.8, 1000.0),\n\"Stone, marble\": (2800.0, 3.5, 1000.0),\n\"Stone, slate\": (2400.0, 2.2, 1000.0),\n\"Stone, limestone, extra soft\": (1600.0, 0.85, 1000.0),\n\"Stone, limestone, soft\": (1800.0, 1.1, 1000.0),\n\"Stone, limestone, semi-hard\": (2000.0, 1.4, 1000.0),\n\"Stone, limestone, hard\": (2200.0, 1.7, 1000.0),\n\"Stone, limestone, extra hard\": (2600.0, 2.3, 1000.0),\n\"Stone, sandstone (silica)\": (2600.0, 2.3, 1000.0),\n\"Stone, natural pumice\": (400.0, 0.12, 1000.0),\n\"Stone, artificial stone\": (1750.0, 1.3, 1000.0),\n\"Tiles, clay\": (2000.0, 1.0, 800.0),\n\"Tiles, concrete\": (2100.0, 1.5, 1000.0),\n\"Tiles, ceramic or porcelain\": (2300.0, 1.3, 840.0),\n\"Tiles, plastic\": (1000.0, 0.2, 1000.0),\n\"Timber, 500 kg/m^3\": (500.0, 0.13, 1600.0),\n\"Timber, 700 kg/m^3\": (700.0, 0.18, 1600.0),\n\"Wood, plywood 300 kg/m^3\": (300.0, 0.09, 1600.0),\n\"Wood, plywood 500 kg/m^3\": (500.0, 0.13, 1600.0),\n\"Wood, plywood 700 kg/m^3\": (700.0, 0.17, 1600.0),\n\"Wood, plywood 1000 kg/m^3\": (1000.0, 0.24, 1600.0),\n\"Wood, cement-bonded particleboard\": (1200.0, 0.23, 1500.0),\n\"Wood, particleboard, 300 kg/m^3\": (300.0, 0.1, 1700.0),\n\"Wood, particleboard, 600 kg/m^3\": (600.0, 0.14, 1700.0),\n\"Wood, particleboard, 900 kg/m^3\": (900.0, 0.18, 1700.0),\n\"Wood, oriented strand board\": (650.0, 0.13, 1700.0),\n\"Wood, fibreboard, 250 kg/m^3\": (250.0, 0.07, 1700.0),\n\"Wood, fibreboard, 400 kg/m^3\": (400.0, 0.1, 1700.0),\n\"Wood, fibreboard, 600 kg/m^3\": (600.0, 0.14, 1700.0),\n\"Wood, fibreboard, 800 kg/m^3\": (800.0, 0.18, 1700.0)}\n\n\n\n# Format for ASHRAE strings: [rho, Cp, k, R, t]\n# Units [kg/m^3, J/kg/K, W/m/K, m^2*K/W, mm]; only t is in non-SI units\n\nASHRAE_board_siding = {\"Board, Asbestos/cement\": [1900.0, 1000.0, 0.57, None, None],\n\"Board, Cement\": [1150.0, 840.0, 0.25, None, None],\n\"Board, Fiber/cement, 1400 kg/m^3\": [1400.0, 840.0, 0.25, None, None],\n\"Board, Fiber/cement, 1000 kg/m^3\": [1000.0, 840.0, 0.19, None, None],\n\"Board, Fiber/cement, 400 kg/m^3\": [400.0, 1880.0, 0.07, None, None],\n\"Board, Fiber/cement, 300 kg/m^3\": [300.0, 1150.0, 0.06, None, None],\n\"Gypsum or plaster board\": [640.0, 1880.0, 0.16, None, None],\n\"Oriented strand board (OSB)\": [650.0, 1880.0, None, 0.12, 12.7],\n\"Plywood (douglas fir)\": [460.0, 1880.0, None, 0.14, 12.7],\n\"Plywood/wood panels\": [450.0, 1880.0, None, 0.19, 19],\n\"Vegetable fiber board, Sheathing, regular density\": [290.0, 1300.0, None, 0.23, 12.7],\n\"Vegetable fiber board, Sheathing, intermediate density\": [350.0, 1300.0, None, 0.19, 12.7],\n\"Vegetable fiber board, Nail-base sheathing\": [400.0, 1300.0, None, 0.19, 12.7],\n\"Vegetable fiber board, Shingle backer\": [290.0, 1300.0, None, 0.17, 9.5],\n\"Vegetable fiber board, Sound deadening board\": [240.0, 1260.0, None, 0.24, 12.7],\n\"Vegetable fiber board, Tile and lay-in panels, plain or acoustic\": [290.0, 590.0, 0.058, None, None],\n\"Vegetable fiber board, Laminated paperboard\": [480.0, 1380.0, 0.072, None, None],\n\"Vegetable fiber board, Homogeneous board from repulped paper\": [480.0, 1170.0, 0.072, None, None],\n\"Hardboard, medium density\": [800.0, 1300.0, 0.105, None, None],\n\"Hardboard, high density, service-tempered grade and service grade\": [880.0, 1340.0, 0.12, None, None],\n\"Hardboard, high density, standard-tempered grade\": [1010.0, 1340.0, 0.144, None, None],\n\"Particleboard, low density\": [590.0, 1300.0, 0.102, None, None],\n\"Particleboard, medium density\": [800.0, 1300.0, 0.135, None, None],\n\"Particleboard, high density\": [1000.0, 1300.0, 1.18, None, None],\n\"Particleboard, underlayment\": [640.0, 1210.0, None, 1.22, 15.9],\n\"Waferboard\": [700.0, 1880.0, 0.072, None, None],\n\"Shingles, Asbestos/cement\": [1900.0, 1000.0, None, 0.037, 6.4],\n\"Shingles, Wood, 400 mm, 190 mm exposure\": [None, 1300.0, None, 0.15, 6],\n\"Shingles, Wood, double, 400 mm, 300 mm exposure\": [None, 1170.0, None, 0.21, 12],\n\"Shingles, Wood, plus ins. backer board\": [None, 1300.0, None, 0.25, 8],\n\"Shingles, Siding, Asbestos/cement, lapped\": [None, 1010.0, None, 0.037, 6.4],\n\"Shingles, Siding, Asphalt roll siding\": [None, 1470.0, None, 0.026, 2],\n\"Siding, Asphalt insulating siding\": [None, 1470.0, None, 0.26, 12.7],\n\"Siding, Hardboard siding\": [None, 1170.0, None, 0.12, 11],\n\"Siding, Wood, drop, 200 mm\": [None, 1170.0, None, 0.14, 25],\n\"Siding, Wood, bevel, 200 mm, lapped\": [None, 1170.0, None, 0.14, 13],\n\"Siding, Wood, bevel, 250 mm, lapped\": [None, 1170.0, None, 0.18, 19],\n\"Siding, Wood, plywood, lapped\": [None, 1220.0, None, 0.1, 9.5],\n\"Siding, Aluminum, steel, or vinyl, over sheathing, hollow-backed\": [None, 1220.0, None, 0.11, 0.6],\n\"Siding, Aluminum, steel, or vinyl, over sheathing, insulating-board-backed\": [None, 1340.0, None, 0.32, 9.5],\n\"Siding, Aluminum, steel, or vinyl, over sheathing foil-backed\": [None, None, None, 0.52, 9.5],\n\"Siding, Architectural (soda-lime float) glass\": [2500.0, 840.0, 1.0, None, None]}\n\n\nASHRAE_flooring = {\"Carpet and rebounded urethane pad\": [110.0, None, None, 0.42, 19],\n\"Carpet and rubber pad, one-piece\": [320.0, None, None, 0.12, 9.5],\n\"Pile carpet with rubber pad\": [290.0, None, None, 0.28, 11],\n\"Linoleum/cork tile\": [465.0, None, None, 0.09, 6.4],\n\"PVC/Rubber floor covering, Rubber tile\": [1900.0, None, 0.4, 0.06, 25],\n\"PVC/Rubber floor covering, Terrazzo\": [None, 800.0, 0.4, 0.014, 25]}\n\nASHRAE_insulation = {\"Glass-fiber batts, 90 mm\": [12.0, 840.0, 0.043, None, 90],\n\"Glass-fiber batts, 50 mm\": [10.5, 840.0, 0.0465, None, 50],\n\"Mineral fiber\": [30.0, 840.0, 0.036, None, 140],\n\"Mineral wool, felted, 32 kg/m^3\": [32.0, 840.0, 0.04, None, None],\n\"Mineral wool, felted, 100 kg/m^3\": [97.5, 840.0, 0.035, None, None],\n\"Slag wool, 120 kg/m^3\": [120.0, 950.0, 0.038, None, None],\n\"Slag wool, 255 kg/m^3\": [255.0, 950.0, 0.04, None, None],\n\"Slag wool, 305 kg/m^3\": [305.0, 950.0, 0.043, None, None],\n\"Slag wool, 350 kg/m^3\": [350.0, 950.0, 0.048, None, None],\n\"Slag wool, 400 kg/m^3\": [400.0, 950.0, 0.05, None, None],\n\"Cellular glass\": [130.0, 750.0, 0.048, None, None],\n\"Cement fiber slabs, shredded wood, with Portland cement binder\": [415.0, 1300.0, 0.074, None, None],\n\"Cement fiber slabs, shredded wood, with magnesia oxysulfide binder\": [350.0, 1300.0, 0.082, None, None],\n\"Glass fiber board\": [160.0, 840.0, 0.036, None, None],\n\"Expanded rubber\": [70.0, 1670.0, 0.032, None, None],\n\"Expanded polystyrene, extruded\": [32.5, 1470.0, 0.026, None, None],\n\"Expanded polystyrene, molded beads\": [20.0, 1470.0, 0.0355, None, None],\n\"Mineral fiberboard, wet felted\": [160.0, 840.0, 0.038, None, None],\n\"Mineral fiberboard, wet felted, core or roof insulation\": [262.5, 840.0, 0.049, None, None],\n\"Mineral fiberboard, wet felted, acoustical tile, 290 kg/m^3\": [290.0, 800.0, 0.05, None, None],\n\"Mineral fiberboard, wet felted, acoustical tile, 335 kg/m^3\": [335.0, None, 0.053, None, None],\n\"Mineral fiberboard, wet-molded, acoustical tile\": [370.0, 590.0, 0.061, None, None],\n\"Perlite board\": [160.0, None, 0.052, None, None],\n\"Polyisocyanurate, aged, unfaced\": [30.0, None, 0.0235, None, None],\n\"Polyisocyanurate, aged, with facers\": [65.0, 1470.0, 0.019, None, None],\n\"Phenolic foam board with facers, aged\": [65.0, None, 0.019, None, None],\n\"Loose fill, Cellulosic\": [42.5, 1380.0, 0.042, None, None],\n\"Loose fill, Perlite, expanded, 50 kg/m^3\": [50.0, 1090.0, 0.042, None, None],\n\"Loose fill, Perlite, expanded, 100 kg/m^3\": [100.0, None, 0.0485, None, None],\n\"Loose fill, Perlite, expanded, 150 kg/m^3\": [150.0, None, 0.0565, None, None],\n\"Loose fill, Mineral fiber, 95 to 130 mm\": [20.0, 710.0, None, 1.92, 112.5],\n\"Loose fill, Mineral fiber, 170 to 220 mm\": [20.0, None, None, 3.33, 195],\n\"Loose fill, Mineral fiber, 190 to 250 mm\": [20.0, None, None, 3.85, 220],\n\"Loose fill, Mineral fiber, 260 to 350 mm\": [20.0, None, None, 5.26, 305],\n\"Loose fill, Mineral fiber, 90 mm\": [42.5, None, None, 2.3, 90],\n\"Loose fill, Vermiculite, exfoliated, 120 kg/m^3\": [120.0, 1340.0, 0.068, None, None],\n\"Loose fill, Vermiculite, exfoliated, 80 kg/m^3\": [80.0, None, 0.063, None, None],\n\"Spray-applied Cellulosic fiber\": [75.0, None, 0.0455, None, None],\n\"Spray-applied Glass fiber\": [62.5, None, 0.0385, None, None],\n\"Spray-applied Polyurethane foam, 7 kg/m^3\": [7.0, 1470.0, 0.042, None, None],\n\"Spray-applied Polyurethane foam, 40 kg/m^3\": [40.0, 1470.0, 0.026, None, None],\n\"Spray-applied Polyurethane foam, aged and dry, 40 mm\": [30.0, 1470.0, None, 1.6, 40],\n\"Spray-applied Polyurethane foam, aged and dry, 50 mm\": [55.0, 1470.0, None, 1.92, 50],\n\"Spray-applied Polyurethane foam, aged and dry, 120 mm\": [30.0, None, None, 3.69, 120],\n\"Spray-applied Ureaformaldehyde foam, dry\": [14.0, None, 0.031, None, None]}\n\nASHRAE_roofing = {\"Asbestos/cement shingles\": [1120.0, 1000.0, None, 0.037, 6],\n\"Asphalt (bitumen with inert fill), 1600 kg/m^3\": [1600.0, None, 0.43, None, None],\n\"Asphalt (bitumen with inert fill), 1900 kg/m^3\": [1900.0, None, 0.58, None, None],\n\"Asphalt (bitumen with inert fill), 2300 kg/m^3\": [2300.0, None, 1.15, None, None],\n\"Asphalt roll roofing\": [920.0, 1510.0, None, 0.027, 2],\n\"Asphalt shingles\": [920.0, 1260.0, None, 0.078, 12],\n\"Built-up roofing\": [920.0, 1470.0, None, 0.059, 10],\n\"Mastic asphalt (heavy, 20% grit)\": [950.0, None, 0.19, None, None],\n\"Reed thatch\": [270.0, None, 0.09, None, None],\n\"Roofing felt\": [2250.0, None, 1.2, None, None],\n\"Slate\": [None, 1260.0, None, 0.009, 13],\n\"Straw thatch\": [240.0, None, 0.07, None, None],\n\"Wood shingles, plain and plastic-film-faced\": [None, 1300.0, None, 0.166, 10]}\n\nASHRAE_plastering = {\"Cement plaster, sand aggregate\": [1860.0, 840.0, 0.72, None, None],\n\"Gypsum plaster, 1120 kg/m^3\": [1120.0, None, 0.38, None, None],\n\"Gypsum plaster, 1280 kg/m^3\": [1280.0, None, 0.46, None, None],\n\"Lightweight aggregate\": [720.0, None, None, 0.056, 13],\n\"Perlite aggregate\": [720.0, 1340.0, 0.22, None, None],\n\"Sand aggregate\": [1680.0, 840.0, 0.81, 0.013, 10],\n\"Vermiculite aggregate, 480 kg/m^3\": [480.0, None, 0.14, None, None],\n\"Vermiculite aggregate, 600 kg/m^3\": [600.0, None, 0.2, None, None],\n\"Vermiculite aggregate, 720 kg/m^3\": [720.0, None, 0.25, None, None],\n\"Vermiculite aggregate, 840 kg/m^3\": [840.0, None, 0.26, None, None],\n\"Vermiculite aggregate, 960 kg/m^3\": [960.0, None, 0.3, None, None],\n\"Perlite plaster, 400 kg/m^3\": [400.0, None, 0.08, None, None],\n\"Perlite plaster, 600 kg/m^3\": [600.0, None, 0.19, None, None],\n\"Pulpboard or paper plaster\": [600.0, None, 0.07, None, None],\n\"Sand/cement plaster, conditioned\": [1560.0, None, 0.63, None, None],\n\"Sand/cement/lime plaster, conditioned\": [1440.0, None, 0.48, None, None],\n\"Sand/gypsum (3:1) plaster, conditioned\": [1550.0, None, 0.65, None, None]}\n\nASHRAE_masonry = {\"Brick, fired clay, 2400 kg/m^3\": [2400.0, 800.0, 1.34, None, None],\n\"Brick, fired clay, 2240 kg/m^3\": [2240.0, 800.0, 1.185, None, None],\n\"Brick, fired clay, 2080 kg/m^3\": [2080.0, 800.0, 1.02, None, None],\n\"Brick, fired clay, 1920 kg/m^3\": [1920.0, 800.0, 0.895, None, None],\n\"Brick, fired clay, 1760 kg/m^3\": [1760.0, 800.0, 0.78, None, None],\n\"Brick, fired clay, 1600 kg/m^3\": [1600.0, 800.0, 0.675, None, None],\n\"Brick, fired clay, 1440 kg/m^3\": [1440.0, 800.0, 0.57, None, None],\n\"Brick, fired clay, 1280 kg/m^3\": [1280.0, 800.0, 0.48, None, None],\n\"Brick, fired clay, 1120 kg/m^3\": [1120.0, 800.0, 0.405, None, None],\n\"Clay tile, hollow, 1 cell deep\": [None, 880.0, None, 0.14, 75],\n\"Clay tile, hollow, 2 cells deep\": [None, 880.0, None, 0.27, 150],\n\"Clay tile, hollow, 3 cells deep\": [None, 880.0, None, 0.44, 300],\n\"Lightweight brick, 800 kg/m^3\": [800.0, None, 0.2, None, None],\n\"Lightweight brick, 770 kg/m^3\": [770.0, None, 0.22, None, None],\n\"Concrete blocks, Limestone aggregate, 200 mm, 16 kg, 2200 kg/m^3, 2 cores with perlite-filled cores\": [None, None, None, 0.37, 200],\n\"Concrete blocks, Limestone aggregate, 300 mm, 25 kg, 2200 kg/m^3, 2 cores with perlite-filled cores.\": [None, None, None, 0.65, 300],\n\"Concrete blocks, normal-weight aggregate, 300 mm, 23 kg, 2100 kg/m^3, 2 or 3 cores\": [None, 920.0, None, 0.185, 200],\n\"Concrete blocks, normal-weight aggregate, 300 mm, 23 kg, 2100 kg/m^3, with perlite-filled cores\": [None, None, None, 0.35, 200],\n\"Concrete blocks, normal-weight aggregate, 300 mm, 23 kg, 2100 kg/m^3, with vermiculite-filled cores\": [None, None, None, 0.29, 200],\n\"Concrete blocks, normal-weight aggregate, 300 mm, 23 kg, 2000 kg/m^3, 2 cores\": [None, 920.0, None, 0.217, 300],\n\"Concrete blocks, medium-weight aggregate, 200 mm, 13 kg, 1650 kg/m^3, 2 or 3 cores\": [1650.0, None, None, 0.26, 200],\n\"Concrete blocks, medium-weight aggregate, 200 mm, 13 kg, 1650 kg/m^3, with perlite-filled cores\": [1650.0, None, None, 0.53, 200],\n\"Concrete blocks, medium-weight aggregate, 200 mm, 13 kg, 1650 kg/m^3, with vermiculite-filled cores\": [None, None, None, 0.58, 200],\n\"Concrete blocks, medium-weight aggregate, 200 mm, 13 kg, 1650 kg/m^3, with molded-EPS-filled cores\": [1650.0, None, None, 0.56, 200],\n\"Concrete blocks, medium-weight aggregate, 200 mm, 13 kg, 1650 kg/m^3, with molded EPS inserts in cores\": [1650.0, None, None, 0.47, 200],\n\"Concrete blocks, low-mass aggregate, 150 mm, 7.5 kg, 1400 kg/m^3, 2 or 3 cores\": [None, None, None, 0.315, 150],\n\"Concrete blocks, low-mass aggregate, 150 mm, 7.5 kg, 1400 kg/m^3, with perlite-filled cores\": [None, None, None, 0.74, 150],\n\"Concrete blocks, low-mass aggregate, 150 mm, 7.5 kg, 1400 kg/m^3, with vermiculite-filled cores\": [None, None, None, 0.53, 150],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3\": [None, 880.0, None, 0.445, 200],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3, with perlite-filled cores\": [None, 880.0, None, 0.985, 200],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3, with vermiculite-filled cores\": [None, 880.0, None, 0.81, 200],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3, with molded-EPS-filled cores\": [None, 880.0, None, 0.85, 200],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3, with UF foam-filled cores\": [None, 880.0, None, 0.79, 200],\n\"Concrete blocks, low-mass aggregate, 200 mm, 9 kg, 1250 kg/m^3, with molded EPS inserts in cores\": [None, 880.0, None, 0.62, 200],\n\"Concrete blocks, low-mass aggregate, 300 mm, 16 kg, 1400 kg/m^3, 2 or 3 cores\": [None, None, None, 0.43, 300],\n\"Concrete blocks, low-mass aggregate, 300 mm, 16 kg, 1400 kg/m^3, with perlite-filled cores\": [None, None, None, 1.35, 300],\n\"Concrete blocks, low-mass aggregate, 300 mm, 16 kg, 1400 kg/m^3, with vermiculite-filled cores\": [None, None, None, 1.0, 300],\n\"Stone, lime, or sand\": [2880.0, None, 10.4, None, None],\n\"Quartzitic and sandstone, 2560 kg/m^3\": [2560.0, None, 6.2, None, None],\n\"Quartzitic and sandstone, 2240 kg/m^3\": [2240.0, None, 3.46, None, None],\n\"Quartzitic and sandstone, 1920 kg/m^3\": [1920.0, 880.0, 1.88, None, None],\n\"Calcitic, dolomitic, limestone, marble, and granite, 2880 kg/m^3\": [2880.0, None, 4.33, None, None],\n\"Calcitic, dolomitic, limestone, marble, and granite, 2560 kg/m^3\": [2560.0, None, 3.17, None, None],\n\"Calcitic, dolomitic, limestone, marble, and granite, 2240 kg/m^3\": [2240.0, None, 2.31, None, None],\n\"Calcitic, dolomitic, limestone, marble, and granite, 1920 kg/m^3\": [1920.0, 880.0, 1.59, None, None],\n\"Calcitic, dolomitic, limestone, marble, and granite, 1600 kg/m^3\": [1600.0, None, 1.15, None, None],\n\"Gypsum partition tile, 75 by 300 by 760 mm, solid, 3 cells\": [None, 790.0, None, 0.222, 75],\n\"Gypsum partition tile, 75 by 300 by 760 mm, with 4 cells\": [None, None, None, 0.238, 75],\n\"Gypsum partition tile, 100 by 300 by 760 mm, 3 cells\": [None, None, None, 0.294, 100],\n\"Limestone, 2400 kg/m^3\": [2400.0, 840.0, 0.57, None, None],\n\"Limestone, 2600 kg/m^3\": [2600.0, 840.0, 0.93, None, None],\n\"Concrete, Sand and gravel or stone aggregate concretes, 2400 kg/m^3\": [2400.0, None, 2.15, None, None],\n\"Concrete, Sand and gravel or stone aggregate concretes, 2240 kg/m^3\": [2240.0, 900.0, 1.95, None, None],\n\"Concrete, Sand and gravel or stone aggregate concretes, 2080 kg/m^3\": [2080.0, None, 1.45, None, None],\n\"Concrete, Low-mass aggregate or limestone\": [1920.0, None, 1.1, None, None],\n\"Concrete, Expanded shale, clay, or slate; expanded slags; cinders; pumice; scoria; 1600 kg/m^3\": [1600.0, 840.0, 0.785, None, None],\n\"Concrete, Expanded shale, clay, or slate; expanded slags; cinders; pumice; scoria; 1280 kg/m^3\": [1280.0, 840.0, 0.535, None, None],\n\"Concrete, Expanded shale, clay, or slate; expanded slags; cinders; pumice; scoria; 960 kg/m^3\": [960.0, None, 0.33, None, None],\n\"Concrete, Expanded shale, clay, or slate; expanded slags; cinders; pumice; scoria; 640 kg/m^3\": [640.0, None, 0.18, None, None],\n\"Concrete, Gypsum/fiber concrete (87.5% gypsum, 12.5% wood chips)\": [800.0, 840.0, 0.24, None, None],\n\"Concrete, Cement/lime, mortar, and stucco, 1920 kg/m^3\": [1920.0, None, 1.4, None, None],\n\"Concrete, Cement/lime, mortar, and stucco, 1600 kg/m^3\": [1600.0, None, 0.97, None, None],\n\"Concrete, Cement/lime, mortar, and stucco, 1280 kg/m^3\": [1280.0, None, 0.65, None, None],\n\"Concrete, Perlite, vermiculite, and polystyrene beads, 800 kg/m^3\": [800.0, None, 0.265, None, None],\n\"Concrete, Perlite, vermiculite, and polystyrene beads, 640 kg/m^3\": [640.0, 795.0, 0.21, None, None],\n\"Concrete, Perlite, vermiculite, and polystyrene beads, 480 kg/m^3\": [480.0, None, 0.16, None, None],\n\"Concrete, Perlite, vermiculite, and polystyrene beads, 320 kg/m^3\": [320.0, None, 0.12, None, None],\n\"Concrete, Foam concretes, 1920 kg/m^3\": [1920.0, None, 0.75, None, None],\n\"Concrete, Foam concretes, 1600 kg/m^3\": [1600.0, None, 0.6, None, None],\n\"Concrete, Foam concretes, 1280 kg/m^3\": [1280.0, None, 0.44, None, None],\n\"Concrete, Foam concretes, 1120 kg/m^3\": [1120.0, None, 0.36, None, None],\n\"Concrete, Foam concretes and cellular concretes, 960 kg/m^3\": [960.0, None, 0.3, None, None],\n\"Concrete, Foam concretes and cellular concretes, 640 kg/m^3\": [640.0, None, 0.2, None, None],\n\"Concrete, Foam concretes and cellular concretes, 320 kg/m^3\": [320.0, None, 0.12, None, None],\n\"Concrete, Aerated concrete (oven-dried)\": [615.0, 840.0, 0.2, None, None],\n\"Concrete, Polystyrene concrete (oven-dried)\": [527.5, 840.0, 0.37, None, None],\n\"Concrete, Polymer concrete, 1950 kg/m^3\": [1950.0, None, 1.64, None, None],\n\"Concrete, Polymer concrete, 2200 kg/m^3\": [2200.0, None, 1.03, None, None],\n\"Concrete, Polymer cement\": [1870.0, None, 0.78, None, None],\n\"Concrete, Slag concrete, 960 kg/m^3\": [960.0, None, 0.22, None, None],\n\"Concrete, Slag concrete, 1280 kg/m^3\": [1280.0, None, 0.32, None, None],\n\"Concrete, Slag concrete, 1600 kg/m^3\": [1600.0, None, 0.43, None, None],\n\"Concrete, Slag concrete, 2000 kg/m^3\": [2000.0, None, 1.23, None, None]}\n\nASHRAE_woods = {\"Oak\": [705.0, 1630.0, 0.17, None, None],\n\"Birch\": [702.5, 1630.0, 0.175, None, None],\n\"Maple\": [667.5, 1630.0, 0.165, None, None],\n\"Ash\": [642.5, 1630.0, 0.155, None, None],\n\"Southern pine\": [615.0, 1630.0, 0.15, None, None],\n\"Southern yellow pine\": [500.0, 1630.0, 0.13, None, None],\n\"Eastern white pine\": [400.0, 1630.0, 0.1, None, None],\n\"Douglas fir/larch\": [557.5, 1630.0, 0.145, None, None],\n\"Southern cypress\": [507.5, 1630.0, 0.13, None, None],\n\"Hem/fir, spruce/pine/fir\": [445.0, 1630.0, 0.12, None, None],\n\"Spruce\": [400.0, 1630.0, 0.09, None, None],\n\"Western red cedar\": [350.0, 1630.0, 0.09, None, None],\n\"West coast woods, cedars\": [425.0, 1630.0, 0.115, None, None],\n\"Eastern white cedar\": [360.0, 1630.0, 0.1, None, None],\n\"California redwood\": [420.0, 1630.0, 0.115, None, None],\n\"Pine (oven-dried)\": [370.0, 1880.0, 0.092, None, None],\n\"Spruce (oven-dried)\": [395.0, 1880.0, 0.1, None, None]}\n\nASHRAE = {}\nfor i in [ASHRAE_board_siding, ASHRAE_flooring, ASHRAE_insulation,\n          ASHRAE_roofing, ASHRAE_plastering, ASHRAE_masonry, ASHRAE_woods]:\n    ASHRAE.update(i)\n\n\n\ndef ASHRAE_k(ID):\n    r\"\"\"Returns thermal conductivity of a building or insulating material\n    from a table in [1]_. Thermal conductivity is independent of temperature\n    here. Many entries in the table are listed for varying densities, but the\n    appropriate ID from the table must be selected to account for that.\n\n    Parameters\n    ----------\n    ID : str\n        ID corresponding to a material in the dictionary `ASHRAE`\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of the material, [W/m/K]\n\n    Examples\n    --------\n    >>> ASHRAE_k(ID='Mineral fiber')\n    0.036\n\n    References\n    ----------\n    .. [1] ASHRAE Handbook: Fundamentals. American Society of Heating,\n       Refrigerating and Air-Conditioning Engineers, Incorporated, 2013.\n    \"\"\"\n    values = ASHRAE[ID]\n    if values[2]:\n        return values[2]\n    else:\n        R = values[3]\n        t = values[4]/1000. # mm to m\n        return R_to_k(R, t)\n\n\n_refractory_Ts = [673.15, 873.15, 1073.15, 1273.15, 1473.15]\n\nrefractories = {\"Silica\": [1820.0, (1.2, 1.36, 1.51, 1.64, 1.76), (915.0, 944.0, 961.0, 969.0, 979.0)],\n\"Silica special\": [1910.0, (1.55, 1.76, 1.95, 2.12, 2.28), (915.0, 944.0, 961.0, 970.0, 980.0)],\n\"Fused silica\": [1940.0, (1.44, 1.53, 1.61, 1.67, 1.73), (917.0, 946.0, 963.0, 972.0, 982.0)],\n\"Fireclay\": [2150.0, (1.05, 1.1, 1.15, 1.18, 1.22), (956.0, 997.0, 1021.0, 1037.0, 1054.0)],\n\"High-duty fireclay\": [2320.0, (1.2, 1.27, 1.33, 1.38, 1.42), (958.0, 999.0, 1024.0, 1040.0, 1058.0)],\n\"Sillimanite\": [2530.0, (1.66, 1.76, 1.84, 1.92, 1.98), (978.0, 1024.0, 1052.0, 1072.0, 1093.0)],\n\"Mullite\": [2540.0, (1.45, 1.52, 1.58, 1.63, 1.67), (987.0, 1035.0, 1065.0, 1087.0, 1109.0)],\n\"Corundum 90%\": [2830.0, (2.0, 2.1, 2.19, 2.27, 2.33), (993.0, 1043.0, 1072.0, 1095.0, 1118.0)],\n\"Bauxite\": [2760.0, (2.06, 2.03, 2.02, 2.0, 1.99), (994.0, 1045.0, 1077.0, 1100.0, 1124.0)],\n\"Corundum 99%\": [2830.0, (4.97, 4.36, 3.93, 3.6, 3.35), (1011.0, 1066.0, 1099.0, 1124.0, 1150.0)],\n\"Corundum Spinel\": [3100.0, (3.01, 3.02, 3.03, 3.04, 3.05), (1013.0, 1067.0, 1100.0, 1126.0, 1152.0)],\n\"ACr 90\": [3180.0, (4.2, 3.81, 3.52, 3.3, 3.12), (782.0, 794.0, 806.0, 816.0, 825.0)],\n\"ACrZ 20\": [3780.0, (2.4, 2.33, 2.27, 2.22, 2.18), (772.0, 789.0, 804.0, 814.0, 825.0)],\n\"ACrZ 60\": [3200.0, (3.8, 3.4, 3.11, 2.89, 2.71), (905.0, 945.0, 970.0, 990.0, 1010.0)],\n\"Magnesite Chrome\": [3060.0, (3.5, 3.27, 3.1, 2.96, 2.85), (1004.0, 1043.0, 1079.0, 1110.0, 1138.0)],\n\"Magnesia\": [3000.0, (7.5, 6.23, 5.37, 4.75, 4.28), (1047.0, 1088.0, 1125.0, 1158.0, 1188.0)],\n\"Magnesite Spinel\": [2850.0, (3.8, 3.44, 3.18, 2.98, 2.82), (1050.0, 1093.0, 1131.0, 1164.0, 1194.0)],\n\"Magnesite Graphite H15\": [2980.0, (9.96, 8.46, 7.44, 6.68, 6.1), (1061.0, 1117.0, 1168.0, 1215.0, 1258.0)],\n\"Dolomite P10\": [2970.0, (4.17, 3.99, 3.92, 3.75, 3.66), (950.0, 988.0, 1022.0, 1051.0, 1078.0)],\n\"Sillimanite P5\": [2740.0, (1.5, 1.5, 1.5, 1.5, 1.5), (986.0, 1037.0, 1070.0, 1095.0, 1120.0)],\n\"Bauxite P5\": [2830.0, (2.9, 2.67, 2.49, 2.36, 2.25), (1000.0, 1056.0, 1092.0, 1121.0, 1149.0)],\n\"Corundum P10\": [3020.0, (5.49, 5.19, 4.96, 4.78, 4.62), (1020.0, 1083.0, 1126.0, 1160.0, 1195.0)],\n\"Magnesite P5\": [2920.0, (5.05, 4.53, 4.15, 3.86, 3.63), (1050.0, 1097.0, 1139.0, 1177.0, 1211.0)],\n\"Zirconia\": [4950.0, (1.63, 1.54, 1.48, 1.43, 1.38), (624.0, 668.0, 698.0, 718.0, 737.0)],\n\"Zircon\": [3940.0, (2.67, 2.49, 2.35, 2.24, 2.15), (708.0, 747.0, 773.0, 788.0, 804.0)],\n\"AZS 41\": [4000.0, (4.55, 4.17, 4.25, 4.85, 5.4), (831.0, 878.0, 908.0, 929.0, 950.0)],\n\"AZS 33\": [3720.0, (5.17, 4.42, 4.0, 4.45, 5.4), (861.0, 908.0, 938.0, 958.0, 980.0)],\n\"a/b-Alumina\": [3200.0, (4.78, 4.45, 4.3, 5.0, 6.05), (989.0, 1044.0, 1080.0, 1107.0, 1133.0)],\n\"SIC 40%\": [2400.0, (4.2, 4.41, 4.58, 4.73, 4.86), (993.0, 1043.0, 1072.0, 1095.0, 1118.0)],\n\"SIC 70%\": [2600.0, (7.0, 6.81, 6.67, 6.55, 6.45), (998.0, 1049.0, 1079.0, 1103.0, 1126.0)],\n\"SIC 90%\": [2680.0, (18.6, 17.55, 16.76, 16.14, 15.62), (1005.0, 1058.0, 1090.0, 1115.0, 1140.0)],\n\"L1260\": [490.0, (0.14, 0.16, 0.18, 0.2, 0.22), (942.0, 979.0, 1002.0, 1017.0, 1033.0)],\n\"L1400\": [790.0, (0.27, 0.3, 0.32, 0.34, 0.36), (954.0, 994.0, 1018.0, 1034.0, 1050.0)],\n\"L1540\": [890.0, (0.32, 0.35, 0.38, 0.41, 0.43), (979.0, 1026.0, 1054.0, 1075.0, 1096.0)],\n\"L1760\": [1270.0, (0.45, 0.47, 0.49, 0.51, 0.53), (991.0, 1040.0, 1070.0, 1092.0, 1114.0)],\n\"L1870\": [1440.0, (1.5, 1.34, 1.23, 1.14, 1.07), (1011.0, 1066.0, 1099.0, 1124.0, 1150.0)],\n\"Carbon, anthracite\": [1540.0, (7.0, 8.51, 9.95, 11.33, 12.65), (1106.0, 1240.0, 1362.0, 1474.0, 1581.0)],\n\"Carbon, graphite\": [1550.0, (67.0, 60.67, 56.06, 52.01, 49.46), (1108.0, 1244.0, 1366.0, 1479.0, 1588.0)]}\n\n\nmaterials_dict = {}\nfor mat_dict, reference in [(refractories, 1), (ASHRAE, 2), (building_materials, 3)]:\n    for key in mat_dict.keys():\n        materials_dict[key] = reference\n\n\ndef refractory_VDI_k(ID, T=None):\n    r\"\"\"Returns thermal conductivity of a refractory material from a table in\n    [1]_. Here, thermal conductivity is a function of temperature between\n    673.15 K and 1473.15 K according to linear interpolation among 5\n    equally-spaced points. Here, thermal conductivity is not a function of\n    porosity, which can affect it. If T is outside the acceptable range, it is\n    rounded to the nearest limit. If T is not provided, the lowest temperature's\n    value is provided.\n\n    Parameters\n    ----------\n    ID : str\n        ID corresponding to a material in the dictionary `refractories`\n    T : float, optional\n        Temperature of the refractory material, [K]\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of the refractory material, [W/m/K]\n\n    Examples\n    --------\n    >>> [refractory_VDI_k('Fused silica', i) for i in [None, 200.0, 1000.0, 1500]]\n    [1.44, 1.44, 1.58074, 1.73]\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if T is None:\n        return float(refractories[ID][1][0])\n    else:\n        ks = refractories[ID][1]\n        if T < _refractory_Ts[0]:\n            T = _refractory_Ts[0]\n        elif T > _refractory_Ts[-1]:\n            T = _refractory_Ts[-1]\n        return float(interp(T, _refractory_Ts, ks))\n\n\ndef refractory_VDI_Cp(ID, T=None):\n    r\"\"\"Returns heat capacity of a refractory material from a table in\n    [1]_. Here, heat capacity is a function of temperature between\n    673.15 K and 1473.15 K according to linear interpolation among 5\n    equally-spaced points. Here, heat capacity is not a function of\n    porosity, affects it. If T is outside the acceptable range, it is\n    rounded to the nearest limit. If T is not provided, the lowest temperature's\n    value is provided.\n\n    Parameters\n    ----------\n    ID : str\n        ID corresponding to a material in the dictionary `refractories`\n    T : float, optional\n        Temperature of the refractory material, [K]\n\n    Returns\n    -------\n    Cp : float\n        Heat capacity of the refractory material, [W/m/K]\n\n    Examples\n    --------\n    >>> [refractory_VDI_Cp('Fused silica', i) for i in [None, 200.0, 1000.0, 1500]]\n    [917.0, 917.0, 956.78225, 982.0]\n\n    References\n    ----------\n    .. [1] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if T is None:\n        return float(refractories[ID][2][0])\n    else:\n        Cps = refractories[ID][2]\n        if T < _refractory_Ts[0]:\n            T = _refractory_Ts[0]\n        elif T > _refractory_Ts[-1]:\n            T = _refractory_Ts[-1]\n        return float(interp(T, _refractory_Ts, Cps))\n\n\ndef nearest_material(name, complete=False):\n    r\"\"\"Returns the nearest hit to a given name from from dictionaries of\n    building, insulating, or refractory material from tables in [1]_, [2]_,\n    and [3]_. Function will pick the closest match based on a fuzzy search.\n    if `complete` is True, will only return hits with all three of density,\n    heat capacity, and thermal conductivity available.\n\n    Parameters\n    ----------\n    name : str\n        Search keywords to be used by difflib function\n    complete : bool, optional\n        If True, returns only hits with all parameters available\n\n    Returns\n    -------\n    ID : str\n        A key to one of the dictionaries mentioned above\n\n    Examples\n    --------\n    >>> nearest_material('stainless steel')\n    'Metals, stainless steel'\n\n    References\n    ----------\n    .. [1] ASHRAE Handbook: Fundamentals. American Society of Heating,\n       Refrigerating and Air-Conditioning Engineers, Incorporated, 2013.\n    .. [2] DIN EN 12524 (2000-07) Building Materials and Products\n       Hygrothermal Properties - Tabulated Design Values; English Version of\n       DIN EN 12524.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    import difflib\n    if complete:\n        hits = difflib.get_close_matches(name, materials_dict.keys(), n=1000, cutoff=0)\n        for hit in hits:\n            if materials_dict[hit] == 1 or materials_dict[hit]==3 or (ASHRAE[hit][0] and ASHRAE[hit][1]):\n                return hit\n    else:\n        ID = difflib.get_close_matches(name, materials_dict.keys(), n=1, cutoff=0.6)\n        if not ID:\n            ID = difflib.get_close_matches(name, materials_dict.keys(), n=1, cutoff=0.3)\n        if not ID:\n            ID = difflib.get_close_matches(name, materials_dict.keys(), n=1, cutoff=0)\n        return ID[0]\n\n\ndef k_material(ID, T=298.15):\n    r\"\"\"Returns thermal conductivity of a building, insulating, or refractory\n    material from tables  in [1]_, [2]_, and [3]_. Thermal conductivity may or\n    may not be dependent on temperature depending on the source used. Function\n    must be provided with either a key to one of the dictionaries\n    `refractories`, `ASHRAE`, or `building_materials` - or a search term which\n    will pick the closest match based on a fuzzy search. To determine which\n    source the fuzzy search will pick, use the function `nearest_material`.\n    Fuzzy searches are slow; it is preferable to call this function with a\n    material key directly.\n\n    Parameters\n    ----------\n    ID : str\n        String as described above\n    T : float, optional\n        Temperature of the material, [K]\n\n    Returns\n    -------\n    k : float\n        Thermal conductivity of the material, [W/m/K]\n\n    Examples\n    --------\n    >>> k_material('Mineral fiber')\n    0.036\n\n    References\n    ----------\n    .. [1] ASHRAE Handbook: Fundamentals. American Society of Heating,\n       Refrigerating and Air-Conditioning Engineers, Incorporated, 2013.\n    .. [2] DIN EN 12524 (2000-07) Building Materials and Products\n       Hygrothermal Properties - Tabulated Design Values; English Version of\n       DIN EN 12524.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if ID not in materials_dict:\n        ID = nearest_material(ID)\n    if ID in refractories:\n        return refractory_VDI_k(ID, T)\n    elif ID in ASHRAE:\n        return ASHRAE_k(ID)\n    else:\n        return float(building_materials[ID][1])\n\n\ndef rho_material(ID):\n    r\"\"\"Returns the density of a building, insulating, or refractory\n    material from tables  in [1]_, [2]_, and [3]_. No temperature dependence is\n    available. Function must be provided with either a key to one of the\n    dictionaries `refractories`, `ASHRAE`, or `building_materials` - or a\n    search term which will pick the closest match based on a fuzzy search. To\n    determine which source the fuzzy search will pick, use the function\n    `nearest_material`. Fuzzy searches are slow; it is preferable to call this\n    function with a material key directly.\n\n    Parameters\n    ----------\n    ID : str\n        String as described above\n\n    Returns\n    -------\n    rho : float\n        Density of the material, [kg/m^3]\n\n    Examples\n    --------\n    >>> rho_material('Board, Asbestos/cement')\n    1900.0\n\n    References\n    ----------\n    .. [1] ASHRAE Handbook: Fundamentals. American Society of Heating,\n       Refrigerating and Air-Conditioning Engineers, Incorporated, 2013.\n    .. [2] DIN EN 12524 (2000-07) Building Materials and Products\n       Hygrothermal Properties - Tabulated Design Values; English Version of\n       DIN EN 12524.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if ID not in materials_dict:\n        ID = nearest_material(ID)\n    if ID in refractories:\n        rho = float(refractories[ID][0]) # Density available for all hits\n    elif ID in building_materials:\n        rho = float(building_materials[ID][0]) # Density available for all hits\n    else:\n        rho = ASHRAE[ID][0]\n        if rho is None:\n            raise ValueError(\"Density is not available for this material\")\n        else:\n            rho = float(rho)\n    return rho\n\n\ndef Cp_material(ID, T=298.15):\n    r\"\"\"Returns heat capacity of a building, insulating, or refractory\n    material from tables  in [1]_, [2]_, and [3]_. Heat capacity may or\n    may not be dependent on temperature depending on the source used. Function\n    must be provided with either a key to one of the dictionaries\n    `refractories`, `ASHRAE`, or `building_materials` - or a search term which\n    will pick the closest match based on a fuzzy search. To determine which\n    source the fuzzy search will pick, use the function `nearest_material`.\n    Fuzzy searches are slow; it is preferable to call this function with a\n    material key directly.\n\n    Parameters\n    ----------\n    ID : str\n        String as described above\n    T : float, optional\n        Temperature of the material, [K]\n\n    Returns\n    -------\n    Cp : float\n        Heat capacity of the material, [W/m/K]\n\n    Examples\n    --------\n    >>> Cp_material('Mineral fiber')\n    840.0\n\n    References\n    ----------\n    .. [1] ASHRAE Handbook: Fundamentals. American Society of Heating,\n       Refrigerating and Air-Conditioning Engineers, Incorporated, 2013.\n    .. [2] DIN EN 12524 (2000-07) Building Materials and Products\n       Hygrothermal Properties - Tabulated Design Values; English Version of\n       DIN EN 12524.\n    .. [3] Gesellschaft, V. D. I., ed. VDI Heat Atlas. 2nd edition.\n       Berlin; New York:: Springer, 2010.\n    \"\"\"\n    if ID not in materials_dict:\n        ID = nearest_material(ID)\n    if ID in refractories:\n        Cp = refractory_VDI_Cp(ID, T)\n    elif ID in building_materials:\n        Cp = float(building_materials[ID][2]) # Density available for all hits\n    else:\n        Cp = ASHRAE[ID][1]\n        if Cp is None:\n            raise ValueError(\"Heat capacity is not available for this material\")\n        else:\n            Cp = float(Cp)\n    return Cp\n\n"
  },
  {
    "path": "ht/numba.py",
    "content": "# type: ignore\n\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2020, 2021, 2022, 2023 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport inspect\n\nimport fluids\nimport fluids.numba\nimport numba\n\nimport ht\n\nnormal_fluids = fluids\nnormal = ht\n\norig_file = __file__\ncaching = False\n\"\"\"\n\n\n\"\"\"\n__all__ = []\n__funcs = {}\n\nnumerics = fluids.numba.numerics\nreplaced = fluids.numba.numerics_dict.copy()\n\n\ndef transform_complete_ht(replaced, __funcs, __all__, normal, vec=False):\n    cache_blacklist = {\"h_Ganguli_VDI\", \"fin_efficiency_Kern_Kraus\", \"h_Briggs_Young\",\n                           \"h_ESDU_high_fin\", \"h_ESDU_low_fin\", \"Nu_Nusselt_Rayleigh_Holling_Herwig\",\n                           \"DBundle_for_Ntubes_Phadkeb\", \"Thome\", \"to_solve_q_Thome\",\n                       \"temperature_effectiveness_air_cooler\", \"factorial\",\n                       \"size_bundle_from_tubecount\", \"crossflow_effectiveness_to_int\",\n                       \"temperature_effectiveness_basic\", \"_NTU_from_P_solver\",\n                       \"NTU_from_P_basic\", \"_NTU_from_P_erf\",\n                       \"NTU_from_P_G\", \"NTU_from_P_J\", \"NTU_from_P_E\",\n                       \"NTU_from_P_H\", \"NTU_from_P_plate\",\n                       \"_NTU_from_P_objective\",\n                       \"temperature_effectiveness_plate\", # dies on recursion\n                       }\n    __funcs.update(normal_fluids.numba.numbafied_fluids_functions.copy())\n    new_mods = normal_fluids.numba.transform_module(normal, __funcs, replaced, vec=vec,\n                                                    cache_blacklist=cache_blacklist)\n    if vec:\n        conv_fun = numba.vectorize\n    else:\n        conv_fun = numba.njit\n\n    to_change_full_output = []\n\n    to_change = {}\n    to_change.update(dict.fromkeys(to_change_full_output, \"full_output\"))\n#    to_change['hx.Ntubes_Phadkeb'] = 'square_C1s is None'\n    to_change[\"boiling_nucleic.Gorenflo\"] = \"h0 is None: # NUMBA: DELETE\"\n\n    for s, bad_branch in to_change.items():\n        mod, func = s.split(\".\")\n        source = inspect.getsource(getattr(getattr(normal, mod), func))\n        fake_mod = __funcs[mod]\n        source = normal_fluids.numba.remove_branch(source, bad_branch)\n        normal_fluids.numba.numba_exec_cacheable(source, fake_mod.__dict__, fake_mod.__dict__)\n        new_func = fake_mod.__dict__[func]\n        obj = conv_fun(cache=caching)(new_func)\n        __funcs[func] = obj\n        globals()[func] = obj\n        obj.__doc__ = \"\"\n    to_change = [\"air_cooler.Ft_aircooler\", \"hx.Ntubes_Phadkeb\",\n                 \"hx.DBundle_for_Ntubes_Phadkeb\", \"boiling_nucleic.h_nucleic_methods\",\n                 \"hx._NTU_from_P_solver\", \"hx.NTU_from_P_plate\"]\n    normal_fluids.numba.transform_lists_to_arrays(normal, to_change, __funcs, cache_blacklist=cache_blacklist)\n\n    for mod in new_mods:\n        mod.__dict__.update(__funcs)\n        try:\n            __all__.extend(mod.__all__)\n        except AttributeError:\n            pass\n\n    __funcs[\"hx\"]._load_coeffs_Phadkeb() # Run after everything is done\n\ntransform_complete_ht(replaced, __funcs, __all__, normal, vec=False)\n\n\n\nglobals().update(__funcs)\nglobals().update(replaced)\n\n__name__ = \"ht.numba\"\n__file__ = orig_file\n"
  },
  {
    "path": "ht/numba_vectorized.py",
    "content": "# type: ignore\n\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2020, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\n\nimport fluids\nimport fluids.numba\n\nimport ht as normal_ht\nimport ht.numba\n\norig_file = __file__\nnormal = normal_ht\n__all__ = []\n__funcs = {}\nnumerics = fluids.numba.numerics\nreplaced = fluids.numba.numerics_dict.copy()\n\nht.numba.transform_complete_ht(replaced, __funcs, __all__, normal, vec=True)\n\n\nglobals().update(__funcs)\nglobals().update(replaced)\n\n__name__ = \"ht.numba_vectorized\"\n__file__ = orig_file\n"
  },
  {
    "path": "ht/py.typed",
    "content": " \n"
  },
  {
    "path": "ht/radiation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\nfrom __future__ import annotations\n\nimport os\nfrom math import e, exp\n\nfrom fluids.constants import c, h, k, sigma\nfrom fluids.numerics import numpy as np\n\n__all__: list[str] = [\n    \"blackbody_spectral_radiance\",\n    \"grey_transmittance\",\n    \"q_rad\",\n    \"solar_spectrum\",\n]\n\n\ndef blackbody_spectral_radiance(T: float, wavelength: float) -> float:\n    r\"\"\"Returns the spectral radiance, in units of W/m^2/sr/µm.\n\n    .. math::\n        I_{\\lambda,blackbody,e}(\\lambda,T)=\\frac{2hc_o^2}\n        {\\lambda^5[\\exp(hc_o/\\lambda k T)-1]}\n\n    Parameters\n    ----------\n    T : float\n        Temperature of the surface, [K]\n    wavelength : float\n        Length of the wave to be considered, [m]\n\n    Returns\n    -------\n    I : float\n        Spectral radiance [W/(m^2*sr*m)]\n\n    Notes\n    -----\n    Can be used to derive the Stefan-Boltzman law, or determine the maximum\n    radiant frequency for a given temperature.\n\n    Examples\n    --------\n    Checked with Spectral-calc.com, at [2]_.\n\n    >>> blackbody_spectral_radiance(800., 4E-6)\n    1311694129.7430933\n\n    Calculation of power from the sun (earth occupies 6.8E-5 steradian of the\n    sun):\n\n    >>> from scipy.integrate import quad\n    >>> rad = lambda l: blackbody_spectral_radiance(5778., l)*6.8E-5\n    >>> quad(rad, 1E-10, 1E-4)[0]\n    1367.9827067638964\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    .. [2] Spectral-calc.com. Blackbody Calculator, 2015.\n       http://www.spectralcalc.com/blackbody_calculator/blackbody.php\n    \"\"\"\n    to_exp = h*c/(wavelength*T*k)\n    if to_exp > 709.7:\n        return 0.0\n    else:\n        exp_term = exp(to_exp)\n    return 2.*h*c*c*wavelength**-5/(exp_term - 1.0)\n\n\ndef q_rad(emissivity: float, T: int, T2: float=0) -> float:\n    r\"\"\"Returns the radiant heat flux of a surface, optionally including\n    assuming radiant heat transfer back to the surface.\n\n    .. math::\n        q = \\epsilon \\sigma (T_1^4 - T_2^4)\n\n    Parameters\n    ----------\n    emissivity : float\n        Fraction of black-body radiation which is emitted, [-]\n    T : float\n        Temperature of the surface, [K]\n    T2 : float, optional\n        Temperature of the surrounding material of the surface [K]\n\n    Returns\n    -------\n    q : float\n        Heat exchange [W/m^2]\n\n    Notes\n    -----\n    Emissivity must be less than 1. T2 may be larger than T.\n\n    Examples\n    --------\n    >>> q_rad(emissivity=1, T=400)\n    1451.613952\n\n    >>> q_rad(.85, T=400, T2=305.)\n    816.7821722650002\n\n    References\n    ----------\n    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and\n       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:\n       Wiley, 2011.\n    \"\"\"\n    T_T = T*T\n    T2_T2 = T2*T2\n    return sigma*emissivity*(T_T*T_T - T2_T2*T2_T2)\n\n\ndef grey_transmittance(extinction_coefficient: float, molar_density: int, length: float, base: float=e) -> float:\n    r\"\"\"Calculates the transmittance of a grey body, given the extinction\n    coefficient of the material, its molar density, and the path length of the\n    radiation.\n\n    .. math::\n        \\tau = base^{(-\\epsilon \\cdot l\\cdot \\rho_m )}\n\n    Parameters\n    ----------\n    extinction_coefficient : float\n        The extinction coefficient of the material the radiation is passing at\n        the modeled frequency, [m^2/mol]\n    molar_density : float\n        The molar density of the material the radiation is passing through,\n        [mol/m^3]\n    length : float\n        The length of the body the radiation is transmitted through, [m]\n    base : float, optional\n        The exponent used in calculations; `e` is more theoretically sound but\n        10 is often used as a base by chemists, [-]\n\n    Returns\n    -------\n    transmittance : float\n        The fraction of spectral radiance which is transmitted through a grey\n        body (can be liquid, gas, or even solid ex. in the case of glasses) [-]\n\n    Notes\n    -----\n    For extinction coefficients, see the HITRAN database. They are temperature\n    and pressure dependent for each chemical and phase.\n\n    Examples\n    --------\n    Overall transmission loss through 1 cm of precipitable water equivalent\n    atmospheric water vapor at a frequency of 1.3 um [2]_:\n\n    >>> grey_transmittance(3.8e-4, molar_density=55300, length=1e-2)\n    0.8104707721191062\n\n    References\n    ----------\n    .. [1] Modest, Michael F. Radiative Heat Transfer, Third Edition. 3rd\n       edition. New York: Academic Press, 2013.\n    .. [2] Eldridge, Ralph G. \"Water Vapor Absorption of Visible and Near\n       Infrared Radiation.\" Applied Optics 6, no. 4 (April 1, 1967): 709-13.\n       https://doi.org/10.1364/AO.6.000709.\n    \"\"\"\n    transmittance = molar_density*extinction_coefficient*length\n    return base**(-transmittance)\n\n\ndef solar_spectrum(model=\"SOLAR-ISS\"):\n    r\"\"\"Returns the solar spectrum of the sun according to the specified model.\n    Only the 'SOLAR-ISS' model is supported.\n\n    Parameters\n    ----------\n    model : str, optional\n        The model to use; 'SOLAR-ISS' is the only model available, [-]\n\n    Returns\n    -------\n    wavelengths : ndarray\n        The wavelengths of the solar spectra, [m]\n    SSI : ndarray\n        The solar spectral irradiance of the sun, [W/(m^2*m)]\n    uncertainties : ndarray\n        The estimated absolute uncertainty of the measured spectral irradiance\n        of the sun, [W/(m^2*m)]\n\n    Notes\n    -----\n    The power of the sun changes as the earth gets closer or further away.\n\n    In [1]_, the UV and VIS data come from observations in 2008; the IR comes\n    from measurements made from 2010-2016. There is a further 28 W/m^2 for the\n    3 micrometer to 160 micrometer range, not included in this model. All data\n    was corrected to a standard distance of one astronomical unit from the Sun,\n    as is the resultant spectrum.\n\n    The variation of the spectrum as a function of distance from the sun should\n    alter only the absolute magnitudes.\n\n    [2]_ contains another dataset.\n\n    99.9% of the time this function takes is to read in the solar data from\n    disk. This could be reduced by using pandas.\n\n    Examples\n    --------\n    >>> wavelengths, SSI, uncertainties = solar_spectrum()\n\n    Calculate the minimum and maximum values of the wavelengths (0.5 nm/3000nm)\n    and SSI:\n\n    >>> float(min(wavelengths)), float(max(wavelengths)), float(min(SSI)), float(max(SSI))\n    (5e-10, 2.9999e-06, 1330.0, 2256817820.0)\n\n    Integration - calculate the solar constant, in units of W/m^2 hitting\n    earth's atmosphere.\n\n    >>> from scipy.integrate import trapezoid\n    >>> float(trapezoid(SSI, wavelengths))\n    1344.802978\n\n    References\n    ----------\n    .. [1] Meftah, M., L. Damé, D. Bolsée, A. Hauchecorne, N. Pereira, D.\n       Sluse, G. Cessateur, et al. \"SOLAR-ISS: A New Reference Spectrum Based\n       on SOLAR/SOLSPEC Observations.\" Astronomy & Astrophysics 611 (March 1,\n       2018): A1. https://doi.org/10.1051/0004-6361/201731316.\n    .. [2] Woods Thomas N., Chamberlin Phillip C., Harder Jerald W., Hock\n       Rachel A., Snow Martin, Eparvier Francis G., Fontenla Juan, McClintock\n       William E., and Richard Erik C. \"Solar Irradiance Reference Spectra\n       (SIRS) for the 2008 Whole Heliosphere Interval (WHI).\" Geophysical\n       Research Letters 36, no. 1 (January 1, 2009).\n       https://doi.org/10.1029/2008GL036373.\n    \"\"\"\n    if model == \"SOLAR-ISS\":\n        folder = os.path.join(os.path.dirname(__file__), \"data\")\n        pth = os.path.join(folder, \"solar_iss_2018_spectrum.dat\")\n        data = np.genfromtxt(pth, dtype=np.float64, delimiter=\" \")\n        wavelengths, SSI, uncertainties = data[:, 0], data[:, 1], data[:, 2]\n\n        wavelengths *= 1E-9\n        SSI *= 1E9\n\n        # Convert -1 uncertainties to nans\n        uncertainties[uncertainties == -1] = np.nan\n\n        uncertainties *= 1E9\n    return wavelengths, SSI, uncertainties\n\n"
  },
  {
    "path": "ht/units.py",
    "content": "# type: ignore\n\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport types\n\nimport ht\nfrom ht import R_to_k, k_to_R, k_to_thermal_resistivity, thermal_resistivity_to_k\n\n__all__ = [\"u\", \"wraps_numpydoc\"]\n\ntry:\n    from pint import _DEFAULT_REGISTRY as u\n\nexcept ImportError: # pragma: no cover\n    raise ImportError(\"The unit handling in fluids requires the installation \"\n                      \"of the package pint, available on pypi or from \"\n                      \"https://github.com/hgrecco/pint\")\nfrom fluids.units import wraps_numpydoc\n\n__funcs = {}\n\n\nfor name in dir(ht):\n    if name in (\"__getattr__\", \"__test__\"):\n        continue\n    obj = getattr(ht, name)\n    if isinstance(obj, types.FunctionType):\n        obj = wraps_numpydoc(u)(obj)\n    elif isinstance(obj, str):\n        continue\n    if name == \"__all__\":\n        continue\n    __all__.append(name)\n    __funcs.update({name: obj})\n\nglobals().update(__funcs)\n\nwrapped_R_to_k = R_to_k\nwrapped_k_to_R = k_to_R\n\n\ndef R_to_k(R, t, A=1*u.m**2):\n    if R.dimensionality == (u.K/u.W).dimensionality:\n        if A.to_base_units().magnitude != 1:\n            raise ValueError(\"The conversion with R in units of K/W is only permissible if A = 1 length**2\")\n        R = R*u.m**2\n    elif R.dimensionality != (u.K*u.m**2/u.W).dimensionality:\n        raise ValueError(\"Units of R must be either K/W  if A = 1 length**2 or m^2*K/W otherwise\")\n    return wrapped_R_to_k(R, t, A)\n\n# k_to_R(k=0.5*u.W/u.m/u.K, t=0.025*u.m)\n# TODO define behavior\n\ndef R_value_to_k(R_value, SI=True):\n    r = R_value.to(\"m*K/W\")\n    return thermal_resistivity_to_k(r)\n\n\ndef k_to_R_value(k, SI=True):\n    r = k_to_thermal_resistivity(k)\n    if SI:\n        return r.to(\"m^2*K/(W*inch)\")\n    else:\n        return r.to(\"ft^2*delta_degF*hour/(BTU*inch)\")\n"
  },
  {
    "path": "ht/vectorized.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import FakePackage\nfrom fluids.numerics import numpy as np\n\nimport ht\n\n\"\"\"Basic module which wraps all ht functions with numpy's vectorize.\nAll other object - dicts, classes, etc - are not wrapped. Supports star\nimports; so the same objects exported when importing from the main library\nwill be imported from here.\n\n>>> from ht.vectorized import *\n\nInputs do not need to be numpy arrays; they can be any iterable:\n\n>>> import ht.vectorized\n>>> ht.vectorized.LMTD([100, 101], 60., 30., 40.2)\narray([ 43.20040929,  43.60182765])\n\nNote that because this needs to import ht itself, ht.vectorized\nneeds to be imported separately; the following will cause an error:\n\n>>> import ht\n>>> ht.vectorized # Won't work, has not been imported yet\n\nThe correct syntax is as follows:\n\n>>> import ht.vectorized # Necessary\n>>> from ht.vectorized import * # May be used without first importing ht\n\"\"\"\n\n__all__ = []\n\n\n__funcs = {}\n\nif isinstance(np, FakePackage):\n    pass\nelse:\n    import types\n    for name in dir(ht):\n        obj = getattr(ht, name)\n        if isinstance(obj, types.FunctionType):\n            obj = np.vectorize(obj)\n        elif isinstance(obj, str):\n            continue\n        __all__.append(name)\n        __funcs.update({name: obj})\nglobals().update(__funcs)\n\n\n\n\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools>=70.1\", \"wheel\", \"python-minifier\"]\nbuild-backend = \"backend\"\nbackend-path = [\"_custom_build\"]\n\n[project]\nname = \"ht\"\nversion = \"1.2.0\"\ndescription = \"Heat transfer component of Chemical Engineering Design Library (ChEDL)\"\nreadme = \"README.rst\"\nrequires-python = \">=3.9\"\nlicense = {text = \"MIT\"}\nauthors = [\n    {name = \"Caleb Bell\", email = \"Caleb.Andrew.Bell@gmail.com\"}\n]\nkeywords = [\n    \"heat-transfer\", \"heat-exchanger\", \"air-cooler\", \"tube-bank\", \"condensation\",\n    \"boiling\", \"chemical-engineering\", \"mechanical-engineering\", \"pressure-drop\",\n    \"radiation\", \"process-simulation\", \"engineering\", \"insulation\", \"flow-boiling\",\n    \"nucleate-boiling\", \"reboiler\", \"cross-flow\"\n]\nclassifiers = [\n    \"Development Status :: 5 - Production/Stable\",\n    \"Intended Audience :: Developers\",\n    \"Intended Audience :: Education\",\n    \"Intended Audience :: Manufacturing\",\n    \"Intended Audience :: Science/Research\",\n    \"Natural Language :: English\",\n    \"Operating System :: MacOS\",\n    \"Operating System :: Microsoft :: Windows\",\n    \"Operating System :: POSIX\",\n    \"Operating System :: POSIX :: BSD\",\n    \"Operating System :: POSIX :: Linux\",\n    \"Operating System :: Unix\",\n    \"Programming Language :: Python\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Programming Language :: Python :: Implementation :: CPython\",\n    \"Programming Language :: Python :: Implementation :: PyPy\",\n    \"Topic :: Education\",\n    \"Topic :: Scientific/Engineering :: Atmospheric Science\",\n    \"Topic :: Scientific/Engineering :: Chemistry\",\n    \"Topic :: Scientific/Engineering :: Physics\",\n]\ndependencies = [\n    \"fluids>=1.2.0\",\n    \"numpy>=1.5.0\",\n    \"scipy>=1.6.0\"\n]\n\n[project.optional-dependencies]\n# Core testing (what all CI uses)\ntest = [\n    \"pytest>=6.0\",\n    \"pytest-cov\",\n    \"pytest-xdist\",\n    \"sympy\",\n    \"fuzzywuzzy\",\n    \"pint\",\n    \"pytz\",\n    \"pandas\",\n    \"IPython\",\n    \"matplotlib\",\n    \"coveralls\",\n    \"mpmath\",\n    \"wheel\",\n]\n\n# For multiarch CI (lighter, no pandas/matplotlib issues, no coverage for speed)\ntest-multiarch = [\n    \"pytest>=6.0\",\n    \"thefuzz\",\n    \"pint\",\n    \"pytz\",\n    \"wheel\",\n]\n\n# Optional performance boost (installed conditionally in CI)\nnumba = [\n    \"numba\",\n    \"coverage>=7.6.1\",  # Required for numba 0.62+ compatibility\n]\n\n# Documentation\ndocs = [\n    \"sphinx\",\n    \"numpydoc\",\n    \"nbsphinx\",\n    \"ipython\",\n    \"numba\",\n    \"sphinxcontrib-katex\",\n    \"sphinx-sitemap\",\n    \"sphinxcontrib-applehelp\",\n    \"sphinxcontrib-devhelp\",\n    \"sphinxcontrib-htmlhelp\",\n    \"sphinxcontrib-qthelp\",\n    \"sphinxcontrib-serializinghtml\",\n    \"sphinxcontrib.googleanalytics\",\n    \"matplotlib\",\n    \"pint\",\n]\n\n# Linting and type checking\nlint = [\"ruff\", \"mypy\"]\n\n# Pre-release validation\nprerelease = [\n    \"ht[test]\",\n    \"ht[docs]\",\n    \"nbval\",\n    \"jacobi\",\n    \"numdifftools\",\n    \"mpmath\",\n]\n\n# Security scanning (barebones for CI)\nsecurity = [\"pip-audit\", \"bandit\"]\n\n# Local development (everything)\ndev = [\n    \"ht[test,numba,docs,lint,security]\",\n    \"prek\",\n    \"wheel\",\n    \"build\",\n    \"twine\",\n]\n\n[project.urls]\nHomepage = \"https://github.com/CalebBell/ht\"\nDownload = \"https://github.com/CalebBell/ht/tarball/1.2.0\"\n\n[tool.setuptools]\npackages = [\"ht\"]\n\n[tool.setuptools.package-data]\nht = [\"data/*\"]\n\n[tool.coverage.run]\nbranch = true\nrelative_files = true\nomit = []\n\n[tool.coverage.report]\nexclude_lines = [\n    \"pragma: no cover\",\n    \"def __repr__\",\n]\n\n[tool.mypy]\nexclude = [\n    \"^_build/\",\n    \"^_custom_build/\",\n    \"^build/\",\n    \"^dist/\",\n    \".*\\\\.egg-info/\",\n    \"^venv/\",\n    \"^\\\\.venv/\",\n    \"^benchmarks/\",\n    \"^dev/\",\n    \"^notebooks/\",\n]\n\n[[tool.mypy.overrides]]\nmodule = [\n    \"scipy.*\",\n    \"numba.*\",\n    \"mpmath.*\",\n    \"sympy.*\",\n    \"matplotlib.*\",\n    \"geopy.*\",\n    \"appdirs.*\",\n    \"pandas.*\",\n    \"pvlib.*\",\n    \"pint.*\",\n]\nignore_missing_imports = true\n\n[[tool.mypy.overrides]]\nmodule = \"fluids.numerics\"\nfollow_imports = \"skip\"\nignore_errors = true\n\n[[tool.mypy.overrides]]\nmodule = \"fluids.numerics.*\"\nignore_errors = true\n\n[tool.ruff]\nline-length = 160\ntarget-version = \"py37\"\nexclude = [\"*.pyi\"]\n\n[tool.ruff.lint]\nselect = [\"ALL\"]\nextend-ignore = [\n    \"FBT001\",  # boolean positional argument\n    \"PD008\",  # .at with pandas is fine with me\n    \"PD011\",  # Use .values instead of .to_numpy() - I prefer not to copy arrays\n    \"RUF059\",  # Allow unused variables\n    \"FIX002\",  # TODO are OK\n    \"FIX004\",  # HACK is OK\n    \"SIM109\",  # multiple equality comparisons are more performant than a set in small cases\n    \"PLR1714\",  # multiple equality comparisons are more performant than a set in small cases\n    \"D415\",  # First docstring line should end with a period, question mark, or exclamation point\n    \"DTZ004\",  # utcfromtimestamp makes sense for atmosphere model\n    \"PGH003\",  # type ignoring makes sense for numba-related things\n    \"S102\",  # Yes, exec is dangerous but it can be quite useful as well\n    \"PYI056\",  # changing __all__\n    \"RUF012\",  # not using typing today\n    \"PERF403\",  # obvious, use an autofix if one becomes available\n    \"PERF203\",  # `try`-`except` within a loop incurs performance overhead\n    \"PERF401\",  # PERF401 Use a list comprehension to create a transformed list\n    \"PLR1730\",  # use of min/max are less performant than `if\n    \"PLC0415\",  # Allow lazy imports\n    # ht specific\n    \"E701\",  # lots of this here\n    \"S302\",  # marshal is OK\n    \"SIM116\",  # 3 if statements does not require a dict\n    # maybe these\n    \"PLE0605\",\n    \"PLE0604\",\n    \"TD002\", \"TD003\", \"TD004\", \"TD005\",\n    # Originally from astropy's pyproject.toml, see about removing many of them later\n    \"A00\",\n    \"ANN\",\n    \"ARG001\", \"ARG002\", \"ARG005\",\n    \"B004\",\n    \"B006\",\n    \"B007\",\n    \"B008\",\n    \"B904\",\n    \"BLE001\",\n    \"C408\", \"C416\",\n    \"C901\",\n    \"COM812\",\n    \"COM819\",\n    \"D101\",\n    \"D102\",\n    \"D103\",\n    \"D105\",\n    \"D107\",\n    \"D200\",\n    \"D203\",\n    \"D205\",\n    \"D212\", \"D213\",\n    \"D403\",\n    \"D404\",\n    \"D400\",\n    \"D401\",\n    \"D413\",\n    \"D414\",\n    \"D417\",\n    \"DTZ001\", \"DTZ007\",\n    \"E501\",\n    # \"E711\",\n    \"E721\",\n    \"E731\",\n    \"E741\",\n    \"EM\",\n    \"ERA001\",\n    \"F841\",\n    \"E722\",\n    \"FBT002\", \"FBT003\",\n    \"N8\",\n    \"PLR2004\",\n    \"PLR0911\",\n    \"PLR0912\",\n    \"PLR5501\",\n    \"PLR0913\",\n    \"PLR0915\",\n    \"PLW2901\",\n    \"PLW0603\",\n    \"PTH\",\n    \"RET\",\n    \"RSE102\",\n    \"RUF001\",\n    \"RUF003\",  # greek characters are used in this project e.g. for allotropes\n    \"RUF005\",  # this one is not micropython compatible\n    # \"S101\",  # Use assert - removed from global ignore, now controlled by per-file-ignores below\n    \"S110\",\n    \"S112\",\n    \"S311\",\n    \"S310\",\n    \"SIM102\",\n    \"SIM105\",\n    \"SIM108\",\n    \"SIM114\",\n    \"SIM115\",\n    \"SIM118\",\n    \"SIM300\",\n    \"SLF001\",\n    \"T201\",\n    \"TRY003\",\n    \"TRY201\",\n    \"TRY300\",\n    \"TRY301\",\n    \"PYI024\",  # PYI024 Use `typing.NamedTuple` instead of `collections.namedtuple\n]\n\n[tool.ruff.lint.mccabe]\nmax-complexity = 10\n\n[tool.ruff.lint.per-file-ignores]\n# Allow asserts and star imports in test files\n\"tests/**/*.py\" = [\"S101\", \"F403\", \"F405\", \"PT011\", \"B017\", \"TRY002\"]  # asserts, star imports, broad exceptions OK in tests\n\"**/test_*.py\" = [\"S101\", \"F403\", \"F405\", \"PT011\", \"B017\", \"TRY002\"]\n# Allow asserts and star imports in documentation examples\n\"docs/**/*.py\" = [\"S101\", \"F403\", \"F405\", \"PT011\", \"B017\", \"TRY002\"]\n\"docs/**/*.ipynb\" = [\"S101\", \"F403\", \"F405\", \"PT011\", \"B017\", \"TRY002\"]\n\n[tool.pytest.ini_options]\naddopts = \"--doctest-glob='*.rst' --ignore='conf.py'\"\nnorecursedirs = [\".cache\", \".git\", \"htmlcov\", \"notebooks\", \"dist\", \"build\", \"*.egg-info\", \".tox\", \"surfaces\", \"prof\", \"benchmarks\", \"dev\", \"_build\", \"_custom_build\", \"__pycache__\", \"plots\"]\ndoctest_optionflags = [\"NORMALIZE_WHITESPACE\"]\nmarkers = [\n    \"slow: slow tests\",\n    \"thermo: relies on the thermo library, for integration testing\",\n    \"online: needs internet\",\n    \"mpmath: needs mpmath to check results against a higher-precision result\",\n    \"fuzz: test not relevant to normal development, but can reveal bugs or provide certainty the results are correct\",\n    \"numba: numba\",\n    \"scipy: Needs scipy to work\",\n    \"numpy: Needs numpy to work\",\n    \"pytz: Needs pytz to work\",\n]\n"
  },
  {
    "path": "requirements_security.txt",
    "content": "numpy>=1.5.0\nscipy>=1.6.0\nfluids>=1.2.0"
  },
  {
    "path": "tests/test_air_cooler.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.constants import foot, hp, inch, minute\nfrom fluids.geometry import AirCooledExchanger\nfrom fluids.numerics import assert_close, assert_close2d\n\nfrom ht import (\n    Ft_aircooler,\n    air_cooler_noise_GPSA,\n    air_cooler_noise_Mukherjee,\n    dP_ESDU_high_fin,\n    dP_ESDU_low_fin,\n    h_Briggs_Young,\n    h_ESDU_high_fin,\n    h_ESDU_low_fin,\n    h_Ganguli_VDI,\n)\n\n### Air Cooler\n\ndef test_air_cooler_Ft():\n    Ft_1 = Ft_aircooler(Thi=93, Tho=52, Tci=35, Tco=54.59, Ntp=2, rows=4)\n    assert_close(Ft_1, 0.9570456123827129)\n\n    # Example 2 as in [1]_; author rounds to obtain a slightly different result.\n    Ft_2 = Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4)\n    assert_close(Ft_2, 0.5505093604092708)\n    Ft_many = [[Ft_aircooler(Thi=125., Tho=80., Tci=25., Tco=95., Ntp=i, rows=j) for i in range(1,6)] for j in range(1, 6)]\n    Ft_values = [[0.6349871996666123, 0.9392743008890244, 0.9392743008890244, 0.9392743008890244, 0.9392743008890244], [0.7993839562360742, 0.9184594715750571, 0.9392743008890244, 0.9392743008890244, 0.9392743008890244], [0.8201055328279105, 0.9392743008890244, 0.9784008071402877, 0.9392743008890244, 0.9392743008890244], [0.8276966706732202, 0.9392743008890244, 0.9392743008890244, 0.9828365967034366, 0.9392743008890244], [0.8276966706732202, 0.9392743008890244, 0.9392743008890244, 0.9392743008890244, 0.9828365967034366]]\n    assert_close2d(Ft_many, Ft_values)\n\n\ndef test_air_cooler_noise_GPSA():\n    noise = air_cooler_noise_GPSA(tip_speed=3177/minute, power=25.1*hp)\n    assert_close(noise, 100.53680477959792)\n\n\ndef test_air_cooler_noise_Mukherjee():\n    \"\"\"# Confirmed to be log10's because of example tip speed reduction\n    # of 60 m/s to 40 m/s saves 5.3 dB.\n    # hp in shaft horse power\n    # d in meters\n    # sound pressure level, ref level 2E-5 pa\n\n    \"\"\"\n    noise = air_cooler_noise_Mukherjee(tip_speed=3177/minute, power=25.1*hp, fan_diameter=4.267)\n    assert_close(noise, 99.11026329092925)\n\n    noise = air_cooler_noise_Mukherjee(tip_speed=3177/minute, power=25.1*hp, fan_diameter=4.267, induced=True)\n    assert_close(noise, 96.11026329092925)\n\n\ndef test_h_ESDU_high_fin():\n\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=20, tube_length=3,\n                            tube_diameter=1*inch, fin_thickness=0.000406, fin_density=1/0.002309,\n                            pitch_normal=.06033, pitch_parallel=.05207,\n                            fin_height=0.0159, tube_thickness=(.0254-.0186)/2,\n                            bundles_per_bay=1, parallel_bays=1, corbels=True)\n    h_bare_tube_basis = h_ESDU_high_fin(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n                         A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n                         fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n                         fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n                         pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel,\n                         rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205.0)\n    assert_close(h_bare_tube_basis, 1390.888918049757)\n\n\ndef test_h_ESDU_low_fin():\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n    tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n                        pitch_normal=0.0313, pitch_parallel=0.0271,\n    fin_height=0.0041,\n   bundles_per_bay=1, parallel_bays=1, corbels=True)\n\n    # All factors are matching again, except for the A min being different!\n    # 5% diff, minor.\n\n    h = h_ESDU_low_fin(m=0.914, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n         A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n         fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n         fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n         pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel,\n         rho=1.217, Cp=1007., mu=1.8E-5, k=0.0253, k_fin=15.0)\n\n    assert_close(h, 553.853836470948)\n\n    h = h_ESDU_low_fin(m=0.914, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n         A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n         fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n         fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n         pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel,\n         rho=1.217, Cp=1007., mu=1.8E-5, k=0.0253, k_fin=15.0, Pr_wall=0.68)\n\n    assert_close(h, 560.74807767957759)\n\ndef test_h_Briggs_Young():\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=20, tube_length=3,\n                        tube_diameter=1*inch, fin_thickness=0.000406, fin_density=1/0.002309,\n                        pitch_normal=.06033, pitch_parallel=.05207,\n                        fin_height=0.0159, tube_thickness=(.0254-.0186)/2,\n                        bundles_per_bay=1, parallel_bays=1, corbels=True)\n\n    h_bare_tube_basis = h_Briggs_Young(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n                             A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n                             fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n                             fin_thickness=AC.fin_thickness,\n                             rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205.)\n    assert_close(h_bare_tube_basis, 1422.8722403237716)\n\n    # Serth Process Heat Transfer Principles, Applications and Rules of Thumb\n    # example with a different correlation entirely\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=56, tube_length=36*foot,\n                            tube_diameter=1*inch, fin_thickness=0.013*inch, fin_density=10/inch,\n                            angle=30, pitch_normal=2.5*inch, fin_height=0.625*inch, corbels=True)\n\n    h = h_Briggs_Young(m=130.70315, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n                 A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n                 fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n                 fin_thickness=AC.fin_thickness,\n                 rho=1.2013848, Cp=1009.0188, mu=1.9304793e-05, k=0.027864828, k_fin=238)\n\n    # Goal. 51.785762\n    # Back converting to their choice of basis - finned heat transfer coefficient\n    # Very close answer\n    assert_close(h/AC.A_increase/.853,  51.785762, atol=.3)\n\n\n\ndef test_h_Ganguli_VDI():\n\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=56, tube_length=36*foot,\n                            tube_diameter=1*inch, fin_thickness=0.013*inch, fin_density=10/inch,\n                            angle=30, pitch_normal=2.5*inch, fin_height=0.625*inch, corbels=True)\n\n    h = h_Ganguli_VDI(m=130.70315, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n                 A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n                 fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n                 fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n                pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal,\n                 rho=1.2013848, Cp=1009.0188, mu=1.9304793e-05, k=0.027864828, k_fin=238.0)\n    assert_close(h, 969.2850818578595)\n\n    # Example in VDI\n    # assumed in-line = angle 45, rest specified\n    # VDI misses some parameters like fin tip area\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=1, tubes_per_row=17, tube_length=0.98,\n                            tube_diameter=1*inch, fin_thickness=0.4E-3, fin_density=9/inch,\n                            angle=45, pitch_normal=0.06, fin_diameter=0.056)\n\n    # Pr forced to match\n    h = h_Ganguli_VDI(m=1.92, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n                 A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n                 fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n                 fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n                pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal,\n                 rho=0.909, Cp=1009.0188, mu=2.237e-05, k=0.03197131806799132, k_fin=209.0)\n    # 22.49 goal, but there was a correction for velocity due to temperature increase\n    # in the vdi answer\n    assert_close(h/AC.A_increase, 22.49, rtol=2e-2)\n\n\ndef test_dP_ESDU_high_fin():\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n        tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n        pitch_normal=0.0313, pitch_parallel=0.0271, fin_height=0.0041, corbels=True)\n\n    dP = dP_ESDU_high_fin(m=0.914, A_min=AC.A_min, A_increase=AC.A_increase, flow_area_contraction_ratio=AC.flow_area_contraction_ratio, tube_diameter=AC.tube_diameter, pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal, tube_rows=AC.tube_rows, rho=1.217,  mu=0.000018)\n    assert_close(dP, 485.6307687791502)\n\n\ndef test_dP_ESDU_low_fin():\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=8, tube_length=0.5,\n        tube_diameter=0.0164, fin_thickness=0.001, fin_density=1/0.003,\n        pitch_normal=0.0313, pitch_parallel=0.0271, fin_height=0.0041, corbels=True)\n\n    dP = dP_ESDU_low_fin(m=0.914, A_min=AC.A_min, A_increase=AC.A_increase, flow_area_contraction_ratio=AC.flow_area_contraction_ratio,\n                     tube_diameter=AC.tube_diameter, fin_height=AC.fin_height, bare_length=AC.bare_length, pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal, tube_rows=AC.tube_rows, rho=1.217,  mu=0.000018)\n    assert_close(dP, 464.54331418655914)\n    # vs 414 Pa; Kf, ka almost perfect - A_min is the source of difference\n\n\n@pytest.mark.slow\n@pytest.mark.fuzz\ndef test_AirCooledExchangerPermutations():\n    \"\"\"Demonstration of permutating all sorts of different options.\n\n    need to try both nonlinear optimization (will work easier, need initial guesses)\n    and some form of discrete problem solution space.\n    2 billion - that's just as many as there are floats! :)\n\n    (len(tube_rows_options)*len(tube_passes_options)*len(tubes_per_row_options)\n     *len(HTRI_Ls)*len(pitches)*len(fin_densities)\n     *len(fin_heights)*len(ODs)*len(angles)\n     *len(fin_thicknesses))/2.**31#15E-6/3600\n\n    \"\"\"\n    from random import choice\n\n    tube_rows_options = range(1, 20)\n    tube_passes_options = range(1, 20)\n    tubes_per_row_options = range(1, 40)\n\n    from ht.air_cooler import ODs, fin_densities, fin_heights\n    from ht.hx import HEDH_pitches, HTRI_Ls\n    angles = [30, 45, 60, 90]\n    pitches = sorted({j for k in HEDH_pitches.values() for j in k})\n    pitches = [1.25, 1.312, 1.33, 1.375, 1.4, 1.5]\n\n    fin_thicknesses = [3E-4, 4E-4, 5E-4, 6E-4, 7E-4] # made up\n\n    for i in range(100):\n        angle = choice(angles)\n        pitch = choice(pitches)\n        tube_length = choice(HTRI_Ls)\n        fin_density = choice(fin_densities)\n        fin_height = choice(fin_heights)\n        fin_thickness = choice(fin_thicknesses)\n        tube_diameter = choice(ODs)\n\n        tube_rows = choice(tube_rows_options)\n        tube_passes = choice(tube_passes_options)\n        tubes_per_row = choice(tubes_per_row_options)\n\n        AC = AirCooledExchanger(tube_rows=tube_rows, tube_passes=tube_passes,\n                                tubes_per_row=tubes_per_row, tube_length=tube_length,\n                            tube_diameter=tube_diameter, fin_thickness=fin_thickness, fin_density=fin_density,\n                            angle=angle, pitch=pitch, fin_height=fin_height)\n\n"
  },
  {
    "path": "tests/test_boiling_flow.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close\n\nfrom ht.boiling_flow import Chen_Bennett, Chen_Edelstein, Lazarek_Black, Li_Wu, Liu_Winterton, Sun_Mishima, Thome, Yun_Heo_Kim\n\n\ndef test_Lazarek_Black():\n    q = 1E7\n    h1 = Lazarek_Black(m=10.0, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6, q=q)\n    Te = q/h1\n    assert_close(h1, 51009.87001967105)\n    h2 = Lazarek_Black(m=10.0, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6, Te=Te)\n    assert_close(h1, h2)\n\n    with pytest.raises(Exception):\n        Lazarek_Black(m=10, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6)\n    \"\"\"\n    The code to derive the form with `Te` specified is\n    as follows:\n\n    >>> from sympy import *\n    >>> Relo, Bgish, kl, D, h, Te = symbols('Relo, Bgish, kl, D, h, Te',\n    ... positive=True, real=True)\n    >>> solve(Eq(h, 30*Relo**Rational(857,1000)*(Bgish*h*Te)**Rational(714,\n    ... 1000)*kl/D), h)\n    [27000*30**(71/143)*Bgish**(357/143)*Relo**(857/286)*Te**(357/143)*kl**(500/143)/D**(500/143)]\n    \"\"\"\n\n\ndef test_Li_Wu():\n    q = 1E5\n    h = Li_Wu(m=1.0, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, q=q)\n    Te = 1E5/h\n    assert_close(h, 5345.409399239493)\n    h2 = Li_Wu(m=1, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, Te=Te)\n    assert_close(h2, h)\n\n    with pytest.raises(Exception):\n         Li_Wu(m=1, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5)\n\n    \"\"\"\n    The code to derive the form with `Te` specified is\n    as follows:\n\n    >>> from sympy import *\n    >>> h, A, Te, G, Hvap = symbols('h, A, Te, G, Hvap', positive=True, real=True)\n    >>> solve(Eq(h, A*(h*Te/G/Hvap)**0.3), h)\n    [A**(10/7)*Te**(3/7)/(G**(3/7)*Hvap**(3/7))]\n    \"\"\"\n\ndef test_Sun_Mishima():\n    h = Sun_Mishima(m=1.0, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, Te=10)\n    assert_close(h, 507.6709168372167)\n\n    q = 1E5\n    h = Sun_Mishima(m=1, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, q=q)\n    Te = q/h\n    h2 = Sun_Mishima(m=1, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, Te=Te)\n    assert_close(h, h2)\n    assert_close(h2, 2538.4455424345983)\n\n    with pytest.raises(Exception):\n        Sun_Mishima(m=1, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5)\n\n    \"\"\"\n    The code to derive the form with `Te` specified is\n    as follows:\n\n    >>> from sympy import *\n    >>> h, A, Te, G, Hvap = symbols('h, A, Te, G, Hvap', positive=True, real=True)\n    >>> solve(Eq(h, A*(h*Te/G/Hvap)**0.54), h)\n    [A**(50/23)*Te**(27/23)/(G**(27/23)*Hvap**(27/23))]\n    \"\"\"\n\ndef test_Thome():\n    h = Thome(m=1.0, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300.0, Cpg=1400, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, q=1E5)\n    assert_close(h, 1633.008836502032)\n\n    h = Thome(m=10, x=0.5, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300.0, Cpg=1400.0, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, q=1E5)\n    assert_close(h, 3120.1787715124824)\n\n    Te = 32.04944566414243\n    h2 = Thome(m=10.0, x=0.5, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300.0, Cpg=1400.0, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, Te=Te)\n    assert_close(h, h2)\n\n    with pytest.raises(Exception):\n        Thome(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300., Cpg=1400., sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6)\n\n\ndef test_Yun_Heo_Kim():\n    q = 1E4\n    h1 = Yun_Heo_Kim(m=1.0, x=0.4, D=0.3, rhol=567., mul=156E-6, sigma=0.02, Hvap=9E5, q=q)\n    Te = q/h1\n    h2 = Yun_Heo_Kim(m=1, x=0.4, D=0.3, rhol=567., mul=156E-6, sigma=0.02, Hvap=9E5, Te=Te)\n    assert_close(h1, h2)\n\n    with pytest.raises(Exception):\n        Yun_Heo_Kim(m=1, x=0.4, D=0.3, rhol=567., mul=156E-6, sigma=0.02, Hvap=9E5)\n\n    \"\"\"\n    The code to derive the form with `Te` specified is\n    as follows:\n\n    >>> from sympy import *\n    >>> h, A = symbols('h, A', positive=True, real=True)\n    >>> solve(Eq(h, A*(h)**0.1993), h)\n    [A**(10000/8707)]\n    \"\"\"\n\ndef test_Liu_Winterton():\n    h = Liu_Winterton(m=1.0, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, Cpl=2300.0, P=1E6, Pc=22E6, MW=44.02, Te=7.0)\n    assert_close(h, 4747.749477190532)\n\ndef test_Chen_Edelstein():\n    # Odd numbers for the test case from Serth, but not actually compared to\n    # anything.\n    h = Chen_Edelstein(m=0.106, x=0.2, D=0.0212, rhol=567.0, rhog=18.09, mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730.0, Hvap=2E5, sigma=0.02, dPsat=1E5, Te=3.0)\n    assert_close(h, 3289.058731974052)\n\n\ndef test_Chen_Bennett():\n    h = Chen_Bennett(m=0.106, x=0.2, D=0.0212, rhol=567.0, rhog=18.09, mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730.0, Hvap=2E5, sigma=0.02, dPsat=1E5, Te=3.0)\n    assert_close(h, 4938.275351219369)\n"
  },
  {
    "path": "tests/test_boiling_nucleic.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d\n\nfrom ht import (\n    Bier,\n    Cooper,\n    Forster_Zuber,\n    Gorenflo,\n    HEDH_Montinsky,\n    HEDH_Taborek,\n    McNelly,\n    Montinsky,\n    Rohsenow,\n    Serth_HEDH,\n    Stephan_Abdelsalam,\n    Zuber,\n    h_nucleic,\n    h_nucleic_methods,\n    qmax_boiling,\n    qmax_boiling_methods,\n)\n\n### Nucleic boiling\n\n\ndef test_boiling_nucleic_Rohsenow():\n    # Checked with 10.30 Problem set 8.\n    h_calc = [Rohsenow(Te=i, Cpl=4180, kl=0.688, mul=2.75E-4, sigma=0.0588, Hvap=2.25E6, rhol=958, rhog=0.597, Csf=0.013, n=1) for i in [4.3, 9.1, 13]]\n    h_values = [2860.6242230238613, 12811.697777642301, 26146.321995188344]\n    assert_close1d(h_calc, h_values)\n    q_test = Rohsenow(Te=4.9, Cpl=4217., kl=0.680, mul=2.79E-4, sigma=0.0589, Hvap=2.257E6, rhol=957.854, rhog=0.595593, Csf=0.011, n=1.26)*4.9\n    assert_close(18245.91080863059, q_test)\n\n    h_Te = 1316.2269561541964\n    h_q = Rohsenow(q=5*h_Te, Cpl=4180, kl=0.688, mul=2.75E-4, sigma=0.0588, Hvap=2.25E6, rhol=958, rhog=0.597)\n    assert_close(h_Te, h_q)\n\n    with pytest.raises(Exception):\n        Rohsenow(Cpl=4180, kl=0.688, mul=2.75E-4, sigma=0.0588, Hvap=2.25E6, rhol=958, rhog=0.597)\n\n\ndef test_boiling_nucleic_McNelly():\n    # Water matches expectations, ammonia is somewhat distant. Likely just\n    # error in the text's calculation.\n    h_McNelly1 = McNelly(Te=4.3, P=101325, Cpl=4180., kl=0.688, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    h_McNelly2 = McNelly(Te=9.1, P=101325, Cpl=4472., kl=0.502, sigma=0.0325, Hvap=1.37E6, rhol=689., rhog=0.843)\n    assert_close1d([h_McNelly1, h_McNelly2], [533.8056972951352, 6387.3951029225855])\n    # Check the the solution with q gives the same h\n    h_Te = 533.8056972951352\n    h_q= McNelly(q=4.3*h_Te, P=101325, Cpl=4180., kl=0.688, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    assert_close(h_Te, h_q)\n    with pytest.raises(Exception):\n        McNelly(P=101325, Cpl=4472., kl=0.502, sigma=0.0325, Hvap=1.37E6, rhol=689., rhog=0.843)\n\n\ndef test_boiling_nucleic_Forster_Zuber():\n    # All examples are for water from [1]_ and match.\n    # 4th example is from [3]_ and matches completely.\n    FZ1 = Forster_Zuber(Te=4.3, dPsat=3906*4.3, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    FZ2 = Forster_Zuber(Te=9.1, dPsat=3906*9.1, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    FZ3 = Forster_Zuber(Te=13, dPsat=3906*13, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    FZ4 = Forster_Zuber(Te=16.2, dPsat=106300., Cpl=2730., kl=0.086, mul=156E-6, sigma=.0082, Hvap=272E3, rhol=567., rhog=18.09)\n    FZ_values = [3519.9239897462644, 7393.507072909551, 10524.54751261952, 5512.279068294656]\n    assert_close1d([FZ1, FZ2, FZ3, FZ4], FZ_values)\n    h_Te = 3519.9239897462644\n    h_q = Forster_Zuber(q=4.3*h_Te, dPsat=3906*4.3, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n    assert_close(h_Te, h_q)\n    with pytest.raises(Exception):\n         Forster_Zuber(dPsat=3906*4.3, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597)\n\n\ndef test_boiling_nucleic_Montinsky():\n    # Fourth example is from [4]_ and matches to within the error of the algebraic\n    # manipulation rounding.\n    # First three examples are for water, ammonia, and benzene, from [1]_, and\n    # match to within 20%.\n    W_Te = [Montinsky(Te=i, P=101325., Pc=22048321.0) for i in [4.3, 9.1, 13]]\n    W_Te_values = [1185.0509770292663, 6814.079848742471, 15661.924462897328]\n    assert_close1d(W_Te, W_Te_values)\n    A_Te = [Montinsky(Te=i, P=101325., Pc=112E5) for i in [4.3, 9.1, 13]]\n    A_Te_values = [377.04493949460635, 2168.0200886557072, 4983.118427770712]\n    assert_close1d(A_Te, A_Te_values)\n    B_Te = [Montinsky(Te=i, P=101325., Pc=48.9E5) for i in [4.3, 9.1, 13]]\n    B_Te_values = [96.75040954887533, 556.3178536987874, 1278.6771501657056]\n    assert_close1d(B_Te, B_Te_values)\n    assert_close(Montinsky(310.3E3, 2550E3, 16.2), 2423.2656339862583)\n\n    h_Te = 1185.0509770292663\n    h_q = Montinsky(q=4.3*h_Te, P=101325., Pc=22048321.0)\n    assert_close(h_Te, h_q)\n    with pytest.raises(Exception):\n        Montinsky(P=101325., Pc=22048321.0)\n\n\ndef test_boiling_nucleic_Stephan_Abdelsalam():\n    # Stephan Abdelsalam function; allow bad function method\n    Stephan_Abdelsalam(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6,  sigma=0.0082, Hvap=272E3, rhol=567.0, rhog=18.09, angle=35.0, correlation=\"fail\")\n\n    cs = [\"general\", \"water\", \"hydrocarbon\", \"cryogenic\", \"refrigerant\"]\n    h_SA = [Stephan_Abdelsalam(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, correlation=i) for i in cs]\n    h_values = [26722.441071108373, 30571.788078886435, 21009.03422203015, 3548.8050360907037, 84657.98595551957]\n    assert_close1d(h_SA, h_values)\n\n    h_qs = []\n    for h, c in zip(h_values, cs):\n        h_qs.append(Stephan_Abdelsalam(q=16.2*h, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567.0, rhog=18.09, correlation=c))\n    assert_close1d(h_qs, h_values)\n\n    with pytest.raises(Exception):\n        Stephan_Abdelsalam(Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6,  sigma=0.0082, Hvap=272E3, rhol=567.0, rhog=18.09)\n\n\ndef test_boiling_nucleic_HEDH_Taborek():\n    h = HEDH_Taborek(Te=16.2, P=310.3E3, Pc=2550E3)\n    assert_close(h, 1397.272486525486)\n\n    h_q = HEDH_Taborek(P=310.3E3, Pc=2550E3, q=16.2*1397.272486525486)\n    assert_close(h, h_q)\n\n    with pytest.raises(Exception):\n        HEDH_Taborek(P=310.3E3, Pc=2550E3)\n\n\ndef test_boiling_nucleic_Bier():\n    h_W = [Bier(Te=i, P=101325., Pc=22048321.0) for i in [4.3, 9.1, 13]]\n    h_W_values = [1290.5349471503353, 7420.6159464293305, 17056.026492351128]\n    assert_close1d(h_W, h_W_values)\n    h_B = [Bier(101325., 48.9E5, i) for i in [4.3, 9.1, 13]]\n    h_B_values = [77.81190344679615, 447.42085661013226, 1028.3812069865799]\n    assert_close1d(h_B, h_B_values)\n\n    h_Te = 1290.5349471503353\n    h_q = Bier(101325., 22048321.0, q=4.3*h_Te)\n    assert_close(h_Te, h_q)\n\n    with pytest.raises(Exception):\n        Bier(P=310.3E3, Pc=2550E3)\n\n\ndef test_boiling_nucleic_Cooper():\n    h_W = [Cooper(Te=i, P=101325., Pc=22048321.0, MW=18.02) for i in [4.3, 9.1, 13]]\n    h_W_values = [1558.1435442153575, 7138.700876530947, 14727.09551225091]\n    assert_close1d(h_W, h_W_values)\n    h_B = [Cooper(101325., 48.9E5, 78.11184, i) for i in [4.3, 9.1, 13]]\n    h_B_values = [504.57942247904055, 2311.7520711767947, 4769.130145905329]\n    assert_close1d(h_B, h_B_values)\n\n    h_Te = 1558.1435442153575\n    h_q = Cooper(P=101325., Pc=22048321.0, MW=18.02, q=h_Te*4.3)\n    assert_close(h_Te, h_q)\n\n    with pytest.raises(Exception):\n        Cooper(P=101325., Pc=22048321.0, MW=18.02)\n\n\ndef test_Gorenflo():\n    # water case, boiling at 3 bar\n    q = 2E4\n    h1 = Gorenflo(P=3E5, Pc=22048320., q=q, CASRN=\"7732-18-5\")\n    assert_close(h1, 3043.344595525422)\n    Te = q/h1\n    h2 = Gorenflo(P=3E5, Pc=22048320., Te=Te, CASRN=\"7732-18-5\")\n    assert_close(h1, h2)\n\n    # Ethanol case, boiling at 3 bar\n    q = 2E4\n    h1 = Gorenflo(P=3E5, Pc=6137000., q=q, CASRN=\"64-17-5\")\n    Te = q/h1\n    assert_close(h1, 3101.133553596696)\n    h2 = Gorenflo(P=3E5, Pc=6137000., Te=Te, CASRN=\"64-17-5\")\n    assert_close(h1, h2)\n\n    # Custom h0 case\n    h = Gorenflo(3E5, 6137000., q=2E4, h0=3700.0)\n    assert_close(h, 2607.771397342676)\n\n    with pytest.raises(Exception):\n        # Case with a CAS number not in the database\n        Gorenflo(3E5, 6137000., q=2E4, CASRN=\"6400-17-5\")\n    with pytest.raises(Exception):\n        # Case with neither Te or q provided:\n        Gorenflo(3E5, 6137000., CASRN=\"64-17-5\")\n\n\ndef test_h_nucleic():\n    h = h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Method=\"Rohsenow\")\n    assert_close(h, 1094.0242011089285)\n\n    h = h_nucleic(Te=4.3, P=101325.0, Cpl=4180., kl=0.688, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597, Method=\"McNelly\")\n    assert_close(h, 533.8056972951352)\n\n    h = h_nucleic(Te=4.3, dPsat=3906*4.3, Cpl=4180., kl=0.688, mul=0.275E-3, sigma=0.0588, Hvap=2.25E6, rhol=958., rhog=0.597, Method=\"Forster-Zuber\")\n    assert_close(h, 3519.9239897462644)\n\n    h = h_nucleic(P=101325, Pc=22048321, Te=4.3, Method=\"Montinsky\")\n    assert_close(h, 1185.0509770292663)\n\n    h = h_nucleic(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, Method=\"Stephan-Abdelsalam\")\n    assert_close(h, 26722.441071108373)\n\n    h = h_nucleic(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, Method=\"Stephan-Abdelsalam water\", CAS=\"7732-18-5\")\n    assert_close(h, 30571.788078886435)\n\n    h = h_nucleic(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, Method=\"Stephan-Abdelsalam cryogenic\", CAS=\"1333-74-0\")\n    assert_close(h, 3548.8050360907037)\n\n    h = h_nucleic(Te=16.2, P=310.3E3, Pc=2550E3, Method=\"HEDH-Taborek\")\n    assert_close(h, 1397.272486525486)\n\n    h = h_nucleic(P=101325., Pc=22048321.0, Te=4.3, Method=\"Bier\")\n    assert_close(h, 1290.5349471503353)\n\n    h = h_nucleic(P=101325., Pc=22048321.0, MW=18.02, Te=4.3, Method=\"Cooper\")\n    assert_close(h, 1558.1435442153575)\n\n    h = h_nucleic(P=3E5, Pc=22048320., q=2E4, CAS=\"7732-18-5\", Method=\"Gorenflo (1993)\")\n    assert_close(h, 3043.344595525422)\n\n    # Test the kwargs\n    h = h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Method=\"Rohsenow\", Csf=0.011, n=1.26)\n    assert_close(h, 3723.655267067467)\n\n\n    # methods\n    methods = h_nucleic_methods(P=101325., Pc=22048321.0, MW=18.02, dPsat=3906*4.3, Tsat=437.5, CAS=\"7732-18-5\", rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9)\n    assert len(methods) == 10\n\n    methods = h_nucleic_methods(Te=16.2, Tsat=437.5, Cpl=2730., kl=0.086, mul=156E-6, sigma=0.0082, Hvap=272E3, rhol=567, rhog=18.09, CAS=\"1333-74-0\")\n    assert len(methods) == 3\n\n    with pytest.raises(Exception):\n        h_nucleic(P=101325., Pc=22048321.0, Te=4.3, Method=\"BADMETHOD\")\n\n    with pytest.raises(Exception):\n        h_nucleic()\n\n    # test the default method\n    h = h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9)\n    assert_close(h, 1094.0242011089285)\n\n\ndef test_qmax_Zuber():\n    q_calc_ex = Zuber(sigma=8.2E-3, Hvap=272E3, rhol=567.0, rhog=18.09, K=0.149)\n    assert_close(q_calc_ex, 444307.22304342285)\n    q_max = Zuber(8.2E-3, 272E3, 567, 18.09, 0.18)\n    assert_close(q_max, 536746.9808578263)\n\n\ndef test_qmax_Serth_HEDH():\n    qmax = Serth_HEDH(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567.0, rhog=18.09)\n    assert_close(qmax, 351867.46522901946)\n    # Test K calculated as a function of R\n    qmax = Serth_HEDH(0.00127, 8.2E-3, 272E3, 567, 18.09)\n    assert_close(qmax, 440111.4740326096)\n\n\ndef test_HEDH_Montinsky():\n    assert_close(HEDH_Montinsky(310.3E3, 2550E3), 398405.66545181436)\n\n\ndef test_qmax_nucleic():\n    q = qmax_boiling(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    assert_close(q, 351867.46522901946)\n\n    q = qmax_boiling(sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09, Method=\"Zuber\")\n    assert_close(q, 536746.9808578263)\n\n    q = qmax_boiling(P=310.3E3, Pc=2550E3)\n    assert_close(q, 398405.66545181436)\n\n    with pytest.raises(Exception):\n        qmax_boiling(D=0.0127)\n    with pytest.raises(Exception):\n        qmax_boiling(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09, Method=\"BADMETHOD\")\n\n\n    methods = qmax_boiling_methods(P=310.3E3, Pc=2550E3, D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    assert len(methods) == 3\n"
  },
  {
    "path": "tests/test_boiling_plate.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close\n\nfrom ht import h_boiling_Amalfi, h_boiling_Han_Lee_Kim, h_boiling_Huang_Sheer, h_boiling_Lee_Kang_Kim, h_boiling_Yan_Lin\n\n\ndef test_h_boiling_Amalfi():\n    h = h_boiling_Amalfi(m=3E-5, x=.4, Dh=0.00172, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=7.11E-6, sigma=0.02, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    assert_close(h, 776.0781179096225)\n\n    h = h_boiling_Amalfi(m=3E-5, x=.4, Dh=0.0172, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=7.11E-6, sigma=0.02, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    assert_close(h, 527.4075513650002)\n\n\ndef test_h_boiling_Lee_Kang_Kim():\n    h = h_boiling_Lee_Kang_Kim(m=3E-5, x=.4, D_eq=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=9E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    assert_close(h, 1229.6271295086806)\n\n    h = h_boiling_Lee_Kang_Kim(m=3E-5, x=.1, D_eq=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=9E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    assert_close(h, 4211.51881493242)\n\ndef test_h_boiling_Han_Lee_Kim():\n    h = h_boiling_Han_Lee_Kim(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6,  Hvap=9E5, Cpl=2200.0, q=1E5, A_channel_flow=0.0003, wavelength=3.7E-3, chevron_angle=45)\n    assert_close(h, 675.7322255419421)\n\n    # Eldeeb said in the Ge1, Ge2 terms it should be b/Dh but the original and\n    # four others agree it's wavelength\n\n    # Solotych has pi*beta/180 which is the same just written differently\n    # Garcia-Cascales documents the original correctly\n\n\ndef test_h_boiling_Huang_Sheer():\n    h = h_boiling_Huang_Sheer(rhol=567., rhog=18.09, kl=0.086, mul=156E-6, Hvap=9E5, sigma=0.02, Cpl=2200.0, q=1E4, Tsat=279.15)\n    assert_close(h, 4401.055635078054)\n\ndef test_h_boiling_Yan_Lin():\n    h = h_boiling_Yan_Lin(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09,  kl=0.086, Cpl=2200.0, mul=156E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003)\n    assert_close(h, 318.7228565961241)\n"
  },
  {
    "path": "tests/test_condensation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom math import pi\n\nfrom fluids import Prandtl\nfrom fluids.numerics import assert_close, assert_close1d, linspace\n\nfrom ht import Akers_Deans_Crosser, Boyko_Kruzhilin, Cavallini_Smith_Zecchin, Nusselt_laminar, Shah, h_kinetic\n\n### Condensation\n\ndef test_h_Nusselt_laminar():\n    h = Nusselt_laminar(370., 350., 7.0, 585., 0.091, 158.9E-6, 776900., 0.1)\n    assert_close(h, 1482.206403453679)\n    h_angle = [Nusselt_laminar(Tsat=370., Tw=350., rhog=7.0, rhol=585., kl=0.091, mul=158.9E-6, Hvap=776900., L=0.1, angle=float(i)) for i in linspace(0, 90, 8)]\n    h_angle_values = [0.0, 1018.0084987903685, 1202.9623322809389, 1317.0917328126477, 1393.7567182107628, 1444.0629692910647, 1472.8272516024929, 1482.206403453679]\n    assert_close1d(h_angle, h_angle_values)\n\n\ndef test_h_Boyko_Kruzhilin():\n    h_xs = [Boyko_Kruzhilin(m=0.35, rhog=6.36, rhol=582.9, kl=0.098,\n\t    mul=159E-6, Cpl=2520., D=0.03, x=i) for i in linspace(0,1,11)]\n    h_xs_values = [1190.3309510899785, 3776.3883678904836, 5206.2779830848758, 6320.5657791981021, 7265.9323628276288, 8101.7278671405438, 8859.0188940546595, 9556.4866502932564, 10206.402815353165, 10817.34162173243, 11395.573750069829]\n    assert_close1d(h_xs, h_xs_values)\n\n\ndef test_Akers_Deans_Crosser():\n    h = Akers_Deans_Crosser(m=0.35, rhog=6.36, rhol=582.9, kl=0.098,  mul=159E-6, Cpl=2520., D=0.03, x=0.85)\n    assert_close(h, 7117.24177265201)\n    h = Akers_Deans_Crosser(m=0.01, rhog=6.36, rhol=582.9, kl=0.098,  mul=159E-6, Cpl=2520., D=0.03, x=0.85)\n    assert_close(h, 737.5654803081094)\n\ndef test_h_kinetic():\n    h = h_kinetic(300.0, 1E5, 18.02, 2441674.0)\n    assert_close(h, 30788845.562480535, rtol=1e-5)\n\n\ndef test_Cavallini_Smith_Zecchin():\n    assert_close(Cavallini_Smith_Zecchin(m=1.0, x=0.4, D=.3, rhol=800.0, rhog=2.5, mul=1E-5, mug=1E-3, kl=0.6, Cpl=2300.0), 5578.218369177804)\n\n\ndef test_Shah():\n    assert_close(Shah(m=1.0, x=0.4, D=.3, rhol=800.0, mul=1E-5, kl=0.6, Cpl=2300.0, P=1E6, Pc=2E7), 2561.2593415479214)\n    # In Shaw's second paper, they used the following definition. However, it\n    # is just rearanged differently. It was coded to verify this, and is left\n    # in case further sources list it in different forms.\n    def Shah3(m, x, D, rhol, mul, kl, Cpl, P, Pc):\n        Pr = P/Pc\n        G = m/(pi/4*D**2)\n        Prl = Prandtl(Cp=Cpl, k=kl, mu=mul)\n        Rel = G*D/mul\n        hL = kl/D*(0.023*Rel**0.8*Prl**0.4)\n        hl = hL*(1-x)**0.8\n        Z = (1/x -1)**0.8*Pr**0.4\n        h_TP = hl*(1 + 3.8/Z**0.95)\n        return h_TP\n    assert_close(Shah(m=1, x=0.4, D=.3, rhol=800, mul=1E-5, kl=0.6, Cpl=2300, P=1E6, Pc=2E7), 2561.2593415479214)\n    # The following is in the review of Balcular (2011), and incorrect.\n    #    Pr = P/Pc\n    #    G = m/(pi/4*D**2)\n    #    Prl = Prandtl(Cp=Cpl, k=kl, mu=mul)\n    #    Rel = G*D*(1-x)/mul\n    #    hl = kl/D*(0.023*(Rel/(1-x))**0.8*Prl**0.4)\n    #    hsf = hl*(1-x)**0.8\n    #    Co = (1/x-1)**0.8*(rhog/rhol)**0.5\n    #    return hsf*1.8/Co**0.8\n"
  },
  {
    "path": "tests/test_conduction.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d\n\nfrom ht import (\n    ASHRAE,\n    ASHRAE_k,\n    Cp_material,\n    R_cylinder,\n    R_to_k,\n    R_value_to_k,\n    S_isothermal_pipe_eccentric_to_isothermal_pipe,\n    S_isothermal_pipe_normal_to_plane,\n    S_isothermal_pipe_to_isothermal_pipe,\n    S_isothermal_pipe_to_plane,\n    S_isothermal_pipe_to_two_planes,\n    S_isothermal_sphere_to_plane,\n    building_materials,\n    cylindrical_heat_transfer,\n    k_material,\n    k_to_R,\n    k_to_R_value,\n    k_to_thermal_resistivity,\n    materials_dict,\n    nearest_material,\n    refractory_VDI_Cp,\n    refractory_VDI_k,\n    rho_material,\n    thermal_resistivity_to_k,\n)\n\n### Conduction\n# Nothing is necessary, it's all in doctests\n\ndef test_conduction():\n    assert_close(R_to_k(R=0.05, t=0.025), 0.5)\n    assert_close(k_to_R(k=0.5, t=0.025), 0.05)\n    assert_close(k_to_thermal_resistivity(0.25), 4.0)\n    assert_close(thermal_resistivity_to_k(4.), 0.25)\n\n    Rs = [R_value_to_k(0.12), R_value_to_k(0.71, SI=False)]\n    assert_close1d(Rs, [0.2116666666666667, 0.20313787163983468])\n    assert_close(R_value_to_k(1., SI=False)/R_value_to_k(1.), 5.678263341113488)\n\n\n    values =  k_to_R_value(R_value_to_k(0.12)), k_to_R_value(R_value_to_k(0.71, SI=False), SI=False)\n    assert_close1d(values, [0.11999999999999998, 0.7099999999999999])\n\n    assert_close(R_cylinder(0.9, 1., 20., 10.), 8.38432343682705e-05)\n\n    ### Shape Factors\n\n    assert_close(S_isothermal_sphere_to_plane(1., 100.), 6.298932638776527)\n    assert_close(S_isothermal_pipe_to_plane(1., 100., 3.), 3.146071454894645)\n    assert_close(S_isothermal_pipe_normal_to_plane(1., 100.), 104.86893910124888)\n    assert_close(S_isothermal_pipe_to_isothermal_pipe(.1, .2, 1., 1.), 1.188711034982268)\n    assert_close(S_isothermal_pipe_to_two_planes(.1, 5., 1.), 1.2963749299921428)\n    assert_close(S_isothermal_pipe_eccentric_to_isothermal_pipe(.1, .4, .05, 10.), 47.709841915608976)\n\n\ndef test_cylindrical_heat_transfer():\n    data = cylindrical_heat_transfer(Ti=453.15, To=301.15, hi=1e12, ho=22.697193, Di=0.0779272, ts=[0.0054864, .05], ks=[56.045, 0.0598535265])\n    expect = {\"Q\": 73.12000884069367,\n     \"Rs\": [0.00022201030738405449, 1.189361782070256],\n     \"Ts\": [453.15, 453.1226455779877, 306.578530147744],\n     \"UA\": 0.48105268974140575,\n     \"U_inner\": 1.9649599487726137,\n     \"U_outer\": 0.8106078714663484,\n     \"q\": 123.21239646288495}\n\n    for k, v in expect.items():\n        if type(v) is float:\n            assert_close(v, data[k])\n        else:\n            assert_close1d(v, data[k])\n\n\ndef test_insulation():\n    rho_tot = sum([i[0] for i in building_materials.values()])\n    k_tot = sum([i[1] for i in building_materials.values()])\n    Cp_tot = sum([i[2] for i in building_materials.values()])\n    ans = [213240.48, 1132.7733999999994, 164486]\n    assert_close1d([rho_tot, k_tot, Cp_tot], ans)\n\n    assert_close(0.036, ASHRAE_k(ID=\"Mineral fiber\"))\n\n    k_VDIs = [refractory_VDI_k(\"Fused silica\", i) for i in [None, 200, 1000, 1500]]\n    assert_close1d(k_VDIs, [1.44, 1.44, 1.58074, 1.73])\n\n    Cp_VDIs = [refractory_VDI_Cp(\"Fused silica\", i) for i in [None, 200, 1000, 1500]]\n    assert_close1d(Cp_VDIs, [917.0, 917.0, 956.78225, 982.0])\n\n\n    k = k_material(\"Mineral fiber\")\n    assert_close(k, 0.036)\n    k = k_material(\"stainless steel\")\n    assert_close(k, 17.0)\n\n    rho = rho_material(\"Mineral fiber\")\n    assert_close(rho, 30.0)\n\n    rho = rho_material(\"stainless steel\")\n    assert_close(rho, 7900.0)\n\n    rho = rho_material(\"Board, Asbestos/cement\")\n    assert_close(rho, 1900.0)\n\n\n    Cp = Cp_material(\"Mineral fiber\")\n    assert_close(Cp, 840.0)\n\n    Cp = Cp_material(\"stainless steel\")\n    assert_close(Cp, 460.0)\n\n    with pytest.raises(Exception):\n        rho_material(\"Clay tile, hollow, 1 cell deep\")\n    with pytest.raises(Exception):\n        Cp_material(\"Siding, Aluminum, steel, or vinyl, over sheathing foil-backed\")\n\n\n@pytest.mark.slow\ndef test_insulation_fuzz():\n    assert_close(sum([ASHRAE_k(ID) for ID in ASHRAE]), 102.33813464784427)\n\n    k_tot = sum([k_material(ID) for ID in materials_dict])\n    assert_close(k_tot, 1436.251534647845)\n\n    rho = sum([rho_material(mat) for mat in materials_dict if (materials_dict[mat] == 1 or materials_dict[mat]==3 or ASHRAE[mat][0])])\n    assert_close(rho, 473135.98)\n\n    Cp = sum([Cp_material(mat) for mat in materials_dict if ( materials_dict[mat] == 1 or materials_dict[mat]==3 or ASHRAE[mat][1])])\n    assert_close(Cp, 353115.0)\n\n    # fuzzy matching is slow\n    assert nearest_material(\"stainless steel\") == \"Metals, stainless steel\"\n    assert nearest_material(\"stainless wood\") == \"Metals, stainless steel\"\n    assert nearest_material(\"asdfasdfasdfasdfasdfasdfads \") == \"Expanded polystyrene, molded beads\"\n\n    assert nearest_material(\"stainless steel\", complete=True) == \"Metals, stainless steel\"\n\n"
  },
  {
    "path": "tests/test_conv_external.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d, logspace\n\nfrom ht import (\n    Nu_cylinder_Churchill_Bernstein,\n    Nu_cylinder_Fand,\n    Nu_cylinder_McAdams,\n    Nu_cylinder_Perkins_Leppert_1962,\n    Nu_cylinder_Perkins_Leppert_1964,\n    Nu_cylinder_Sanitjai_Goldstein,\n    Nu_cylinder_Whitaker,\n    Nu_cylinder_Zukauskas,\n    Nu_external_cylinder,\n    Nu_external_cylinder_methods,\n    Nu_external_horizontal_plate,\n    Nu_external_horizontal_plate_methods,\n    Nu_horizontal_plate_laminar_Baehr,\n    Nu_horizontal_plate_laminar_Churchill_Ozoe,\n    Nu_horizontal_plate_turbulent_Kreith,\n    Nu_horizontal_plate_turbulent_Schlichting,\n)\nfrom ht.conv_external import conv_horizontal_plate_laminar_methods, conv_horizontal_plate_turbulent_methods\n\n### Conv external\n\ndef test_Nu_cylinder_Zukauskas():\n    Nu = Nu_cylinder_Zukauskas(7992, 0.707, 0.69)\n    assert_close(Nu, 50.523612661934386)\n\n    Nus_allRe = [Nu_cylinder_Zukauskas(Re, 0.707, 0.69) for Re in logspace(0, 6, 8)]\n    Nus_allRe_values = [0.66372630070423799, 1.4616593536687801, 3.2481853039940831, 8.7138930573143227, 26.244842388228189, 85.768869004450067, 280.29503021904566, 1065.9610995854582]\n    assert_close1d(Nus_allRe, Nus_allRe_values)\n\n    Nu_highPr = Nu_cylinder_Zukauskas(7992, 42.)\n    assert_close(Nu_highPr, 219.24837219760443)\n\n\n\ndef test_Nu_cylinder_Churchill_Bernstein():\n    Nu = Nu_cylinder_Churchill_Bernstein(6071.0, 0.7)\n    assert_close(Nu, 40.63708594124974)\n\n\ndef test_Nu_cylinder_Sanitjai_Goldstein():\n    Nu = Nu_cylinder_Sanitjai_Goldstein(6071.0, 0.7)\n    assert_close(Nu, 40.38327083519522)\n\n\ndef test_Nu_cylinder_Fand():\n    Nu = Nu_cylinder_Fand(6071.0, 0.7)\n    assert_close(Nu, 45.19984325481126)\n\n\ndef test_Nu_cylinder_McAdams():\n    Nu = Nu_cylinder_McAdams(6071.0, 0.7)\n    assert_close(Nu, 46.98179235867934)\n\n\ndef test_Nu_cylinder_Whitaker():\n    Nu = Nu_cylinder_Whitaker(6071.0, 0.7)\n    assert_close(Nu, 45.94527461589126)\n    Nu = Nu_cylinder_Whitaker(6071.0, 0.7, 1E-3, 1.2E-3)\n    assert_close(Nu, 43.89808146760356)\n\n\ndef test_Nu_cylinder_Perkins_Leppert_1962():\n    Nu = Nu_cylinder_Perkins_Leppert_1962(6071.0, 0.7)\n    assert_close(Nu, 49.97164291175499)\n    Nu = Nu_cylinder_Perkins_Leppert_1962(6071.0, 0.7, 1E-3, 1.2E-3)\n    assert_close(Nu, 47.74504603464674)\n\n\ndef test_Nu_cylinder_Perkins_Leppert_1964():\n    Nu = Nu_cylinder_Perkins_Leppert_1964(6071.0, 0.7)\n    assert_close(Nu, 53.61767038619986)\n    Nu = Nu_cylinder_Perkins_Leppert_1964(6071.0, 0.7, 1E-3, 1.2E-3)\n    assert_close(Nu, 51.22861670528418)\n\n\ndef test_Nu_external_cylinder():\n    Nu = Nu_external_cylinder(6071.0, 0.7)\n    assert_close(Nu, 40.38327083519522)\n\n    Nu = Nu_external_cylinder(6071.0, 0.7, Method=\"Zukauskas\")\n    assert_close(Nu, 42.4244052368103)\n\n    methods = Nu_external_cylinder_methods(6071.0, 0.7, Prw=.8, mu=1e-4, muw=2e-4)\n\n    with pytest.raises(Exception):\n        Nu_external_cylinder(6071.0, 0.7, Method=\"BADMETHOD\")\n\n    Nu = Nu_external_cylinder(6071.0, 0.7, Prw=.8, Method=\"Zukauskas\")\n    assert_close(Nu, 41.0315360788783)\n\n    Nu = Nu_external_cylinder(6071.0, 0.7, mu=1e-4, muw=2e-4, Method=\"Whitaker\")\n    assert_close(Nu, 38.63521672235044)\n\n\ndef test_Nu_horizontal_plate_laminar_Baehr():\n    Prs = [1e-4, 1e-1, 1, 100]\n    Nu_expects = [3.5670492006699317, 97.46187137010543, 209.9752366351804, 995.1679034477633]\n\n    for Pr, Nu_expect in zip(Prs, Nu_expects):\n        assert_close(Nu_horizontal_plate_laminar_Baehr(1e5, Pr), Nu_expect)\n\n\ndef test_Nu_horizontal_plate_laminar_Churchill_Ozoe():\n    assert_close(Nu_horizontal_plate_laminar_Churchill_Ozoe(1e5, .7), 183.08600782591418)\n\n\ndef test_Nu_horizontal_plate_turbulent_Schlichting():\n    assert_close(Nu_horizontal_plate_turbulent_Schlichting(1e5, 0.7), 309.620048541267)\n\n\ndef test_Nu_horizontal_plate_turbulent_Kreith():\n    Nu = Nu_horizontal_plate_turbulent_Kreith(1.03e6, 0.71)\n    assert_close(Nu, 2074.8740070411122)\n\n\ndef test_Nu_external_horizontal_plate():\n    # default function - turbulent\n    assert_close(Nu_external_horizontal_plate(5e6, .7),\n                    Nu_external_horizontal_plate(5e6, .7, turbulent_method=\"Schlichting\"))\n\n    # specific function - turbulent - vs specify turbulent method\n    assert_close(Nu_horizontal_plate_turbulent_Kreith(5e6, .7),\n                    Nu_external_horizontal_plate(5e6, .7, turbulent_method=\"Kreith\"))\n\n    # specific function - turbulent - vs specify method\n    assert_close(Nu_horizontal_plate_turbulent_Kreith(5e6, .7),\n                    Nu_external_horizontal_plate(5e6, .7, Method=\"Kreith\"))\n\n    # default function - laminar\n    assert_close(Nu_external_horizontal_plate(5e3, .7),\n                    Nu_external_horizontal_plate(5e3, .7, laminar_method=\"Baehr\"))\n\n    # specific function - laminar - vs specify laminar method\n    assert_close(Nu_horizontal_plate_laminar_Baehr(5e3, .7),\n                    Nu_external_horizontal_plate(5e3, .7, laminar_method=\"Baehr\"))\n\n    # specific function - laminar - vs specify method\n    assert_close(Nu_horizontal_plate_laminar_Churchill_Ozoe(5e6, .7),\n                    Nu_external_horizontal_plate(5e6, .7, Method=\"Churchill Ozoe\"))\n\n    # Swith the transition region to be higher\n    assert_close(Nu_horizontal_plate_laminar_Baehr(5e6, .7),\n                    Nu_external_horizontal_plate(5e6, .7, Re_transition=1e7))\n\n    # Check the AvailableMethods\n    assert (set(Nu_external_horizontal_plate_methods(1e5, .7, L=1.0, x=0.5, check_ranges=True))\n            == set(conv_horizontal_plate_laminar_methods.keys()) )\n\n    assert (set(Nu_external_horizontal_plate_methods(1e7, .7))\n            == set(conv_horizontal_plate_turbulent_methods.keys()) )\n\n\n\n"
  },
  {
    "path": "tests/test_conv_free_enclosed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close, assert_close1d\nfrom fluids.numerics import numpy as np\n\nfrom ht import (\n    Nu_Nusselt_Rayleigh_Hollands,\n    Nu_Nusselt_Rayleigh_Probert,\n    Nu_Nusselt_vertical_Thess,\n    Nu_vertical_helical_coil_Ali,\n    Rac_Nusselt_Rayleigh,\n    Rac_Nusselt_Rayleigh_disk,\n)\nfrom ht.conv_free_enclosed import Nu_Nusselt_Rayleigh_Holling_Herwig\n\ntry:\n    from scipy.interpolate import UnivariateSpline, bisplrep\nexcept:\n    pass\n\n\ndef test_Nu_Nusselt_Rayleigh_Holling_Herwig():\n    Ras = [10.0**n for n in range(5, 16)]\n    Nus_expect = [4.566, 8.123, 15.689, 31.526, 64.668, 134.135, 279.957, 586.404, 1230.938, 2587.421, 5443.761]\n    Nus_calc = [round(Nu_Nusselt_Rayleigh_Holling_Herwig(1., Gr), 3) for Gr in Ras]\n    assert_close1d(Nus_expect, Nus_calc)\n\n    assert 1 == Nu_Nusselt_Rayleigh_Holling_Herwig(1., 100., buoyancy=True)\n    assert 1 == Nu_Nusselt_Rayleigh_Holling_Herwig(1., 100., buoyancy=False)\n\n\ndef test_Nu_Nusselt_Rayleigh_Probert():\n    Nu =  Nu_Nusselt_Rayleigh_Probert(5.54, 3.21e8, buoyancy=True)\n    assert_close(Nu, 111.46181048289132)\n\n\n    # Test the boundary\n    Nu = Nu_Nusselt_Rayleigh_Probert(1., 2.19999999999999e4, buoyancy=True)\n    assert_close(Nu, 2.5331972341122833)\n\n    Nu = Nu_Nusselt_Rayleigh_Probert(1., 2.2e4, buoyancy=True)\n    assert_close(Nu, 2.577876184202956)\n\n    assert 1 == Nu_Nusselt_Rayleigh_Probert(1., 100., buoyancy=True)\n    assert 1 == Nu_Nusselt_Rayleigh_Probert(1., 100., buoyancy=False)\n\n\ndef test_Rac_Nusselt_Rayleigh():\n    for Rac_expect, insulation in zip([3011480.513694726, 9802960.0], [True, False]):\n        for L in (8.0, 9.0, 100.0):\n            W_L = .125\n            Rac = Rac_Nusselt_Rayleigh(1., L, W_L*L, insulation)\n            assert_close(Rac, Rac_expect)\n\n\ndef test_Rac_Nusselt_Rayleigh_disk():\n    assert_close(Rac_Nusselt_Rayleigh_disk(4., 1., True), 51800)\n    assert_close(Rac_Nusselt_Rayleigh_disk(H=1, D=.4, insulated=True), 51800)\n    assert_close(Rac_Nusselt_Rayleigh_disk(H=1, D=.4, insulated=False), 151200)\n\n    for r in (4,10, 100):\n        assert_close(Rac_Nusselt_Rayleigh_disk(r, 1., False), 151200)\n\n\n    for D in (5.9999999999, 6, 7, 50):\n        assert_close(Rac_Nusselt_Rayleigh_disk(H=1., D=D, insulated=False), 1708.)\n        assert_close(Rac_Nusselt_Rayleigh_disk(H=1., D=D, insulated=True), 1708.)\n\n\ndef test_Nu_Nusselt_vertical_Thess():\n    Nu =  Nu_Nusselt_vertical_Thess(.7, 3.21e6)\n    assert_close(Nu, 6.112587569602785)\n\n    Nu = Nu_Nusselt_vertical_Thess(.7, 3.21e6, L=10, H=1)\n    assert_close(Nu, 28.79328626041646)\n\n    Nu = Nu_Nusselt_vertical_Thess(.7, 2e7)\n    assert_close(Nu, 11.179395785432854)\n\n\ndef test_Nu_Nusselt_Rayleigh_Hollands():\n    assert_close(Nu_Nusselt_Rayleigh_Hollands(5.54, 3.21e8, buoyancy=True), 69.02668649510164)\n    assert_close(Nu_Nusselt_Rayleigh_Hollands(.7, 3.21e6, buoyancy=True, Rac=Rac_Nusselt_Rayleigh(H=1, L=2, W=.2, insulated=False)), 4.666249131876477)\n\n    assert_close(Nu_Nusselt_Rayleigh_Hollands(.7, 3.21e6, buoyancy=True, Rac=Rac_Nusselt_Rayleigh(H=1, L=1, W=1, insulated=False)), 8.786362614129537)\n\ndef test_Rac_Nusselt_Rayleigh_fit_uninsulated():\n    from ht.conv_free_enclosed import Racs_uninstulated_Catton, ratios_uninsulated_Catton, tck_uninstulated_Catton\n    all_zs = []\n    all_xs = []\n    all_ys = []\n    for ratio1, Rac_row in zip(ratios_uninsulated_Catton, Racs_uninstulated_Catton):\n        for Rac, ratio2 in zip(Rac_row, ratios_uninsulated_Catton):\n            all_zs.append(Rac)\n            all_xs.append(ratio1)\n            all_ys.append(ratio2)\n\n    tck = bisplrep(all_xs, all_ys, np.log(all_zs), kx=3, ky=3, s=0)\n\n    for i in range(len(tck)-2):\n        assert_close1d(tck[i], tck_uninstulated_Catton[i], rtol=1e-5)\n\n#    for i, Racs in enumerate(Racs_uninstulated_Catton):\n#        plt.semilogy(ratios_uninsulated_Catton, Racs, label=str(ratios_uninsulated_Catton[i]))\n#        fit = np.exp(bisplev(ratios_uninsulated_Catton[i], ratios_uninsulated_Catton, tck))\n#        plt.semilogy(ratios_uninsulated_Catton, fit, 'o')\n#\n#    plt.legend()\n#    plt.show()\n\ndef test_Rac_Nusselt_Rayleigh_fit_insulated():\n    from ht.conv_free_enclosed import Racs_instulated_Catton, ratios_insulated_Catton\n\n    all_zs = []\n    all_xs = []\n    all_ys = []\n    for ratio1, Rac_row in zip(ratios_insulated_Catton, Racs_instulated_Catton):\n        for Rac, ratio2 in zip(Rac_row, ratios_insulated_Catton):\n            if Rac is not None:\n                all_zs.append(Rac)\n                all_xs.append(ratio1)\n                all_ys.append(ratio2)\n\n    # This fit is not great, might be worth refitting at some point\n    # Do not compare anything.\n    tck = bisplrep(all_xs, all_ys, np.log(all_zs), kx=1, ky=2)\n#    for i in range(len(tck)):\n#        assert_close1d(tck[i], tck_insulated_Catton[i], rtol=1e-5)\n\n#    for i, Racs in enumerate(Racs_instulated_Catton):\n#        plt.semilogy(ratios_insulated_Catton, Racs, '-', label=str(ratios_insulated_Catton[i]))\n#        fit = np.exp(bisplev(ratios_insulated_Catton[i], ratios_insulated_Catton, tck))\n#        plt.semilogy(ratios_insulated_Catton, fit, 'o')\n#\n#    plt.legend()\n#    plt.show()\n\n\ndef test_Rac_Nusselt_Rayleigh_disk_fits():\n    from fluids.optional import pychebfun\n\n    from ht.conv_free_enclosed import insulated_disk_coeffs, uninsulated_disk_coeffs\n    ratios = [0.4, 0.5, 0.7, 1.0, 1.4, 2.0, 3.0, 4.0, 6]\n    Ras_uninsulated = [151200, 66600, 21300, 8010, 4350, 2540, 2010, 1880, 1708]\n    Ras_insulated = [51800, 23800, 8420, 3770, 2650, 2260, 1900, 1830, 1708]\n\n    uninsulated = UnivariateSpline(ratios, 1/np.log(Ras_uninsulated), k=1, s=0)\n    insulated = UnivariateSpline(ratios, 1/np.log(Ras_insulated), k=1, s=0)\n\n    N = 8\n    insulated_fun = pychebfun.chebfun(insulated, domain=[ratios[0], ratios[-1]], N=N)\n    uninsulated_fun = pychebfun.chebfun(uninsulated, domain=[ratios[0], ratios[-1]], N=N)\n\n\n    insulated_coeffs = pychebfun.chebfun_to_poly(insulated_fun)\n    uninsulated_coeffs = pychebfun.chebfun_to_poly(uninsulated_fun)\n\n    assert_close1d(insulated_coeffs, insulated_disk_coeffs)\n    assert_close1d(uninsulated_coeffs, uninsulated_disk_coeffs)\n\n#    more_ratios = np.logspace(np.log10(ratios[0]), np.log10(ratios[-1]), 1000)\n#    plt.semilogy(ratios, Ras_insulated)\n#    plt.semilogy(ratios, Ras_uninsulated)\n#\n#    plt.semilogy(more_ratios, np.exp(1/insulated_fun(np.array(more_ratios))), 'x')\n#    plt.semilogy(more_ratios, np.exp(1/uninsulated_fun(np.array(more_ratios))), 'o')\n#    plt.show()\n\n\n\ndef test_Nu_vertical_helical_coil_Ali():\n    Nu = Nu_vertical_helical_coil_Ali(4.4, 1E11)\n    assert_close(Nu, 1808.5774997297106)\n"
  },
  {
    "path": "tests/test_conv_free_immersed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d, assert_close2d, logspace\n\nfrom ht import (\n    Nu_coil_Xin_Ebadian,\n    Nu_free_horizontal_plate,\n    Nu_free_horizontal_plate_methods,\n    Nu_free_vertical_plate,\n    Nu_free_vertical_plate_methods,\n    Nu_horizontal_cylinder,\n    Nu_horizontal_cylinder_Churchill_Chu,\n    Nu_horizontal_cylinder_Kuehn_Goldstein,\n    Nu_horizontal_cylinder_methods,\n    Nu_horizontal_cylinder_Morgan,\n    Nu_horizontal_plate_McAdams,\n    Nu_horizontal_plate_Rohsenow,\n    Nu_horizontal_plate_VDI,\n    Nu_sphere_Churchill,\n    Nu_vertical_cylinder,\n    Nu_vertical_cylinder_Al_Arabi_Khamis,\n    Nu_vertical_cylinder_Carne_Morgan,\n    Nu_vertical_cylinder_Eigenson_Morgan,\n    Nu_vertical_cylinder_Griffiths_Davis_Morgan,\n    Nu_vertical_cylinder_Hanesian_Kalish_Morgan,\n    Nu_vertical_cylinder_Jakob_Linke_Morgan,\n    Nu_vertical_cylinder_Kreith_Eckert,\n    Nu_vertical_cylinder_McAdams_Weiss_Saunders,\n    Nu_vertical_cylinder_methods,\n    Nu_vertical_cylinder_Popiel_Churchill,\n    Nu_vertical_cylinder_Touloukian_Morgan,\n    Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan,\n    Nu_vertical_plate_Churchill,\n)\n\n### Free convection immersed\n\ndef test_Nu_free_vertical_plate():\n    Nu = Nu_free_vertical_plate(0.69, 2.63E9)\n    assert_close(147.16185223770603, Nu)\n\n    Nu = Nu_free_vertical_plate(0.69, 2.63E9, H=1.0, W=1.0)\n    assert_close(147.16185223770603, Nu)\n\n    methods = Nu_free_vertical_plate_methods(0.69, 2.63E9, H=1.0, W=1.0, check_ranges=True)\n    assert methods[0] == \"Churchill\"\n    assert len(methods) == 1\n\n    with pytest.raises(Exception):\n        Nu_free_vertical_plate(0.69, 2.63E9, Method=\"BADMETHOD\")\n\ndef test_Nu_horizontal_plate_VDI():\n    Nu = Nu_horizontal_plate_VDI(5.54, 3.21e8, buoyancy=True)\n    assert_close(Nu, 203.89681224927565)\n    Nu = Nu_horizontal_plate_VDI(5.54, 3.21e8, buoyancy=False)\n    assert_close(Nu, 39.16864971535617)\n\n    Nu = Nu_horizontal_plate_VDI(5.54, 3.21e3, buoyancy=True)\n    assert_close(Nu, 5.810590581487902)\n\ndef test_Nu_horizontal_plate_Rohsenow():\n    Nu = Nu_horizontal_plate_Rohsenow(5.54, 3.21e8, buoyancy=True)\n    assert_close(Nu, 175.91054716322836)\n\n    Nu = Nu_horizontal_plate_Rohsenow(5.54, 3.21e8, buoyancy=False)\n    assert_close(Nu, 35.95799244863986)\n\n\ndef test_Nu_free_horizontal_plate():\n    Nu = Nu_free_horizontal_plate(5.54, 3.21e8, L=1.0, W=1.0, buoyancy=True)\n    assert_close(Nu, 203.89681224927565)\n\n    Nu = Nu_free_horizontal_plate(5.54, 3.21e8, buoyancy=True, Method=\"McAdams\")\n    assert_close(Nu, 181.73121274384457)\n\n    assert Nu_free_horizontal_plate_methods(5.54, 3.21e8, buoyancy=True, L=1.0, W=1.0, check_ranges=True) == [\"VDI\", \"McAdams\", \"Rohsenow\"]\n\ndef test_Nu_horizontal_plate_McAdams():\n    Nu = Nu_horizontal_plate_McAdams(5.54, 3.21e8, buoyancy=True)\n    assert_close(Nu, 181.73121274384457)\n\n    Nu = Nu_horizontal_plate_McAdams(5.54, 3.21e8, buoyancy=False)\n    assert_close(Nu, 55.44564799362829)\n\n    Nu = Nu_horizontal_plate_McAdams(.01, 3.21e8, buoyancy=True)\n    assert_close(Nu, 22.857041558492334)\n    Nu = Nu_horizontal_plate_McAdams(.01, 3.21e8, buoyancy=False)\n    assert_close(Nu, 11.428520779246167)\n\ndef test_Nu_vertical_plate_Churchill():\n    Nu = Nu_vertical_plate_Churchill(0.69, 2.63E9)\n    assert_close(Nu, 147.16185223770603)\n\n\ndef test_Nu_sphere_Churchill():\n    Nu_Res = [Nu_sphere_Churchill(.7, i) for i in logspace(0, 10, 11)]\n    Nu_Res_values = [2.415066377224484, 2.7381040025746382, 3.3125553308635283, 4.3340933312726548, 6.1507272232235417, 9.3821675084055443, 15.145453144794978, 25.670869440317578, 47.271761310748289, 96.479305628419823, 204.74310854292045]\n    assert_close1d(Nu_Res, Nu_Res_values)\n\n\ndef test_Nu_vertical_cylinder_Griffiths_Davis_Morgan():\n    Nu_all = [[Nu_vertical_cylinder_Griffiths_Davis_Morgan(i, 1E9, j) for i in (0.999999, 1.000001)] for j in (True, False, None)]\n    Nu_all_values = [[127.7046167347578, 127.7047079158867], [119.14469068641654, 119.14475025877677], [119.14469068641654, 127.7047079158867]]\n    assert_close2d(Nu_all, Nu_all_values)\n\n\ndef test_Nu_vertical_cylinder_Jakob_Linke_Morgan():\n    Nu_all = [[Nu_vertical_cylinder_Jakob_Linke_Morgan(i, 1E8, j) for i in (0.999999, 1.000001)] for j in (True, False, None)]\n    Nu_all_values = [[59.87647599476619, 59.87651591243016], [55.499986124994805, 55.5000138749948], [55.499986124994805, 59.87651591243016]]\n    assert_close2d(Nu_all, Nu_all_values)\n\n\ndef test_Nu_vertical_cylinder_Carne_Morgan():\n    Nu_all = [[Nu_vertical_cylinder_Carne_Morgan(i, 2E8, j) for i in (0.999999, 1.000001)] for j in (True, False, None)]\n    Nu_all_values = [[216.88764905616722, 216.88781389084312], [225.77302655456344, 225.77315298749372], [225.77302655456344, 216.88781389084312]]\n    assert_close2d(Nu_all, Nu_all_values)\n\n\ndef test_Nu_vertical_cylinder_Eigenson_Morgan():\n    Grs = [1.42E9, 1.43E9, 2.4E10, 2.5E10]\n    Nus_expect = [85.22908647061865, 85.47896057139417, 252.35445465640387, 256.64456353698154]\n    Nus = [Nu_vertical_cylinder_Eigenson_Morgan(0.7, Gr) for Gr in Grs]\n    assert_close1d(Nus, Nus_expect)\n\n\ndef test_Nu_vertical_cylinder_Touloukian_Morgan():\n    Nus = [Nu_vertical_cylinder_Touloukian_Morgan(.7, i) for i in (5.7E10, 5.8E10)]\n    assert_close1d(Nus, [324.47395664562873, 223.80067132541936])\n\n    assert_close(249.72879961097854, Nu_vertical_cylinder_Touloukian_Morgan(.7, 2E10, False))\n\n\ndef test_Nu_vertical_cylinder_McAdams_Weiss_Saunders():\n    Nus = [Nu_vertical_cylinder_McAdams_Weiss_Saunders(.7, i) for i in [1.42E9,  1.43E9]]\n    assert_close1d(Nus, [104.76075212013542, 130.04331889690818])\n\n    Nu = Nu_vertical_cylinder_McAdams_Weiss_Saunders(.7, 2E10, False)\n    assert_close(Nu, 202.9476470667732)\n\n\ndef test_Nu_vertical_cylinder_Kreith_Eckert():\n    Nus = [Nu_vertical_cylinder_Kreith_Eckert(.7, i) for i in [1.42E9, 1.43E9]]\n    assert_close1d(Nus, [98.54613123165282, 83.63593679160734])\n\n    Nu = Nu_vertical_cylinder_Kreith_Eckert(.7, 2E10, False)\n    assert_close(Nu, 190.90837986789683)\n\n\ndef test_Nu_vertical_cylinder_Hanesian_Kalish_Morgan():\n    Nu = Nu_vertical_cylinder_Hanesian_Kalish_Morgan(.7, 1E7)\n    assert_close(Nu, 18.014150492696604)\n\n\ndef test_Nu_vertical_cylinder_Al_Arabi_Khamis():\n    Nus = [Nu_vertical_cylinder_Al_Arabi_Khamis(.71, i, 10.0, 1.0) for i in [3.6E9, 3.7E9]]\n    assert_close1d(Nus, [185.32314790756703, 183.89407579255627])\n\n\ndef test_Nu_vertical_cylinder_Popiel_Churchill():\n    Nu = Nu_vertical_cylinder_Popiel_Churchill(0.7, 1E10, 2.5, 1.0)\n    assert_close(Nu, 228.8979005514989)\n\n\ndef test_Nu_vertical_cylinder():\n    Nu = Nu_vertical_cylinder(0.72, 1E7)\n    assert_close(Nu, 30.562236756513943)\n\n    Nu = Nu_vertical_cylinder(0.72, 1E7, L=1., D=.1)\n    assert_close(Nu, 36.82833881084525)\n\n    with pytest.raises(Exception):\n        Nu_vertical_cylinder(0.72, 1E7, Method=\"BADMETHOD\")\n\n    l = Nu_vertical_cylinder_methods(0.72, 1E7, L=1.0, D=.1)\n    assert len(l) == 11\n\n\n\ndef test_Nu_horizontal_cylinder_Churchill_Chu():\n    Nu = Nu_horizontal_cylinder_Churchill_Chu(0.69, 2.63E9)\n    assert_close(Nu, 139.13493970073597)\n\n\ndef test_Nu_horizontal_cylinder_Kuehn_Goldstein():\n    Nu = Nu_horizontal_cylinder_Kuehn_Goldstein(0.69, 2.63E9)\n    assert_close(Nu, 122.99323525628186)\n\n\ndef test_Nu_horizontal_cylinder_Morgan():\n    Nus = [Nu_horizontal_cylinder_Morgan(.9, i) for i in (1E-2, 1E2, 1E4, 1E7, 1E10)]\n    Nus_expect = [0.5136293570857408, 1.9853087795801612, 4.707783879945983, 26.290682760247975, 258.0315247153301]\n    assert_close1d(Nus, Nus_expect)\n\n\ndef test_Nu_horizontal_cylinder():\n    Nu = Nu_horizontal_cylinder(Pr=0.72, Gr=1E7)\n    assert_close(Nu, 24.864192615468973)\n\n    l = Nu_horizontal_cylinder_methods(0.72, 1E7)\n    assert len(l) == 3\n\n    with pytest.raises(Exception):\n        Nu_horizontal_cylinder(Pr=0.72, Gr=1E7, Method=\"BADMETHOD\")\n\n\n\ndef test_Nu_coil_Xin_Ebadian():\n    Nu = Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=False)\n    assert_close(Nu, 4.755689726250451)\n    Nu = Nu_coil_Xin_Ebadian(0.7, 2E4, horizontal=True)\n    assert_close(Nu, 5.2148597687849785)\n\n\ndef test_Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan():\n    Nu = Nu_vertical_helical_coil_Prabhanjan_Rennie_Raghavan(4.4, 1E11)\n    assert_close(Nu, 720.6211067718227)\n"
  },
  {
    "path": "tests/test_conv_internal.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d, linspace\n\nfrom ht.conv_internal import (\n    Morimoto_Hotta,\n    Nu_conv_internal,\n    Nu_conv_internal_methods,\n    Nu_laminar_rectangular_Shan_London,\n    conv_tube_methods,\n    helical_turbulent_Nu_Mori_Nakayama,\n    helical_turbulent_Nu_Schmidt,\n    helical_turbulent_Nu_Xin_Ebadian,\n    laminar_entry_Baehr_Stephan,\n    laminar_entry_Seider_Tate,\n    laminar_entry_thermal_Hausen,\n    laminar_Q_const,\n    laminar_T_const,\n    turbulent_Bhatti_Shah,\n    turbulent_Churchill_Zajic,\n    turbulent_Colburn,\n    turbulent_Dipprey_Sabersky,\n    turbulent_Dittus_Boelter,\n    turbulent_Drexel_McAdams,\n    turbulent_entry_Hausen,\n    turbulent_ESDU,\n    turbulent_Friend_Metzner,\n    turbulent_Gnielinski,\n    turbulent_Gnielinski_smooth_1,\n    turbulent_Gnielinski_smooth_2,\n    turbulent_Gowen_Smith,\n    turbulent_Kawase_De,\n    turbulent_Kawase_Ulbrecht,\n    turbulent_Martinelli,\n    turbulent_Nunner,\n    turbulent_Petukhov_Kirillov_Popov,\n    turbulent_Prandtl,\n    turbulent_Sandall,\n    turbulent_Sieder_Tate,\n    turbulent_von_Karman,\n    turbulent_Webb,\n)\n\n\n### conv_internal\ndef test_Nu_const():\n    assert_close(laminar_T_const(), 3.66)\n    assert_close(laminar_Q_const(), 48/11.)\n\n\ndef test_laminar_entry_region():\n    Nu = laminar_entry_thermal_Hausen(100000.0, 1.1, 5.0, .5)\n    assert_close(Nu, 39.01352358988535)\n\n    Nu = laminar_entry_Seider_Tate(Re=100000, Pr=1.1, L=5, Di=.5)\n    assert_close(Nu, 41.366029684589265)\n    Nu_wall = laminar_entry_Seider_Tate(100000, 1.1, 5, .5, 1E-3, 1.2E-3)\n    assert_close(Nu_wall, 40.32352264095969)\n\n    Nu = laminar_entry_Baehr_Stephan(100000, 1.1, 5, .5)\n    assert_close(Nu, 72.65402046550976)\n\ndef test_turbulent_complicated():\n    Nu1 = turbulent_Dittus_Boelter(1E5, 1.2, True, False)\n    Nu2 = turbulent_Dittus_Boelter(Re=1E5, Pr=1.2, heating=False, revised=False)\n    Nu3 = turbulent_Dittus_Boelter(Re=1E5, Pr=1.2, heating=False)\n    Nu4 = turbulent_Dittus_Boelter(Re=1E5, Pr=1.2)\n    Nu_values = [261.3838629346147, 279.89829163640354, 242.9305927410295, 247.40036409449127]\n    assert_close1d([Nu1, Nu2, Nu3, Nu4], Nu_values)\n\n    Nu1 = turbulent_Sieder_Tate(Re=1E5, Pr=1.2)\n    Nu2 = turbulent_Sieder_Tate(1E5, 1.2, 0.01, 0.067)\n    assert_close1d([Nu1, Nu2], [286.9178136793052, 219.84016455766044])\n\n    Nus = [turbulent_entry_Hausen(1E5, 1.2, 0.154, i) for i in linspace(1e-3,1,11)]\n    Nus_values = [6464.503822124652, 505.67127136455525, 399.6147653094695, 356.6182206114823, 332.39191624636305, 316.53483318707475, 305.21220965431286, 296.6521831991236, 289.91358493027764, 284.4463173972796, 279.90553997822707]\n    assert_close1d(Nus, Nus_values)\n\ndef test_turbulent_simple():\n    Nu = turbulent_Colburn(1E5, 1.2)\n    assert_close(Nu, 244.41147091200068)\n\n    Nu = turbulent_Drexel_McAdams(1E5, 0.6)\n    assert_close(Nu, 171.19055301724387)\n\n    Nu = turbulent_von_Karman(1E5, 1.2, 0.0185)\n    assert_close(Nu, 255.7243541243272)\n\n    Nu = turbulent_Prandtl(1E5, 1.2, 0.0185)\n    assert_close(Nu, 256.073339689557)\n\n    Nu = turbulent_Friend_Metzner(1E5, 100., 0.0185)\n    assert_close(Nu, 1738.3356262055322)\n\n    Nu = turbulent_Petukhov_Kirillov_Popov(1E5, 1.2, 0.0185)\n    assert_close(Nu, 250.11935088905105)\n\n    Nu = turbulent_Webb(1E5, 1.2, 0.0185)\n    assert_close(Nu, 239.10130376815872)\n\n    Nu = turbulent_Sandall(1E5, 1.2, 0.0185)\n    assert_close(Nu, 229.0514352970239)\n\n    Nu = turbulent_Gnielinski(1E5, 1.2, 0.0185)\n    assert_close(Nu, 254.62682749359632)\n\n    Nu = turbulent_Gnielinski_smooth_1(1E5, 1.2)\n    assert_close(Nu, 227.88800494373442)\n\n    Nu = turbulent_Gnielinski_smooth_2(1E5, 7.)\n    assert_close(Nu, 577.7692524513449)\n\n    Nu = turbulent_Churchill_Zajic(1E5, 1.2, 0.0185)\n    assert_close(Nu, 260.5564907817961)\n\n    Nu = turbulent_ESDU(1E5, 1.2)\n    assert_close(Nu, 232.3017143430645)\n\ndef test_turbulent_rough():\n    Nu = turbulent_Martinelli(1E5, 100., 0.0185)\n    assert_close(Nu, 887.1710686396347)\n\n    Nu = turbulent_Nunner(1E5, 0.7, 0.0185, 0.005)\n    assert_close(Nu, 101.15841010919947)\n\n    Nu = turbulent_Dipprey_Sabersky(1E5, 1.2, 0.0185, 1E-3)\n    assert_close(Nu, 288.33365198566656)\n\n    Nu = turbulent_Gowen_Smith(1E5, 1.2, 0.0185)\n    assert_close(Nu, 131.72530453824106)\n\n    Nu = turbulent_Kawase_Ulbrecht(1E5, 1.2, 0.0185)\n    assert_close(Nu, 389.6262247333975)\n\n    Nu = turbulent_Kawase_De(1E5, 1.2, 0.0185)\n    assert_close(Nu, 296.5019733271324)\n\n    Nu = turbulent_Bhatti_Shah(1E5, 1.2, 0.0185, 1E-3)\n    assert_close(Nu, 302.7037617414273)\n\n# TODO meta function  Nu internal\n\n\ndef test_Morimoto_Hotta():\n    Nu = Morimoto_Hotta(1E5, 5.7, .05, .5)\n    assert_close(Nu, 634.4879473869859)\n\n\ndef test_helical_turbulent_Nu_Mori_Nakayama():\n    Nu = helical_turbulent_Nu_Mori_Nakayama(2E5, 0.7, 0.01, .2)\n    assert_close(Nu, 496.2522480663327)\n    # High Pr\n    Nu = helical_turbulent_Nu_Mori_Nakayama(2E5, 4.0, 0.01, .2)\n    assert_close(Nu, 889.3060078437253)\n\n    # Bad behavior!\n    # 1 sun power output per m^2 per K\n    assert 4E24 < helical_turbulent_Nu_Mori_Nakayama(2E6, 0.7, 1.0, 1E80)\n\n    # .[3]_ specified that the high-Pr formula is calculated using Dean number,\n    # but the actual article says it is not. We use the 2.5 power specified\n    # in the original.\n\ndef test_helical_turbulent_Nu_Schmidt():\n    Nu = helical_turbulent_Nu_Schmidt(2E5, 0.7, 0.01, .2)\n    assert_close(Nu, 466.2569996832083)\n    Nus = [helical_turbulent_Nu_Schmidt(i, 0.7, 0.01, .2) for i in [2.2E4, 2.2E4+1E-9]]\n    assert_close1d(Nus, [80.1111786843, 79.75161984693375])\n\n\ndef test_helical_turbulent_Nu_Xin_Ebadian():\n    Nu = helical_turbulent_Nu_Xin_Ebadian(2E5, 0.7, 0.01, .2)\n    assert_close(Nu, 474.11413424344755)\n\n    # No bad behavior\n    # Checked with the original\n\ndef test_Nu_laminar_rectangular_Shan_London():\n    Nu = Nu_laminar_rectangular_Shan_London(.7)\n    assert_close(Nu, 3.751762675455)\n\ndef test_Nu_conv_internal_methods():\n    from fluids.units import func_args\n\n    for (func, args) in conv_tube_methods.values():\n        assert tuple(list(func_args(func))[0:len(args)]) == args\n\n\ndef test_Nu_conv_internal():\n    Nu = Nu_conv_internal(1E2, .7)\n    assert_close(Nu, laminar_T_const())\n\n    Nu = Nu_conv_internal(1E2, .7, Method=\"Laminar - constant Q\")\n    assert_close(Nu, laminar_Q_const())\n\n    Nu = Nu_conv_internal(1E2, .7, x=.01, Di=.1)\n    assert_close(Nu, 14.91799128769779)\n\n    # test the other laminar entrylength methods\n    Nu = Nu_conv_internal(1E2, .7, x=.01, Di=.1, Method=\"Hausen laminar thermal entry\")\n    assert_close(Nu, 16.51501443241237)\n    Nu = Nu_conv_internal(1E2, .7, x=.01, Di=.1, Method=\"Seider-Tate laminar thermal entry\")\n    assert_close(Nu, 21.054212255270848)\n\n    # martinili\n    Nu = Nu_conv_internal(1E5, .02, eD=0.0)\n    assert_close(Nu, 8.246171632616187)\n\n    Nu = Nu_conv_internal(1E5, .7, x=.01, Di=.1)\n    assert_close(Nu, 978.1729258857774)\n\n    Nu = Nu_conv_internal(1E5, .7)\n    assert_close(Nu, 183.71057902604906)\n\n    other_methods = [\"Churchill-Zajic\", \"Petukhov-Kirillov-Popov\", \"Gnielinski\",\n                     \"Bhatti-Shah\", \"Dipprey-Sabersky\", \"Sandall\", \"Webb\",\n                     \"Friend-Metzner\", \"Prandtl\", \"von-Karman\", \"Gowen-Smith\",\n                     \"Kawase-Ulbrecht\", \"Kawase-De\", \"Nunner\", \"Dittus-Boelter\",\n                     \"Sieder-Tate\", \"Drexel-McAdams\", \"Colburn\", \"ESDU\",\n                     \"Gnielinski smooth low Pr\",\"Gnielinski smooth high Pr\"]\n\n    expected = [103.65851760127596, 96.66083769419261, 95.7206648591076,\n                124.96666518189072, 124.96666518189072, 126.8559349821517,\n                89.04183860378171, 82.62190521404274, 96.39509181385534,\n                97.64409839390211, 63.69345925482798, 218.78659693866075,\n                169.9758751276217, 113.72592148878971, 199.41923780765848,\n                239.73408047050233, 182.078434520036, 204.21792040079825,\n                177.52639370276017, 183.6911292257849, 230.01408232621412]\n\n\n    for method, expect in zip(other_methods, expected):\n        Nu = Nu_conv_internal(1E5, .7, fd=.01, Method=method)\n        assert_close(Nu, expect)\n\n    with pytest.raises(Exception):\n        Nu_conv_internal(1E5, .7, Method=\"NOTAMETHOD\")\n\n    l = Nu_conv_internal_methods(1E5, .7)\n    assert len(l) == 21\n\ntest_Nu_conv_internal()\n"
  },
  {
    "path": "tests/test_conv_jacket.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close\n\nfrom ht import Lehrer, Stein_Schmidt\n\n\ndef test_conv_jacket():\n    # actual example\n    h = Lehrer(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, 355E-6, dT=20.)\n    assert_close(h, 2922.128124761829)\n    # no wall correction\n    h = Lehrer(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, dT=20.)\n    assert_close(h, 2608.8602693706853)\n\n    # with isobaric expansion, all cases\n    h = Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", isobaric_expansion=0.000303)\n    assert_close(h, 3269.4389632666557)\n\n    h = Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", inletlocation=\"top\", isobaric_expansion=0.000303)\n    assert_close(h, 2566.1198726589996)\n\n    h = Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=-20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", isobaric_expansion=0.000303)\n    assert_close(h, 3269.4389632666557)\n\n    h = Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=-20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", inletlocation=\"bottom\", isobaric_expansion=0.000303)\n    assert_close(h, 2566.1198726589996)\n\n\n    ### Stein Schmidt\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, 355E-6, 971.8)\n    assert_close(h, 5695.204169808863)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, 355E-6, 971.8, inlettype=\"radial\")\n    assert_close(h, 1217.1449686341773)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, 355E-6, 971.8, inletlocation=\"top\")\n    assert_close(h, 5675.841635061595)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 995.7, 4178.1, 0.615, 798E-6, 355E-6, 971.8, inletlocation=\"bottom\")\n    assert_close(h, 5695.2041698088633)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 971.8, 4178.1, 0.615, 798E-6, 355E-6, 995.7, inletlocation=\"bottom\")\n    assert_close(h, 5694.9722658952096)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 971.8, 4178.1, 0.615, 798E-6, 355E-6, 995.7, inletlocation=\"top\")\n    assert_close(h, 5676.0744960391157)\n\n    h = Stein_Schmidt(2.5, 0.6, 0.65, 0.6, 0.025, 971.8, 4178.1, 0.615, 798E-6, 355E-6)\n    assert_close(h, 5685.532991556428)\n\n    h = Stein_Schmidt(.1, 0.6, 0.65, 0.6, 0.025, 971.8, 4178.1, 0.615, 798E-6)\n    assert_close(h, 151.78819106776797)\n"
  },
  {
    "path": "tests/test_conv_packed_bed.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close\n\nfrom ht import Nu_Achenbach, Nu_KTA, Nu_packed_bed_Gnielinski, Nu_Wakao_Kagei\n\n\ndef test_Nu_packed_bed_Gnielinski():\n    Nu = Nu_packed_bed_Gnielinski(8E-4, 0.4, 1.0, 1E3, 1E-3, 0.7)\n    assert_close(Nu, 61.37823202546954)\n\n    # fa=2 test\n    Nu = Nu_packed_bed_Gnielinski(8E-4, 0.4, 1.0, 1E3, 1E-3, 0.7, 2.0)\n    assert_close(Nu, 64.60866528996795)\n\n\ndef test_Nu_Wakao_Kagei():\n    Nu = Nu_Wakao_Kagei(2000., 0.7)\n    assert_close(Nu, 95.40641328041248)\n\ndef test_Nu_Achenbach():\n    Nu = Nu_Achenbach(2000., 0.7, 0.4)\n    assert_close(Nu, 117.70343608599121)\n\ndef test_Nu_KTA():\n    Nu = Nu_KTA(2000., 0.7, 0.4)\n    assert_close(Nu, 102.08516480718129)\n"
  },
  {
    "path": "tests/test_conv_plate.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2018 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close\n\nfrom ht.conv_plate import Nu_plate_Khan_Khan, Nu_plate_Kumar, Nu_plate_Martin, Nu_plate_Muley_Manglik\n\n\n@pytest.mark.numpy\ndef test_Nu_plate_Kumar():\n    from fluids.friction import Kumar_beta_list\n    from numpy.testing import assert_allclose\n\n    Kumar_Nu_Res = [[10.0],\n              [10.0, 100.0],\n              [20.0, 300.0],\n              [20.0, 400.0],\n              [20.0, 500.0]]\n\n\n    Nu = Nu_plate_Kumar(2000.0, 0.7, 30.0)\n    assert_close(Nu, 47.757818892853955)\n\n    Nu = Nu_plate_Kumar(Re=2000.0, Pr=0.7, chevron_angle=30.0, mu=1E-3, mu_wall=8E-4)\n    assert_close(Nu, 49.604284135097544)\n\n    all_ans_expected = [[[1.3741604132237337, 1.5167183720237427], [1.3741604132237337, 1.4917469901578877]],\n     [[1.3741604132237337, 1.4917469901578877, 5.550501072445418, 5.686809480248301],\n      [1.1640875871334992, 1.2445337163511674, 3.9101709259523125, 3.9566649343960067]],\n     [[1.4929588988864342, 1.563892674590831, 7.514446806331191, 7.535921750318442],\n      [1.3046449654318206, 1.3616258463940976, 5.549244219363172, 5.568849176342506]],\n     [[1.3046449654318206, 1.3616258463940976, 6.464254426666383, 6.491074633865849],\n      [1.3046449654318206, 1.360776035122095, 5.9841120030888915, 5.999181017513207]],\n     [[1.3046449654318206, 1.360776035122095, 6.696608679807539, 6.712512276614001],\n      [1.3046449654318206, 1.360776035122095, 6.696608679807539, 6.712512276614001]]]\n\n    all_ans = []\n    for i, beta_main in enumerate(Kumar_beta_list):\n        beta_ans = []\n        for beta in (beta_main-1, beta_main+1):\n            Re_ans = []\n            for Re_main in Kumar_Nu_Res[i]:\n                for Re in [Re_main-1, Re_main+1]:\n                    ans = Nu_plate_Kumar(Re, 0.7, beta)\n                    Re_ans.append(ans)\n            beta_ans.append(Re_ans)\n        all_ans.append(beta_ans)\n\n        for row1, row2 in zip(all_ans_expected, all_ans):\n            assert_allclose(row1, row2)\n#            assert_close(row1, row2)\n\n\ndef test_Nu_plate_Martin():\n    Nu = Nu_plate_Martin(2000.0, .7, 45.0)\n    assert_close(Nu, 30.427601053757712)\n\n    Nu = Nu_plate_Martin(2000.0, .7, 45.0, variant=\"VDI\")\n    assert_close(Nu, 30.418672)\n\n\ndef test_Nu_plate_Muley_Manglik():\n    Nu = Nu_plate_Muley_Manglik(Re=2000.0, Pr=.7, chevron_angle=45.0, plate_enlargement_factor=1.18)\n    assert_close(Nu, 36.49087100602062)\n\n\ndef test_Nu_plate_Khan_Khan():\n    # The author presented three correlations; all of them are well matched by\n    # the fourth correlation. beta max is not the largest angle in *your*\n    # PHE, but of the ones they tested.\n    Nu = Nu_plate_Khan_Khan(Re=1000.0, Pr=4.5, chevron_angle=30.0)\n    assert_close(Nu, 38.40883639103741 )\n\n\n\n\n"
  },
  {
    "path": "tests/test_conv_supercritical.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017, 2018, 2019, Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close, assert_close1d\n\nfrom ht import (\n    Nu_Bishop,\n    Nu_Bringer_Smith,\n    Nu_Gorban,\n    Nu_Griem,\n    Nu_Gupta,\n    Nu_Jackson,\n    Nu_Kitoh,\n    Nu_Krasnoshchekov,\n    Nu_Krasnoshchekov_Protopopov,\n    Nu_McAdams,\n    Nu_Mokry,\n    Nu_Ornatsky,\n    Nu_Petukhov,\n    Nu_Shitsman,\n    Nu_Swenson,\n    Nu_Xu,\n    Nu_Yamagata,\n    Nu_Zhu,\n)\n\n\ndef test_Nu_McAdams():\n    Nu = Nu_McAdams(1E5, 1.2)\n    assert_close(Nu, 261.3838629346147)\n\n\ndef test_Nu_Shitsman():\n     Nus = [Nu_Shitsman(1E5, 1.2, 1.6), Nu_Shitsman(1E5, 1.6, 1.2)]\n     assert_close1d(Nus, [266.1171311047253]*2)\n\n\ndef test_Nu_Griem():\n    Nu = Nu_Griem(1E5, 1.2)\n    assert_close(Nu, 275.4818576600527)\n    hs = [225.8951232812432, 240.77114359488607, 275.4818576600527]\n    hs_calc = [Nu_Griem(1E5, 1.2, H) for H in [1.52E6, 1.6E6, 1.8E6]]\n    assert_close1d(hs, hs_calc)\n\n\ndef test_Nu_Jackson():\n    Nu = Nu_Jackson(1E5, 1.2)\n    assert_close(Nu, 252.37231572974918)\n\n    Nu_calc = [Nu_Jackson(1E5, 1.2, rho_w=125.8, rho_b=249.0233,\n                          Cp_avg=2080.845, Cp_b=2048.621, T_b=650, T_w=700,\n                          T_pc=T) for T in [750, 675, 600]]\n    Nu_exp = [206.91175020307264, 206.93567238866916, 206.97455183928113]\n    assert_close1d(Nu_calc, Nu_exp)\n\n\ndef test_Nu_Gupta():\n    Nu = Nu_Gupta(1E5, 1.2)\n    assert_close(Nu, 189.78727690467736)\n    Nu = Nu_Gupta(1E5, 1.2, 330, 290., 8e-4, 9e-4)\n    assert_close(Nu, 186.20135477175126)\n\n\ndef test_Nu_Swenson():\n    Nu = Nu_Swenson(1E5, 1.2)\n    assert_close(Nu, 211.51968418167206)\n    Nu = Nu_Swenson(1E5, 1.2, 330, 290.)\n    assert_close(Nu, 217.92827034803668)\n\n\ndef test_Nu_Xu():\n    Nu = Nu_Xu(1E5, 1.2)\n    assert_close(Nu, 293.9572513612297)\n    Nu = Nu_Xu(1E5, 1.2, 330, 290., 8e-4, 9e-4)\n    assert_close(Nu, 289.133054256742)\n\n\ndef test_Nu_Mokry():\n    Nu = Nu_Mokry(1E5, 1.2)\n    assert_close(Nu, 228.8178008454556)\n    Nu = Nu_Mokry(1E5, 1.2, 330, 290.)\n    assert_close(Nu, 246.1156319156992)\n\n\ndef test_Nu_Bringer_Smith():\n    Nu = Nu_Bringer_Smith(1E5, 1.2)\n    assert_close(Nu, 208.17631753279107)\n\n\ndef test_Nu_Ornatsky():\n    Nu = Nu_Ornatsky(1E5, 1.2, 1.5, 330, 290.)\n    assert_close(Nu, 276.63531150832307)\n    Nu = Nu_Ornatsky(1E5, 1.2, 1.5)\n    assert_close(Nu, 266.1171311047253)\n\n\ndef test_Nu_Gorban():\n    Nu = Nu_Gorban(1E5, 1.2)\n    assert_close(Nu, 182.5367282733999)\n\n\ndef test_Nu_Zhu():\n    Nu = Nu_Zhu(1E5, 1.2, 330, 290., 0.63, 0.69)\n    assert_close(Nu, 240.1459854494706)\n    Nu = Nu_Zhu(1E5, 1.2)\n    assert_close(Nu, 241.2087720246979)\n\n\ndef test_Nu_Bishop():\n    Nu = Nu_Bishop(1E5, 1.2, 330.0, 290., .01, 1.2)\n    assert_close(Nu, 265.3620050072533)\n    Nu = Nu_Bishop(1E5, 1.2)\n    assert_close(Nu, 246.09835634820243)\n\n\ndef test_Nu_Yamagata():\n    Nu = Nu_Yamagata(1E5, 1.2)\n    assert_close(Nu, 283.9383689412967)\n\n    Nu_calc = [Nu_Yamagata(1E5, 1.2, 1.5, Cp_avg=2080.845, Cp_b=2048.621,\n                           T_b=650, T_w=700, T_pc=T) for T in [750.0, 675.0, 600.0]]\n    Nu_exp = [283.9383689412967, 187.02304885276828, 292.3473428004679]\n    assert_close1d(Nu_calc, Nu_exp)\n\n\ndef test_Nu_Kitoh():\n    Nu = Nu_Kitoh(1E5, 1.2)\n    assert_close(Nu, 302.5006546293724)\n\n    Nu_calc = [Nu_Kitoh(1E5, 1.2, H, 1500, 5E6) for H in [1.4E6, 2E6, 3.5E6]]\n    Nu_exp = [331.80234139591306, 174.8417387874232, 308.40146536866945]\n    assert_close1d(Nu_calc, Nu_exp)\n\n\ndef test_Nu_Krasnoshchekov_Protopopov():\n    Nu = Nu_Krasnoshchekov_Protopopov(1E5, 1.2, 330, 290., 0.62, 0.52, 8e-4, 9e-4)\n    assert_close(Nu, 228.85296737400222)\n\n\ndef test_Nu_Petukhov():\n    Nu = Nu_Petukhov(1E5, 1.2, 330.0, 290., 8e-4, 9e-4)\n    assert_close(Nu, 254.8258598466738)\n\n\ndef test_Nu_Krasnoshchekov():\n    Nu_calc = [Nu_Krasnoshchekov(1E5, 1.2, rho_w=125.8, rho_b=249.0233,\n                          Cp_avg=2080.845, Cp_b=2048.621, T_b=650, T_w=700,\n                          T_pc=T) for T in [750.0, 675.0]]\n    Nu_exp = [192.52819597784372, 192.54822916468785]\n    assert_close1d(Nu_calc, Nu_exp)\n\n    Nu_3 = Nu_Krasnoshchekov(1E5, 1.2, rho_w=125.8, rho_b=249.0233,\n                      Cp_avg=2080.845, Cp_b=2048.621, T_b=400.0, T_w=200.0, T_pc=400.0)\n    assert_close(Nu_3, 192.2579518680533)\n\n    Nu = Nu_Krasnoshchekov(1E5, 1.2)\n    assert_close(Nu, 234.82855185610364)\n"
  },
  {
    "path": "tests/test_conv_tube_bank.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport numpy as np\nfrom fluids.numerics import assert_close, assert_close1d, assert_close2d, bisplev, linspace\nfrom scipy.interpolate import RectBivariateSpline, UnivariateSpline, interp1d, splrep\n\nfrom ht import (\n    ESDU_tube_angle_correction,\n    ESDU_tube_row_correction,\n    Nu_ESDU_73031,\n    Nu_Grimison_tube_bank,\n    Nu_HEDH_tube_bank,\n    Nu_Zukauskas_Bejan,\n    Zukauskas_tube_row_correction,\n    baffle_correction_Bell,\n    baffle_leakage_Bell,\n    bundle_bypassing_Bell,\n    dP_Kern,\n    dP_Zukauskas,\n    laminar_correction_Bell,\n    unequal_baffle_spacing_Bell,\n)\nfrom ht.conv_tube_bank import dP_inline_correction_tck, dP_inline_f_tck, dP_staggered_correction_tck, dP_staggered_f_tck\n\n\ndef test_Nu_Grimison_tube_bank_tcks():\n    from ht.conv_tube_bank import Grimison_C1_aligned, Grimison_C1_aligned_tck, Grimison_SL_aligned, Grimison_ST_aligned\n    Grimison_C1_aligned_interp = RectBivariateSpline(Grimison_ST_aligned,\n                                                     Grimison_SL_aligned,\n                                                     np.array(Grimison_C1_aligned))\n\n    tck_recalc = Grimison_C1_aligned_interp.tck\n    [assert_close1d(i, j) for i, j in zip(Grimison_C1_aligned_tck, tck_recalc)]\n\n    from ht.conv_tube_bank import Grimison_m_aligned, Grimison_m_aligned_tck\n    Grimison_m_aligned_interp = RectBivariateSpline(Grimison_ST_aligned,\n                                                    Grimison_SL_aligned,\n                                                    np.array(Grimison_m_aligned))\n    tck_recalc = Grimison_m_aligned_interp.tck\n    [assert_close1d(i, j) for i, j in zip(Grimison_m_aligned_tck, tck_recalc)]\n\ndef test_Nu_Grimison_tube_bank():\n    Nu = Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=11,  pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(Nu, 79.07883866010096)\n\n    Nu = Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=11,  pitch_normal=.07, pitch_parallel=.05, Do=.025)\n    assert_close(Nu, 79.92721078571385)\n\n    Nu = Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=7,  pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(Nu, 77.49726188689894)\n\n    Nu = Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=7,  pitch_normal=.07, pitch_parallel=.05, Do=.025)\n    assert_close(Nu, 78.32866656999958)\n\n    # Test the negative input\n    args = dict(Re=10263.37, Pr=.708, tube_rows=-1, pitch_normal=.07, pitch_parallel=.05, Do=.025)\n    Nu_neg = Nu_Grimison_tube_bank(**args)\n    args[\"tube_rows\"] = 1\n    Nu_pos =  Nu_Grimison_tube_bank(**args)\n    assert_close(Nu_neg, Nu_pos)\n\n    # Check all data - for changing interpolations\n    Nu_bulk = [[Nu_Grimison_tube_bank(Re=10263.37, Pr=.708, tube_rows=11,  pitch_normal=j, pitch_parallel=i, Do=.025) for i in [.025, .04, .05, .75, .1, .15, .2]] for j in [.025, .04, .05, .75, .1, .15, .2]]\n    Nu_bulk_expect = [[83.05244932418451, 152.02626127499462, 92.67853984384722, 80.45909971688272, 80.45909971688272, 80.45909971688272, 80.45909971688272], [81.37409021240403, 75.87989409125535, 88.19403137832364, 90.10492890754932, 90.10492890754932, 90.10492890754932, 90.10492890754932], [80.154658166616, 79.27931854213506, 79.07883866010096, 88.31182349500988, 88.31182349500988, 88.31182349500988, 88.31182349500988], [73.98350370839236, 76.51020564051443, 78.3597838488104, 79.12612063682283, 86.25920529135, 86.25920529135, 86.25920529135], [73.98350370839236, 76.51020564051443, 78.3597838488104, 86.25920529135, 79.12612063682283, 86.25920529135, 86.25920529135], [73.98350370839236, 76.51020564051443, 78.3597838488104, 86.25920529135, 86.25920529135, 79.12612063682283, 86.25920529135], [73.98350370839236, 76.51020564051443, 78.3597838488104, 86.25920529135, 86.25920529135, 86.25920529135, 79.12612063682283]]\n    assert_close2d(Nu_bulk, Nu_bulk_expect)\n\ndef test_Gimison_coeffs_regeneration():\n    # These fits are bad, don't check them\n    # SciPy has warnings for both of them\n    pass\n#    tck = bisplrep(Grimson_ST_staggered, Grimson_SL_staggered, Grimson_C1_staggered, kx=1, ky=1, task=0, s=0)\n#    [assert_close1d(i, j) for i, j in zip(tck, tck_Grimson_C1_staggered)]\n#\n#    tck = bisplrep(Grimson_ST_staggered, Grimson_SL_staggered, Grimson_m_staggered, kx=1, ky=1, task=0, s=0)\n#    [assert_close1d(i, j) for i, j in zip(tck, tck_Grimson_m_staggered)]\n#\n\n\ndef test_ESDU_tube_row_correction():\n    F2 = ESDU_tube_row_correction(4, staggered=True)\n    assert_close(F2, 0.8984, rtol=1e-4)\n    F2 = ESDU_tube_row_correction(6, staggered=False)\n    assert_close(F2, 0.9551, rtol=1E-4)\n\n    # Test all of the inputs work\n    all_values = [ESDU_tube_row_correction(i, staggered=j) for i in range(12) for j in (True, False)]\n\ndef test_ESDU_tube_row_correction_refit():\n    # Re-fit the data\n    from ht.conv_tube_bank import ESDU_73031_F2_inline, ESDU_73031_F2_staggered\n\n    ## Commands used to obtain the fitted data:\n    ESDU_nrs = [3., 3.0189, 3.04129, 3.04891, 3.06251, 3.06481, 3.08274, 3.09166, 3.10623, 3.11518, 3.12645, 3.13538, 3.14668, 3.16219, 3.1669, 3.18571, 3.1871,\n        3.20732, 3.20924, 3.23084, 3.23273, 3.25107, 3.25625, 3.27126, 3.27977, 3.29808, 3.30329, 3.32816, 3.33011, 3.35363, 3.37712, 3.40394, 3.42746,\n        3.45428, 3.47777, 3.48683, 3.50461, 3.51691, 3.5281, 3.54369, 3.55492, 3.56721, 3.57841, 3.59077, 3.6019, 3.61426, 3.62872, 3.63778, 3.6949,\n        3.80655, 3.80918, 3.93332, 3.99431, 4.10792, 4.20204, 4.36618, 4.47351, 4.56706, 4.60082, 4.7014, 4.78854, 4.808, 4.90913, 4.97601, 5.05637, 5.0589,\n        5.1132, 5.11574, 5.14332, 5.14582, 5.1701, 5.17593, 5.19692, 5.20601, 5.22704, 5.2361, 5.25709, 5.26621, 5.28711, 5.293, 5.32308, 5.35319, 5.38324,\n        5.39435, 5.41336, 5.42088, 5.42116, 5.44347, 5.47355, 5.50364, 5.53372, 5.56159, 5.56383, 5.58834, 5.59392, 5.61846, 5.624, 5.64857, 5.65408,\n        5.67865, 5.68416, 5.70877, 5.71424, 5.73885, 5.74436, 5.76896, 5.77777, 5.79905, 5.80782, 5.82913, 5.8379, 5.85592, 5.86798, 5.88936, 5.89807,\n        5.92815, 5.95823, 5.98828, 6.01836, 6.02978, 6.04845, 6.06313, 6.08186, 6.09321, 6.11191, 6.1233, 6.14202, 6.15338, 6.17207, 6.18346, 6.20215,\n        6.21354, 6.23556, 6.24363, 6.26565, 6.27704, 6.2957, 6.30709, 6.32908, 6.33717, 6.35916, 6.36725, 6.38924, 6.41929, 6.42076, 6.45267, 6.48275,\n        6.5128, 6.52099, 6.54289, 6.55431, 6.57626, 6.58439, 6.60635, 6.6364, 6.66978, 6.69983, 6.71797, 6.72991, 6.74805, 6.76329, 6.78143, 6.79334,\n        6.81148, 6.82672, 6.84156, 6.8568, 6.87491, 6.89014, 6.90499, 6.9202, 6.93837, 6.95028, 6.96842, 6.98362, 6.99847, 7.01371, 7.03185, 7.04376,\n        7.0619, 7.07714, 7.09195, 7.11048, 7.14056, 7.17062, 7.17544, 7.19874, 7.20399, 7.23212, 7.23404, 7.26409, 7.2655, 7.29555, 7.29744, 7.3289,\n        7.33082, 7.35895, 7.36087, 7.389, 7.39425, 7.42234, 7.42427, 7.45239, 7.45432, 7.48574, 7.4877, 7.51579, 7.51772, 7.54914, 7.55109, 7.57919,\n        7.58114, 7.61253, 7.61449, 7.64454, 7.67792, 7.70794, 7.74132, 7.74599, 7.77134, 7.80471, 7.83473, 7.86811, 7.87284, 7.89813, 7.90273, 7.93148,\n        7.93275, 7.96153, 7.9661, 7.99487, 7.99612, 8.02493, 8.02947, 8.05827, 8.06281, 8.08829, 8.09283, 8.12164, 8.12618, 8.15502, 8.1562, 8.18503,\n        8.18951, 8.21838, 8.22286, 8.2484, 8.25288, 8.28178, 8.28619, 8.31509, 8.34514, 8.37849, 8.40851, 8.40956, 8.43958, 8.44186, 8.46957, 8.47187,\n        8.50291, 8.50522, 8.53524, 8.53623, 8.56625, 8.56859, 8.5986, 8.59956, 8.63192, 8.63288, 8.66286, 8.66527, 8.69529, 8.69621, 8.72863, 8.72953,\n        8.75865, 8.75951, 8.792, 8.79283, 8.82202, 8.82614, 8.84944, 8.85533, 8.88868, 8.91866, 8.94938, 8.95201, 8.98273, 8.98536, 9.01269, 9.01538,\n        9.04869, 9.08201, 9.18589, 9.22535, 9.25866, 9.28865, 9.32196, 9.35531, 9.38862, 9.41861, 9.45193, 9.48524, 9.51852, 9.55184, 9.58183, 9.61511,\n        9.64842, 9.68174, 9.71502, 9.74834, 9.77832, 9.81161, 9.84492, 9.8782, 9.91152, 9.94483, 9.97482\n    ]\n    ESDU_F_in = [0.847863, 0.847938, 0.848157, 0.848231, 0.849657, 0.8498, 0.850916, 0.851272, 0.851854, 0.852412, 0.853114, 0.853669, 0.854374, 0.85534,\n        0.855633, 0.856658, 0.856734, 0.857993, 0.858083, 0.859091, 0.859208, 0.86035, 0.860633, 0.861451, 0.861747, 0.862385, 0.862491, 0.862997, 0.863133,\n        0.864769, 0.866404, 0.86827, 0.869906, 0.871772, 0.873407, 0.874037, 0.874399, 0.874649, 0.874973, 0.875424, 0.875948, 0.876521, 0.877119, 0.877778,\n        0.878223, 0.878716, 0.87939, 0.879813, 0.882477, 0.88784, 0.887966, 0.892807, 0.895431, 0.900319, 0.903854, 0.910018, 0.914049, 0.917017, 0.918089,\n        0.921673, 0.92463, 0.925231, 0.928356, 0.929894, 0.932218, 0.932273, 0.933445, 0.93351, 0.934217, 0.934289, 0.934992, 0.935195, 0.935926, 0.936159,\n        0.936698, 0.936834, 0.93715, 0.937239, 0.937443, 0.937639, 0.938643, 0.939648, 0.940651, 0.941021, 0.940661, 0.940518, 0.941956, 0.942443, 0.943101,\n        0.943758, 0.944416, 0.945025, 0.945076, 0.94564, 0.945783, 0.946412, 0.946554, 0.947183, 0.947295, 0.947795, 0.947937, 0.948567, 0.948679, 0.949179,\n        0.94932, 0.949951, 0.95013, 0.950563, 0.950742, 0.951175, 0.951429, 0.95195, 0.952227, 0.952719, 0.952909, 0.953567, 0.954224, 0.954881, 0.955538,\n        0.955788, 0.95595, 0.956078, 0.956459, 0.95669, 0.95707, 0.957302, 0.957683, 0.957914, 0.958294, 0.958526, 0.958906, 0.959138, 0.959586, 0.95975,\n        0.960152, 0.960359, 0.96064, 0.960812, 0.961259, 0.961424, 0.961871, 0.962036, 0.962541, 0.963232, 0.963266, 0.963848, 0.964396, 0.964944, 0.965093,\n        0.965178, 0.965223, 0.96567, 0.965835, 0.966183, 0.966659, 0.967188, 0.967664, 0.967952, 0.968195, 0.968564, 0.968769, 0.969013, 0.969193, 0.969466,\n        0.969776, 0.970078, 0.97021, 0.970367, 0.970678, 0.97098, 0.971184, 0.971429, 0.971608, 0.971881, 0.97211, 0.972334, 0.972539, 0.972783, 0.972962,\n        0.973235, 0.973465, 0.973688, 0.97399, 0.974481, 0.974972, 0.975051, 0.97503, 0.975101, 0.975479, 0.975505, 0.97591, 0.975929, 0.976381, 0.976397,\n        0.976671, 0.9767, 0.977123, 0.977152, 0.977575, 0.977621, 0.977865, 0.977894, 0.978317, 0.978334, 0.978607, 0.978636, 0.979059, 0.979076, 0.979349,\n        0.979378, 0.979801, 0.979818, 0.980091, 0.980113, 0.980446, 0.980815, 0.981148, 0.981517, 0.981569, 0.981929, 0.982404, 0.982831, 0.983305,\n        0.983373, 0.98308, 0.983026, 0.983307, 0.983319, 0.983569, 0.983609, 0.983889, 0.983901, 0.984151, 0.984191, 0.984441, 0.984481, 0.984729, 0.984773,\n        0.985023, 0.985063, 0.985344, 0.985355, 0.985468, 0.985485, 0.985736, 0.985775, 0.986024, 0.986068, 0.98618, 0.986198, 0.986434, 0.986679, 0.986952,\n        0.987197, 0.987206, 0.987498, 0.987508, 0.987631, 0.987651, 0.987921, 0.98793, 0.988047, 0.988051, 0.988343, 0.988352, 0.98847, 0.988473, 0.988599,\n        0.988603, 0.988736, 0.988757, 0.989018, 0.989026, 0.989152, 0.989156, 0.989285, 0.989289, 0.989415, 0.989419, 0.989532, 0.989548, 0.989528,\n        0.989551, 0.989681, 0.989798, 0.989917, 0.98994, 0.990207, 0.990205, 0.99018, 0.990188, 0.990281, 0.990374, 0.990664, 0.990775, 0.990868, 0.990952,\n        0.991045, 0.991138, 0.991231, 0.991315, 0.991408, 0.991501, 0.991594, 0.991687, 0.991771, 0.991864, 0.991957, 0.99205, 0.992143, 0.992236, 0.99232,\n        0.992413, 0.992506, 0.992599, 0.992692, 0.992785, 0.992869\n    ]\n    ESDU_F_st = [0.859287, 0.859485, 0.860059, 0.860415, 0.861049, 0.861156, 0.861887, 0.86225, 0.86293, 0.863347, 0.863962, 0.864448, 0.864841, 0.865382,\n        0.865602, 0.866479, 0.866544, 0.867487, 0.867576, 0.868439, 0.868514, 0.869369, 0.869611, 0.870311, 0.870708, 0.871562, 0.871805, 0.872672, 0.87274,\n        0.873837, 0.874774, 0.875709, 0.876806, 0.877741, 0.878678, 0.879047, 0.879772, 0.880263, 0.88071, 0.881253, 0.881644, 0.882135, 0.882582, 0.883075,\n        0.883519, 0.88395, 0.884454, 0.884812, 0.88707, 0.891483, 0.891577, 0.896007, 0.898184, 0.901839, 0.904867, 0.909992, 0.913054, 0.915723, 0.91661,\n        0.919254, 0.921545, 0.922057, 0.924542, 0.926185, 0.92816, 0.928222, 0.929395, 0.929449, 0.93001, 0.930061, 0.930684, 0.930833, 0.93126, 0.931445,\n        0.931873, 0.932057, 0.932595, 0.932829, 0.933433, 0.933604, 0.934216, 0.934988, 0.93544, 0.935724, 0.936212, 0.936404, 0.936412, 0.936983, 0.937596,\n        0.938208, 0.93882, 0.939534, 0.939591, 0.94009, 0.940204, 0.940703, 0.940816, 0.941316, 0.941428, 0.941928, 0.94204, 0.94254, 0.942652, 0.943282,\n        0.943424, 0.943872, 0.944033, 0.944353, 0.944485, 0.944919, 0.945097, 0.945464, 0.945709, 0.946144, 0.946321, 0.946933, 0.947545, 0.947998, 0.94861,\n        0.948842, 0.949222, 0.94949, 0.949831, 0.950002, 0.950283, 0.950575, 0.951055, 0.951226, 0.951507, 0.951739, 0.952119, 0.952327, 0.952729, 0.952893,\n        0.953341, 0.953512, 0.953793, 0.953946, 0.954242, 0.954407, 0.954854, 0.955019, 0.955466, 0.955919, 0.955939, 0.956368, 0.95698, 0.957433, 0.957599,\n        0.958045, 0.958198, 0.958494, 0.958659, 0.959106, 0.959558, 0.960008, 0.96046, 0.960829, 0.961072, 0.961317, 0.961522, 0.961795, 0.961974, 0.962218,\n        0.962423, 0.962725, 0.963035, 0.963193, 0.963325, 0.963549, 0.963777, 0.964147, 0.96439, 0.964547, 0.964679, 0.964981, 0.965291, 0.965564, 0.965744,\n        0.965988, 0.966193, 0.966322, 0.966483, 0.967095, 0.967547, 0.967612, 0.967926, 0.967996, 0.96842, 0.968449, 0.968901, 0.968913, 0.969174, 0.969191,\n        0.969614, 0.96964, 0.970064, 0.970093, 0.970471, 0.970542, 0.970816, 0.970835, 0.971258, 0.971287, 0.97171, 0.971736, 0.97201, 0.972029, 0.972452,\n        0.972478, 0.972901, 0.972931, 0.973203, 0.97322, 0.973673, 0.974122, 0.974415, 0.974864, 0.97491, 0.975157, 0.975606, 0.975899, 0.976348, 0.976394,\n        0.976641, 0.976681, 0.97693, 0.97695, 0.977383, 0.977422, 0.977672, 0.977691, 0.978125, 0.978164, 0.978414, 0.978459, 0.978707, 0.978746, 0.978997,\n        0.979058, 0.979446, 0.979457, 0.979739, 0.979778, 0.980028, 0.980072, 0.980321, 0.980381, 0.98077, 0.980788, 0.9809, 0.981353, 0.981642, 0.981935,\n        0.981944, 0.982205, 0.982225, 0.982495, 0.982517, 0.982787, 0.982807, 0.983099, 0.983108, 0.983369, 0.983389, 0.983682, 0.983685, 0.983812, 0.98382,\n        0.98408, 0.984101, 0.984394, 0.984402, 0.984684, 0.984692, 0.984976, 0.984984, 0.985266, 0.985274, 0.985559, 0.985575, 0.985666, 0.985689, 0.985978,\n        0.986111, 0.986378, 0.986401, 0.986668, 0.98669, 0.986957, 0.986983, 0.987113, 0.987243, 0.98796, 0.988233, 0.988363, 0.988496, 0.988626, 0.988915,\n        0.989045, 0.989178, 0.989308, 0.989438, 0.989408, 0.989538, 0.989671, 0.989641, 0.989771, 0.989901, 0.989872, 0.990001, 0.990134, 0.990105,\n        0.990235, 0.990205, 0.990335, 0.990465, 0.990598\n    ]\n    ESDU_in = interp1d(ESDU_nrs, ESDU_F_in)\n    ESDU_st = interp1d(ESDU_nrs, ESDU_F_st)\n\n\n    inline_factors = [round(float(ESDU_in(i)),4) for i in range(3, 10)]\n    staggered_factors = [round(float(ESDU_st(i)),4) for i in range(3, 10)]\n    assert_close1d(inline_factors, ESDU_73031_F2_inline)\n    assert_close1d(staggered_factors, ESDU_73031_F2_staggered)\n\n    #import matplotlib.pyplot as plt\n    #plt.plot(ESDU_nrs, ESDU_F_in)\n    #plt.plot(ESDU_nrs, ESDU_F_st)\n    #\n    #plt.plot(range(3, 10), inline_factors, 'o')\n    #plt.plot(range(3, 10), staggered_factors, 'o')\n    #plt.show()\n\ndef test_ESDU_tube_angle_correction():\n    F3 = ESDU_tube_angle_correction(75)\n    assert_close(F3, 0.9794139080247666)\n\n    # Digitized data from graph\n#    angles = [19.7349, 20.1856, 20.4268, 20.8778, 21.3597, 21.8404, 22.3523, 22.8326, 23.3148, 23.8252, 24.1867, 24.6375, 25.0891, 25.5697, 26.021, 26.5312, 26.9528, 27.4633, 27.9745, 28.455, 28.8762, 29.3867, 30.0483, 30.5291, 30.9798, 31.4905, 31.9712, 32.4519, 32.9026, 33.3833, 33.8938, 34.3743, 34.855, 35.3655, 35.846, 36.3268, 36.8372, 37.3178, 37.8282, 38.3385, 38.8491, 39.3893, 39.8995, 40.38, 40.9203, 41.4305, 41.9706, 42.511, 43.081, 43.5912, 44.1612, 44.7312, 45.2416, 45.8415, 46.3814, 46.9513, 47.5213, 48.0911, 48.6611, 49.231, 49.8008, 50.4004, 50.9701, 51.5698, 52.1694, 52.7393, 53.3386, 53.9382, 54.5378, 55.1372, 55.7069, 56.3062, 56.9356, 57.5648, 58.1642, 58.7935, 59.4227, 60.0818, 60.711, 61.3103, 61.9694, 62.5986, 63.2573, 63.9163, 64.5752, 65.234, 65.8929, 66.5514, 67.2102, 67.869, 68.5575, 69.2162, 69.9047, 70.5632, 71.2813, 71.94, 72.6284, 73.3464, 74.0346, 74.7526, 75.4706, 76.1587, 76.8765, 77.5944, 78.3122, 79.0299, 79.7476, 80.4952, 81.2129, 81.9305, 82.6479, 83.3952, 84.083, 84.8003, 85.5179, 86.2652, 86.9825, 87.7295, 88.4468, 89.1642, 89.9112, 90]\n#    F3s = [0.528819, 0.534137, 0.538566, 0.544474, 0.552447, 0.557766, 0.566034, 0.570763, 0.579326, 0.584351, 0.590551, 0.59587, 0.602957, 0.608276, 0.614774, 0.619504, 0.626296, 0.631616, 0.63841, 0.643434, 0.649342, 0.654662, 0.663523, 0.669137, 0.674456, 0.680071, 0.685685, 0.691004, 0.696322, 0.701641, 0.706961, 0.711986, 0.7176, 0.72292, 0.727944, 0.733558, 0.738583, 0.743902, 0.748928, 0.753953, 0.759273, 0.764299, 0.769029, 0.774053, 0.779079, 0.78381, 0.788541, 0.793862, 0.798594, 0.803324, 0.808056, 0.812788, 0.817813, 0.822546, 0.826982, 0.831419, 0.836151, 0.840588, 0.84532, 0.849757, 0.854194, 0.858337, 0.86248, 0.866917, 0.871061, 0.875498, 0.879051, 0.883194, 0.887337, 0.891185, 0.895328, 0.898881, 0.90273, 0.906284, 0.910133, 0.913982, 0.917536, 0.921091, 0.924645, 0.928199, 0.931754, 0.935308, 0.938273, 0.941533, 0.944794, 0.947759, 0.951019, 0.953395, 0.95636, 0.959326, 0.961997, 0.964668, 0.967339, 0.969715, 0.971797, 0.974468, 0.976844, 0.978632, 0.980714, 0.982501, 0.984289, 0.986076, 0.987569, 0.989062, 0.990555, 0.991753, 0.992951, 0.99415, 0.995348, 0.996251, 0.996859, 0.997468, 0.998666, 0.998979, 0.999883, 1, 1, 1, 1, 1, 1, 1]\n#\n#    import matplotlib.pyplot as plt\n#    import numpy as np\n#\n#    plt.plot(angles, F3s)\n#    plt.plot(angles, np.sin(np.radians(angles))**0.6)\n#    plt.show()\n\ndef test_Zukauskas_tube_row_correction():\n    F = Zukauskas_tube_row_correction(4, staggered=True)\n    assert_close(F, 0.8942)\n    F = Zukauskas_tube_row_correction(6, staggered=False)\n    assert_close(F, 0.9465)\n\ndef test_Zukauskas_tube_row_correction_refit():\n    from scipy.interpolate import UnivariateSpline\n\n    from ht.conv_tube_bank import Zukauskas_Czs_high_Re_staggered, Zukauskas_Czs_inline, Zukauskas_Czs_low_Re_staggered\n    # Commands used to obtain the fitted data:\n    Zukauskas_Cz_Zs = [0.968219, 1.01968, 1.04164, 1.04441, 1.07539, 1.09332, 1.13914, 1.16636, 1.23636, 1.2394, 1.24505, 1.3125, 1.33358, 1.38554, 1.43141, 1.48282, 1.4876, 1.55352, 1.58004, 1.60466, 1.65726, 1.67493, 1.70188, 1.79682, 1.91823, 1.99323, 1.99665, 2.04002, 2.16306, 2.18556, 2.19045, 2.30691, 2.3086, 2.36006, 2.45272, 2.45413, 2.57543, 2.59826, 2.72341, 2.7451, 2.8896, 2.91482, 2.98759, 3.1572, 3.23203, 3.25334, 3.3511, 3.42295, 3.4499, 3.52072, 3.6168, 3.83565, 3.9076, 3.9826, 4.02939, 4.17411, 4.20042, 4.44242, 4.48937, 4.61023, 4.82811, 4.95071, 5.07038, 5.28825, 5.31232, 5.3621, 5.50606, 5.53014, 5.60405, 5.74801, 5.74807, 5.82181, 5.99012, 5.99017, 6.13636, 6.23207, 6.23212, 6.37826, 6.44983, 6.44988, 6.62015, 6.69183, 6.69188, 6.95807, 6.95812, 6.98312, 7.1767, 7.20001, 7.41772, 7.41848, 7.65967, 7.87743, 7.90156, 7.95003, 7.97416, 7.97476, 8.21606, 8.2166, 8.45795, 8.60365, 8.67571, 8.79712, 8.91809, 8.96597, 9.18368, 9.20824, 9.42551, 9.45013, 9.66741, 9.69197, 10.0786, 10.3208, 10.5623, 10.5626, 10.7803, 10.9737, 10.9978, 11.2398, 11.2399, 11.4574, 11.4575, 11.6993, 11.7478, 11.9653, 11.9896, 12.2072, 12.2315, 12.4491, 12.691, 12.7152, 12.9812, 13.2231, 13.2715, 13.465, 13.7068, 13.9246, 13.9487, 14.1905, 14.4324, 14.6743, 14.9161, 14.9887, 15.2305, 15.4724, 15.7142, 15.787, 15.811, 15.8835, 16.0046, 16.0287, 16.2465, 16.3673, 16.4883, 16.5124, 16.706, 16.7301, 16.9477, 16.9479, 17.1897, 17.2138, 17.4315, 17.6734, 17.9152, 17.9636, 18.2054, 18.2055, 18.4473, 18.6891, 18.9068, 18.931, 18.9793, 19.2212, 19.4631, 19.5599, 19.7049, 19.9467, 19.9952]\n    low_Re_staggered_Cz = [0.828685, 0.831068, 0.832085, 0.832213, 0.833647, 0.834478, 0.836599, 0.83786, 0.8411, 0.841241, 0.841503, 0.845561, 0.84683, 0.849956, 0.852715, 0.855808, 0.856096, 0.859148, 0.860376, 0.861516, 0.863952, 0.864828, 0.866165, 0.870874, 0.876897, 0.880617, 0.880787, 0.882293, 0.886566, 0.887348, 0.887517, 0.89214, 0.892207, 0.894249, 0.897396, 0.897444, 0.901563, 0.902338, 0.906589, 0.907258, 0.911719, 0.912497, 0.914744, 0.91998, 0.92229, 0.922729, 0.92474, 0.926218, 0.926772, 0.928561, 0.930987, 0.936514, 0.938332, 0.940226, 0.940947, 0.943179, 0.943584, 0.946941, 0.947769, 0.9499, 0.95374, 0.955902, 0.957529, 0.960492, 0.96082, 0.961497, 0.962826, 0.963048, 0.96373, 0.965208, 0.965208, 0.965965, 0.967759, 0.96776, 0.969318, 0.969757, 0.969758, 0.970428, 0.970757, 0.970757, 0.971538, 0.972422, 0.972422, 0.975703, 0.975704, 0.976012, 0.978249, 0.978139, 0.977115, 0.977111, 0.977585, 0.978013, 0.97806, 0.978155, 0.978202, 0.978204, 0.97819, 0.97819, 0.979578, 0.980416, 0.980411, 0.980405, 0.981521, 0.981333, 0.980478, 0.980382, 0.981379, 0.981492, 0.981479, 0.981478, 0.982147, 0.982566, 0.982553, 0.982553, 0.98254, 0.981406, 0.98171, 0.98476, 0.984762, 0.98475, 0.98475, 0.984736, 0.984733, 0.985732, 0.985843, 0.986842, 0.986953, 0.985817, 0.986825, 0.986926, 0.986911, 0.987834, 0.988018, 0.988008, 0.987994, 0.991353, 0.991148, 0.98909, 0.9902, 0.990187, 0.991297, 0.991293, 0.991279, 0.991266, 0.992054, 0.992292, 0.99237, 0.992366, 0.992359, 0.992358, 0.993068, 0.993463, 0.993456, 0.993454, 0.994443, 0.994566, 0.994553, 0.994553, 0.99454, 0.994539, 0.996774, 0.99676, 0.996746, 0.996744, 0.99673, 0.99673, 0.997466, 0.998201, 0.998863, 0.998936, 0.99902, 0.999439, 0.999857, 1.00002, 1.00002, 1, 1]\n    high_Re_staggered_Cz = [0.617923, 0.630522, 0.635897, 0.636344, 0.64134, 0.644232, 0.651621, 0.654452, 0.661728, 0.662045, 0.662632, 0.669643, 0.671835, 0.683767, 0.694302, 0.704706, 0.705673, 0.719014, 0.721221, 0.72327, 0.727649, 0.729119, 0.73359, 0.749337, 0.759443, 0.770509, 0.771014, 0.777413, 0.785006, 0.786394, 0.786756, 0.795376, 0.795545, 0.800697, 0.809975, 0.810062, 0.817547, 0.818955, 0.829084, 0.830839, 0.842534, 0.843935, 0.847977, 0.857398, 0.861555, 0.862739, 0.866619, 0.869471, 0.870563, 0.873432, 0.877325, 0.886614, 0.889668, 0.89251, 0.894282, 0.899765, 0.900781, 0.910119, 0.911931, 0.916595, 0.921077, 0.925619, 0.930052, 0.932064, 0.932286, 0.933053, 0.935273, 0.935644, 0.937165, 0.940127, 0.940128, 0.941835, 0.945731, 0.945731, 0.947081, 0.947964, 0.947965, 0.949465, 0.950199, 0.9502, 0.952562, 0.953557, 0.953558, 0.958036, 0.958037, 0.958267, 0.960054, 0.96027, 0.961381, 0.961388, 0.963615, 0.964614, 0.964725, 0.965472, 0.965844, 0.965847, 0.966954, 0.966957, 0.968064, 0.96956, 0.970299, 0.970762, 0.971224, 0.971406, 0.972518, 0.972516, 0.972504, 0.972617, 0.973614, 0.97368, 0.974715, 0.975264, 0.975811, 0.975814, 0.978048, 0.980033, 0.980281, 0.982515, 0.982515, 0.982502, 0.982503, 0.983612, 0.98361, 0.983597, 0.983709, 0.984707, 0.984819, 0.985817, 0.985804, 0.985896, 0.986911, 0.986898, 0.98712, 0.988008, 0.987994, 0.988994, 0.989104, 0.98909, 0.9902, 0.990187, 0.991297, 0.991293, 0.991279, 0.991266, 0.991252, 0.995742, 0.994903, 0.992366, 0.99573, 0.995729, 0.995716, 0.99571, 0.995703, 0.995826, 0.996814, 0.996813, 0.996801, 0.996801, 0.996787, 0.996786, 0.996774, 0.99676, 0.997682, 0.997867, 0.997854, 0.997854, 0.99784, 0.997826, 0.997814, 0.997813, 0.99781, 0.99892, 0.998907, 0.998901, 0.998893, 0.998879, 0.998877]\n    inline_Cz = [0.658582, 0.681965, 0.69194, 0.6932, 0.700314, 0.704433, 0.710773, 0.714541, 0.724228, 0.724649, 0.725518, 0.735881, 0.738799, 0.74599, 0.751285, 0.75722, 0.757717, 0.76457, 0.767327, 0.776314, 0.781783, 0.783619, 0.786421, 0.794105, 0.803931, 0.81, 0.810227, 0.813093, 0.821227, 0.822615, 0.822917, 0.830103, 0.830207, 0.833383, 0.839101, 0.839188, 0.847046, 0.848103, 0.853898, 0.854902, 0.862547, 0.863881, 0.868371, 0.875104, 0.878568, 0.879555, 0.884081, 0.886933, 0.888003, 0.890813, 0.894236, 0.902032, 0.904114, 0.906285, 0.907639, 0.910812, 0.911389, 0.916696, 0.917725, 0.92029, 0.924912, 0.927513, 0.930052, 0.934534, 0.934906, 0.935673, 0.937893, 0.938227, 0.939252, 0.941249, 0.94125, 0.942957, 0.946853, 0.946854, 0.948204, 0.949088, 0.949088, 0.950588, 0.951322, 0.951323, 0.953685, 0.954679, 0.95468, 0.959159, 0.95916, 0.959274, 0.960163, 0.96027, 0.961381, 0.961388, 0.963615, 0.96585, 0.966222, 0.966969, 0.966968, 0.966968, 0.966954, 0.966957, 0.968064, 0.96956, 0.970299, 0.970762, 0.971224, 0.971406, 0.972518, 0.972516, 0.972504, 0.972617, 0.973614, 0.973737, 0.975675, 0.976888, 0.978099, 0.9781, 0.979191, 0.98016, 0.980281, 0.982515, 0.982515, 0.982502, 0.982503, 0.983612, 0.98361, 0.983597, 0.983709, 0.984707, 0.984819, 0.985817, 0.985804, 0.985896, 0.986911, 0.986898, 0.98712, 0.988008, 0.987994, 0.988994, 0.989104, 0.98909, 0.9902, 0.990187, 0.991297, 0.991293, 0.991279, 0.991266, 0.991252, 0.995742, 0.994903, 0.992366, 0.99573, 0.995729, 0.995716, 0.99571, 0.995703, 0.995826, 0.996814, 0.996813, 0.996801, 0.996801, 0.996787, 0.996786, 0.996774, 0.99676, 0.997682, 0.997867, 0.997854, 0.997854, 0.99784, 0.997826, 0.997814, 0.997813, 0.99781, 0.99892, 0.998907, 0.998901, 0.998893, 0.998879, 0.998877]\n\n    # hand tuned smoothing\n    Zukauskas_Cz_low_Re_staggered_obj = UnivariateSpline(Zukauskas_Cz_Zs, low_Re_staggered_Cz, s=0.0001)\n    Zukauskas_Cz_high_Re_staggered_obj = UnivariateSpline(Zukauskas_Cz_Zs, high_Re_staggered_Cz, s=0.0005)\n    Zukauskas_Cz_inline_obj = UnivariateSpline(Zukauskas_Cz_Zs, inline_Cz, s=0.0005)\n\n    Zukauskas_Czs_inline2 = np.round(Zukauskas_Cz_inline_obj(range(1, 20)), 4).tolist()\n    assert_close1d(Zukauskas_Czs_inline, Zukauskas_Czs_inline2)\n\n    Zukauskas_Czs_low_Re_staggered2 = np.round(Zukauskas_Cz_low_Re_staggered_obj(range(1, 20)), 4).tolist()\n    assert_close1d(Zukauskas_Czs_low_Re_staggered, Zukauskas_Czs_low_Re_staggered2)\n\n    Zukauskas_Czs_high_Re_staggered2 = np.round(Zukauskas_Cz_high_Re_staggered_obj(range(1, 20)), 4).tolist()\n    assert_close1d(Zukauskas_Czs_high_Re_staggered, Zukauskas_Czs_high_Re_staggered2)\n\n\ndef test_Nu_Zukauskas_Bejan():\n    Nu = Nu_Zukauskas_Bejan(Re=1E4, Pr=7., tube_rows=10, pitch_parallel=.05, pitch_normal=.05)\n    assert_close(Nu, 175.9202277145248)\n\n    Nu = Nu_Zukauskas_Bejan(Re=1E4, Pr=7., tube_rows=10, pitch_parallel=.05, pitch_normal=.05, Pr_wall=9.0)\n    assert_close(Nu, 165.2074626671159)\n\n    Nus = [Nu_Zukauskas_Bejan(Re=Re, Pr=7., tube_rows=30, pitch_parallel=.05, pitch_normal=.05) for Re in (10, 2000, 1E5, 1E7)]\n    Nus_expect = [4.554889061992833, 65.35035570869223, 768.4207053648229, 26469.71311148279]\n    assert_close1d(Nus, Nus_expect)\n\n    Nus = [Nu_Zukauskas_Bejan(Re=Re, Pr=7., tube_rows=30, pitch_parallel=.05, pitch_normal=.09) for Re in (10, 2000, 1E5, 1E7)]\n    Nus_expect = [5.263427360525052, 75.85353712516013, 793.1545862201796, 27967.361063088636]\n    assert_close1d(Nus, Nus_expect)\n\ndef test_Nu_ESDU_73031():\n    Nu = Nu_ESDU_73031(Re=1.32E4, Pr=0.71, tube_rows=8, pitch_parallel=.09, pitch_normal=.05)\n    assert_close(98.2563319140594, Nu)\n\n    Nu = Nu_ESDU_73031(Re=1.32E4, Pr=0.71, tube_rows=8, pitch_parallel=.09, pitch_normal=.05, Pr_wall=0.71)\n    assert_close(98.2563319140594, Nu)\n\n    Nu = Nu_ESDU_73031(Re=1.32E4, Pr=0.71, tube_rows=8, pitch_parallel=.05, pitch_normal=.05, Pr_wall=0.75)\n    assert_close(87.69324193674449, Nu)\n\n    Nu = Nu_ESDU_73031(Re=1.32E4, Pr=0.71, tube_rows=3, pitch_parallel=.05, pitch_normal=.05, Pr_wall=0.75)\n    assert_close(Nu, 75.57180591337092)\n\n    Nus = [Nu_ESDU_73031(Re=Re, Pr=0.71, tube_rows=3, pitch_parallel=pp, pitch_normal=.05, Pr_wall=0.75) for pp in [0.09, 0.05] for Re in [100, 1E5, 1E6]]\n    Nus_expect = [5.179925804379317, 307.9970377601136, 1481.8545490578865, 4.0177935875859365, 282.40096167747, 1367.860174719831]\n    assert_close1d(Nus, Nus_expect)\n\n\ndef test_Nu_HEDH_tube_bank():\n    Nu = Nu_HEDH_tube_bank(Re=1E4, Pr=7., tube_rows=10, pitch_normal=.05, pitch_parallel=.05, Do=.03)\n    assert_close(Nu, 382.4636554404698)\n\n    Nu = Nu_HEDH_tube_bank(Re=10263.37, Pr=.708, tube_rows=11, pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(Nu, 149.18735251017594)\n\n    Nu =  Nu_HEDH_tube_bank(Re=1E4, Pr=7., tube_rows=5, pitch_normal=.05, pitch_parallel=.05, Do=.03)\n    assert_close(Nu, 359.0551204831393)\n\n\ndef test_dP_Kern():\n    from ht.conv_tube_bank import Kern_f_Re\n    f = [Kern_f_Re(v) for v in linspace(10, 1E6, 10)]\n    f_values = [6.0155491322862771, 0.19881943524161752, 0.1765198121811164, 0.16032260681398205, 0.14912064432650635, 0.14180674990498099, 0.13727374873569789, 0.13441446600494875, 0.13212172689902535, 0.12928835660421958]\n    assert_close1d(f, f_values)\n\n    dP = dP_Kern(11., 995., 0.000803, 0.584, 0.1524, 0.0254, .019, 22, 0.000657)\n    assert_close(dP, 18980.58768759033)\n\n    dP = dP_Kern(m=11., rho=995., mu=0.000803, DShell=0.584, LSpacing=0.1524, pitch=0.0254, Do=.019, NBaffles=22)\n    assert_close(dP, 19521.38738647667)\n\ndef test_dP_Kern_data():\n    from ht.conv_tube_bank import Kern_f_Re_tck\n\n    _Kern_dP_Res = np.array([9.9524, 11.0349, 12.0786, 13.0504, 14.0121, 15.0431, 16.1511, 17.1176, 17.9105, 18.9822,\n        19.9879, 21.0484, 22.0217, 23.1893, 24.8973, 26.0495, 27.7862, 29.835, 31.8252, 33.9506, 35.9822, 38.3852,\n        41.481, 43.9664, 47.2083, 50.6891, 54.0782, 58.0635, 63.5667, 68.2537, 74.247, 78.6957, 83.9573, 90.1511,\n        95.5596, 102.613, 110.191, 116.806, 128.724, 137.345, 150.384, 161.484, 171.185, 185.031, 196.139, 210.639,\n        230.653, 250.933, 281.996, 300.884, 329.472, 353.842, 384.968, 408.108, 444.008, 505.513, 560.821, 638.506,\n        690.227, 741.254, 827.682, 918.205, 1018.63, 1122.76, 1213.62, 1320.38, 1417.94, 1522.93, 1667.69, 1838.11,\n        2012.76, 2247.44, 2592.21, 2932.18, 3381.87, 3875.42, 4440.83, 5056.16, 5608.95, 6344.58, 7038.48, 8224.34,\n        9123.83, 10121.7, 11598, 12701.4, 14090, 15938.5, 17452.9, 19112.6, 20929.3, 24614, 29324.6, 34044.8,\n        37282.2, 42999.9, 50570.2, 55737.9, 59860.6, 65553, 70399.2, 78101.5, 84965.7, 96735.3, 110139, 122977,\n        136431, 152339, 165740, 180319, 194904, 207981, 223357, 241440, 257621, 283946, 317042, 353996, 408315,\n        452956, 519041, 590939, 668466, 751216, 827981, 894985, 1012440\n    ])\n    _Kern_dP_fs = 144.0 * np.array([0.0429177, 0.0382731, 0.0347901, 0.0316208, 0.0298653, 0.0276702, 0.0259671, 0.024523,\n        0.0237582, 0.0224369, 0.0211881, 0.0202668, 0.0193847, 0.0184234, 0.0172894, 0.0166432, 0.0155182,\n        0.0147509, 0.0138423, 0.0131572, 0.0124255, 0.0118105, 0.0110842, 0.0106028, 0.0100785, 0.00958019,\n        0.0092235, 0.00871144, 0.00817649, 0.0077722, 0.00743616, 0.0071132, 0.00684836, 0.00655159, 0.00634789,\n        0.00611185, 0.00592242, 0.00577517, 0.00552603, 0.00542355, 0.00522267, 0.00502847, 0.00493497, 0.00481301,\n        0.00469334, 0.00460654, 0.00449314, 0.00438231, 0.00424799, 0.00416922, 0.00406658, 0.00401703, 0.00394314,\n        0.0038947, 0.00382305, 0.00373007, 0.00368555, 0.00359592, 0.00357512, 0.003509, 0.00344515, 0.00338229,\n        0.00332057, 0.00328077, 0.00322026, 0.00316102, 0.00308274, 0.00308446, 0.00302787, 0.00297247, 0.0028993,\n        0.00284654, 0.00277759, 0.0027099, 0.00262738, 0.00256361, 0.00248541, 0.00244055, 0.00238072, 0.0023227,\n        0.00228032, 0.00222531, 0.00218471, 0.00214484, 0.00206613, 0.00205439, 0.00200402, 0.00196775, 0.00191932,\n        0.00189622, 0.00186143, 0.00180501, 0.0017393, 0.00170817, 0.00168761, 0.00163622, 0.00158663, 0.0015576,\n        0.00153862, 0.0015201, 0.00149199, 0.00147418, 0.00142864, 0.00139389, 0.00136874, 0.00133524, 0.00131931,\n        0.0012953, 0.00127147, 0.00124808, 0.00121724, 0.00121785, 0.00119533, 0.00118082, 0.00116638, 0.00114504,\n        0.00111702, 0.00108969, 0.00107013, 0.00104389, 0.00101205, 0.000987437, 0.000969567, 0.000939849,\n        0.000922653, 0.000905634, 0.000894962\n    ])\n#    # Used in preference over interp1d as saves 30% of execution time, and\n#    # performs some marginally small amount of smoothing\n#    # s=0.1 is chosen to have 9 knots, a reasonable amount.\n#    Kern_f_Re = UnivariateSpline(_Kern_dP_Res, _Kern_dP_fs, s=0.1)\n    tck = splrep(_Kern_dP_Res, _Kern_dP_fs, s=0.1)\n    [assert_close1d(i, j) for i, j in zip(Kern_f_Re_tck[:-1], tck[:-1])]\n\n\ndef test_dP_Zukauskas():\n    dP1 = dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0343, D=0.0164, rho=1.217, Vmax=12.6)\n    dP2 = dP_Zukauskas(Re=13943., n=7, ST=0.0313, SL=0.0313, D=0.0164, rho=1.217, Vmax=12.6)\n    assert_close1d([dP1, dP2], [235.22916169118335, 161.14703721855741])\n\n\ndef test_dP_Zukauskas_dP_dP_staggered_f_spline():\n    _dP_staggered_Res = np.array([10, 10.9129, 11.6733, 13.1024, 14.0153, 14.9918, 17.1536, 18.5267, 19.8182, 20.7261, 22.243, 23.7936, 26.7057, 28.5663, 32.2732,\n        34.858, 37.2879, 41.0554, 44.4722, 47.8949, 51.2337, 55.3369, 65.1821, 70.4025, 76.0437, 82.1368, 88.7182, 95.1284, 100.553, 103.386, 108.398,\n        116.441, 118.455, 127.808, 129.188, 139.389, 140.899, 153.665, 155.444, 167.595, 168.914, 182.793, 197.771, 201.613, 217.768, 223.559, 241.759,\n        246.457, 268.516, 278.915, 292.866, 304.208, 322.535, 335.015, 351.772, 366.482, 402.412, 415.414, 451.79, 465.314, 497.559, 512.453, 542.68,\n        570.321, 609.312, 610.163, 671.039, 671.953, 731.917, 732.915, 813.886, 839.919, 896.808, 977.69, 1016.19, 1119.14, 1221.31, 1244.48, 1346.07,\n        1455.66, 1482.44, 1603.12, 1616.93, 1748.56, 1780.79, 1925.77, 1961.27, 2056.71, 2060.37, 2266.81, 2308.27, 2474.96, 2542.2, 2723.03, 2799.84,\n        2996.9, 3053.95, 3274.27, 3363.57, 3606.09, 4001.84, 4005.75, 4367.03, 4411.71, 4809.6, 4854.24, 5297.21, 5346.19, 5777.99, 5836.5, 6184.44,\n        6739.62, 6817.15, 7422.65, 7435.62, 8188.61, 8256.81, 9005.89, 9089.79, 9914.09, 9931.42, 10832, 11357.6, 11913.2, 12508.2, 13011.2, 13642.4,\n        14309.8, 15024.5, 15759.5, 16387, 17188.6, 18046.5, 18772.3, 19683.7, 20458.2, 22313.4, 22950.8, 24573.9, 26311.7, 27049.2, 28976.2, 29516.6, 31605,\n        32505.6, 34805.6, 35453.4, 37961.9, 39045, 39838.4, 40171.7, 43802.4, 43836, 47853, 48253.3, 52629.1, 57429.8, 57958.7, 60823.7, 63808, 66429.9,\n        72454.1, 76644.8, 79791.3, 86914.7, 87727.5, 94796.5, 95846.9, 102543, 103393, 112734, 123172, 124193, 134342, 136770, 147946, 149173, 161368,\n        162701, 177710, 179183, 193825, 197329, 203406, 205093, 224028, 225878, 246499, 248787, 268891, 271756, 296172, 299307, 323098, 329652, 355768,\n        363073, 388139, 399883, 411321, 411637, 453053, 453370, 494224, 499159, 539099, 549766, 593776, 617117, 617548, 679896, 741914, 748826, 816818,\n        899347, 899975, 991217, 1029890, 1039630, 1134310, 1145030, 1249310, 1261120, 1375630, 1388740, 1515150, 1529530, 1668760, 1684660, 1837940,\n        1855450, 2063320, 2064190, 2251140, 2273460, 2479450, 2502990, 2730830, 2756750\n    ])\n    _dP_staggered_Re_125 = np.array([23.9929, 22.6513, 21.1808, 19.0604, 17.8231, 16.6661, 14.5725, 13.6264, 12.8644, 12.1931, 11.3569, 10.7219, 9.55649, 8.93611,\n        7.91304, 7.32822, 6.89654, 6.28568, 5.80434, 5.44301, 5.08949, 4.72306, 4.06698, 3.79555, 3.5683, 3.30447, 3.1177, 2.91006, 2.77913, 2.71412,\n        2.60635, 2.4487, 2.41753, 2.2802, 2.25939, 2.12672, 2.11005, 1.98054, 1.96397, 1.85661, 1.84576, 1.74274, 1.66846, 1.63677, 1.56011, 1.53763,\n        1.47248, 1.45689, 1.38943, 1.36053, 1.32959, 1.30743, 1.27402, 1.2528, 1.22604, 1.20401, 1.15477, 1.13664, 1.10541, 1.09271, 1.06394, 1.05209,\n        1.02957, 1.01043, 0.985509, 0.984989, 0.950966, 0.950537, 0.92446, 0.924083, 0.894818, 0.885516, 0.868347, 0.848317, 0.840024, 0.819658, 0.801646,\n        0.797824, 0.782058, 0.766644, 0.763863, 0.752037, 0.75061, 0.737713, 0.736366, 0.730623, 0.728723, 0.723802, 0.723618, 0.709974, 0.707146, 0.696311,\n        0.694446, 0.689689, 0.685538, 0.675409, 0.672874, 0.663594, 0.66181, 0.657217, 0.636046, 0.63585, 0.619904, 0.619273, 0.613337, 0.612083, 0.601667,\n        0.601114, 0.595116, 0.592882, 0.580202, 0.570252, 0.568954, 0.558333, 0.558117, 0.542262, 0.541366, 0.532074, 0.530674, 0.517089, 0.516819,\n        0.502141, 0.497421, 0.492707, 0.484889, 0.478584, 0.471858, 0.465173, 0.458449, 0.451954, 0.448019, 0.443305, 0.436261, 0.430589, 0.424819,\n        0.420179, 0.409927, 0.406655, 0.398825, 0.391145, 0.387928, 0.380033, 0.378482, 0.372795, 0.369679, 0.362205, 0.359995, 0.351918, 0.34995, 0.348549,\n        0.347907, 0.341093, 0.341015, 0.332198, 0.331281, 0.322228, 0.316669, 0.315569, 0.310077, 0.30713, 0.304674, 0.296022, 0.29109, 0.287612, 0.282751,\n        0.282227, 0.277435, 0.276759, 0.271491, 0.270748, 0.263364, 0.258755, 0.258047, 0.251406, 0.250064, 0.244264, 0.243818, 0.239612, 0.239024,\n        0.232805, 0.232168, 0.226194, 0.225387, 0.224028, 0.224027, 0.224011, 0.22401, 0.223994, 0.223993, 0.223979, 0.223977, 0.223962, 0.22396, 0.223947,\n        0.223943, 0.22393, 0.223926, 0.223915, 0.223909, 0.223904, 0.223904, 0.223887, 0.223887, 0.226011, 0.225818, 0.224086, 0.223853, 0.22384, 0.225949,\n        0.225988, 0.225971, 0.225955, 0.225954, 0.225938, 0.225921, 0.225921, 0.225904, 0.223951, 0.224158, 0.22588, 0.225878, 0.225863, 0.225861, 0.225846,\n        0.225844, 0.225829, 0.225827, 0.225812, 0.22581, 0.225794, 0.225793, 0.225774, 0.225774, 0.225759, 0.225757, 0.227901, 0.227913, 0.227897, 0.227896\n    ])\n    _dP_staggered_Re_15 = np.array([9.34201, 8.81965, 8.28809, 7.42806, 6.97391, 6.57517, 5.84093, 5.50985, 5.16014, 4.93488, 4.68126, 4.42254, 3.99955, 3.773,\n        3.39505, 3.20519, 3.02598, 2.77577, 2.61488, 2.474, 2.33566, 2.20505, 1.96531, 1.8554, 1.76851, 1.68568, 1.60674, 1.54592, 1.47385, 1.45584,\n        1.42566, 1.36641, 1.35191, 1.29626, 1.28859, 1.24598, 1.24005, 1.18197, 1.17596, 1.13745, 1.13449, 1.10514, 1.04611, 1.03299, 1.01551, 1.00639,\n        0.975508, 0.956979, 0.921361, 0.906001, 0.886645, 0.876509, 0.861323, 0.848885, 0.833067, 0.820018, 0.790987, 0.781353, 0.757982, 0.750599, 0.73523,\n        0.72878, 0.715526, 0.703825, 0.690704, 0.69043, 0.671089, 0.670816, 0.658238, 0.65804, 0.642607, 0.638042, 0.628642, 0.616468, 0.611099, 0.59789,\n        0.592593, 0.59088, 0.5807, 0.571709, 0.569635, 0.559848, 0.558786, 0.554428, 0.553416, 0.5491, 0.548097, 0.54293, 0.542793, 0.537633, 0.53548,\n        0.52734, 0.525928, 0.522325, 0.519436, 0.51244, 0.510312, 0.502563, 0.501212, 0.497646, 0.483767, 0.483639, 0.479479, 0.478991, 0.469919, 0.469457,\n        0.465373, 0.464541, 0.457403, 0.456485, 0.452112, 0.44443, 0.443408, 0.435131, 0.434907, 0.419981, 0.418722, 0.415054, 0.414669, 0.405475, 0.405291,\n        0.396251, 0.391403, 0.387694, 0.383945, 0.378953, 0.373041, 0.369506, 0.365933, 0.360178, 0.355541, 0.350503, 0.34544, 0.342437, 0.338861, 0.33562,\n        0.326088, 0.324262, 0.319875, 0.312702, 0.30994, 0.303633, 0.301961, 0.295857, 0.293384, 0.286801, 0.285051, 0.281193, 0.27962, 0.27688, 0.276192,\n        0.269144, 0.269082, 0.261395, 0.260961, 0.256484, 0.249175, 0.248418, 0.244472, 0.240616, 0.237428, 0.23135, 0.228333, 0.226286, 0.219953, 0.21934,\n        0.21432, 0.213615, 0.209306, 0.208785, 0.203406, 0.198042, 0.197549, 0.193322, 0.192633, 0.189133, 0.188615, 0.183883, 0.183431, 0.178539, 0.17805,\n        0.173635, 0.172752, 0.171298, 0.171157, 0.169685, 0.169823, 0.171289, 0.171462, 0.172926, 0.173289, 0.176258, 0.176871, 0.181386, 0.182469,\n        0.186641, 0.188307, 0.193913, 0.196789, 0.199552, 0.199594, 0.201486, 0.2015, 0.203218, 0.203417, 0.203404, 0.203401, 0.204688, 0.205335, 0.205334,\n        0.203367, 0.203354, 0.203352, 0.203338, 0.205273, 0.20528, 0.205265, 0.205258, 0.205257, 0.205243, 0.205241, 0.205227, 0.205226, 0.205212, 0.20521,\n        0.205196, 0.205195, 0.205181, 0.205179, 0.205165, 0.205164, 0.205146, 0.205146, 0.205132, 0.205131, 0.205117, 0.205115, 0.205101, 0.2051\n    ])\n    _dP_staggered_Re_2 = np.array([3.3699, 3.25874, 3.1513, 2.97524, 2.87715, 2.78229, 2.60185, 2.504, 2.4214, 2.36801, 2.2862, 2.21078, 2.08731, 2.01849, 1.89955,\n        1.82808, 1.76778, 1.68508, 1.61934, 1.56066, 1.50918, 1.4524, 1.33872, 1.28835, 1.23986, 1.19319, 1.14827, 1.10908, 1.07889, 1.06407, 1.03929,\n        1.00291, 0.994386, 0.957472, 0.951802, 0.912623, 0.908283, 0.874086, 0.869647, 0.841073, 0.838095, 0.808676, 0.780364, 0.773598, 0.747536, 0.738905,\n        0.721828, 0.717582, 0.690875, 0.682216, 0.671254, 0.666188, 0.658464, 0.647496, 0.633663, 0.625691, 0.607864, 0.60192, 0.586506, 0.581184, 0.573473,\n        0.57011, 0.559368, 0.551449, 0.543432, 0.543274, 0.533071, 0.532917, 0.522924, 0.522784, 0.512946, 0.509741, 0.503124, 0.493595, 0.490661, 0.483683,\n        0.479474, 0.477483, 0.469851, 0.466187, 0.465338, 0.461708, 0.461273, 0.453348, 0.452088, 0.448562, 0.447435, 0.443915, 0.443836, 0.439616, 0.43882,\n        0.43577, 0.434512, 0.431212, 0.430014, 0.427098, 0.426293, 0.423332, 0.422987, 0.422964, 0.422929, 0.422883, 0.414874, 0.414451, 0.410887, 0.410884,\n        0.410855, 0.410436, 0.40691, 0.406003, 0.40083, 0.393272, 0.392277, 0.385608, 0.385474, 0.374217, 0.373188, 0.36608, 0.365067, 0.355721, 0.355584,\n        0.349483, 0.344411, 0.338995, 0.335717, 0.333088, 0.328254, 0.323091, 0.319967, 0.316935, 0.312854, 0.307934, 0.303486, 0.299932, 0.296289,\n        0.293462, 0.288427, 0.286092, 0.279681, 0.274029, 0.271776, 0.265638, 0.264031, 0.260457, 0.258987, 0.253176, 0.251647, 0.24824, 0.2468, 0.243526,\n        0.242183, 0.237587, 0.237538, 0.231397, 0.230821, 0.224266, 0.218493, 0.217895, 0.215809, 0.213044, 0.210747, 0.20588, 0.202787, 0.200602, 0.196037,\n        0.195433, 0.19047, 0.189774, 0.185568, 0.18506, 0.181897, 0.176863, 0.176379, 0.172288, 0.171368, 0.166958, 0.166501, 0.162215, 0.161773, 0.158952,\n        0.15869, 0.15501, 0.154182, 0.153022, 0.152707, 0.151364, 0.15124, 0.152546, 0.152684, 0.155311, 0.155668, 0.158336, 0.158692, 0.162743, 0.164018,\n        0.169607, 0.171511, 0.177917, 0.179674, 0.181351, 0.181379, 0.184846, 0.184874, 0.188409, 0.188408, 0.188396, 0.18876, 0.190196, 0.190315, 0.190318,\n        0.190617, 0.190888, 0.190917, 0.191188, 0.191489, 0.191491, 0.191793, 0.191913, 0.191942, 0.191929, 0.191928, 0.191915, 0.191913, 0.1919, 0.192079,\n        0.193733, 0.193731, 0.193718, 0.193717, 0.193703, 0.193702, 0.193686, 0.193686, 0.193673, 0.193861, 0.195522, 0.195521, 0.195508, 0.195506\n    ])\n    _dP_staggered_Re_25 = np.array([1.79994, 1.76013, 1.72122, 1.65648, 1.61986, 1.58405, 1.51479, 1.47657, 1.44391, 1.4226, 1.38964, 1.3589, 1.30781, 1.2789,\n        1.22814, 1.19714, 1.17066, 1.13385, 1.10416, 1.07732, 1.05349, 1.02689, 0.972573, 0.948019, 0.924073, 0.900732, 0.877981, 0.857886, 0.842238,\n        0.834508, 0.821498, 0.802211, 0.797489, 0.771119, 0.767464, 0.742087, 0.738758, 0.71986, 0.717012, 0.693528, 0.691126, 0.673248, 0.655161, 0.650796,\n        0.633605, 0.627855, 0.611017, 0.606947, 0.589142, 0.581418, 0.572075, 0.564906, 0.555118, 0.548858, 0.542958, 0.537932, 0.523109, 0.517617,\n        0.503395, 0.500444, 0.493804, 0.488993, 0.479779, 0.472711, 0.470631, 0.4705, 0.461663, 0.461524, 0.45287, 0.452758, 0.444238, 0.442841, 0.439921,\n        0.431589, 0.431576, 0.423352, 0.4167, 0.415283, 0.415257, 0.412759, 0.412007, 0.408794, 0.408443, 0.405032, 0.404211, 0.400713, 0.399901, 0.39662,\n        0.396488, 0.389473, 0.388156, 0.385458, 0.384426, 0.381792, 0.380731, 0.377866, 0.377075, 0.377054, 0.377046, 0.374429, 0.36984, 0.369804, 0.366623,\n        0.366285, 0.36626, 0.366258, 0.363072, 0.362738, 0.359622, 0.35915, 0.352384, 0.349036, 0.348637, 0.345681, 0.345518, 0.336581, 0.335833, 0.330069,\n        0.329459, 0.320103, 0.320041, 0.316923, 0.313944, 0.310956, 0.305966, 0.302055, 0.299216, 0.296371, 0.292087, 0.287957, 0.285478, 0.282464,\n        0.277935, 0.274359, 0.271138, 0.268545, 0.263228, 0.261591, 0.256305, 0.250791, 0.248501, 0.244499, 0.2436, 0.239026, 0.236807, 0.231877, 0.230603,\n        0.225941, 0.22405, 0.222707, 0.222159, 0.217943, 0.217893, 0.21226, 0.211731, 0.206127, 0.20064, 0.200073, 0.197111, 0.194215, 0.192662, 0.188591,\n        0.185104, 0.182162, 0.178493, 0.178125, 0.174048, 0.173476, 0.170156, 0.169754, 0.16495, 0.160643, 0.160246, 0.156122, 0.155402, 0.152988, 0.15273,\n        0.148798, 0.148394, 0.144533, 0.144169, 0.139245, 0.138483, 0.137648, 0.137427, 0.136218, 0.136117, 0.137425, 0.137564, 0.138759, 0.139196,\n        0.142785, 0.143115, 0.145559, 0.14672, 0.151214, 0.152571, 0.157129, 0.160246, 0.163232, 0.163273, 0.168458, 0.168493, 0.172862, 0.173428, 0.177879,\n        0.178569, 0.181323, 0.18658, 0.18658, 0.186566, 0.186553, 0.186552, 0.186539, 0.186525, 0.186508, 0.184125, 0.183189, 0.182964, 0.182952, 0.18295,\n        0.182938, 0.182936, 0.182924, 0.182922, 0.18291, 0.182909, 0.184483, 0.184655, 0.184643, 0.184641, 0.182866, 0.182873, 0.18444, 0.184612, 0.184599,\n        0.184598, 0.184585, 0.184584\n    ])\n    _dP_staggered_Re_parameters = np.array([_dP_staggered_Re_125, _dP_staggered_Re_15, _dP_staggered_Re_2, _dP_staggered_Re_25]).T\n    others = np.array([1.25, 1.5, 2, 2.5])\n    # do not delete\n    dP_staggered_f = RectBivariateSpline(_dP_staggered_Res, others, _dP_staggered_Re_parameters, kx=3, ky=3, s=0.002)\n\n    # Excellent plot, though it does linear extrapolation on some lines\n    #import matplotlib.pyplot as plt\n    #dP_staggered_f_zs = np.array([1.25, 1.5, 2, 2.5])\n    #low, high = min(_dP_staggered_Res), max(_dP_staggered_Res)\n    #xs = np.linspace(low, high, 50000)\n    #for i in range(4):\n    #    plt.loglog(_dP_staggered_Res, _dP_staggered_Re_parameters.T[i, :], '.')\n    #    plt.loglog(xs, dP_staggered_f(xs, dP_staggered_f_zs[i]), '--')\n    #plt.show()\n\n    errors = []\n    for i, param in enumerate(_dP_staggered_Res):\n        for j, z in enumerate(others):\n            original_value = _dP_staggered_Re_parameters[i][j]\n            interpolated = bisplev(param, z, dP_staggered_f_tck)\n            errors.append(abs(abs(original_value - interpolated) / original_value))\n    assert np.mean(errors) < 0.01\n\ndef test_dP_Zukauskas_dP_staggered_correction_spline():\n    _dP_staggered_correction_parameters = np.array([0.4387, 0.470647, 0.494366, 0.52085, 0.542787, 0.583019, 0.609319, 0.659047, 0.685413, 0.729582, 0.800982,\n        0.84214, 0.892449, 0.947309, 1.00903, 1.07052, 1.16389, 1.22243, 1.26584, 1.32314, 1.37597, 1.40437, 1.45385, 1.51093, 1.55814, 1.61775, 1.68647,\n        1.74589, 1.79853, 1.86586, 1.92335, 1.97322, 2.12053, 2.22751, 2.34521, 2.45793, 2.58193, 2.71226, 2.84909, 2.99282, 3.14389, 3.22668, 3.32915,\n        3.54351\n    ])\n    _dP_staggered_correction_Re_100 = np.array([0.996741, 0.996986, 0.997157, 0.997339, 0.997482, 0.997731, 0.997885, 0.998158, 0.998294, 0.998512, 0.998836,\n        0.999011, 0.999213, 0.99942, 0.99964, 0.999846, 1.00241, 1.02216, 1.0392, 1.06545, 1.08705, 1.0995, 1.1206, 1.14708, 1.16583, 1.18871, 1.21407,\n        1.23518, 1.25628, 1.27868, 1.29996, 1.31593, 1.36025, 1.39055, 1.42224, 1.45114, 1.48144, 1.51175, 1.54205, 1.57235, 1.60267, 1.62032, 1.64208,\n        1.68552\n    ])\n    _dP_staggered_correction_Re_1000 = np.array([1.03576, 1.02714, 1.02111, 1.01712, 1.01206, 1.00798, 1.00547, 1.001, 0.999839, 0.999378, 0.998689, 0.998319,\n        0.997891, 0.997451, 0.996985, 0.999249, 1.00245, 1.0135, 1.02415, 1.03618, 1.04682, 1.0534, 1.06478, 1.07524, 1.0836, 1.09539, 1.10811, 1.11825,\n        1.12833, 1.13858, 1.1481, 1.15678, 1.17941, 1.19487, 1.21106, 1.22398, 1.24068, 1.25657, 1.27109, 1.28706, 1.30317, 1.31111, 1.3196, 1.33956\n    ])\n    _dP_staggered_correction_Re_10000 = np.array([1.20211, 1.18293, 1.16951, 1.15527, 1.14308, 1.12148, 1.10821, 1.09069, 1.08213, 1.06633, 1.04824, 1.04041,\n        1.03015, 1.02269, 1.01509, 1.00905, 1.00302, 1.00302, 1.00304, 1.00623, 1.00905, 1.0103, 1.01246, 1.01508, 1.01696, 1.01926, 1.0225, 1.02674,\n        1.03074, 1.03432, 1.03618, 1.03931, 1.04813, 1.05451, 1.05855, 1.0674, 1.07355, 1.08006, 1.08719, 1.09572, 1.10324, 1.10854, 1.11428, 1.12663\n    ])\n    _dP_staggered_correction_Re_100000 = np.array([1.45829, 1.42587, 1.40486, 1.38291, 1.36389, 1.32864, 1.30754, 1.27136, 1.25327, 1.22447, 1.18203, 1.15678,\n        1.12845, 1.10251, 1.07182, 1.04763, 1.00824, 0.984925, 0.975402, 0.965711, 0.960152, 0.957646, 0.9534, 0.948334, 0.945015, 0.942714, 0.940164,\n        0.937857, 0.936683, 0.936683, 0.934823, 0.933668, 0.933668, 0.933668, 0.933668, 0.933668, 0.933668, 0.936683, 0.936683, 0.936683, 0.939698,\n        0.939698, 0.939698, 0.939698\n    ])\n    _dP_staggered_correction_Re_parameters = np.array([_dP_staggered_correction_Re_100, _dP_staggered_correction_Re_1000, _dP_staggered_correction_Re_10000, _dP_staggered_correction_Re_100000]).T\n    others = np.array([1E2, 1E3, 1E4, 1E5])\n    # do not delete\n    dP_staggered_correction = RectBivariateSpline(_dP_staggered_correction_parameters, others, _dP_staggered_correction_Re_parameters, kx=1, ky=3, s=0.002)\n\n    # Maybe good plot - bad around the middle\n    #dP_staggered_correction_zs = np.array([1E2, 1E3, 1E4, 1E5])\n    #low, high = min(_dP_staggered_correction_parameters), max(_dP_staggered_correction_parameters)\n    #xs = np.linspace(low, high, 50000)\n    #for i in range(4):\n    #    plt.loglog(_dP_staggered_correction_parameters, _dP_staggered_correction_Re_parameters.T[i, :], '.')\n    #    plt.loglog(xs, dP_staggered_correction(xs, dP_staggered_correction_zs[i]), '--')\n    #plt.show()\n\n    errors = []\n    for i, param in enumerate(_dP_staggered_correction_parameters):\n        for j, z in enumerate(others):\n            original_value = _dP_staggered_correction_Re_parameters[i][j]\n            interpolated = bisplev(param, z, dP_staggered_correction_tck)\n            errors.append(abs(abs(original_value - interpolated) / original_value))\n    assert np.mean(errors) < 0.01\n\n\ndef test_dP_Zukauskas_dP_inline_correction_spline():\n    \"\"\"Test that the pre-computed spline correctly reproduces the original data points\"\"\"\n    _dP_inline_correction_parameters = np.array([0.02, 0.04, 0.066164, 0.08, 0.16, 0.32, 0.64, 1.28, 2.56, 5.12, 5.7141,\n    ])\n    _dP_inline_correction_Re_1000 = np.array([16.05, 10.359, 7.538, 6.6218, 3.9933, 2.3397, 1.3794, 0.8336, 0.50239, 0.29469, 0.27113,\n    ])\n    _dP_inline_correction_Re_10000 = np.array([13.181, 8.507, 6.1906, 5.4908, 3.4734, 2.2042, 1.3876, 0.8735, 0.54642, 0.33857, 0.3115\n    ])\n    _dP_inline_correction_Re_100000 = np.array([9.092, 6.0549, 4.5073, 4.0322, 2.7957, 1.9162, 1.308, 0.9011, 0.62078, 0.42537, 0.39996,\n    ])\n    _dP_inline_correction_Re_1000000 = np.array([5.3722, 3.9373, 3.1421, 2.8857, 2.1799, 1.6421, 1.2364, 0.9349, 0.7131, 0.53922, 0.51587,\n    ])\n\n    _dP_inline_correction_zs = np.array([1E3, 1E4, 1E5, 1E6])\n    _dP_inline_correction_Re_parameters = np.array([_dP_inline_correction_Re_1000, _dP_inline_correction_Re_10000, _dP_inline_correction_Re_100000, _dP_inline_correction_Re_1000000]).T\n    dP_inline_correction = RectBivariateSpline(_dP_inline_correction_parameters, _dP_inline_correction_zs, _dP_inline_correction_Re_parameters, kx=3, ky=3, s=0.0) # s=0.002\n    # 2024 cleaned up the fit\n\n    #import matplotlib.pyplot as plt\n    #low, high = min(_dP_inline_correction_parameters), max(_dP_inline_correction_parameters)\n    #xs = np.logspace(np.log10(low), np.log10(high), 300000)\n    #for i in range(4):\n    #    plt.loglog(_dP_inline_correction_parameters, _dP_inline_correction_Re_parameters.T[i, :], '.')\n    #    plt.loglog(xs, dP_inline_correction(xs, _dP_inline_correction_zs[i]), '--')\n    #plt.show()\n\n    errors = []\n    for i, param in enumerate(_dP_inline_correction_parameters):\n        for j, z in enumerate(_dP_inline_correction_zs):\n            original_value = _dP_inline_correction_Re_parameters[i][j]\n            interpolated = bisplev(param, z, dP_inline_correction_tck)\n            errors.append(abs(abs(original_value - interpolated) / original_value))\n    assert np.mean(errors) < 0.01\n\ndef test_dP_Zukauskas_dP_inline_f_tck_spline():\n    _dP_inline_Res = np.array([28.5094, 30.8092, 32.9727, 35.3563, 41.2101, 45.9365, 49.1622, 52.6143, 56.3102, 59.107, 63.7533, 68.3605, 73.1607, 82.9896, 91.2679,\n        107.829, 116.528, 124.713, 134.774, 144.237, 157.106, 169.784, 183.484, 202.173, 218.488, 241.163, 278.938, 301.447, 325.772, 352.069, 402.667,\n        439.431, 479.551, 528.457, 576.706, 600.39, 654.321, 666.665, 722.026, 795.679, 802.401, 883.594, 965.211, 973.774, 1022.26, 1107.38, 1126.59,\n        1220.48, 1343.51, 1368.32, 1468.16, 1616.19, 1646.72, 1764.04, 1814.79, 1944.21, 1998.93, 2038.12, 2041.06, 2246.18, 2249.48, 2455.2, 2476.81,\n        2705.84, 2729.59, 2982.07, 3008.17, 3257.9, 3313.34, 3590.4, 3618.29, 3946.71, 4030.55, 4063.47, 4434.98, 4446.05, 4852.32, 4895.14, 5347.3,\n        5394.74, 5830.48, 5994.16, 6003.24, 6545.85, 6615.94, 7143.99, 7226.2, 7873.1, 8101.49, 8113.39, 8928.33, 8941.23, 9765.31, 9845.06, 10343.9,\n        10430.3, 11407.3, 11956.6, 12562.5, 13176.9, 13719.7, 14521.4, 15236.6, 16651, 17465.4, 18505, 20393.2, 20419.3, 22474.5, 22503.3, 24559, 25546.2,\n        27064.9, 29789.7, 30724.6, 32829.2, 34810.9, 36179.8, 38362.8, 39871.4, 40721.2, 41061.4, 44854.2, 45239.5, 48975.7, 49855.5, 53971.7, 54426.4,\n        59979.7, 60058.1, 66101.3, 66184.5, 72230.6, 72907, 81043.8, 81128.8, 89317.2, 89406.8, 97574.2, 98430.6, 103433, 104341, 112924, 114990, 123239,\n        126726, 135811, 139659, 149668, 153913, 163348, 169621, 180015, 186933, 206011, 206189, 227042, 227233, 247788, 250418, 273078, 275976, 300948,\n        304142, 331663, 335183, 365513, 369392, 406751, 407092, 448264, 448640, 494013, 494428, 544433, 544890, 605857, 606365, 667691, 668251, 735835,\n        736453, 803766, 810935, 877478, 893699, 967033, 984910, 1044050, 1044920, 1150600, 1151570, 1268030, 1269100, 1397450, 1398620, 1540070, 1541370,\n        1697250, 1698680, 1854500, 1871040\n    ])\n    _dP_inline_Re_125 = np.array([5.93109, 5.54354, 5.22463, 4.91025, 4.2207, 3.80075, 3.54753, 3.31117, 3.12106, 2.97108, 2.75394, 2.58829, 2.41584, 2.14646,\n        1.9677, 1.6944, 1.58146, 1.49066, 1.3913, 1.29861, 1.20507, 1.12508, 1.05285, 0.971815, 0.909568, 0.833438, 0.747763, 0.704808, 0.66432, 0.632336,\n        0.581074, 0.549915, 0.52122, 0.493379, 0.470594, 0.461052, 0.443442, 0.440821, 0.430173, 0.421676, 0.421664, 0.422183, 0.429662, 0.431075, 0.438954,\n        0.446788, 0.449097, 0.46, 0.468865, 0.471657, 0.482859, 0.492167, 0.493224, 0.496938, 0.499697, 0.506586, 0.50325, 0.502485, 0.502646, 0.512335,\n        0.512408, 0.516812, 0.517255, 0.52129, 0.521276, 0.521127, 0.521113, 0.520979, 0.520951, 0.520816, 0.520351, 0.51557, 0.515536, 0.515148, 0.51047,\n        0.510337, 0.505209, 0.504298, 0.49523, 0.493744, 0.480865, 0.480679, 0.480676, 0.476399, 0.47587, 0.467664, 0.466446, 0.453034, 0.456863, 0.457087,\n        0.448375, 0.448242, 0.439335, 0.438121, 0.430813, 0.430369, 0.426369, 0.421825, 0.417567, 0.415493, 0.413748, 0.40895, 0.404931, 0.397616, 0.393735,\n        0.389087, 0.3814, 0.3813, 0.373863, 0.373765, 0.366718, 0.36344, 0.361258, 0.355173, 0.352681, 0.347915, 0.343752, 0.341039, 0.33675, 0.333804,\n        0.332203, 0.331636, 0.325673, 0.325338, 0.322369, 0.321193, 0.316002, 0.315506, 0.309826, 0.30975, 0.303711, 0.303632, 0.297644, 0.297168, 0.291819,\n        0.291767, 0.288848, 0.288818, 0.283136, 0.281514, 0.272212, 0.272406, 0.274764, 0.273631, 0.269345, 0.267807, 0.264025, 0.263257, 0.261364, 0.26134,\n        0.26129, 0.260266, 0.258656, 0.257969, 0.256205, 0.25619, 0.255938, 0.255937, 0.253893, 0.253614, 0.253287, 0.253278, 0.253208, 0.253199, 0.251176,\n        0.2509, 0.250577, 0.250568, 0.250491, 0.25049, 0.250412, 0.250412, 0.250334, 0.250333, 0.250256, 0.250255, 0.25017, 0.250169, 0.250092, 0.250091,\n        0.250013, 0.250013, 0.249942, 0.250177, 0.252337, 0.252322, 0.252258, 0.252244, 0.252196, 0.252196, 0.252117, 0.252117, 0.252039, 0.252038, 0.25196,\n        0.251959, 0.251881, 0.25188, 0.251802, 0.251802, 0.254214, 0.25446\n    ])\n    _dP_inline_Re_15 = np.array([2.51237, 2.49499, 2.32876, 2.1908, 1.87501, 1.68786, 1.5828, 1.484, 1.38705, 1.31326, 1.23965, 1.16623, 1.08879, 0.973353, 0.88678,\n        0.773105, 0.72388, 0.681815, 0.636838, 0.600558, 0.55801, 0.525955, 0.495741, 0.458149, 0.43183, 0.403164, 0.367208, 0.350209, 0.334532, 0.32017,\n        0.299699, 0.288076, 0.276903, 0.268782, 0.258357, 0.25326, 0.250756, 0.249796, 0.245772, 0.243513, 0.243318, 0.245622, 0.252914, 0.25366, 0.257801,\n        0.264766, 0.266548, 0.276173, 0.284237, 0.286562, 0.295607, 0.301306, 0.303191, 0.310225, 0.312873, 0.319399, 0.321166, 0.322408, 0.3225, 0.328697,\n        0.328793, 0.335219, 0.335506, 0.338421, 0.33871, 0.341653, 0.341978, 0.344926, 0.344907, 0.344818, 0.344809, 0.344713, 0.34469, 0.344681, 0.344584,\n        0.344549, 0.341421, 0.341109, 0.341012, 0.341002, 0.331021, 0.337212, 0.337554, 0.33746, 0.337449, 0.334469, 0.334034, 0.33154, 0.330712, 0.33067,\n        0.327386, 0.327336, 0.324341, 0.324066, 0.320821, 0.320812, 0.320676, 0.317593, 0.314385, 0.312656, 0.311204, 0.309367, 0.30782, 0.304983, 0.303469,\n        0.301435, 0.296008, 0.295937, 0.295845, 0.295844, 0.29001, 0.28882, 0.287086, 0.284229, 0.28322, 0.280847, 0.277486, 0.275535, 0.273856, 0.272992,\n        0.272948, 0.272482, 0.267582, 0.267318, 0.264881, 0.264389, 0.262202, 0.261791, 0.257077, 0.257024, 0.254467, 0.254434, 0.252125, 0.25188, 0.246946,\n        0.246897, 0.244434, 0.244409, 0.239588, 0.239582, 0.239543, 0.239114, 0.235263, 0.234574, 0.232704, 0.232439, 0.232387, 0.231931, 0.230263,\n        0.230024, 0.22998, 0.229521, 0.228102, 0.227634, 0.227563, 0.227562, 0.227491, 0.227491, 0.225446, 0.225198, 0.225135, 0.225127, 0.225065, 0.225057,\n        0.224994, 0.224987, 0.224924, 0.224916, 0.224846, 0.224846, 0.224776, 0.224776, 0.224706, 0.224705, 0.224636, 0.224635, 0.224558, 0.224558,\n        0.224488, 0.224488, 0.224418, 0.224417, 0.224354, 0.224348, 0.224291, 0.224278, 0.224221, 0.224208, 0.224166, 0.224165, 0.224095, 0.224095,\n        0.224025, 0.224025, 0.223955, 0.223955, 0.223885, 0.223885, 0.223815, 0.223815, 0.223752, 0.223745\n    ])\n    _dP_inline_Re_2 = np.array([0.225144, 0.225088, 0.225039, 0.224988, 0.224877, 0.224799, 0.22475, 0.224701, 0.224652, 0.224617, 0.224562, 0.224511, 0.224462,\n        0.224371, 0.224303, 0.224182, 0.224127, 0.224078, 0.224022, 0.223973, 0.223911, 0.223855, 0.223799, 0.22373, 0.223674, 0.223603, 0.223498, 0.223442,\n        0.223386, 0.223331, 0.223234, 0.223171, 0.223109, 0.223039, 0.222976, 0.222947, 0.222886, 0.222872, 0.222815, 0.222745, 0.222739, 0.22267, 0.222607,\n        0.222601, 0.222566, 0.222509, 0.222496, 0.222439, 0.22237, 0.222357, 0.222307, 0.222238, 0.222225, 0.222176, 0.222155, 0.222106, 0.222086, 0.222072,\n        0.222091, 0.224181, 0.224192, 0.224129, 0.224123, 0.224059, 0.224053, 0.223989, 0.223983, 0.225938, 0.226122, 0.226064, 0.226058, 0.225995, 0.22598,\n        0.225974, 0.22591, 0.225909, 0.225845, 0.225839, 0.225774, 0.225768, 0.225712, 0.225692, 0.225715, 0.227854, 0.227574, 0.225564, 0.225556, 0.225494,\n        0.225473, 0.225472, 0.225402, 0.225401, 0.225337, 0.225331, 0.224173, 0.223979, 0.221897, 0.220812, 0.220777, 0.220743, 0.219816, 0.218518,\n        0.217425, 0.215326, 0.214141, 0.212854, 0.209889, 0.209854, 0.207766, 0.207721, 0.204025, 0.20238, 0.199994, 0.196092, 0.194852, 0.192218, 0.189918,\n        0.189156, 0.188004, 0.185898, 0.184756, 0.184308, 0.182455, 0.18245, 0.182403, 0.182219, 0.180718, 0.18056, 0.17874, 0.178739, 0.178684, 0.178683,\n        0.178633, 0.178614, 0.176826, 0.176836, 0.178506, 0.17851, 0.17846, 0.178455, 0.178427, 0.178422, 0.178376, 0.178366, 0.178326, 0.17831, 0.17827,\n        0.178254, 0.178215, 0.178199, 0.179233, 0.179895, 0.179866, 0.179844, 0.179788, 0.179788, 0.179732, 0.179731, 0.179681, 0.179675, 0.179625,\n        0.179619, 0.179569, 0.179563, 0.179513, 0.179507, 0.179457, 0.179451, 0.179395, 0.179395, 0.179339, 0.179339, 0.179283, 0.179282, 0.179227,\n        0.179226, 0.179165, 0.179165, 0.179109, 0.179109, 0.179053, 0.179053, 0.179002, 0.178997, 0.178952, 0.178941, 0.178896, 0.178885, 0.178852,\n        0.178851, 0.178796, 0.178795, 0.17874, 0.178739, 0.178684, 0.178684, 0.178628, 0.178628, 0.178572, 0.178572, 0.178521, 0.178516\n    ])\n    _dP_inline_Re_25 = np.array([0.349884, 0.344353, 0.339587, 0.334753, 0.324384, 0.31723, 0.31284, 0.308509, 0.304238, 0.301224, 0.296579, 0.292359, 0.288312,\n        0.280944, 0.275511, 0.266235, 0.262027, 0.258398, 0.254314, 0.250794, 0.24643, 0.242534, 0.238699, 0.233991, 0.230291, 0.225667, 0.219023, 0.21556,\n        0.212151, 0.208795, 0.203116, 0.199504, 0.195956, 0.192086, 0.18867, 0.187117, 0.18384, 0.183136, 0.179837, 0.176255, 0.175964, 0.174204, 0.174155,\n        0.17415, 0.174122, 0.174078, 0.174068, 0.175436, 0.175686, 0.175676, 0.175636, 0.175582, 0.175571, 0.175532, 0.175516, 0.176657, 0.177193, 0.175451,\n        0.175475, 0.177126, 0.177125, 0.177076, 0.177071, 0.17702, 0.177015, 0.176965, 0.17696, 0.176915, 0.176905, 0.176859, 0.176855, 0.176805, 0.176793,\n        0.176789, 0.178483, 0.178481, 0.178431, 0.178426, 0.178375, 0.17837, 0.178326, 0.17831, 0.178309, 0.178259, 0.178253, 0.178209, 0.178203, 0.178154,\n        0.178137, 0.178136, 0.178082, 0.178081, 0.17803, 0.178026, 0.177997, 0.177992, 0.177941, 0.177208, 0.176296, 0.175343, 0.174528, 0.175213, 0.176039,\n        0.175988, 0.175263, 0.17421, 0.172454, 0.172453, 0.1724, 0.172399, 0.17235, 0.171731, 0.170592, 0.168894, 0.168351, 0.167192, 0.16716, 0.167139,\n        0.166121, 0.165455, 0.165443, 0.165435, 0.163918, 0.163771, 0.162422, 0.162121, 0.160642, 0.1605, 0.16361, 0.163528, 0.158824, 0.158823, 0.158779,\n        0.158774, 0.15872, 0.158736, 0.160236, 0.160219, 0.158765, 0.15862, 0.158595, 0.158591, 0.15855, 0.158541, 0.158506, 0.158492, 0.158456, 0.158442,\n        0.158407, 0.158392, 0.158362, 0.158343, 0.158313, 0.158293, 0.158244, 0.158257, 0.159755, 0.15974, 0.15815, 0.158145, 0.158101, 0.158095, 0.158051,\n        0.158046, 0.158002, 0.157996, 0.157952, 0.157947, 0.157898, 0.157898, 0.157849, 0.157848, 0.157799, 0.157799, 0.15775, 0.15775, 0.157696, 0.157695,\n        0.157646, 0.157646, 0.157597, 0.157597, 0.157552, 0.157548, 0.157508, 0.157499, 0.157459, 0.157449, 0.15742, 0.157419, 0.157371, 0.15737, 0.157321,\n        0.157321, 0.157272, 0.157272, 0.157223, 0.157223, 0.157174, 0.157173, 0.157129, 0.157125\n    ])\n    _dP_inline_Re_parameters = np.array([_dP_inline_Re_125, _dP_inline_Re_15, _dP_inline_Re_2, _dP_inline_Re_25]).T\n    other_things = np.array([1.25, 1.5, 2, 2.5])\n    # do not delete\n    dP_inline_f = RectBivariateSpline(_dP_inline_Res, other_things, _dP_inline_Re_parameters, kx = 3, ky = 3, s = 0.002)\n\n    errors = []\n    for i, param in enumerate(_dP_inline_Res):\n        for j, z in enumerate(other_things):\n            original_value = _dP_inline_Re_parameters[i][j]\n            interpolated = bisplev(param, z, dP_inline_f_tck)\n            errors.append(abs(abs(original_value - interpolated) / original_value))\n    assert np.mean(errors) < 0.01\n\nBell_baffle_configuration_Fcs = np.array([0, 0.0138889, 0.0277778, 0.0416667, 0.0538194, 0.0659722, 0.100694, 0.114583,\n    0.126736, 0.140625, 0.152778, 0.166667, 0.178819, 0.192708, 0.215278, 0.227431, 0.241319, 0.255208,\n    0.267361, 0.28125, 0.295139, 0.340278, 0.354167, 0.366319, 0.380208, 0.394097, 0.402778, 0.416667, 0.430556,\n    0.444444, 0.475694, 0.489583, 0.503472, 0.517361, 0.53125, 0.545139, 0.560764, 0.574653, 0.588542, 0.625,\n    0.638889, 0.652778, 0.668403, 0.682292, 0.697917, 0.701389, 0.713542, 0.729167, 0.743056, 0.758681,\n    0.802083, 0.817708, 0.833333, 0.848958, 0.866319, 0.881944, 0.901042, 0.918403, 0.934028, 0.947917,\n    0.960069, 0.970486, 0.977431, 0.984375, 0.991319, 0.994792, 1\n])\nBell_baffle_configuration_Jcs = np.array([0.534317, 0.544632, 0.556665, 0.566983, 0.579014, 0.591045, 0.620271,\n    0.630589, 0.640904, 0.652937, 0.663252, 0.675286, 0.685601, 0.697635, 0.71483, 0.725145, 0.737179, 0.747497,\n    0.757812, 0.76813, 0.780163, 0.81627, 0.826588, 0.836903, 0.847221, 0.857539, 0.867848, 0.874734, 0.885052,\n    0.89537, 0.916012, 0.92633, 0.936648, 0.946966, 0.955568, 0.965886, 0.974492, 0.984809, 0.993412, 1.01578,\n    1.0261, 1.0347, 1.0433, 1.05362, 1.06223, 1.06052, 1.07083, 1.07944, 1.08804, 1.09664, 1.11731, 1.1242,\n    1.13109, 1.13798, 1.14487, 1.15004, 1.15522, 1.15354, 1.1467, 1.13815, 1.12787, 1.11588, 1.10388, 1.09017,\n    1.07474, 1.05759, 1.03015\n])\n\ndef test_baffle_correction_Bell():\n    Jc = baffle_correction_Bell(0.82)\n    assert_close(Jc, 1.1258554691854046, 5e-4)\n\n    # Check the match is reasonably good\n    errs = np.array([(baffle_correction_Bell(float(Fc))-Jc)/Jc for Fc, Jc in zip(Bell_baffle_configuration_Fcs, Bell_baffle_configuration_Jcs)])\n    assert np.abs(errs).sum()/len(errs) < 1e-3\n\n    Jc = baffle_correction_Bell(0.1, \"chebyshev\")\n    assert_close(Jc, 0.61868011359447)\n\n    Jc = baffle_correction_Bell(0.82, \"HEDH\")\n    assert_close(Jc, 1.1404)\n\n    # Example in spreadsheet 02 - Heat Exchangers, tab Shell htc imperial,\n    # Rules of Thumb for Chemical Engineers 5E\n    Jc = baffle_correction_Bell(0.67292816689362900, method=\"HEDH\")\n    assert_close(1.034508280163413, Jc)\n\n\ndef test_baffle_correction_Bell_fit():\n    from ht.conv_tube_bank import Bell_baffle_configuration_tck\n    # 125 us to create.\n    spl = splrep(Bell_baffle_configuration_Fcs, Bell_baffle_configuration_Jcs, s=8e-5)\n    [assert_close1d(i, j) for (i, j) in zip(spl[:-1], Bell_baffle_configuration_tck[:-1])]\n\n    Bell_baffle_configuration_obj = UnivariateSpline(Bell_baffle_configuration_Fcs,\n                                                     Bell_baffle_configuration_Jcs,\n                                                     s=8e-5)\n#    import matplotlib.pyplot as plt\n#    plt.plot(Bell_baffle_configuration_Fcs, Bell_baffle_configuration_Jcs)\n#    pts = np.linspace(0, 1, 5000)\n#    plt.plot(pts, [Bell_baffle_configuration_obj(i) for i in pts])\n#    plt.plot(pts, [0.55 + 0.72*i for i in pts]) # Serth and HEDH 3.3.6g misses the tip\n#    plt.show()\n#\n\nBell_baffle_leakage_x = np.array([0.0, 1e-5, 1e-4, 1e-3, 0.0037779, 0.00885994, 0.012644, 0.0189629, 0.0213694, 0.0241428, 0.0289313, 0.0339093, 0.0376628,\n    0.0425124, 0.0487152, 0.0523402, 0.0552542, 0.0614631, 0.0676658, 0.0719956, 0.0770838, 0.081302, 0.0885214, 0.0956308, 0.101638, 0.102145,\n    0.111508, 0.119266, 0.12261, 0.129155, 0.136778, 0.144818, 0.148914, 0.15592, 0.164774, 0.16868, 0.177552, 0.181501, 0.189224, 0.196087, 0.200557,\n    0.209209, 0.220317, 0.230683, 0.236096, 0.242525, 0.247198, 0.255653, 0.2591, 0.266228, 0.274193, 0.281732, 0.285993, 0.295601, 0.302042, 0.311269,\n    0.312575, 0.322107, 0.33016, 0.332909, 0.341261, 0.347109, 0.353899, 0.360408, 0.369312, 0.374301, 0.380413, 0.388831, 0.392836, 0.401746, 0.403961,\n    0.413723, 0.422502, 0.424825, 0.432931, 0.442274, 0.450602, 0.454815, 0.463804, 0.46923, 0.475645, 0.483563, 0.491432, 0.501277, 0.501713, 0.510247,\n    0.513193, 0.523506, 0.530019, 0.534607, 0.544912, 0.550679, 0.557212, 0.563826, 0.569142, 0.576997, 0.583585, 0.588979, 0.595518, 0.601215,\n    0.601702, 0.611585, 0.613221, 0.623417, 0.629753, 0.634211, 0.640009, 0.646851, 0.653971, 0.665084, 0.672758, 0.683136, 0.689056, 0.698932,\n    0.702129, 0.711523, 0.712532, 0.722415, 0.724566, 0.732996, 0.738886, 0.743614\n])\n\nBell_baffle_leakage_z_0 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.982615, 0.962505, 0.952607, 0.939987, 0.935206, 0.930216, 0.922288, 0.91564, 0.910813,\n    0.904659, 0.896788, 0.892188, 0.889224, 0.883885, 0.879147, 0.875888, 0.872059, 0.868884, 0.86345, 0.858585, 0.854816, 0.854561, 0.849863, 0.846402,\n    0.844911, 0.841261, 0.837352, 0.833765, 0.831938, 0.828814, 0.824864, 0.823122, 0.819164, 0.817403, 0.813958, 0.810877, 0.80887, 0.804985, 0.799998,\n    0.795344, 0.792913, 0.790046, 0.787961, 0.78419, 0.782652, 0.779473, 0.776134, 0.773108, 0.771208, 0.766569, 0.762947, 0.758832, 0.758249, 0.753997,\n    0.750695, 0.749592, 0.746005, 0.743396, 0.740368, 0.737464, 0.733493, 0.731267, 0.728541, 0.723847, 0.721761, 0.717786, 0.716798, 0.712444,\n    0.708528, 0.707492, 0.703876, 0.699709, 0.695994, 0.694115, 0.690105, 0.687685, 0.684824, 0.681292, 0.677782, 0.672841, 0.672691, 0.669838,\n    0.668675, 0.662925, 0.66002, 0.657973, 0.653377, 0.651026, 0.648404, 0.645491, 0.64312, 0.639616, 0.636677, 0.634271, 0.633926, 0.628263, 0.628045,\n    0.623637, 0.622907, 0.618359, 0.615533, 0.613545, 0.611204, 0.608458, 0.605055, 0.599743, 0.596076, 0.591447, 0.588806, 0.584179, 0.582574,\n    0.578371, 0.577921, 0.573513, 0.572554, 0.568793, 0.566166, 0.564057\n])\nBell_baffle_leakage_z_0_25 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.969362, 0.950324, 0.942087, 0.92833, 0.923091, 0.917463, 0.908263, 0.8987, 0.89149,\n    0.884407, 0.874926, 0.868404, 0.865482, 0.859179, 0.851926, 0.847458, 0.842356, 0.838126, 0.831234, 0.824993, 0.820171, 0.819781, 0.812734,\n    0.807844, 0.805761, 0.801747, 0.797071, 0.792124, 0.789555, 0.785317, 0.78038, 0.778202, 0.773138, 0.77066, 0.766058, 0.76223, 0.761802, 0.754362,\n    0.748168, 0.742388, 0.73989, 0.737023, 0.734092, 0.729014, 0.727092, 0.723117, 0.718675, 0.713975, 0.711407, 0.706049, 0.702306, 0.696944, 0.696185,\n    0.690717, 0.686227, 0.685001, 0.681275, 0.677607, 0.67354, 0.66991, 0.664945, 0.662097, 0.658262, 0.653372, 0.651139, 0.645344, 0.644356, 0.639733,\n    0.633126, 0.63202, 0.628405, 0.623295, 0.618256, 0.615613, 0.610601, 0.607588, 0.604035, 0.59965, 0.595292, 0.58984, 0.589599, 0.58484, 0.583239,\n    0.578639, 0.573864, 0.570568, 0.564821, 0.562249, 0.559118, 0.554969, 0.55186, 0.54748, 0.543806, 0.540727, 0.536551, 0.532912, 0.532604, 0.528196,\n    0.527417, 0.521732, 0.51779, 0.515024, 0.511791, 0.507996, 0.504098, 0.498013, 0.493805, 0.488017, 0.484304, 0.479275, 0.477805, 0.471912, 0.47135,\n    0.465839, 0.464639, 0.459938, 0.456295, 0.453329\n])\nBell_baffle_leakage_z_0_5 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.963548, 0.945291, 0.931697, 0.915513, 0.90935, 0.903126, 0.892379, 0.882357, 0.875546,\n    0.864662, 0.854734, 0.849292, 0.844917, 0.836477, 0.828194, 0.822412, 0.815618, 0.810932, 0.803692, 0.796563, 0.790539, 0.79003, 0.780769, 0.774098,\n    0.771163, 0.765418, 0.759681, 0.754353, 0.751784, 0.746512, 0.739848, 0.736908, 0.73023, 0.727831, 0.723525, 0.722361, 0.716403, 0.709498, 0.702106,\n    0.695343, 0.69183, 0.687797, 0.684784, 0.679126, 0.676934, 0.672463, 0.666468, 0.660794, 0.657587, 0.652229, 0.647674, 0.641886, 0.641039, 0.634661,\n    0.629571, 0.627846, 0.62156, 0.618, 0.614214, 0.609549, 0.603166, 0.599589, 0.595259, 0.589978, 0.587232, 0.580972, 0.579691, 0.574139, 0.567532,\n    0.566006, 0.560921, 0.553889, 0.548597, 0.545865, 0.539851, 0.536447, 0.532176, 0.526217, 0.52128, 0.514403, 0.514091, 0.509272, 0.507629, 0.500514,\n    0.49602, 0.49275, 0.485255, 0.481637, 0.477351, 0.472925, 0.46959, 0.46425, 0.459291, 0.456283, 0.452506, 0.448422, 0.448072, 0.440693, 0.439462,\n    0.433776, 0.429185, 0.42583, 0.422193, 0.417554, 0.412196, 0.404759, 0.399625, 0.392681, 0.38872, 0.382111, 0.379972, 0.374079, 0.373424, 0.366812,\n    0.365433, 0.360144, 0.355712, 0.352153\n])\nBell_baffle_leakage_z_0_75 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.952164, 0.932054, 0.918775, 0.898166, 0.89158, 0.884084, 0.873337, 0.862164, 0.849748,\n    0.841023, 0.827707, 0.821818, 0.817167, 0.80764, 0.798123, 0.79148, 0.784355, 0.778722, 0.769082, 0.759588, 0.752322, 0.751711, 0.742222, 0.733336,\n    0.730403, 0.724627, 0.716983, 0.709925, 0.706578, 0.701202, 0.694408, 0.691425, 0.684748, 0.681776, 0.675771, 0.66987, 0.665387, 0.658756, 0.650396,\n    0.642594, 0.63852, 0.633681, 0.630164, 0.623243, 0.620278, 0.614914, 0.608773, 0.60289, 0.599564, 0.592066, 0.587039, 0.580086, 0.579103, 0.571929,\n    0.565004, 0.562871, 0.556585, 0.552183, 0.547073, 0.542175, 0.535473, 0.531288, 0.526005, 0.518616, 0.51564, 0.509016, 0.507369, 0.500113, 0.493584,\n    0.491836, 0.485642, 0.477775, 0.471507, 0.468336, 0.461571, 0.457487, 0.452093, 0.445202, 0.43798, 0.428108, 0.42792, 0.424141, 0.421924, 0.414162,\n    0.409255, 0.405735, 0.397827, 0.393402, 0.387784, 0.382579, 0.378578, 0.372665, 0.367707, 0.363647, 0.359545, 0.35391, 0.353453, 0.346015, 0.344783,\n    0.336861, 0.331413, 0.328057, 0.323694, 0.318544, 0.312629, 0.303584, 0.297808, 0.289997, 0.285542, 0.279346, 0.275077, 0.267704, 0.266945,\n    0.259507, 0.257888, 0.251468, 0.246404, 0.242337\n])\nBell_baffle_leakage_z_1 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.934094, 0.899408, 0.88689, 0.864752, 0.855175, 0.846, 0.832233, 0.820088, 0.811664, 0.80142,\n    0.78835, 0.781726, 0.776483, 0.765313, 0.755385, 0.749603, 0.742282, 0.73553, 0.725889, 0.716396, 0.709586, 0.709021, 0.698593, 0.690044, 0.686691,\n    0.680127, 0.67261, 0.665553, 0.662016, 0.655963, 0.648118, 0.644201, 0.635976, 0.63258, 0.626768, 0.621075, 0.617208, 0.609726, 0.60012, 0.591542,\n    0.587468, 0.582048, 0.578005, 0.570583, 0.567619, 0.561455, 0.554463, 0.548789, 0.545376, 0.537063, 0.531409, 0.523465, 0.522319, 0.51407, 0.508009,\n    0.50576, 0.49867, 0.493705, 0.487867, 0.482187, 0.474436, 0.470146, 0.465546, 0.458712, 0.455268, 0.43738, 0.445348, 0.436779, 0.429227, 0.42748,\n    0.42131, 0.413109, 0.406841, 0.403448, 0.395933, 0.391023, 0.38459, 0.37863, 0.372074, 0.361413, 0.360967, 0.356072, 0.353486, 0.344855, 0.339953,\n    0.336008, 0.327035, 0.322011, 0.316393, 0.310588, 0.306074, 0.299769, 0.294481, 0.290318, 0.285397, 0.279684, 0.279195, 0.271757, 0.27035, 0.261526,\n    0.255964, 0.252562, 0.248199, 0.241338, 0.234956, 0.226232, 0.219861, 0.210806, 0.205706, 0.197321, 0.194638, 0.187568, 0.186719, 0.178183,\n    0.176295, 0.168945, 0.16388, 0.160321\n])\n\nBell_baffle_leakage_zs = np.array([Bell_baffle_leakage_z_0, Bell_baffle_leakage_z_0_25, Bell_baffle_leakage_z_0_5, Bell_baffle_leakage_z_0_75, Bell_baffle_leakage_z_1]).T\nBell_baffle_leakage_z_values = np.array([0, .25, .5, .75, 1])\n\nBell_baffle_leakage_obj = RectBivariateSpline(Bell_baffle_leakage_x, Bell_baffle_leakage_z_values, Bell_baffle_leakage_zs, kx=3, ky=1, s=0.002)\n\n\ndef test_baffle_leakage_Bell():\n    Jl = baffle_leakage_Bell(1, 1, 4)\n    assert_close(Jl, 0.5159239501898142, rtol=1e-3)\n\n    Jl = baffle_leakage_Bell(1, 1, 8)\n    assert_close(Jl, 0.6820523047494141, rtol=1e-3)\n\n    Jl = baffle_leakage_Bell(1, 3, 8)\n    assert_close(Jl, 0.5906621282470395, rtol=1e-3)\n\n    # Silent clipping\n    Jl = baffle_leakage_Bell(1, .0001, .00001)\n    assert_close(Jl,  0.16072739052053492)\n\n    Jl = baffle_leakage_Bell(1, 3, 8, method=\"HEDH\")\n    assert_close(Jl, 0.5530236260777133)\n\n    # Example in spreadsheet 02 - Heat Exchangers, tab Shell htc imperial,\n    # Rules of Thumb for Chemical Engineers 5E\n    # Has an error\n    Jl = baffle_leakage_Bell(Ssb=5.5632369907320000000, Stb=4.7424109055909500, Sm=42.7842616174504, method=\"HEDH\")\n    assert_close(Jl, 0.6719386427830639)\n\n\ndef test_baffle_leakage_Bell_refit():\n    from ht.conv_tube_bank import Bell_baffle_leakage_tck\n    # Test refitting the data\n    obj = RectBivariateSpline(Bell_baffle_leakage_x, Bell_baffle_leakage_z_values, Bell_baffle_leakage_zs, kx=3, ky=1, s=0.002)\n    new_tck = obj.tck + obj.degrees\n    [assert_close1d(i, j) for (i, j) in zip(Bell_baffle_leakage_tck[:-2], new_tck[:-2])]\n\n\n#import matplotlib.pyplot as plt\n#for ys in Bell_baffle_leakage_zs.T:\n#    plt.plot(Bell_baffle_leakage_x, ys)\n#for z in Bell_baffle_leakage_z_values:\n#    xs = np.linspace(min(Bell_baffle_leakage_x), max(Bell_baffle_leakage_x), 1000)\n#    ys = np.clip(Bell_baffle_leakage_obj(xs, z), 0, 1)\n#    plt.plot(xs, ys, '--')\n#\n#for z in Bell_baffle_leakage_z_values:\n#    xs = np.linspace(min(Bell_baffle_leakage_x), max(Bell_baffle_leakage_x), 1000)\n#    rs = z\n#    rl = xs\n#    ys = 0.44*(1.0 - rs) + (1.0 - 0.44*(1.0 - rs))*np.exp(-2.2*rl)\n#    plt.plot(xs, ys, '--')\n\n\ndef test_bundle_bypassing_Bell():\n    Jb = bundle_bypassing_Bell(0.5, 5, 25)\n    assert_close(Jb, 0.8469611760884599, rtol=1e-3)\n    Jb = bundle_bypassing_Bell(0.5, 5, 25, laminar=True)\n    assert_close(Jb, 0.8327442867825271, rtol=1e-3)\n\n    Jb = bundle_bypassing_Bell(0.99, 5, 25, laminar=True)\n    assert_close(Jb, 0.7786963825447165, rtol=1e-3)\n\n    Jb = bundle_bypassing_Bell(0.5, 5, 25, method=\"HEDH\")\n    assert_close(Jb, 0.8483210970579099)\n\n    Jb = bundle_bypassing_Bell(0.5, 5, 25, method=\"HEDH\", laminar=True)\n    assert_close(0.8372305924553625, Jb)\n\n    # Example in spreadsheet 02 - Heat Exchangers, tab Shell htc imperial,\n    # Rules of Thumb for Chemical Engineers 5E\n    Jb = bundle_bypassing_Bell(bypass_area_fraction=0.331946755407654, seal_strips=2, crossflow_rows=10.6516290726817, method=\"HEDH\")\n    assert_close(Jb, 0.8908547260332952)\n\n\nBell_bundle_bypass_x = np.array([0.0, 1e-5, 1e-4, 1e-3, 0.0388568, 0.0474941, 0.0572083, 0.0807999, 0.0915735, 0.0959337, 0.118724, 0.128469, 0.134716,\n    0.142211, 0.146821, 0.156504, 0.162821, 0.169488, 0.178126, 0.185301, 0.194997, 0.200798, 0.210512, 0.212373, 0.221063, 0.222122, 0.228864,\n    0.232856, 0.238578, 0.242605, 0.250104, 0.257958, 0.262866, 0.268403, 0.273639, 0.280289, 0.284999, 0.291067, 0.295186, 0.30005, 0.309764, 0.312548,\n    0.31468, 0.320144, 0.323405, 0.328111, 0.33213, 0.333111, 0.33857, 0.341836, 0.343889, 0.349352, 0.351401, 0.35359, 0.359058, 0.361102, 0.366408,\n    0.370597, 0.375601, 0.379541, 0.382811, 0.386913, 0.392363, 0.39766, 0.401106, 0.401841, 0.410811, 0.412615, 0.419939, 0.421633, 0.42633, 0.431067,\n    0.434967, 0.440908, 0.444682, 0.450614, 0.45373, 0.457036, 0.462565, 0.464508, 0.47016, 0.47227, 0.477519, 0.480474, 0.482794, 0.486874, 0.490639,\n    0.492758, 0.499075, 0.501281, 0.506824, 0.5116, 0.51494, 0.52159, 0.52187, 0.530498, 0.532368, 0.537013, 0.541276, 0.542244, 0.546385, 0.551805,\n    0.553801, 0.5575, 0.562325, 0.56668, 0.568283, 0.572153, 0.576377, 0.580676, 0.582252, 0.5886, 0.591953, 0.599019, 0.601715, 0.602385, 0.610103,\n    0.612441, 0.613194, 0.62061, 0.622146, 0.622934, 0.630324, 0.631852, 0.633669, 0.637109, 0.64136, 0.644447, 0.647887, 0.649879, 0.652335, 0.656363,\n    0.657593, 0.661839, 0.665333, 0.667924, 0.672258, 0.674841, 0.678694, 0.681955, 0.685396, 0.688789, 0.69198, 0.69532\n])\nBell_bundle_bypass_x_max = float(Bell_bundle_bypass_x[-1])\nBell_bundle_bypass_z_values = np.array([0.0, 0.05, 0.1, 1.0 / 6.0, 0.3, 0.5])\n\nBell_bundle_bypass_z_high_0_5 = np.ones(144)\nBell_bundle_bypass_z_high_0_3 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.990537, 0.988984, 0.98724, 0.983016, 0.980614, 0.979535, 0.974346, 0.972054, 0.970522,\n    0.968688, 0.967675, 0.965549, 0.964164, 0.963959, 0.963171, 0.961603, 0.959253, 0.959162, 0.957048, 0.956644, 0.954757, 0.954523, 0.9529, 0.95197,\n    0.950734, 0.949953, 0.951574, 0.949936, 0.947587, 0.946396, 0.945271, 0.943845, 0.942835, 0.941537, 0.940656, 0.940788, 0.942546, 0.940563,\n    0.939047, 0.935797, 0.935104, 0.934105, 0.933252, 0.933045, 0.931888, 0.931164, 0.930682, 0.9294, 0.929485, 0.929948, 0.931104, 0.931397, 0.928907,\n    0.926946, 0.925893, 0.925065, 0.924344, 0.923388, 0.922149, 0.92104, 0.92032, 0.920166, 0.918293, 0.917917, 0.917341, 0.917207, 0.916838, 0.916466,\n    0.916159, 0.915693, 0.915397, 0.914931, 0.914687, 0.914428, 0.913994, 0.913842, 0.91334, 0.912902, 0.911815, 0.911203, 0.91078, 0.910038, 0.909353,\n    0.908968, 0.907821, 0.907421, 0.906416, 0.905551, 0.904947, 0.903745, 0.903694, 0.902137, 0.9018, 0.900963, 0.900195, 0.900021, 0.899276, 0.898303,\n    0.897944, 0.897281, 0.896416, 0.895636, 0.895349, 0.894656, 0.893901, 0.893133, 0.892852, 0.89172, 0.891122, 0.889865, 0.889385, 0.889266, 0.887895,\n    0.88748, 0.887347, 0.887002, 0.887002, 0.887002, 0.886113, 0.885805, 0.88544, 0.884748, 0.883894, 0.883275, 0.882575, 0.882132, 0.881585, 0.880689,\n    0.880426, 0.879577, 0.878879, 0.878362, 0.878362, 0.878362, 0.878362, 0.877712, 0.877026, 0.87635, 0.875715, 0.875051\n])\nBell_bundle_bypass_z_high_0_167 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.98326, 0.97947, 0.974498, 0.962528, 0.957986, 0.956693, 0.949964, 0.947102, 0.945271,\n    0.94206, 0.94009, 0.935965, 0.93353, 0.932117, 0.928823, 0.925995, 0.923086, 0.921351, 0.918452, 0.917897, 0.915313, 0.914999, 0.913, 0.911818,\n    0.910127, 0.90895, 0.907403, 0.905106, 0.903391, 0.90146, 0.899637, 0.897328, 0.895696, 0.893598, 0.892176, 0.8905, 0.886812, 0.885691, 0.884834,\n    0.882399, 0.880948, 0.879769, 0.878966, 0.87877, 0.87685, 0.875407, 0.874501, 0.873182, 0.872775, 0.872342, 0.870581, 0.869774, 0.86768, 0.865848,\n    0.863665, 0.862771, 0.862131, 0.861322, 0.859193, 0.857129, 0.859086, 0.858609, 0.852897, 0.852509, 0.850934, 0.85034, 0.848528, 0.846705, 0.845041,\n    0.842545, 0.841823, 0.840689, 0.839677, 0.838418, 0.836305, 0.835485, 0.833106, 0.832278, 0.831286, 0.830728, 0.830291, 0.828583, 0.827011,\n    0.826114, 0.823157, 0.822169, 0.82102, 0.820047, 0.819426, 0.818189, 0.818085, 0.814886, 0.814194, 0.812289, 0.810543, 0.810058, 0.806263, 0.806263,\n    0.806263, 0.806137, 0.804373, 0.802783, 0.802256, 0.801473, 0.800619, 0.799812, 0.799526, 0.798328, 0.796926, 0.793982, 0.792861, 0.792583,\n    0.789808, 0.78897, 0.788701, 0.787226, 0.786921, 0.786757, 0.784122, 0.783578, 0.782932, 0.781709, 0.780202, 0.779109, 0.778433, 0.778042, 0.77756,\n    0.776422, 0.775988, 0.774494, 0.77333, 0.772824, 0.77198, 0.771442, 0.770094, 0.768954, 0.767753, 0.766571, 0.765461, 0.764301\n])\nBell_bundle_bypass_z_high_0_1 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.978035, 0.974378, 0.970282, 0.960405, 0.955928, 0.953958, 0.941171, 0.935756, 0.932301,\n    0.928172, 0.925642, 0.92035, 0.916913, 0.9133, 0.908641, 0.904789, 0.899741, 0.89745, 0.893627, 0.892897, 0.889494, 0.88908, 0.886716, 0.885913,\n    0.884594, 0.881903, 0.877493, 0.874369, 0.87224, 0.869806, 0.867741, 0.865076, 0.863023, 0.86048, 0.858872, 0.856977, 0.853205, 0.851584, 0.850211,\n    0.846705, 0.845452, 0.843647, 0.842058, 0.841641, 0.839327, 0.837996, 0.837215, 0.835141, 0.834364, 0.833443, 0.831147, 0.830291, 0.828293,\n    0.826718, 0.824687, 0.82305, 0.821515, 0.819223, 0.816189, 0.814075, 0.812703, 0.81241, 0.808849, 0.808135, 0.805242, 0.804574, 0.802726, 0.800866,\n    0.799338, 0.797016, 0.795545, 0.793199, 0.791952, 0.790633, 0.78865, 0.787955, 0.785378, 0.784125, 0.781018, 0.779971, 0.779149, 0.777707, 0.776379,\n    0.775632, 0.77341, 0.77338, 0.770144, 0.767521, 0.766358, 0.764048, 0.763944, 0.760626, 0.759946, 0.758344, 0.756878, 0.756543, 0.754964, 0.752903,\n    0.752217, 0.750955, 0.749311, 0.74768, 0.747075, 0.745618, 0.743505, 0.741332, 0.740537, 0.738255, 0.737132, 0.731632, 0.729296, 0.729296, 0.729296,\n    0.728522, 0.728273, 0.725825, 0.725318, 0.725059, 0.72263, 0.722122, 0.72146, 0.720209, 0.718666, 0.71766, 0.716539, 0.715891, 0.715086, 0.713635,\n    0.713192, 0.711666, 0.708853, 0.706773, 0.705828, 0.705414, 0.704797, 0.703715, 0.702494, 0.701293, 0.700165, 0.698986\n])\nBell_bundle_bypass_z_high_0_05 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.972281, 0.967922, 0.961369, 0.943692, 0.935729, 0.932525, 0.915956, 0.908961,\n    0.906104, 0.904563, 0.901473, 0.895196, 0.891354, 0.885977, 0.87906, 0.874187, 0.86913, 0.86655, 0.862245, 0.861423, 0.857594, 0.857129, 0.852769,\n    0.850462, 0.848255, 0.846705, 0.842424, 0.837963, 0.835187, 0.832066, 0.829126, 0.825407, 0.822783, 0.819415, 0.817095, 0.814308, 0.808771, 0.80719,\n    0.805982, 0.802895, 0.801058, 0.798414, 0.796163, 0.795615, 0.79257, 0.79081, 0.789705, 0.786773, 0.785555, 0.784255, 0.781018, 0.780293, 0.778416,\n    0.776757, 0.773823, 0.77152, 0.769804, 0.767657, 0.764814, 0.76206, 0.760275, 0.759852, 0.754714, 0.753788, 0.750038, 0.749171, 0.746514, 0.743844,\n    0.742476, 0.740476, 0.738142, 0.733741, 0.732227, 0.731129, 0.729296, 0.728224, 0.725118, 0.723961, 0.721379, 0.719929, 0.718793, 0.716592,\n    0.714554, 0.71341, 0.709585, 0.708255, 0.706445, 0.704915, 0.703256, 0.699727, 0.699579, 0.694462, 0.693873, 0.692411, 0.691072, 0.690566, 0.688406,\n    0.685632, 0.684701, 0.682979, 0.68071, 0.678471, 0.677649, 0.675704, 0.673763, 0.671794, 0.671073, 0.668927, 0.667797, 0.664237, 0.662887, 0.662584,\n    0.659112, 0.658063, 0.657689, 0.65401, 0.65325, 0.652861, 0.649222, 0.648472, 0.647937, 0.646926, 0.645678, 0.64442, 0.642745, 0.641777, 0.640586,\n    0.638832, 0.638297, 0.636454, 0.634836, 0.633593, 0.631519, 0.630382, 0.628731, 0.627336, 0.626066, 0.624995, 0.62399, 0.622939\n])\nBell_bundle_bypass_z_high_0 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.952236, 0.940656, 0.929217, 0.902172, 0.890997, 0.886514, 0.863444, 0.851755, 0.845079,\n    0.837139, 0.832293, 0.822203, 0.816984, 0.810801, 0.80192, 0.794615, 0.78485, 0.779066, 0.769592, 0.767791, 0.759517, 0.758605, 0.752824, 0.749047,\n    0.743669, 0.739906, 0.73295, 0.725735, 0.722154, 0.717987, 0.713174, 0.707108, 0.702842, 0.697384, 0.693703, 0.689382, 0.680999, 0.678318, 0.676273,\n    0.671537, 0.669333, 0.666165, 0.662801, 0.661983, 0.657447, 0.654748, 0.653057, 0.648578, 0.646907, 0.645126, 0.640517, 0.638664, 0.634016,\n    0.631344, 0.628167, 0.625058, 0.622488, 0.619125, 0.614363, 0.610288, 0.607796, 0.607265, 0.60083, 0.599544, 0.59421, 0.592943, 0.589445, 0.585503,\n    0.582277, 0.577936, 0.575196, 0.571767, 0.569973, 0.567464, 0.563036, 0.561619, 0.557635, 0.556155, 0.55249, 0.550438, 0.548878, 0.546625, 0.544554,\n    0.543231, 0.538071, 0.536281, 0.532469, 0.529276, 0.527497, 0.523935, 0.52375, 0.518089, 0.516762, 0.513373, 0.51047, 0.509884, 0.507382, 0.504126,\n    0.502932, 0.500727, 0.497867, 0.495143, 0.494144, 0.491733, 0.488799, 0.485831, 0.484868, 0.481006, 0.479285, 0.476413, 0.473514, 0.472869,\n    0.469205, 0.468011, 0.467512, 0.462626, 0.461732, 0.461273, 0.457, 0.456012, 0.45484, 0.452628, 0.450352, 0.448953, 0.447398, 0.446281, 0.444731,\n    0.442201, 0.44145, 0.439096, 0.437168, 0.435842, 0.433942, 0.432813, 0.430923, 0.429157, 0.427301, 0.425479, 0.423772, 0.421993\n])\nBell_bundle_bypass_z_high = np.array([Bell_bundle_bypass_z_high_0, Bell_bundle_bypass_z_high_0_05, Bell_bundle_bypass_z_high_0_1, Bell_bundle_bypass_z_high_0_167, Bell_bundle_bypass_z_high_0_3, Bell_bundle_bypass_z_high_0_5]).T\nBell_bundle_bypass_high_obj = RectBivariateSpline(Bell_bundle_bypass_x, Bell_bundle_bypass_z_values, Bell_bundle_bypass_z_high, kx = 3, ky = 3, s = 0.0007)\n\n\n#import matplotlib.pyplot as plt\n#for ys in Bell_bundle_bypass_z_high.T:\n#    plt.plot(Bell_bundle_bypass_x, ys)\n#for z in Bell_bundle_bypass_z_values:\n#    xs = np.linspace(min(Bell_bundle_bypass_x), max(Bell_bundle_bypass_x), 1000)\n#    ys = np.clip(Bell_bundle_bypass_high_obj(xs, z), 0, 1)\n#    plt.plot(xs, ys, '--')\n#for z in Bell_bundle_bypass_z_values:\n#    xs = np.linspace(min(Bell_bundle_bypass_x), max(Bell_bundle_bypass_x), 1000)\n#    ys = np.exp(-1.25*xs*(1.0 - (2.0*z)**(1/3.) )) # This one is a good fit!\n#    plt.plot(xs, ys, '.')\n#plt.show()\n\nBell_bundle_bypass_z_low_0_5 = Bell_bundle_bypass_z_high_0_5\nBell_bundle_bypass_z_low_0_3 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.991796, 0.989982, 0.987945, 0.983016, 0.980614, 0.979535, 0.974346, 0.972054, 0.970522,\n    0.968688, 0.967675, 0.965549, 0.964164, 0.963959, 0.963171, 0.961603, 0.959253, 0.959162, 0.957048, 0.956644, 0.954757, 0.954523, 0.9529, 0.95197,\n    0.950734, 0.949953, 0.951574, 0.949936, 0.947587, 0.946396, 0.945271, 0.943845, 0.942835, 0.941537, 0.940656, 0.940788, 0.942546, 0.940563,\n    0.939047, 0.935797, 0.935104, 0.934105, 0.933252, 0.933045, 0.931888, 0.931164, 0.930682, 0.9294, 0.929485, 0.929948, 0.931104, 0.931397, 0.928907,\n    0.926946, 0.925893, 0.925065, 0.924344, 0.923388, 0.922112, 0.920852, 0.920034, 0.919859, 0.917732, 0.917305, 0.915572, 0.915172, 0.914063,\n    0.912946, 0.912028, 0.910631, 0.909744, 0.908352, 0.907622, 0.906848, 0.905555, 0.905101, 0.903781, 0.903289, 0.902066, 0.901379, 0.900839,\n    0.899919, 0.899149, 0.898717, 0.897483, 0.897083, 0.89608, 0.895216, 0.894613, 0.893412, 0.893362, 0.891807, 0.89147, 0.890635, 0.889868, 0.889694,\n    0.888923, 0.887829, 0.887427, 0.886681, 0.88571, 0.884834, 0.884477, 0.883613, 0.882672, 0.881954, 0.881691, 0.880632, 0.880073, 0.878897, 0.878448,\n    0.878332, 0.876793, 0.876328, 0.876178, 0.874703, 0.874398, 0.874242, 0.872631, 0.872295, 0.871914, 0.871488, 0.870962, 0.87058, 0.870155, 0.869909,\n    0.869486, 0.868691, 0.868448, 0.867611, 0.866922, 0.866412, 0.86556, 0.864996, 0.864155, 0.863444, 0.86277, 0.862105, 0.86148, 0.860827\n])\nBell_bundle_bypass_z_low_0_167 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.980974, 0.977905, 0.97446, 0.966143, 0.962368, 0.960686, 0.951112, 0.947048, 0.944452,\n    0.941346, 0.939441, 0.935452, 0.93269, 0.92946, 0.925293, 0.921845, 0.917207, 0.914443, 0.909833, 0.908959, 0.905975, 0.905612, 0.903304, 0.90194,\n    0.899989, 0.898618, 0.896071, 0.893412, 0.891754, 0.889887, 0.887916, 0.885239, 0.883183, 0.880493, 0.879259, 0.877803, 0.874903, 0.874074,\n    0.873134, 0.870731, 0.869578, 0.868649, 0.867856, 0.867642, 0.865256, 0.863831, 0.862988, 0.860849, 0.860049, 0.859186, 0.856524, 0.855531,\n    0.852959, 0.852139, 0.851171, 0.84986, 0.848459, 0.846705, 0.844612, 0.842583, 0.841212, 0.840919, 0.837359, 0.836645, 0.833751, 0.833084, 0.831743,\n    0.830749, 0.829968, 0.828849, 0.827989, 0.825515, 0.824217, 0.822981, 0.820918, 0.820193, 0.817941, 0.817102, 0.815018, 0.813871, 0.813014,\n    0.811509, 0.810137, 0.809474, 0.8075, 0.806811, 0.805085, 0.8036, 0.802563, 0.800503, 0.800417, 0.797752, 0.797175, 0.795746, 0.794422, 0.794073,\n    0.792581, 0.790633, 0.789837, 0.788364, 0.786627, 0.785849, 0.785563, 0.784873, 0.783229, 0.781532, 0.780917, 0.778551, 0.777304, 0.774683,\n    0.773686, 0.773438, 0.772069, 0.771659, 0.771527, 0.768654, 0.768059, 0.767753, 0.765181, 0.764651, 0.76402, 0.76335, 0.762532, 0.76154, 0.75956,\n    0.758417, 0.757994, 0.757301, 0.757089, 0.75611, 0.754779, 0.753793, 0.752544, 0.752102, 0.751445, 0.750747, 0.749575, 0.748421, 0.747337, 0.746205\n])\nBell_bundle_bypass_z_low_0_1 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.978947, 0.974857, 0.970278, 0.959247, 0.954251, 0.952236, 0.938267, 0.932356, 0.928587,\n    0.924085, 0.921326, 0.915559, 0.911816, 0.907882, 0.902811, 0.89862, 0.892988, 0.889635, 0.885582, 0.884834, 0.879037, 0.878345, 0.87566, 0.874074,\n    0.87124, 0.869251, 0.86556, 0.862478, 0.860473, 0.858072, 0.85515, 0.850859, 0.849041, 0.846705, 0.844334, 0.841542, 0.835995, 0.834411, 0.833976,\n    0.832942, 0.832325, 0.829367, 0.82685, 0.826237, 0.824191, 0.82297, 0.822203, 0.81994, 0.819093, 0.818189, 0.815149, 0.814015, 0.81124, 0.809258,\n    0.806898, 0.805045, 0.80351, 0.801588, 0.799042, 0.796575, 0.794975, 0.794634, 0.791377, 0.790729, 0.787823, 0.78715, 0.784863, 0.782599, 0.781214,\n    0.779109, 0.776888, 0.77341, 0.772317, 0.771158, 0.769179, 0.768425, 0.766237, 0.765263, 0.762533, 0.761, 0.759834, 0.757882, 0.756085, 0.755076,\n    0.752075, 0.751029, 0.749142, 0.747519, 0.746277, 0.743778, 0.743677, 0.740769, 0.74014, 0.737582, 0.735207, 0.73467, 0.733289, 0.731487, 0.730713,\n    0.728963, 0.726686, 0.724636, 0.723901, 0.722489, 0.720951, 0.719026, 0.718255, 0.715157, 0.713949, 0.711376, 0.710288, 0.710018, 0.706915,\n    0.705978, 0.705676, 0.702713, 0.7021, 0.701786, 0.698849, 0.698244, 0.697524, 0.696164, 0.694821, 0.693848, 0.692765, 0.691722, 0.690438, 0.688338,\n    0.687698, 0.686042, 0.684684, 0.683677, 0.681998, 0.680999, 0.680403, 0.679899, 0.679368, 0.677706, 0.676072, 0.674366\n])\nBell_bundle_bypass_z_low_0_05 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.97132, 0.966107, 0.959971, 0.942755, 0.934996, 0.931875, 0.915726, 0.908906, 0.906104,\n    0.904563, 0.901473, 0.895196, 0.891354, 0.885977, 0.87906, 0.874187, 0.867386, 0.86321, 0.856262, 0.854938, 0.84878, 0.848124, 0.843964, 0.841509,\n    0.838004, 0.835546, 0.830988, 0.826241, 0.823289, 0.81997, 0.816844, 0.812892, 0.810104, 0.806526, 0.804106, 0.801259, 0.795601, 0.793967, 0.792688,\n    0.789419, 0.787596, 0.785077, 0.782932, 0.782351, 0.779127, 0.777205, 0.776119, 0.773238, 0.77216, 0.770953, 0.767771, 0.766585, 0.763514, 0.761099,\n    0.758428, 0.756396, 0.754714, 0.752376, 0.749281, 0.745922, 0.743739, 0.743322, 0.738296, 0.737388, 0.73372, 0.732874, 0.730275, 0.727663, 0.725519,\n    0.722266, 0.720207, 0.716983, 0.715295, 0.713509, 0.710531, 0.709487, 0.70646, 0.705709, 0.703842, 0.702816, 0.702076, 0.700776, 0.699579, 0.698012,\n    0.693361, 0.691743, 0.687698, 0.686208, 0.685168, 0.682279, 0.682134, 0.677697, 0.676739, 0.674366, 0.671761, 0.671172, 0.668654, 0.666449,\n    0.665778, 0.664536, 0.662357, 0.660396, 0.659676, 0.657624, 0.655391, 0.653126, 0.652298, 0.648972, 0.647223, 0.643551, 0.642155, 0.64196, 0.639714,\n    0.639035, 0.638682, 0.635109, 0.634371, 0.633993, 0.63046, 0.629731, 0.628867, 0.627232, 0.625218, 0.62376, 0.622139, 0.621202, 0.62005, 0.618248,\n    0.617731, 0.615947, 0.614484, 0.61328, 0.611273, 0.61008, 0.608305, 0.606806, 0.605229, 0.603678, 0.602222, 0.600702\n])\nBell_bundle_bypass_z_low_0 = np.array([1.0, 0.99999, 0.9999, 0.999, 0.952236, 0.940656, 0.929217, 0.90002, 0.886521, 0.880701, 0.850893, 0.838458, 0.831886,\n    0.823549, 0.818189, 0.807989, 0.801404, 0.794512, 0.78485, 0.776988, 0.766488, 0.760275, 0.751029, 0.749052, 0.740111, 0.739124, 0.732874, 0.729198,\n    0.723961, 0.720158, 0.713129, 0.705842, 0.701326, 0.696132, 0.690988, 0.684186, 0.679334, 0.67352, 0.66971, 0.665448, 0.657018, 0.654621, 0.652811,\n    0.648334, 0.645676, 0.641432, 0.637791, 0.636967, 0.632602, 0.630005, 0.628212, 0.623369, 0.621616, 0.619905, 0.61565, 0.61403, 0.609576, 0.606083,\n    0.601936, 0.598691, 0.596011, 0.592666, 0.588251, 0.583992, 0.581238, 0.580668, 0.574145, 0.572724, 0.566812, 0.565183, 0.56069, 0.556978, 0.55452,\n    0.550223, 0.547289, 0.543116, 0.540988, 0.538616, 0.534414, 0.532944, 0.528694, 0.527116, 0.523265, 0.521112, 0.519429, 0.516481, 0.514038,\n    0.512668, 0.508511, 0.507017, 0.503284, 0.500089, 0.497867, 0.493714, 0.49354, 0.487757, 0.486467, 0.482972, 0.479717, 0.478981, 0.476477, 0.473881,\n    0.472928, 0.470456, 0.467252, 0.464687, 0.46375, 0.461495, 0.458195, 0.45486, 0.453935, 0.45032, 0.448303, 0.443758, 0.442035, 0.441609, 0.437337,\n    0.436027, 0.435562, 0.431011, 0.430169, 0.429742, 0.425761, 0.424942, 0.423971, 0.422137, 0.42001, 0.418705, 0.417255, 0.416416, 0.414108, 0.41035,\n    0.409842, 0.408091, 0.406656, 0.405331, 0.402949, 0.401536, 0.399438, 0.39767, 0.395938, 0.394249, 0.392668, 0.391019\n])\nBell_bundle_bypass_z_low = np.array([Bell_bundle_bypass_z_low_0, Bell_bundle_bypass_z_low_0_05, Bell_bundle_bypass_z_low_0_1, Bell_bundle_bypass_z_low_0_167, Bell_bundle_bypass_z_low_0_3, Bell_bundle_bypass_z_low_0_5]).T\nBell_bundle_bypass_low_obj = RectBivariateSpline(Bell_bundle_bypass_x, Bell_bundle_bypass_z_values, Bell_bundle_bypass_z_low, kx = 3, ky = 3, s = 0.0007)\n#for ys in Bell_bundle_bypass_z_low.T:\n#    plt.plot(Bell_bundle_bypass_x, ys)\n#\n#for z in Bell_bundle_bypass_z_values:\n#    xs = np.linspace(min(Bell_bundle_bypass_x), max(Bell_bundle_bypass_x), 1000)\n#    ys = np.clip(Bell_bundle_bypass_low_obj(xs, z), 0, 1)\n#    plt.plot(xs, ys, '--')\n#plt.show()\n\ndef test_bundle_bypassing_Bell():\n    from ht.conv_tube_bank import Bell_bundle_bypass_high_spl, Bell_bundle_bypass_low_spl\n\n    low_spl = Bell_bundle_bypass_low_obj.tck + Bell_bundle_bypass_low_obj.degrees\n    high_spl = Bell_bundle_bypass_high_obj.tck + Bell_bundle_bypass_high_obj.degrees\n\n    [assert_close1d(i, j) for i, j in zip(Bell_bundle_bypass_high_spl[:-2], high_spl[:-2])]\n    [assert_close1d(i, j) for i, j in zip(Bell_bundle_bypass_low_spl[:-2], low_spl[:-2])]\n\n\ndef test_unequal_baffle_spacing_Bell():\n    Js = unequal_baffle_spacing_Bell(16, .1, .15, 0.15)\n    assert_close(Js, 0.9640087802805195)\n\ndef test_laminar_correction_Bell():\n    Jr = laminar_correction_Bell(30.0, 80)\n    assert_close(Jr, 0.7267995454361379)\n\n    assert_close(0.4, laminar_correction_Bell(30, 80000))\n"
  },
  {
    "path": "tests/test_conv_two_phase.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close\n\nfrom ht import Aggour, Davis_David, Elamvaluthi_Srinivas, Groothuis_Hendal, Hughmark, Knott, Kudirka_Grosh_McFadden, Martin_Sims, Ravipudi_Godbold, h_two_phase\n\n\ndef test_Davis_David():\n    h = Davis_David(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mul=1E-3)\n    assert_close(h, 1437.3282869955121)\n\n\ndef test_Elamvaluthi_Srinivas():\n    h = Elamvaluthi_Srinivas(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    assert_close(h, 3901.2134471578584)\n\n\ndef test_Groothuis_Hendal():\n    h = Groothuis_Hendal(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    assert_close(h, 1192.9543445455754)\n\n    h = Groothuis_Hendal(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3, water=True)\n    assert_close(h, 6362.8989677634545)\n\n\ndef test_Hughmark():\n    h = Hughmark(m=1., x=.9, D=.3, L=.5, alpha=.9, Cpl=2300., kl=0.6, mu_b=1E-3, mu_w=1.2E-3)\n    assert_close(h, 212.7411636127175)\n\n\ndef test_Knott():\n    h = Knott(m=1., x=.9, D=.3, rhol=1000, rhog=2.5, Cpl=2300., kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=4.)\n    assert_close(h, 4225.536758045839)\n\n\ndef test_Kudirka_Grosh_McFadden():\n    h = Kudirka_Grosh_McFadden(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    assert_close(h, 303.9941255903587)\n\n\ndef test_Martin_Sims():\n    h = Martin_Sims(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, hl=141.2)\n    assert_close(h, 5563.280000000001)\n\n    h = Martin_Sims(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=24.)\n    assert_close(h, 5977.505465781747)\n\n\ndef test_Ravipudi_Godbold():\n    h = Ravipudi_Godbold(m=1., x=.9, D=.3, rhol=1000., rhog=2.5, Cpl=2300., kl=.6, mug=1E-5, mu_b=1E-3, mu_w=1.2E-3)\n    assert_close(h, 299.3796286459285)\n\n\ndef test_Aggour():\n    h = Aggour(m=1., x=.9, D=.3, alpha=.9, rhol=1000., Cpl=2300., kl=.6, mu_b=1E-3)\n    assert_close(h, 420.9347146885667)\n\n    h = Aggour(m=.1, x=.9, D=.3, alpha=.9, rhol=1000., Cpl=2300., kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=4.)\n    assert_close(h, 33.64542760558181)\n\n\ndef test_h_two_phase():\n    h = h_two_phase(m=1., x=.9, D=.3, alpha=.9, rhol=1000., Cpl=2300., kl=.6, mu_b=1E-3, mu_w=1.2E-3, L=5., method=\"Aggour\")\n    assert_close(h, 420.9347146885667)\n\n"
  },
  {
    "path": "tests/test_core.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close\n\nfrom ht import LMTD, countercurrent_hx_temperature_check, fin_efficiency_Kern_Kraus, wall_factor\nfrom ht.core import WALL_FACTOR_PRANDTL, WALL_FACTOR_TEMPERATURE, WALL_FACTOR_VISCOSITY, is_heating_property, is_heating_temperature\n\n\ndef test_core():\n    dT = LMTD(100., 60., 30., 40.2)\n    assert_close(dT, 43.200409294131525)\n    dT = LMTD(100., 60., 30., 40.2, counterflow=False)\n    assert_close(dT, 39.75251118049003)\n\n    assert LMTD(100., 60., 20., 60) == 40\n    assert LMTD(100., 60., 20., 60, counterflow=False) == 0\n    \"\"\"Test code for limits\n    from sympy import *\n    Thi, Tho, Tci, Tco = symbols('Thi, Tho, Tci, Tco')\n    Thi = 100\n    Tho=60\n    Tci=20\n    dTF1 = Thi-Tco\n    dTF2 = Tho-Tci\n    expression = (dTF2 - dTF1)/log(dTF2/dTF1)\n    limit(expression, Tco, 60)\n    # evaluates to 40\n\n    # Numerical check - goes to zero\n    Thi = 100\n    Tho=60\n    Tci=20\n    dTF1 = Thi-Tci\n    dTF2 = Tho-Tco\n    expression = (dTF2 - dTF1)/log(dTF2/dTF1)\n    N(limit(expression, Tco, Rational('60')-Rational('1e-50000')))\n    limit(expression, Tco, 60)\n    # evaluates to zero\n    \"\"\"\n\n\ndef test_is_heating_temperature():\n    assert is_heating_temperature(T=200, T_wall=500)\n\n    assert not is_heating_temperature(T=400, T_wall=200)\n\n    # not heating when 400 K\n    assert not is_heating_temperature(T=400, T_wall=400)\n\n\ndef test_is_heating_property():\n    T1, T2 = 280, 330\n#    C1, C2 = Chemical('hexane', T=T1), Chemical('hexane', T=T2)\n#    mu1, mu2 = C1.mu, C2.mu\n#    Pr1, Pr2 = C1.Pr, C2.Pr\n    mu1, mu2 = 0.0003595695325135477, 0.0002210964201834834\n    Pr1, Pr2 = 6.2859707150337805, 4.810661011475006\n\n    assert is_heating_property(prop=mu1, prop_wall=mu2)\n    assert is_heating_property(prop=Pr1, prop_wall=Pr2)\n\n    # Equal temperatures - not heating in that case\n    T1, T2 = 280, 280\n    mu1, mu2 = 0.0003595695325135477, 0.0003595695325135477\n    Pr1, Pr2 = 6.2859707150337805, 6.2859707150337805\n    assert not is_heating_property(prop=mu1, prop_wall=mu2)\n    assert not is_heating_property(prop=Pr1, prop_wall=Pr2)\n\n    # Lower wall temperatures - not heating in that case\n    T1, T2 = 280, 260\n    mu1, mu2 = 0.0003595695325135477, 0.0004531397378208441\n    Pr1, Pr2 = 6.2859707150337805, 7.27333944072039\n    assert not is_heating_property(prop=mu1, prop_wall=mu2)\n    assert not is_heating_property(prop=Pr1, prop_wall=Pr2)\n\ndef test_wall_factor():\n    # Only one value provided\n    with pytest.raises(Exception):\n        wall_factor(mu=1, property_option=WALL_FACTOR_VISCOSITY)\n\n    with pytest.raises(Exception):\n        wall_factor(mu_wall=1, property_option=WALL_FACTOR_VISCOSITY)\n\n    with pytest.raises(Exception):\n        wall_factor(Pr=1, property_option=WALL_FACTOR_PRANDTL)\n\n    with pytest.raises(Exception):\n        wall_factor(Pr_wall=1, property_option=WALL_FACTOR_PRANDTL)\n\n    with pytest.raises(Exception):\n        wall_factor(T=1, property_option=WALL_FACTOR_TEMPERATURE)\n\n    with pytest.raises(Exception):\n        wall_factor(T_wall=1, property_option=WALL_FACTOR_TEMPERATURE)\n\n\ndef test_fin_efficiency_Kern_Kraus():\n\n    assert type(fin_efficiency_Kern_Kraus(0.0254, 0.05715, 3.8E-4, 200, 58)) is float\n\n    eta = fin_efficiency_Kern_Kraus(0.0254, 0.05715, 3.8E-4, 200, 58)\n    assert_close(eta, 0.8412588620231153)\n    \"\"\"Code for comparing against several formulas:\n    def fin_efficiency_Kern_Kraus(Do, Dfin, fin_thickness, kfin, h):\n        # Should now be about 50/50 function vs special function\n        kf = kfin\n        tf = fin_thickness\n        re = Dfin/2.\n        ro = Do/2.\n        m = (2.0*h/(kf*tf))**0.5\n\n        mre = m*re\n        mro = m*ro\n        x0 = i1(mre)\n        x1 = k1(mre)\n        num = x0*k1(mro) - x1*i1(mro)\n        den = i0(mro)*x1 + x0*k0(mro)\n\n    #     num = i1(m*re)*k1(m*ro) - k1(m*re)*i1(m*ro)\n    #     den = i0(m*ro)*k1(m*re) + i1(m*re)*k0(m*ro)\n\n    #     num = iv(1, m*re)*kn(1, m*ro) - kn(1, m*re)*iv(1, m*ro)\n    #     den = iv(0, m*ro)*kn(1, m*re) + iv(1, m*re)*kn(0, m*ro)\n    #     print(num/den)\n\n    #     r2c = re\n    #     r1 = ro\n    #     num = kn(1, m*r1)*iv(1, m*r2c) - iv(1, m* r1)*kn(1, m*r2c)\n    #     den = iv(0, m*r1)*kn(1, m*r2c) + kn(0, m*r1)*iv(1, m*r2c)\n    #     print(num/den)\n\n\n        eta = 2.0*ro/(m*(re*re - ro*ro))*num/den # r2c = r2, r1 = ro\n        return eta\n        # Confirmed with Introduction to Heat Transfer\n        # To create a pade approximation of this, it would require f(m, re, ro). Not worth it.\n    \"\"\"\n\ndef test_countercurrent_hx_temperature_check():\n    assert not countercurrent_hx_temperature_check(T0i=500, T0o=466, T1i=348, T1o=329)\n    assert not countercurrent_hx_temperature_check(T0i=453, T0o=466, T1i=310, T1o=329)\n    assert not countercurrent_hx_temperature_check(T0i=453, T0o=466, T1i=348, T1o=329)\n    assert countercurrent_hx_temperature_check(T0i=500, T0o=466, T1i=310, T1o=329)\n"
  },
  {
    "path": "tests/test_hx.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom math import exp, factorial, isnan, sqrt, tanh\nfrom random import choice, randint, seed, uniform\n\nimport numpy as np\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d, assert_close2d\n\nimport ht\nfrom ht import (\n    LMTD,\n    D_for_Ntubes_VDI,\n    DBundle_for_Ntubes_HEDH,\n    DBundle_for_Ntubes_Phadkeb,\n    DBundle_min,\n    F_LMTD_Fakheri,\n    L_unsupported_max,\n    NTU_from_effectiveness,\n    NTU_from_P_basic,\n    NTU_from_P_E,\n    NTU_from_P_G,\n    NTU_from_P_H,\n    NTU_from_P_J,\n    NTU_from_P_plate,\n    Ntubes,\n    Ntubes_HEDH,\n    Ntubes_Perrys,\n    Ntubes_Phadkeb,\n    Ntubes_VDI,\n    P_NTU_method,\n    effectiveness_from_NTU,\n    effectiveness_NTU_method,\n    shell_clearance,\n    size_bundle_from_tubecount,\n    temperature_effectiveness_air_cooler,\n    temperature_effectiveness_basic,\n    temperature_effectiveness_plate,\n    temperature_effectiveness_TEMA_E,\n    temperature_effectiveness_TEMA_G,\n    temperature_effectiveness_TEMA_H,\n    temperature_effectiveness_TEMA_J,\n)\n\nseed(0)\n\n\ndef test_Ntubes_Perrys():\n    Nt_perry = [[Ntubes_Perrys(DBundle=1.184, Ntp=i, Do=.028, angle=j) for i in [1,2,4,6]] for j in [30, 45, 60, 90]]\n    Nt_values = [[1001, 973, 914, 886], [819, 803, 784, 769], [1001, 973, 914, 886], [819, 803, 784, 769]]\n    assert_close2d(Nt_perry, Nt_values)\n#    angle = 30 or 60 and ntubes = 1.5 raise exception\n\n    with pytest.raises(Exception):\n        Ntubes_Perrys(DBundle=1.184, Ntp=5, Do=.028, angle=30)\n    with pytest.raises(Exception):\n        Ntubes_Perrys(DBundle=1.184, Ntp=5, Do=.028, angle=45)\n\n\n\n\ndef test_Ntubes_Phadkeb():\n    # For the 45 degree case, ten exanples are given and known to be correct.\n    # Unfortunately no examples were given for any other case.\n    Ntubes_calc = [Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=i, angle=45.) for i in [1,2,4,6,8]]\n    assert_close1d(Ntubes_calc, [805, 782, 760, 698, 680])\n    Ntubes_calc = [Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.035, Ntp=i, angle=45.) for i in [1,2,4,6,8]]\n    assert_close1d(Ntubes_calc, [861, 838, 816, 750, 732])\n\n    # Extra tests\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=2, angle=30.)\n    assert N == 898\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=2, angle=60.)\n    assert N == 876\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=6, angle=60.)\n    assert N == 822\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=8, angle=60.)\n    assert N == 772\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.092, Ntp=8, angle=60.)\n    assert N == 88\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=8, angle=30.)\n    assert N == 788\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.04, Ntp=6, angle=30.)\n    assert N == 652\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=8, angle=90.)\n    assert N == 684\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=2, angle=90.)\n    assert N == 772\n    N = Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=6, angle=90.)\n    assert N == 712\n\n    # Big case\n    N = Ntubes_Phadkeb(DBundle=5, Do=.028, pitch=.036, Ntp=2, angle=90.)\n    assert N == 14842\n\n    # negative case\n    N = Ntubes_Phadkeb(DBundle=0.004750018463796297, Do=.001, pitch=.0015, Ntp=8, angle=60)\n    assert N == 0\n\n    # reverse case\n    # DBundle_for_Ntubes_Phadkeb(Ntubes=17546, Do=.001, pitch=.00125, Ntp=6, angle=45) 0.19052937784048926\n\n    with pytest.raises(Exception):\n        Ntubes_Phadkeb(DBundle=1.008, Do=.028, pitch=.036, Ntp=11, angle=45.)\n\n    # Test the case of too small for anything\n    assert 0 == Ntubes_Phadkeb(DBundle=.01, Do=.028, pitch=.036, Ntp=2, angle=45.)\n\ndef test_Ntubes_Phadkeb_fuzz():\n    seed(100)\n    D_main = 1E-3\n    for angle in [30, 45, 60, 90]:\n        for Ntp in [1, 2, 4, 6, 8]:\n            for pitch_ratio in [1.25, 1.31, 1.33, 1.375, 1.4, 1.42, 1.5]:\n                pitch = D_main*pitch_ratio\n                for _ in range(10):\n                    DBundle = uniform(pitch*2, pitch*300)\n                    N = Ntubes_Phadkeb(DBundle=DBundle, Do=D_main, pitch=pitch, Ntp=Ntp, angle=angle)\n\n    # Test the reverse correlation\n    D_main = 1E-2\n    for angle in [30, 45, 60, 90]:\n        for Ntp in [1, 2, 4, 6, 8]:\n            for pitch_ratio in [1.25, 1.31, 1.33, 1.375, 1.4, 1.42, 1.5]:\n                pitch = D_main*pitch_ratio\n                DBundle = uniform(pitch*5, pitch*300)\n                N = Ntubes_Phadkeb(DBundle=DBundle, Do=D_main, pitch=pitch, Ntp=Ntp, angle=angle)\n                if N > 2:\n                    DBundle2 = DBundle_for_Ntubes_Phadkeb(Ntubes=N, Do=D_main, pitch=pitch, Ntp=Ntp, angle=angle)\n                    assert type(DBundle2) is float\n                    N2 = Ntubes_Phadkeb(DBundle=DBundle2, Do=D_main, pitch=pitch, Ntp=Ntp, angle=angle)\n                    assert N2 == N\n\n\n@pytest.mark.slow\ndef test_Phadkeb_numbers():\n    # One pain point of this code is that it takes 880 kb to store the results\n    # in memory as a list\n    ht.hx._load_coeffs_Phadkeb()\n    from math import ceil, floor, sqrt\n\n    from ht.hx import square_C1s, square_Ns, triangular_C1s, triangular_Ns\n    # Triangular Ns\n    # https://oeis.org/A003136\n    # Translated expression originally in Wolfram Mathematica\n    # nn = 14; Select[Union[Flatten[Table[x^2 + x*y + y^2, {x, 0, nn}, {y, 0, x}]]], # <= nn^2 &] (* T. D. Noe, Apr 18 2011 *)\n    nums = []\n    nn = 400 # Increase this to generate more numbers\n    for x in range(nn+1):\n        for y in range(x+1):\n            nums.append(x*x + x*y + y*y)\n\n    nums = sorted(set(nums))\n\n    nn_square = nn*nn\n    nums = [i for i in nums if i < nn_square]\n\n    nums = nums[0:len(triangular_Ns)]\n    assert_close1d(nums, triangular_Ns)\n\n\n    # triangular C1s\n    # https://oeis.org/A038590 is the sequence, and it is the unique numbers in:\n    # https://oeis.org/A038589\n    # Translated from pari expression a(n)=1+6*sum(k=0, n\\3, (n\\(3*k+1))-(n\\(3*k+2)))\n    # Tested with the online interpreter http://pari.math.u-bordeaux.fr/gp.html\n    # This one is very slow, 300 seconds+\n    # Used to be 300 + seconds, now 50+ seconds\n\n    def a(n):\n        tot = 0\n        for k in range(ceil(n/3.)):\n            # numpy could do this\n            k3 = k*3.\n            tot += floor(n/(k3 + 1.)) - floor(n/(k3 + 2.))\n        return 1 + int(6*tot)\n\n    s = set()\n    len_triangular_C1s = len(triangular_C1s)\n    i = 0\n    while len(s) < len_triangular_C1s:\n        val = a(i)\n        s.update([val])\n        i += 1\n\n    ans2 = sorted(s)\n    assert np.all(ans2[0:len(triangular_C1s)] == triangular_C1s)\n\n    # square Ns\n    # https://oeis.org/A001481\n    # Quick and efficient\n    # Translated from Mathematica\n    # up to = 160; With[{max = Ceiling[Sqrt[upTo]]}, Select[Union[Total /@ (Tuples[Range[0, max], {2}]^2)], # <= upTo &]]  (* Harvey P. Dale, Apr 22 2011 *)\n    # 10 loops, best of 3: 17.3 ms per loop\n    # Confirmed with SymPy\n    up_to = 100000\n    max_range = ceil(up_to**0.5)\n    squares = [i*i for i in range(max_range+1)]\n    seq = [i+j for i in squares for j in squares]\n    seq = [i for i in set(seq) if i < up_to] # optional\n    seq.sort() # on PyPy, the  [i+j for i in squares for j in squares] look yields results in a different order\n    # so we need to sort the result\n    nums = seq[0:len(square_Ns)]\n    assert_close1d(nums, square_Ns)\n\n    # square C1s\n    # https://oeis.org/A057961 is the sequence, there is one mathematica expression\n    # but it needs SymPy or some hard work to be done\n    # It is also the uniqiue elements in https://oeis.org/A057655\n    # That has a convenient expression for pari, tested online and translated\n    # a(n)=1+4*sum(k=0, sqrtint(n), sqrtint(n-k^2) ); /* Benoit Cloitre, Oct 08 2012 */\n    # Currently 1.8 seconds\n    # No numerical issues up to 35000 (confirmed with SymPy to do the root, int)\n    sqrtint = lambda i: int(sqrt(i))\n    def a2(n):\n        # numpy would be good at this\n        rtf = sqrtint\n        tot = 0.0\n        for k in range(sqrtint(n) + 1):\n            tot += rtf(n - k*k)\n        return 1 + 4*tot\n\n    ans = {a2(i) for i in range(35000)}\n    ans = sorted(ans)\n    nums = ans[0:len(square_C1s)]\n    assert_close1d(nums, square_C1s)\n\n\n\ndef test_Ntubes_HEDH():\n    Ntubes_HEDH_c = [Ntubes_HEDH(DBundle=1.200-.008*2, Do=.028, pitch=.036, angle=i) for i in [30, 45, 60, 90]]\n    assert_close1d(Ntubes_HEDH_c, [928, 804, 928, 804])\n\n    with pytest.raises(Exception):\n        # unsuported angle\n        Ntubes_HEDH(DBundle=1.200-.008*2, Do=.028, pitch=.036, angle=20)\n\n    with pytest.raises(Exception):\n        # unsuported angle\n        DBundle_for_Ntubes_HEDH(N=100, Do=.028, pitch=.036, angle=20)\n\n    # Fuzzing test\n    Do = 0.028\n    for angle in [30, 45, 60, 90]:\n        for pitch_ratio in [1.01, 1.1, 1.175, 1.25, 1.5, 1.75, 2]:\n            pitch = Do*pitch_ratio\n            for i in range(100):\n                N = int(uniform(10, 10000))\n                DBundle = DBundle_for_Ntubes_HEDH(N=N, Do=Do, pitch=pitch, angle=angle)\n                # If we don't increase the bundle by a hair, int() will round the wrong way\n                N_recalculated = Ntubes_HEDH(DBundle=DBundle*(1+1E-12), Do=Do, pitch=pitch, angle=angle)\n                assert N == N_recalculated\n\ndef test_Ntubes_VDI():\n    VDI_t = [[Ntubes_VDI(DBundle=1.184, Ntp=i, Do=.028, pitch=.036, angle=j) for i in [1,2,4,6,8]] for j in [30, 45, 60, 90]]\n    VDI_values = [[983, 966, 929, 914, 903], [832, 818, 790, 778, 769], [983, 966, 929, 914, 903], [832, 818, 790, 778, 769]]\n    assert_close2d(VDI_t, VDI_values)\n    with pytest.raises(Exception):\n        Ntubes_VDI(DBundle=1.184, Ntp=5, Do=.028, pitch=.036, angle=30)\n    with pytest.raises(Exception):\n        Ntubes_VDI(DBundle=1.184, Ntp=2, Do=.028, pitch=.036, angle=40)\n\n    D_VDI =  [[D_for_Ntubes_VDI(N=970, Ntp=i, Do=0.00735, pitch=0.015, angle=j) for i in [1, 2, 4, 6, 8]] for j in [30, 60, 45, 90]]\n    D_VDI_values = [[0.489981989464919, 0.5003600119829544, 0.522287673753684, 0.5311570964003711, 0.5377131635291736], [0.489981989464919, 0.5003600119829544, 0.522287673753684, 0.5311570964003711, 0.5377131635291736], [0.5326653264480428, 0.5422270203444146, 0.5625250342473964, 0.5707695340997739, 0.5768755899087357], [0.5326653264480428, 0.5422270203444146, 0.5625250342473964, 0.5707695340997739, 0.5768755899087357]]\n    assert_close2d(D_VDI, D_VDI_values)\n\n    with pytest.raises(Exception):\n        D_for_Ntubes_VDI(N=970, Ntp=5., Do=0.00735, pitch=0.015, angle=30.)\n    with pytest.raises(Exception):\n        D_for_Ntubes_VDI(N=970, Ntp=2., Do=0.00735, pitch=0.015, angle=40.)\n\n\ndef test_Ntubes():\n    methods = [\"Phadkeb\", \"HEDH\", \"VDI\", \"Perry\"]\n    Ntubes_calc = [Ntubes(DBundle=1.2, Do=0.025, pitch=.025*1.25, Method=i) for i in methods]\n    assert Ntubes_calc == [1285, 1272, 1340, 1297]\n\n    assert_close(Ntubes(DBundle=1.2, Do=0.025, pitch=.025*1.25), 1285)\n\n    with pytest.raises(Exception):\n        Ntubes(DBundle=1.2, Do=0.025, pitch=.025*1.25, Method=\"failure\")\n\n    D = size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125)\n    assert type(D) is float\n    assert_close(D, 1.1985676402390355)\n    D = size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125, Method=\"HEDH\")\n    assert type(D) is float\n    assert_close(D, 1.205810838411941)\n    D = size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125, Method=\"VDI\")\n    assert type(D) is float\n    assert_close(D, 1.1749025890472795)\n\n    D = size_bundle_from_tubecount(N=13252, Do=.028, Ntp=2, angle=45, pitch=.028*1.25, Method=\"Perry\")\n    assert type(D) is float\n    assert_close(D, 3.598336054740235, rtol=5e-5)\n\n    with pytest.raises(Exception):\n        size_bundle_from_tubecount(N=1285, Do=0.025, pitch=0.03125, Method=\"BADMETHOD\")\n\n\ndef test_effectiveness_NTU():\n    # Counterflow\n    for i in range(20):\n        eff = uniform(0, 1)\n        Cr = uniform(0, 1)\n        units = NTU_from_effectiveness(effectiveness=eff, Cr=Cr, subtype=\"counterflow\")\n        eff_calc = effectiveness_from_NTU(NTU=units, Cr=Cr, subtype=\"counterflow\")\n        assert_close(eff, eff_calc)\n    # Case with Cr = 1\n    NTU = NTU_from_effectiveness(effectiveness=.9, Cr=1, subtype=\"counterflow\")\n    assert_close(NTU, 9)\n    e = effectiveness_from_NTU(NTU=9, Cr=1, subtype=\"counterflow\")\n    assert_close(e, 0.9)\n\n\n    # Parallel\n    for i in range(20):\n        Cr = uniform(0, 1)\n        eff = uniform(0, 1./(Cr + 1.)*(1-1E-7))\n        units = NTU_from_effectiveness(effectiveness=eff, Cr=Cr, subtype=\"parallel\")\n        eff_calc = effectiveness_from_NTU(NTU=units, Cr=Cr, subtype=\"parallel\")\n        assert_close(eff, eff_calc)\n\n    with pytest.raises(Exception):\n        Cr = 0.6\n        NTU_from_effectiveness(effectiveness=0.62500001, Cr=Cr, subtype=\"parallel\")\n\n\n    # Crossflow, Cmin mixed, Cmax unmixed\n\n    for i in range(20):\n        Cr = uniform(0, 1)\n        eff = uniform(0, (1 - exp(-1/Cr))*(1-1E-7))\n        N = NTU_from_effectiveness(eff, Cr=Cr, subtype=\"crossflow, mixed Cmin\")\n        eff_calc = effectiveness_from_NTU(N, Cr=Cr, subtype=\"crossflow, mixed Cmin\")\n        assert_close(eff, eff_calc)\n\n    with pytest.raises(Exception):\n        Cr = 0.7\n        NTU_from_effectiveness(0.760348963559, Cr=Cr, subtype=\"crossflow, mixed Cmin\")\n\n\n    # Crossflow, Cmax mixed, Cmin unmixed\n    for i in range(20):\n        Cr = uniform(0, 1)\n        eff = uniform(0, (exp(Cr) - 1)*exp(-Cr)/Cr-1E-5)\n        N = NTU_from_effectiveness(eff, Cr=Cr, subtype=\"crossflow, mixed Cmax\")\n        eff_calc = effectiveness_from_NTU(N, Cr=Cr, subtype=\"crossflow, mixed Cmax\")\n        assert_close(eff, eff_calc)\n\n    with pytest.raises(Exception):\n        Cr = 0.7\n        eff = 0.7201638517265581\n        NTU_from_effectiveness(eff, Cr=Cr, subtype=\"crossflow, mixed Cmax\")\n\n    # Crossflow, this one needed a closed-form solver\n    for i in range(100):\n        Cr = uniform(0, 1)\n        eff = uniform(0, 1)\n        N = NTU_from_effectiveness(eff, Cr=Cr, subtype=\"crossflow approximate\")\n        eff_calc = effectiveness_from_NTU(N, Cr=Cr, subtype=\"crossflow approximate\")\n        assert_close(eff, eff_calc, rtol=1E-6) # brenth differs in old Python versions, rtol is needed\n\n    # Shell and tube - this one doesn't have a nice effectiveness limit,\n    # and it depends on the number of shells\n\n    for i in range(20):\n        Cr = uniform(0, 1)\n        shells = randint(1, 10)\n        eff_max = (-((-Cr + sqrt(Cr**2 + 1) + 1)/(Cr + sqrt(Cr**2 + 1) - 1))**shells + 1)/(Cr - ((-Cr + sqrt(Cr**2 + 1) + 1)/(Cr + sqrt(Cr**2 + 1) - 1))**shells)\n        eff = uniform(0, eff_max-1E-5)\n        N = NTU_from_effectiveness(eff, Cr=Cr, n_shell_tube=shells, subtype=\"S&T\")\n        eff_calc = effectiveness_from_NTU(N, Cr=Cr, n_shell_tube=shells, subtype=\"S&T\")\n        assert_close(eff, eff_calc)\n\n    with pytest.raises(Exception):\n        NTU_from_effectiveness(.99, Cr=.7, n_shell_tube=5, subtype=\"S&T\")\n\n    # Easy tests\n    effectiveness = effectiveness_from_NTU(NTU=5, Cr=0.7, subtype=\"crossflow, mixed Cmin\")\n    assert_close(effectiveness, 0.7497843941508544)\n    NTU = NTU_from_effectiveness(effectiveness=effectiveness, Cr=0.7, subtype=\"crossflow, mixed Cmin\")\n    assert_close(NTU, 5)\n\n    eff = effectiveness_from_NTU(NTU=5, Cr=0.7, subtype=\"crossflow, mixed Cmax\")\n    assert_close(eff, 0.7158099831204696)\n    NTU = NTU_from_effectiveness(eff, Cr=0.7, subtype=\"crossflow, mixed Cmax\")\n    assert_close(5, NTU)\n\n    eff = effectiveness_from_NTU(NTU=5, Cr=0, subtype=\"boiler\")\n    assert_close(eff, 0.9932620530009145)\n    NTU = NTU_from_effectiveness(eff, Cr=0, subtype=\"boiler\")\n    assert_close(NTU, 5)\n\n    with pytest.raises(Exception):\n        effectiveness_from_NTU(NTU=5, Cr=1.01, subtype=\"crossflow, mixed Cmin\")\n\n    with pytest.raises(Exception):\n        NTU_from_effectiveness(effectiveness=.2, Cr=1.01, subtype=\"crossflow, mixed Cmin\")\n\n\n    # bad names\n    with pytest.raises(Exception):\n        NTU_from_effectiveness(.99, Cr=.7, subtype=\"FAIL\")\n    with pytest.raises(Exception):\n        effectiveness_from_NTU(NTU=5, Cr=.5, subtype=\"FAIL\")\n\n\n    # Crossflow analytical solution\n    eff = effectiveness_from_NTU(NTU=5, Cr=.7, subtype=\"crossflow\")\n    assert_close(eff, 0.8444821799748551)\n\n    def crossflow_unmixed_sum_infinite(NTU, Cr):\n        def Pn(NTU, n):\n            tot = sum([(n+1.-j)/factorial(j)*NTU**(n+j) for j in range(1, n+1)])\n            return tot/factorial(n + 1)\n        tot = sum([Cr**n*Pn(NTU, n) for n in range(1, 150)])\n        return 1 - exp(-NTU) - exp(-(1+Cr)*NTU)*tot\n\n    eff_old = crossflow_unmixed_sum_infinite(5, .7)\n    assert_close(eff, eff_old)\n\n    # Crossflow analytical, this one needed a closed-form solver\n    for i in range(20):\n        Cr = uniform(0, 1)\n        eff = uniform(0, .9)\n        # A good anser is not always obtainable at eff> 0.9 at very high NTU,\n        # because the integral term gets too close to 1 for floating point numbers\n        # to capture any more accuracy\n        # This is not likely to be a problem to users\n        N = NTU_from_effectiveness(eff, Cr=Cr, subtype=\"crossflow\")\n        eff_calc = effectiveness_from_NTU(N, Cr=Cr, subtype=\"crossflow\")\n        assert_close(eff, eff_calc, rtol=1E-6) # brenth differs in old Python versions, rtol is needed\n\n\n\ndef test_effectiveness_NTU_method():\n    ans_known = {\"Q\": 192850.0, \"Thi\": 130, \"Cmax\": 9672.0, \"Tho\": 110.06100082712986, \"Cmin\": 2755.0, \"NTU\": 1.1040839095588, \"Tco\": 85, \"Tci\": 15, \"Cr\": 0.2848428453267163, \"effectiveness\": 0.6086956521739131, \"UA\": 3041.751170834494}\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85, Tho=110.06100082712986)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85, Thi=130)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Thi=130, Tho=110.06100082712986, Tci=15)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Thi=130, Tho=110.06100082712986, Tco=85)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tco=85, Tho=110.06100082712986, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Thi=130, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tho=110.06100082712986, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tco=85, Thi=130, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85, Tho=110.06100082712986, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tco=85, Thi=130, Tho=110.06100082712986, UA=3041.751170834494)\n    [assert_close(ans_known[i], ans[i]) for i in ans_known.keys()]\n\n    with pytest.raises(Exception):\n        # Test raising an error with only on set of stream information\n        effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Thi=130, Tho=110.06100082712986, UA=3041.751170834494)\n\n    with pytest.raises(Exception):\n        # Inconsistent hot and cold temperatures and heat capacity ratios\n        effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Thi=130, Tho=110.06100082712986, Tco=85, Tci=5)\n\n    with pytest.raises(Exception):\n        # Calculate UA, but no code side temperature information given\n        effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Thi=130, Tho=110.06100082712986)\n\n    with pytest.raises(Exception):\n        # Calculate UA, but no hot side temperature information given\n        effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85)\n\n    with pytest.raises(Exception):\n        # Calculate UA, but only two temperatures given\n        effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Thi=130)\n\ndef test_F_LMTD_Fakheri():\n    \"\"\"Number of tube passes must be a multiple of 2N for correlation to work.\n    N can be 1.\n\n    Example from http://excelcalculations.blogspot.ca/2011/06/lmtd-correction-factor.html\n    spreadsheet file which Bowman et al (1940).\n    This matches for 3, 6, and 11 shell passes perfectly.\n\n    This also matches that from the sheet:\n    http://www.mhprofessional.com/getpage.php?c=0071624082_download.php&cat=113\n    \"\"\"\n    F_calc = F_LMTD_Fakheri(Tci=15, Tco=85, Thi=130, Tho=110, shells=1)\n    assert_close(F_calc, 0.9438358829645933)\n\n    # R = 1 check\n    F_calc = F_LMTD_Fakheri(Tci=15, Tco=35, Thi=130, Tho=110, shells=1)\n    assert_close(F_calc, 0.9925689447100824)\n\n    for i in range(1, 10):\n        ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, n_shell_tube=i, subtype=\"S&T\", Tci=15, Tco=85, Thi=130)\n        dTlm = LMTD(Thi=130, Tho=110.06100082712986,  Tci=15, Tco=85)\n        F_expect = ans[\"Q\"]/ans[\"UA\"]/dTlm\n\n        F_calc = F_LMTD_Fakheri(Tci=15, Tco=85, Thi=130, Tho=110.06100082712986, shells=i)\n        assert_close(F_expect, F_calc)\n        F_calc = F_LMTD_Fakheri(Thi=15, Tho=85, Tci=130, Tco=110.06100082712986, shells=i)\n        assert_close(F_expect, F_calc)\n\n\ndef test_temperature_effectiveness_basic():\n    # Except for the crossflow mixed 1&2 cases, taken from an example and checked that\n    # it matches the e-NTU method. The approximate formula for crossflow is somewhat\n    # different - it is believed the approximations are different.\n\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"counterflow\")\n    assert_close(P1, 0.173382601503)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"parallel\")\n    assert_close(P1, 0.163852912049)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"crossflow approximate\")\n    assert_close(P1, 0.149974594007)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"crossflow\")\n    assert_close(P1, 0.1698702121873175)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"crossflow, mixed 1\")\n    assert_close(P1, 0.168678230894)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"crossflow, mixed 2\")\n    assert_close(P1, 0.16953790774)\n    P1 = temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"crossflow, mixed 1&2\")\n    assert_close(P1, 0.168411216829)\n\n    with pytest.raises(Exception):\n        temperature_effectiveness_basic(R1=3.5107078039927404, NTU1=0.29786672449248663, subtype=\"FAIL\")\n\n    # Formulas are in [1]_, [3]_, and [2]_.\n\ndef test_temperature_effectiveness_TEMA_J():\n    # All three models are checked with Rosenhow and then Shaw\n    # Formulas presented in Thulukkanam are with respect to the other side of the\n    # exchanger\n    P1 = temperature_effectiveness_TEMA_J(R1=1/3., NTU1=1., Ntp=1)\n    assert_close(P1, 0.5699085193651295)\n    P1 = temperature_effectiveness_TEMA_J(R1=2., NTU1=1.,  Ntp=1) # R = 2 case\n    assert_close(P1, 0.3580830895954234)\n    P1 = temperature_effectiveness_TEMA_J(R1=1/3., NTU1=1., Ntp=2)\n    assert_close(P1, 0.5688878232315694)\n    P1 = temperature_effectiveness_TEMA_J(R1=1/3., NTU1=1., Ntp=4)\n    assert_close(P1, 0.5688711846568247)\n\n    with pytest.raises(Exception):\n        temperature_effectiveness_TEMA_J(R1=1/3., NTU1=1., Ntp=3)\n\n\n\n\n\ndef test_temperature_effectiveness_TEMA_H():\n    P1 = temperature_effectiveness_TEMA_H(R1=1/3., NTU1=1., Ntp=1)\n    assert_close(P1, 0.5730728284905833)\n    P1 = temperature_effectiveness_TEMA_H(R1=2., NTU1=1., Ntp=1) # R = 2 case\n    assert_close(P1, 0.3640257049950876)\n    P1 = temperature_effectiveness_TEMA_H(R1=1/3., NTU1=1., Ntp=2)\n    assert_close(P1, 0.5824437803128222)\n    P1 = temperature_effectiveness_TEMA_H(R1=4., NTU1=1., Ntp=2) # R = 4 case\n    assert_close(P1, 0.2366953352462191)\n\n    P1 = temperature_effectiveness_TEMA_H(R1=1/3., NTU1=1., Ntp=2, optimal=False)\n    assert_close(P1, 0.5560057072310012)\n    P1 = temperature_effectiveness_TEMA_H(R1=4, NTU1=1., Ntp=2, optimal=False)\n    assert_close(P1, 0.19223481412807347) # R2 = 0.25\n\n    # The 1 and 2 case by default are checked with Rosenhow and Shah\n    # for the two pass unoptimal case, the result is from Thulukkanam only.\n    # The 2-pass optimal arrangement from  Rosenhow and Shaw is the same\n    # as that of Thulukkanam however, and shown below.\n    m1 = .5\n    m2 = 1.2\n    Cp1 = 1800.\n    Cp2 = 2200.\n    UA = 500.\n    C1 = m1*Cp1\n    C2 = m2*Cp2\n    R1_orig = R1 = C1/C2\n    NTU1 = UA/C1\n    R2 = C2/C1\n    NTU2 = UA/C2\n\n    R1 = R2\n    NTU1 = NTU2\n\n    alpha = NTU1*(4*R1 + 1)/8.\n    beta = NTU1*(4*R1 - 1)/8.\n    D = (1 - exp(-alpha))/(4.*R1 + 1)\n\n    E = (1 - exp(-beta))/(4*R1 - 1)\n    H = (1 - exp(-2*beta))/(4.*R1 - 1)\n\n    G = (1-D)**2*(D**2 + E**2) + D**2*(1+E)**2\n    B = (1 + H)*(1 + E)**2\n    P1 = (1 - (1-D)**4/(B - 4.*R1*G))\n    P1 = P1/R1_orig\n    assert_close(P1, 0.40026600037802335)\n\n\n    with pytest.raises(Exception):\n        temperature_effectiveness_TEMA_H(R1=1/3., NTU1=1., Ntp=5)\n\n\ndef test_temperature_effectiveness_TEMA_G():\n        # Checked with Shah and Rosenhow, formula typed and then the other case is working\n    P1 = temperature_effectiveness_TEMA_G(R1=1/3., NTU1=1., Ntp=1)\n    assert_close(P1, 0.5730149350867675)\n    P1 = temperature_effectiveness_TEMA_G(R1=1/3., NTU1=1., Ntp=2) # TEST CASSE\n    assert_close(P1, 0.5824238778134628)\n\n    # Ntp = 1, R=1 case\n    P1_Ntp_R1 = 0.8024466201983814\n    P1 = temperature_effectiveness_TEMA_G(R1=1., NTU1=7., Ntp=1) # R = 1 case\n    assert_close(P1, P1_Ntp_R1)\n    P1_near = temperature_effectiveness_TEMA_G(R1=1-1E-9, NTU1=7, Ntp=1)\n    assert_close(P1_near, P1_Ntp_R1)\n\n    # Ntp = 2, optimal, R=2 case\n    P1_Ntp_R1 = 0.4838424889135673\n    P1 = temperature_effectiveness_TEMA_G(R1=2., NTU1=7., Ntp=2) # R = 2 case\n    assert_close(P1, P1_Ntp_R1)\n    P1_near = temperature_effectiveness_TEMA_G(R1=2-1E-9, NTU1=7., Ntp=2)\n    assert_close(P1_near, P1_Ntp_R1)\n\n\n    # Ntp = 2, not optimal case, R1=0.5 case\n    P1 = temperature_effectiveness_TEMA_G(R1=1/3., NTU1=1., Ntp=2, optimal=False)\n    assert_close(P1, 0.5559883028569507)\n\n    P1_Ntp_R1 = 0.3182960796403764\n    P1 = temperature_effectiveness_TEMA_G(R1=2, NTU1=1., Ntp=2, optimal=False)\n    assert_close(P1, P1_Ntp_R1)\n    P1_near = temperature_effectiveness_TEMA_G(R1=2-1E-9, NTU1=1., Ntp=2, optimal=False)\n    assert_close(P1_near, P1_Ntp_R1)\n\n    with pytest.raises(Exception):\n        temperature_effectiveness_TEMA_G(R1=2., NTU1=7., Ntp=5)\n\n    # The optimal 2 pass case from Thulukkanam is checked with the following case\n    # to be the same as those in Rosenhow and Shah\n    # Believed working great.\n    m1 = .5\n    m2 = 1.2\n    Cp1 = 1800.\n    Cp2 = 2200.\n    UA = 500.\n    C1 = m1*Cp1\n    C2 = m2*Cp2\n    R1_orig = R1 = C1/C2\n    NTU1 = UA/C1\n    R2 = C2/C1\n    NTU2 = UA/C2\n\n    P1_good = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=2)\n\n\n    # Good G 2 pass case, working\n    R1 = R2\n    NTU1 = NTU2\n\n    beta = exp(-NTU1*(2*R1 - 1)/2.)\n    alpha = exp(-NTU1*(2*R1 + 1)/4.)\n    B = (4*R1 - beta*(2*R1 + 1))/(2*R1 - 1.)\n    A = -1*(1-alpha)**2/(R1 + 0.5)\n    P1 = (B - alpha**2)/(R1*(A + 2 + B/R1))\n\n    P1 = P1/R1_orig\n    assert_close(P1, P1_good)\n\n\n\ndef test_temperature_effectiveness_TEMA_E():\n    # 1, 2 both cases are perfect\n    eff = temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=1)\n    assert_close(eff, 0.5870500654031314)\n    eff = temperature_effectiveness_TEMA_E(R1=1., NTU1=7., Ntp=1)\n    assert_close(eff, 0.875)\n\n    # Remaining E-shells, checked\n    eff = temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=2)\n    assert_close(eff, 0.5689613217664634)\n    eff = temperature_effectiveness_TEMA_E(R1=1., NTU1=7., Ntp=2) # R = 1 case\n    assert_close(eff, 0.5857620762776082)\n\n    eff = temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=2, optimal=False)\n    assert_close(eff, 0.5699085193651295) # unoptimal case\n    eff = temperature_effectiveness_TEMA_E(R1=2, NTU1=1., Ntp=2, optimal=False)\n    assert_close(eff, 0.3580830895954234)\n\n\n\n    eff = temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=3)\n    assert_close(eff, 0.5708624888990603)\n    eff = temperature_effectiveness_TEMA_E(R1=1., NTU1=7., Ntp=3) # R = 1 case\n    assert_close(eff, 0.6366132064792461)\n\n    eff = temperature_effectiveness_TEMA_E(R1=3., NTU1=1., Ntp=3, optimal=False)\n    assert_close(eff, 0.276815590660033)\n\n    eff = temperature_effectiveness_TEMA_E(R1=1/3., NTU1=1., Ntp=4)\n    assert_close(eff, 0.56888933865756)\n    eff = temperature_effectiveness_TEMA_E(R1=1., NTU1=7., Ntp=4) # R = 1 case, even though it's no longer used\n    assert_close(eff, 0.5571628802075902)\n\n\n    with pytest.raises(Exception):\n         temperature_effectiveness_TEMA_E(R1=1., NTU1=7., Ntp=7)\n\n    # Compare the expression for 4 tube passes in two of the sources with that\n    # in the third.\n    R1 = 1/3.\n    NTU1 = 1\n    D = (4 + R1**2)**0.5\n    B = tanh(R1*NTU1/4.)\n    A = 1/tanh(D*NTU1/4.)\n    P1 = 4*(2*(1 + R1) + D*A + R1*B)**-1\n    assert_close(P1, 0.56888933865756)\n\n\ndef test_temperature_effectiveness_air_cooler():\n    # 1 pass-N rows case\n    R1 = 0.9090909090909091\n    NTU1 = 14.958251192851375\n\n    expected_P1s = [0.6568205178185993, 0.7589599992302802, 0.8064227529035781, 0.8330202134563712, 0.8491213831157698, 0.8594126317585193, 0.8662974164766494, 0.871087594489211, 0.8745345926002213, 0.8770877118478316, 0.8790262425246239, 0.8805299599498708, 0.8817182454510963, 0.8826726050451953, 0.8834500769975893, 0.8840914654885264, 0.8846265414931143, 0.88507741320138, 0.8854607616314836, 0.8857893552314147, 0.886073095973165, 0.8863197546874396, 0.8865354963468465, 0.8867252608860744, 0.8868930430686396]\n    P1s_calc = [temperature_effectiveness_air_cooler(R1=R1, NTU1=NTU1, rows=N, passes=1) for N in  range(1, 26)]\n    assert_close1d(expected_P1s, P1s_calc)\n\n    # Compare the results of 1-N against the function without the annoying optimizations;\n    # may be helpful for debugging\n    def calc_N_1_orig(NTU1, R1, N):\n        NTU, R = NTU1, R1\n        K = 1 - exp(-NTU/N)\n        top = N*exp(N*K*R)\n\n        tot = 0\n        for i in range(1, N):\n            for j in range(i+1):\n                prod = factorial(i)/factorial(i-j)/factorial(j)\n                tot1 = prod*K**j*exp(-(i-j)*NTU/N)\n                tot2 = 0\n                for k in range(j+1):\n                    tot2 += (N*K*R)**k/factorial(k)\n\n                tot += tot1*tot2\n\n        P = 1/R*(1 - (top/(1+tot))**-1)\n        return P\n    P1s_calc = [calc_N_1_orig(R1=R1, NTU1=NTU1, N=N) for N in  range(1, 26)]\n    assert_close1d(expected_P1s, P1s_calc)\n\n\n    # N rows / N passes (N from 2 to 5) cases\n    R1, NTU1 = 1.1, .5\n    expected_P1s = [0.3254086785640332, 0.3267486216405819, 0.3272282999575143, 0.3274325680785421]\n    P1s_calc = [temperature_effectiveness_air_cooler(R1, NTU1, rows=N, passes=N) for N in  range(2, 6)]\n    assert_close1d(expected_P1s, P1s_calc)\n\n    # 4 row / 2 pass special case\n    P1_calc = temperature_effectiveness_air_cooler(R1, NTU1, rows=4, passes=2)\n    assert_close(P1_calc, 0.32552127419957044)\n\n    # Tentative checking of the above has been done with hete.c for isolated cases\n\ndef test_temperature_effectiveness_air_cooler_coerce():\n    # Simple test a call that the number of row and passes can be domain reduced\n    # without causing a recursion depth error\n    # Do not test the results for any specific answer, as they will ideally one day\n    # be replaced with the exactly correct one\n    [temperature_effectiveness_air_cooler(.5, 2, rows=j, passes=i) for i in range(1, 10) for j in range(1, 10)]\n\n\n@pytest.mark.mpmath\ndef test_P_NTU_method():\n    # Counterflow case\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"counterflow\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1i=130, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    # Parallel flow case\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"parallel\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1i=130, T2i=15, subtype=\"parallel\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    # Mixed Cmax/ 1\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1i=130, T2i=15, subtype=\"crossflow, mixed 1\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    # Mixed Cmin/2\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmin\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1i=130, T2i=15, subtype=\"crossflow, mixed 2\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n\n    # Counterflow case but with all five different temperature input cases (both inlets known already done)\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"counterflow\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1o=110.06100082712986, T2o=85, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1i=130, T2o=85, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1o=110.06100082712986, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T2o=85, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=ans[\"UA\"], T1o=110.06100082712986, T1i=130, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n\n    # Only 1 temperature input\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, subtype=\"counterflow\")\n\n    # Bad HX type input\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"BADTYPE\")\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"E\", Ntp=10)\n    assert_close(ans[\"Q\"], 32212.185563086336,)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"G\", Ntp=2)\n    assert_close(ans[\"Q\"], 32224.88788570008)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"H\", Ntp=2)\n    assert_close(ans[\"Q\"], 32224.888572366734)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"J\", Ntp=2)\n    assert_close(ans[\"Q\"], 32212.185699719837)\n\n    # Plate tests\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"3/1\")\n    assert_close(ans[\"Q\"], 32214.179745602625)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"3/1\", optimal=False)\n    assert_close(ans[\"Q\"], 32210.4190840378)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"2/2\")\n    assert_close(ans[\"Q\"], 32229.120739501937)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"2/2\", optimal=False)\n    assert_close(ans[\"Q\"], 32203.721238671216)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"2/2c\", optimal=False)\n    assert_close(ans[\"Q\"], 32203.721238671216)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., UA=300, T1i=130, T2i=15, subtype=\"2/2p\", optimal=False)\n    assert_close(ans[\"Q\"], 32195.273806845064)\n\n\ndef test_P_NTU_method_backwards():\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"counterflow\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T2i=15, T2o=85, T1o=110.06100082712986, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n#    # Parallel flow case\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"parallel\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1i=130, T2i=15, T1o=110.06100082712986, subtype=\"parallel\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n#    # Mixed Cmax/ 1\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmax\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, T2i=15, subtype=\"crossflow, mixed 1\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n#    # Mixed Cmin/2\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"crossflow, mixed Cmin\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, T2i=15, subtype=\"crossflow, mixed 2\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n\n#    # Counterflow case but with all five different temperature input cases (both inlets known already done)\n    ans = effectiveness_NTU_method(mh=5.2, mc=1.45, Cph=1860., Cpc=1900, subtype=\"counterflow\", Tci=15, Tco=85, Tho=110.06100082712986)\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1i=130, T1o=110.06100082712986, T2o=85, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, T2o=85, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1i=130, T1o=110.06100082712986, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T2o=85, T2i=15, T1o=110.06100082712986, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n\n\n    ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T2o=85, T1i=130, T2i=15, subtype=\"counterflow\")\n    assert_close(ans2[\"Q\"], ans[\"Q\"])\n\n    # TEMA types\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1i=130, T1o=126.66954243557834, T2i=15, subtype=\"E\", Ntp=10)\n    assert_close(ans[\"Q\"], 32212.185563086336,)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.66822912678866, T1i=130, T2i=15, subtype=\"G\", Ntp=2)\n    assert_close(ans[\"Q\"], 32224.88788570008)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.66822905579335, T1i=130, T2i=15, subtype=\"H\", Ntp=2)\n    assert_close(ans[\"Q\"], 32224.888572366734)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.66954242145162, T1i=130, T2i=15, subtype=\"J\", Ntp=2)\n    assert_close(ans[\"Q\"], 32212.185699719837)\n\n    # Plate tests\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.6693362545903, T1i=130, T2i=15, subtype=\"3/1\")\n    assert_close(ans[\"Q\"], 32214.179745602625)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.66972507402421, T1i=130, T2i=15, subtype=\"3/1\", optimal=False)\n    assert_close(ans[\"Q\"], 32210.4190840378)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.66779148681742, T1i=130, T2i=15, subtype=\"2/2\")\n    assert_close(ans[\"Q\"], 32229.120739501937)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.67041757251124, T1i=130, T2i=15, subtype=\"2/2\", optimal=False)\n    assert_close(ans[\"Q\"], 32203.721238671216)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.67041757251124, T1i=130, T2i=15, subtype=\"2/2c\", optimal=False)\n    assert_close(ans[\"Q\"], 32203.721238671216)\n\n    ans = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=126.67129096289857, T1i=130, T2i=15, subtype=\"2/2p\", optimal=False)\n    assert_close(ans[\"Q\"], 32195.273806845064)\n\n\n\n\n\n\n\n    # Q for both streams don't match case\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T2o=85, T1i=170, T2i=15, subtype=\"counterflow\")\n    # No T speced on side 2\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, subtype=\"counterflow\")\n    # No T specified on side 1\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T2o=85, T2i=15, subtype=\"counterflow\")\n    # No T information at all\n    with pytest.raises(Exception):\n        ans2 = P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., subtype=\"counterflow\")\n    # subtype not recognized\n    with pytest.raises(Exception):\n        P_NTU_method(m1=5.2, m2=1.45, Cp1=1860., Cp2=1900., T1o=110.06100082712986, T1i=130, T2i=15, subtype=\"NOTAREALTYPEOFHEATEXCHANGER\")\n\n\n\n\n\n\n\ndef test_Pp():\n    from ht.hx import P_NTU_Pc, P_NTU_Pp\n    # randomly chosen test value\n    ans = P_NTU_Pp(5, .4)\n    assert_close(ans, 0.713634370024604)\n\n    # Test the limit works with a small difference\n    assert_close(P_NTU_Pp(2, -1), P_NTU_Pp(2, -1+1E-9))\n\n    # randomly chosen test value\n    assert_close(P_NTU_Pc(5, .7), 0.9206703686051108)\n    # Test the limit works with a small difference\n    assert_close(P_NTU_Pc(5, 1), P_NTU_Pc(5, 1-1E-8))\n\n\ndef test_temperature_effectiveness_plate():\n    R1 = 0.5\n    NTU1 = 1.5\n\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=1, counterflow=True)\n    assert_close(P1, 0.6907854082479168)\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=1, counterflow=False)\n    assert_close(P1, 0.5964005169587571)\n\n    # 1 pass/2 pass\n    for b1 in [True, False]:\n        for b2 in [True, False]:\n            P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=2, counterflow=b1, passes_counterflow=b2)\n            assert_close(P1, 0.6439306988115887)\n            # We can check we did the conversion right as follows:\n            NTU2 = NTU1*R1\n            R2 = 1./R1 # switch 2\n            P2 = P1*R1\n            P2_reversed = temperature_effectiveness_plate(R2, NTU2, Np1=2, Np2=1)\n            assert_close(P2, P2_reversed)\n\n            # in reverse\n            P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=1, counterflow=b1, passes_counterflow=b2)\n            assert_close(P1, 0.6505342399575915)\n\n\n\n\n    # 1 pass/3 pass, counterflow\n    for b1 in [True, False]:\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=3, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.6491132138517642)\n        # In reverse\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=3, Np2=1, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.6565261377239298)\n\n    # 1 pass/3 pass, parallel\n    for b1 in [True, False]:\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=3, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6385443460862099)\n        # in reverse\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=3, Np2=1, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6459675147406085)\n\n    # 1 pass/4 pass\n    for b1 in [True, False]:\n        for b2 in [True, False]:\n            P1 = temperature_effectiveness_plate(R1, NTU1, Np1=1, Np2=4, counterflow=b1, passes_counterflow=b2)\n            assert_close(P1, 0.6438068496552443)\n            # In reverse\n            P1 = temperature_effectiveness_plate(R1, NTU1, Np1=4, Np2=1, counterflow=b1, passes_counterflow=b2)\n            assert_close(P1, 0.6515539888566283)\n\n\n\n    # Four different results for 4 passes\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n    assert_close(P1, 0.5964005169587571)\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n    assert_close(P1, 0.6123845839665905)\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=2, counterflow=True, passes_counterflow=False)\n    assert_close(P1, 0.6636659009073801)\n    P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=2, counterflow=True, passes_counterflow=True)\n    assert_close(P1, 0.6907854082479168)\n\n    # 2-3 counterflow\n    for b1 in [True, False]:\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=3, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.67478876724034)\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=3, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6102922060616937)\n        # In reverse\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=3, Np2=2, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.675522913050678)\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=3, Np2=2, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6105764872072659)\n\n\n    # 2-4 counterflow\n    for b1 in [True, False]:\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=4, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.6777107269336475)\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=2, Np2=4, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6048585344522575)\n        # In reverse\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=4, Np2=2, counterflow=True, passes_counterflow=b1)\n        assert_close(P1, 0.6786601861219819)\n        P1 = temperature_effectiveness_plate(R1, NTU1, Np1=4, Np2=2, counterflow=False, passes_counterflow=b1)\n        assert_close(P1, 0.6054166111196166)\n\n\n    with pytest.raises(Exception):\n        temperature_effectiveness_plate(R1=1/3., NTU1=1., Np1=3, Np2=3)\n\n\n@pytest.mark.mpmath\ndef test_NTU_from_P_basic():\n    # Analytical result for counterflow\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E2), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E2), 10000).tolist()\n\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            # Not all of the guesses work forward; some overflow, some divide by 0\n            P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"counterflow\")\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"counterflow\")\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        # Again, multiple values of NTU1 can produce the same P1\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"counterflow\")\n        assert_close(P1, P1_calc)\n\n    # Analytical result for parallel flow\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"parallel\")\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"parallel\")\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"parallel\")\n        assert_close(P1, P1_calc)\n\n    # Analytical result for 'crossflow, mixed 1'\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            # Not all of the guesses work forward; some overflow, some divide by 0\n            P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow, mixed 1\")\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"crossflow, mixed 1\")\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        # Again, multiple values of NTU1 can produce the same P1\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"crossflow, mixed 1\")\n        assert_close(P1, P1_calc)\n\n    # Analytical result for 'crossflow, mixed 2'\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            # Not all of the guesses work forward; some overflow, some divide by 0\n            P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow, mixed 2\")\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"crossflow, mixed 2\")\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        # Again, multiple values of NTU1 can produce the same P1\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"crossflow, mixed 2\")\n        assert_close(P1, P1_calc)\n\n\n    # Test 'crossflow, mixed 1&2':\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E2), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E2), 10000).tolist()\n\n    seed(0)\n    tot = 0\n    for i in range(100):\n        R1 = choice(R1s)\n        NTU1 = choice(NTU1s)\n\n        P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow, mixed 1&2\")\n        try:\n            # Very rarely, the pade approximation will get a result too close to the infeasibility region and\n            # the solver cannot start as it is already outside the region\n            NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"crossflow, mixed 1&2\")\n        except:\n            continue\n        # May not get the original NTU1, but the found NTU1 needs to produce the same P1.\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"crossflow, mixed 1&2\")\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot == 100\n\n\n    # crossflow approximate - easy as 1 is always a possibility for any R\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow approximate\")\n        NTU1_calc = NTU_from_P_basic(P1, R1, subtype=\"crossflow approximate\")\n        # We have to compare the re calculated P1 values, because for many values of NTU1,\n        # at the initial far guess of 10000 P1 = 1 and at the random NTU1 P1 is also 1\n        P1_calc = temperature_effectiveness_basic(R1=R1, NTU1=NTU1_calc, subtype=\"crossflow approximate\")\n        # In python 2.6 and 3.3 the solver doesn't converge as well, so we need\n        # to add a little tolerance\n        assert_close(P1, P1_calc, rtol=5E-6)\n\n    # Crossflow approximate test case\n    R1 = .1\n    NTU1 = 2\n    P1_calc_orig = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow approximate\")\n    P1_expect = 0.8408180737140558\n    assert_close(P1_calc_orig, P1_expect)\n    NTU1_backwards = NTU_from_P_basic(P1=P1_expect, R1=R1, subtype=\"crossflow approximate\")\n    assert_close(NTU1, NTU1_backwards)\n\n\n    # Test cross flow - failes VERY OFTEN, should rely on crossflow approximate\n    NTU1 = 10\n    R1 = 0.5\n    P1 = temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype=\"crossflow\")\n    NTU1_calc = NTU_from_P_basic(P1, R1=R1, subtype=\"crossflow\")\n    assert_close(NTU1, NTU1_calc)\n\n    # bad type of exchanger\n    with pytest.raises(Exception):\n        NTU_from_P_basic(P1=.975, R1=.1, subtype=\"BADTYPE\")\n\n\n@pytest.mark.mpmath\ndef test_NTU_from_P_E():\n    # not yet documented\n\n    # 1 tube pass AKA counterflow\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E2), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E2), 10000).tolist()\n\n    # Exact same asa as the counterflow basic case\n    tot = 0\n    seed(0)\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            # Not all of the guesses work forward; some overflow, some divide by 0\n            P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=1)\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_E(P1, R1, Ntp=1)\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        # Again, multiple values of NTU1 can produce the same P1\n        P1_calc = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1_calc, Ntp=1)\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 85\n\n    # 2 tube passes (optimal arrangement) (analytical)\n    R1 = 1.1\n    NTU1 = 10\n    P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=2, optimal=True)\n    P1_expect = 0.5576299522073297\n    assert_close(P1, P1_expect)\n    NTU1_calc = NTU_from_P_E(P1, R1, Ntp=2, optimal=True)\n    assert_close(NTU1_calc, NTU1)\n\n    # 2 tube pass (unoptimal)\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            # Not all of the guesses work forward; some overflow, some divide by 0\n            P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=2, optimal=False)\n            # Backwards, it's the same divide by zero or log(negative number)\n            NTU1_calc = NTU_from_P_E(P1, R1, Ntp=2, optimal=False)\n        except (ValueError, OverflowError, ZeroDivisionError):\n            continue\n        # Again, multiple values of NTU1 can produce the same P1\n        try:\n            P1_calc = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1_calc, Ntp=2, optimal=False)\n        except (ZeroDivisionError):\n            continue\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 90\n\n    # At the default mpmath precision, the following will predict a value larger\n    # than one\n    bad_P1 = temperature_effectiveness_TEMA_E(R1=1E-8 , NTU1=19.60414246043446, Ntp=2, optimal=False)\n    assert_close(bad_P1, 1.0000000050247593)\n\n    # 4 pass\n    for Ntp in [4, 6, 8, 10, 12]:\n        tot = 0\n        for i in range(100):\n            R1 = float(choice(R1s))\n            NTU1 = float(choice(NTU1s))\n            try:\n                P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=Ntp)\n                NTU1_calc = NTU_from_P_E(P1, R1, Ntp=Ntp)\n            except ValueError:\n                # The case where with mpmath being used, the result is too high for\n                # the bounded solver to be able to solve it\n                continue\n            P1_calc = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1_calc, Ntp=Ntp)\n            assert_close(P1, P1_calc)\n            tot +=1\n        assert tot >= 70\n\n    # 3 pass optimal and not optimal\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E1), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E1), 10000).tolist()\n\n    seed(0)\n    for optimal in [True, False]:\n        tot = 0\n        for i in range(100):\n            R1 = float(choice(R1s))\n            NTU1 = float(choice(NTU1s))\n            try:\n                P1 = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1, Ntp=3, optimal=optimal)\n                NTU1_calc = NTU_from_P_E(P1, R1, Ntp=3, optimal=optimal)\n            except (ValueError):\n                # The case where with mpmath being used, the result is too high for\n                # the bounded solver to be able to solve it\n                continue\n            # Again, multiple values of NTU1 can produce the same P1\n            P1_calc = temperature_effectiveness_TEMA_E(R1=R1, NTU1=NTU1_calc, Ntp=3, optimal=optimal)\n            assert_close(P1, P1_calc)\n            tot +=1\n        assert tot >= 97\n\n    with pytest.raises(Exception):\n        NTU_from_P_E(P1=1, R1=1, Ntp=17)\n\n\n@pytest.mark.mpmath\ndef test_NTU_from_P_H():\n    # Within these limits everything is fund\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E1), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(10), 10000).tolist()\n\n    seed(0)\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1, Ntp=1)\n        NTU1_calc = NTU_from_P_H(P1, R1, Ntp=1)\n        P1_calc = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1_calc, Ntp=1)\n        assert_close(P1, P1_calc)\n\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1, Ntp=2)\n        NTU1_calc = NTU_from_P_H(P1, R1, Ntp=2)\n        P1_calc = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1_calc, Ntp=2)\n        assert_close(P1, P1_calc)\n\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1, Ntp=2, optimal=False)\n        NTU1_calc = NTU_from_P_H(P1, R1, Ntp=2, optimal=False)\n        P1_calc = temperature_effectiveness_TEMA_H(R1=R1, NTU1=NTU1_calc, Ntp=2, optimal=False)\n        assert_close(P1, P1_calc, rtol=1E-6)\n\n    with pytest.raises(Exception):\n        NTU_from_P_H(P1=0.573, R1=1/3., Ntp=101)\n\n\n\n@pytest.mark.mpmath\ndef test_NTU_from_P_G():\n    # 1 tube pass, random point\n    R1 = 1.1\n    NTU1 = 2\n    P1_calc_orig = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=1)\n    P1_expect = 0.5868787117241955\n    assert_close(P1_calc_orig, P1_expect)\n    NTU1_backwards = NTU_from_P_G(P1=P1_expect, R1=R1, Ntp=1)\n    assert_close(NTU1, NTU1_backwards)\n\n\n    # 2 tube pass, randompoint\n    R1 = 1.1\n    NTU1 = 2\n    P1_calc_orig = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=2)\n    P1_calc_orig\n    P1_expect = 0.6110347802764724\n    assert_close(P1_calc_orig, P1_expect)\n    NTU1_backwards = NTU_from_P_G(P1=P1_expect, R1=R1, Ntp=2)\n    assert_close(NTU1, NTU1_backwards)\n\n\n    # 2 tube pass, not optimal\n    R1 = .1\n    NTU1 = 2\n    P1_calc_orig = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=2, optimal=False)\n    P1_calc_orig\n    P1_expect = 0.8121969945075509\n    assert_close(P1_calc_orig, P1_expect)\n    NTU1_backwards = NTU_from_P_G(P1=P1_expect, R1=R1, Ntp=2, optimal=False)\n    assert_close(NTU1, NTU1_backwards)\n\n\n    # Run the gamut testing all the solvers\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E2), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E2), 10000).tolist()\n    seed(0)\n    tot = 0\n    for Ntp, optimal in zip([1, 2, 2], [True, True, False]):\n        for i in range(100):\n            R1 = float(choice(R1s))\n            NTU1 = float(choice(NTU1s))\n            try:\n                P1 = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1, Ntp=Ntp, optimal=optimal)\n                NTU1_calc = NTU_from_P_G(P1, R1, Ntp=Ntp, optimal=optimal)\n                P1_calc = temperature_effectiveness_TEMA_G(R1=R1, NTU1=NTU1_calc, Ntp=Ntp, optimal=optimal)\n            except (ValueError, OverflowError, ZeroDivisionError, RuntimeError) as e:\n                continue\n            if isnan(P1) or isnan(P1_calc):\n                continue\n            assert_close(P1, P1_calc)\n            tot +=1\n    assert tot > 270\n\n    with pytest.raises(Exception):\n        NTU_from_P_G(P1=.573, R1=1/3., Ntp=10)\n\n\n@pytest.mark.mpmath\ndef test_NTU_from_P_J():\n    # Run the gamut testing all the solvers\n    R1s = np.logspace(np.log10(2E-5), np.log10(1E2), 10000).tolist()\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(1E2), 10000).tolist()\n    seed(0)\n    tot = 0\n    for Ntp in [1, 2, 4]:\n        for i in range(100):\n            R1 = float(choice(R1s))\n            NTU1 = float(choice(NTU1s))\n            try:\n                P1 = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1, Ntp=Ntp)\n                NTU1_calc = NTU_from_P_J(P1, R1, Ntp=Ntp)\n                P1_calc = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1_calc, Ntp=Ntp)\n            except (ValueError, OverflowError, ZeroDivisionError, RuntimeError) as e:\n                continue\n            assert_close(P1, P1_calc)\n            tot +=1\n    assert tot > 270\n    # Actual individual understandable working test cases\n\n    # 1 tube pass\n    R1 = 1.1\n    NTU1 = 3\n    P1_calc_orig = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1, Ntp=1)\n    P1_expect = 0.5996529947927913\n    assert_close(P1_calc_orig, P1_expect)\n    NTU1_backwards = NTU_from_P_J(P1=P1_expect, R1=R1, Ntp=1)\n    assert_close(NTU1, NTU1_backwards)\n\n\n    # 2 tube passes\n    R1 = 1.1\n    NTU1 = 2.7363888898379249\n    P1_calc_orig = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1, Ntp=2)\n    P1_expect = 0.53635261090479802\n    assert_close(P1_calc_orig, P1_expect)\n    # The exact P1 is slightly higher than that calculated as the upper limit\n    # of the pade approximation, so we multiply it by a small fraction\n    NTU1_backwards = NTU_from_P_J(P1=P1_expect*(1-2E-9), R1=R1, Ntp=2)\n    assert_close(NTU1, NTU1_backwards, rtol=1E-3)\n    # Unfortunately the derivative is so large we can't compare it exactly\n\n\n    # 4 tube passes\n    R1 = 1.1\n    NTU1 = 2.8702676768833268\n    P1_calc_orig = temperature_effectiveness_TEMA_J(R1=R1, NTU1=NTU1, Ntp=4)\n    P1_expect = 0.53812561986477236\n    assert_close(P1_calc_orig, P1_expect)\n    # The exact P1 is slightly higher than that calculated as the upper limit\n    # of the pade approximation, so we multiply it by a small fraction\n    NTU1_backwards = NTU_from_P_J(P1=P1_expect*(1-1E-15), R1=R1, Ntp=4)\n    assert_close(NTU1, NTU1_backwards)\n    # The derivative is very large but the pade approximation is really good, ant it works\n\n\n    with pytest.raises(Exception):\n        # unsupported number of tube passes case\n        NTU_from_P_J(P1=.57, R1=1/3., Ntp=10)\n\n\ndef test_NTU_from_P_plate():\n    # 1 pass-1 pass counterflow\n    NTU1 = 3.5\n    R1 = 0.25\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=1)\n    assert_close(P1_calc, 0.944668125335067)\n\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=1, Np2=1)\n    assert_close(NTU1, NTU1_calc)\n\n    with pytest.raises(Exception):\n        NTU_from_P_plate(P1=.10001, R1=10, Np1=1, Np2=1, counterflow=True)\n\n    # 1 pass-1 pass parallelflow\n    NTU1 = 3.5\n    R1 = 0.25\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=1, counterflow=False)\n    assert_close(P1_calc, 0.7899294862060529)\n\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=1, Np2=1, counterflow=False)\n    assert_close(NTU1, NTU1_calc)\n\n    with pytest.raises(Exception):\n        NTU_from_P_plate(P1=.091, R1=10, Np1=1, Np2=1, counterflow=False)\n\n    # 1-2 True True\n    R1s = np.logspace(np.log10(2E-5), np.log10(10), 10000).tolist() # too high R1 causes overflows\n    NTU1s = np.logspace(np.log10(1E-4), np.log10(99), 10000).tolist()\n\n    tot = 0\n    seed(0)\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=2)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=1, Np2=2)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=1, Np2=2)\n        except (OverflowError, ValueError):\n            continue\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot > 97\n\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=3)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=1, Np2=3)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=1, Np2=3)\n        except (OverflowError, ValueError):\n            continue\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 99\n\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=3, counterflow=False)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=1, Np2=3, counterflow=False)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=1, Np2=3, counterflow=False)\n        except (OverflowError, ValueError):\n            continue\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 99\n\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=1, Np2=4)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=1, Np2=4)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=1, Np2=4)\n        except (OverflowError, ValueError):\n            continue\n\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 99\n\n    # 2-2 pass cases\n\n    # counterflow and not passes_counterflow\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=True, passes_counterflow=False)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=2, counterflow=True, passes_counterflow=False)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=2, counterflow=True, passes_counterflow=False)\n        except (OverflowError, ValueError):\n            continue\n\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot >= 99\n\n    # not counterflow and not passes_counterflow\n    # random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n    assert_close(P1_calc, 0.5174719601105934)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n    assert_close(NTU1, NTU1_calc)\n    # methodical test\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=2, counterflow=False, passes_counterflow=False)\n        except (ZeroDivisionError, ValueError):\n            continue\n        assert_close(P1, P1_calc)\n        tot +=1\n    assert tot > 85\n\n    # not counterflow and passes_counterflow\n    # random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n    assert_close(P1_calc, 0.529647502598342)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n    assert_close(NTU1, NTU1_calc)\n    # methodical\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n        NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n        P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=2, counterflow=False, passes_counterflow=True)\n        assert_close(P1, P1_calc)\n\n\n    # 2-2 counterflow and passes_counterflow\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=2, counterflow=True, passes_counterflow=True)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=2, counterflow=True, passes_counterflow=True)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=2, counterflow=True, passes_counterflow=True)\n        except (ValueError, ZeroDivisionError):\n            continue\n        tot +=1\n        assert_close(P1, P1_calc)\n    assert tot > 90\n\n\n    # 2-3 counterflow - random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=3, counterflow=True)\n    assert_close(P1_calc, 0.5696402802155714)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=3, counterflow=True)\n    assert_close(NTU1, NTU1_calc)\n    # 2-3 counterflow - methodical\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=3, counterflow=True)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=3, counterflow=True)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=3, counterflow=True)\n        except (ValueError, ZeroDivisionError):\n            continue\n        tot +=1\n        assert_close(P1, P1_calc, rtol=5E-4)\n    assert tot > 85\n\n    # 2-3 parallelflow - random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=3, counterflow=False)\n    assert_close(P1_calc, 0.5272339114328507)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=3, counterflow=False)\n    assert_close(NTU1, NTU1_calc)\n    # 2-3 parallelflow - methodical (all work for given range)\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=3, counterflow=False)\n        NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=3, counterflow=False)\n        P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=3, counterflow=False)\n        assert_close(P1, P1_calc)\n\n\n    # 2-4 counterflow - random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=4, counterflow=True)\n    assert_close(P1_calc, 0.5717083161054717)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=4, counterflow=True)\n    assert_close(NTU1, NTU1_calc)\n    # 2-4 counterflow - methodical\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=4, counterflow=True)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=4, counterflow=True)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=4, counterflow=True)\n        except (ValueError, ZeroDivisionError):\n            continue\n        tot +=1\n        assert_close(P1, P1_calc)\n    assert tot > 95\n\n    # 2-4 parallelflow - random example\n    NTU1 = 1.1\n    R1 = .6\n    P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=4, counterflow=False)\n    assert_close(P1_calc, 0.5238412695944656)\n    NTU1_calc = NTU_from_P_plate(P1=P1_calc, R1=R1, Np1=2, Np2=4, counterflow=False)\n    assert_close(NTU1, NTU1_calc)\n    # 2-4 counterflow - methodical\n    tot = 0\n    for i in range(100):\n        R1 = float(choice(R1s))\n        NTU1 = float(choice(NTU1s))\n        try:\n            P1 = temperature_effectiveness_plate(R1=R1, NTU1=NTU1, Np1=2, Np2=4, counterflow=False)\n            NTU1_calc = NTU_from_P_plate(P1, R1, Np1=2, Np2=4, counterflow=False)\n            P1_calc = temperature_effectiveness_plate(R1=R1, NTU1=NTU1_calc, Np1=2, Np2=4, counterflow=False)\n        except (ValueError, ZeroDivisionError):\n            continue\n        tot +=1\n        assert_close(P1, P1_calc)\n    assert tot > 95\n\n\n    # Backwards, only one example in the tests\n    # No real point in being exhaustive\n    NTU1 = NTU_from_P_plate(P1=0.5743514352720835, R1=1/3., Np1=3, Np2=1)\n    assert_close(NTU1, 1)\n\n    # Bad number of plates\n    with pytest.raises(Exception):\n        NTU_from_P_plate(P1=0.5743, R1=1/3., Np1=3, Np2=13415151213)\n\ndef test_DBundle_min():\n    assert_close(DBundle_min(0.0254), 1)\n    assert_close(DBundle_min(0.005), .1)\n    assert_close(DBundle_min(0.014), .3)\n    assert_close(DBundle_min(0.015), .5)\n    assert_close(DBundle_min(.1), 1.5)\n\ndef test_shell_clearance():\n    assert_close(shell_clearance(DBundle=1.245), 0.0064)\n    assert_close(shell_clearance(DBundle=4), 0.011)\n    assert_close(shell_clearance(DBundle=.2), .0032)\n    assert_close(shell_clearance(DBundle=1.778), 0.0095)\n\n    assert_close(shell_clearance(DShell=1.245), 0.0064)\n    assert_close(shell_clearance(DShell=4), 0.011)\n    assert_close(shell_clearance(DShell=.2), .0032)\n    assert_close(shell_clearance(DShell=1.778), 0.0095)\n\n    with pytest.raises(Exception):\n        shell_clearance()\n\ndef test_L_unsupported_max():\n    assert_close(L_unsupported_max(Do=.0254, material=\"CS\"), 1.88)\n    assert_close(L_unsupported_max(Do=.0253, material=\"CS\"), 1.753)\n    assert_close(L_unsupported_max(Do=1E-5, material=\"CS\"), 0.66)\n    assert_close(L_unsupported_max(Do=.00635, material=\"CS\"), 0.66)\n\n    assert_close(L_unsupported_max(Do=.00635, material=\"aluminium\"), 0.559)\n\n    with pytest.raises(Exception):\n        L_unsupported_max(Do=.0254, material=\"BADMATERIAL\")\n\n    # Terribly pessimistic\n    assert_close(L_unsupported_max(Do=10, material=\"CS\"), 3.175)\n\n\ndef test_issue_6():\n    at_error = P_NTU_method(m1=3, m2=3, Cp1=1860., Cp2=1860,\n    subtype=\"counterflow\", Ntp=4, T2i=15, T1i=130, UA=3041.75)\n    before_error = P_NTU_method(m1=3, m2=3*(1+1e-8), Cp1=1860., Cp2=1860,\n    subtype=\"counterflow\", Ntp=4, T2i=15, T1i=130, UA=3041.75)\n    for k, v in at_error.items():\n        assert_close(v, before_error[k], rtol=1e-8)\n\n    Flowh = 5\n    Flowc = 5\n    Cph = 4000\n    Cpc = 4000\n    subtype = \"counterflow\"\n    UA = 2500\n    Thi = 90\n    Tci = 0\n    results = effectiveness_NTU_method(Flowh,Flowc,Cph,Cpc,subtype=subtype,UA=UA,\n                                        Thi = Thi, Tci=Tci)\n"
  },
  {
    "path": "tests/test_numba.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2020, 2021, 2022 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids import AirCooledExchanger\nfrom fluids.constants import foot, inch\nfrom fluids.numerics import assert_close\n\nimport ht.vectorized\nfrom ht import Nu_external_horizontal_plate_methods, h_Ganguli_VDI\n\ntry:\n    import numba\n\n    import ht.numba\n    import ht.numba_vectorized\nexcept:\n    numba = None\nimport numpy as np\n\n\ndef mark_as_numba(func):\n    func = pytest.mark.numba(func)\n#    func = pytest.mark.slow(func)\n    func = pytest.mark.skipif(numba is None, reason=\"Numba is missing\")(func)\n    return func\n\n@mark_as_numba\ndef test_tube_bank():\n    # not implemented - dP_Zukauskas\n\n    kwargs = dict(Re=10263.37, Pr=.708, tube_rows=11, pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(ht.numba.Nu_Grimison_tube_bank(**kwargs), ht.Nu_Grimison_tube_bank(**kwargs))\n\n    assert_close(ht.numba.Zukauskas_tube_row_correction(4, staggered=True),\n                 ht.Zukauskas_tube_row_correction(4, staggered=True))\n\n    kwargs = dict(Re=1E4, Pr=7., tube_rows=10, pitch_parallel=.05, pitch_normal=.05)\n    assert_close(ht.numba.Nu_Zukauskas_Bejan(**kwargs), ht.Nu_Zukauskas_Bejan(**kwargs))\n\n    kwargs = dict(Re=1.32E4, Pr=0.71, tube_rows=8, pitch_parallel=.09, pitch_normal=.05)\n    assert_close(ht.numba.Nu_ESDU_73031(**kwargs), ht.Nu_ESDU_73031(**kwargs))\n\n    kwargs = dict(Re=10263.37, Pr=.708, tube_rows=11, pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(ht.numba.Nu_HEDH_tube_bank(**kwargs), ht.Nu_HEDH_tube_bank(**kwargs))\n    kwargs = dict(Re=10263.37, Pr=.708, tube_rows=5, pitch_normal=.05, pitch_parallel=.05, Do=.025)\n    assert_close(ht.numba.Nu_HEDH_tube_bank(**kwargs), ht.Nu_HEDH_tube_bank(**kwargs))\n\n    kwargs = dict(m=11., rho=995., mu=0.000803, mu_w=0.000657, DShell=0.584, LSpacing=0.1524, pitch=0.0254, Do=.019, NBaffles=22)\n    assert_close(ht.numba.dP_Kern(**kwargs), ht.dP_Kern(**kwargs))\n\n    assert_close(ht.numba.baffle_correction_Bell(0.82, \"chebyshev\"), ht.numba.baffle_correction_Bell(0.82, \"chebyshev\"))\n    assert_close(ht.numba.baffle_correction_Bell(0.82), ht.numba.baffle_correction_Bell(0.82))\n\n    assert_close(ht.numba.baffle_leakage_Bell(1, 3, 8), ht.baffle_leakage_Bell(1, 3, 8))\n    assert_close(ht.numba.baffle_leakage_Bell(1, 3, 8, \"HEDH\"), ht.baffle_leakage_Bell(1, 3, 8, \"HEDH\"))\n\n    assert_close(ht.numba.bundle_bypassing_Bell(0.5, 5, 25), ht.bundle_bypassing_Bell(0.5, 5, 25))\n    assert_close(ht.numba.unequal_baffle_spacing_Bell(16, .1, .15, 0.15), ht.unequal_baffle_spacing_Bell(16, .1, .15, 0.15))\n\n\n@mark_as_numba\ndef test_conv_internal():\n    assert_close(ht.numba.Nu_conv_internal(Re=1E2, Pr=.7, x=.01, Di=.1),\n                 ht.Nu_conv_internal(Re=1E2, Pr=.7, x=.01, Di=.1))\n\n\n@mark_as_numba\ndef test_conv_free_immersed():\n    assert_close(ht.numba.Nu_vertical_cylinder(0.72, 1E7, L=1.0, D=3.),\n                 ht.Nu_vertical_cylinder(0.72, 1E7, L=1.0, D=3.0))\n\n\n@mark_as_numba\ndef test_conv_free_enclosed():\n    assert_close(ht.numba.Nu_Nusselt_Rayleigh_Holling_Herwig(5.54, 3.21e8, buoyancy=True),\n                 ht.Nu_Nusselt_Rayleigh_Holling_Herwig(5.54, 3.21e8, buoyancy=True))\n\n    assert_close(ht.numba.Rac_Nusselt_Rayleigh(1, .5, 2, False),\n                 ht.Rac_Nusselt_Rayleigh(1, .5, 2, False))\n    assert_close(ht.numba.Rac_Nusselt_Rayleigh(1, .5, 2, True),\n                 ht.Rac_Nusselt_Rayleigh(1, .5, 2, True))\n\n    assert_close(ht.numba.Rac_Nusselt_Rayleigh_disk(H=1, D=4, insulated=False),\n                 ht.Rac_Nusselt_Rayleigh_disk(H=1, D=4, insulated=False))\n    assert_close(ht.numba.Rac_Nusselt_Rayleigh_disk(H=1, D=4, insulated=True),\n                 ht.Rac_Nusselt_Rayleigh_disk(H=1, D=4, insulated=True))\n\n    assert_close(ht.numba.Nu_free_vertical_plate(0.69, 2.63E9, False),\n                 ht.Nu_free_vertical_plate(0.69, 2.63E9, False))\n\n    assert_close(ht.numba.Nu_free_horizontal_plate(5.54, 3.21e8, buoyancy=True),\n                 ht.Nu_free_horizontal_plate(5.54, 3.21e8, buoyancy=True))\n\n\n\n\n@mark_as_numba\ndef test_conv_external():\n    assert_close(ht.numba.Nu_cylinder_Whitaker(6071.0, 0.7), ht.Nu_cylinder_Whitaker(6071.0, 0.7))\n    assert_close(ht.numba.Nu_cylinder_Perkins_Leppert_1962(6071.0, 0.7),\n                 ht.Nu_cylinder_Perkins_Leppert_1962(6071.0, 0.7))\n    assert_close(ht.numba.Nu_cylinder_Perkins_Leppert_1964(6071.0, 0.7),\n                 ht.Nu_cylinder_Perkins_Leppert_1964(6071.0, 0.7))\n\n    assert ht.numba.Nu_external_cylinder_methods(0.72, 1E7) == ht.Nu_external_cylinder_methods(0.72, 1E7)\n\n    assert_close(ht.numba.Nu_external_cylinder(6071, 0.7), ht.Nu_external_cylinder(6071, 0.7))\n\n    assert Nu_external_horizontal_plate_methods(Re=1e7, Pr=.7) == ht.numba.Nu_external_horizontal_plate_methods(Re=1e7, Pr=.7)\n\n    assert_close(ht.numba.Nu_external_horizontal_plate(Re=1E7, Pr=.7),\n                 ht.Nu_external_horizontal_plate(Re=1E7, Pr=.7))\n\n\n@mark_as_numba\ndef test_core_misc():\n    assert_close(ht.numba.LMTD(100., 60., 20., 60, counterflow=False),\n                 ht.LMTD(100., 60., 20., 60, counterflow=False))\n\n    assert_close(ht.numba.fin_efficiency_Kern_Kraus(0.0254, 0.05715, 3.8E-4, 200, 58),\n                 ht.fin_efficiency_Kern_Kraus(0.0254, 0.05715, 3.8E-4, 200, 58),)\n\n    assert_close(ht.numba.wall_factor(mu=8E-4, mu_wall=3E-4, Pr=1.2, Pr_wall=1.1, T=300,T_wall=350, property_option=\"Prandtl\"),\n                 ht.wall_factor(mu=8E-4, mu_wall=3E-4, Pr=1.2, Pr_wall=1.1, T=300,T_wall=350, property_option=\"Prandtl\"))\n\n\n@mark_as_numba\ndef test_air_cooler():\n    assert_close(ht.numba.Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4),\n                 ht.air_cooler.Ft_aircooler(Thi=125., Tho=45., Tci=25., Tco=95., Ntp=1, rows=4))\n\n    assert_close(ht.numba.air_cooler_noise_GPSA(tip_speed=3177/60, power=25.1*750),\n                 ht.air_cooler_noise_GPSA(tip_speed=3177/60, power=25.1*750))\n\n\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=20, tube_length=3,\n    tube_diameter=1*inch, fin_thickness=0.000406, fin_density=1/0.002309,\n    pitch_normal=.06033, pitch_parallel=.05207,\n    fin_height=0.0159, tube_thickness=(.0254-.0186)/2,\n    bundles_per_bay=1, parallel_bays=1, corbels=True)\n\n    # 2.5 us numba, 30 us CPython, 100 us PyPy\n    assert_close(ht.numba.h_Briggs_Young(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205),\n                ht.h_Briggs_Young(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205),)\n\n    assert_close(ht.numba.h_ESDU_high_fin(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows, pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel, rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205, Pr_wall=7.0),\n                ht.h_ESDU_high_fin(m=21.56, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows, pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel, rho=1.161, Cp=1007., mu=1.85E-5, k=0.0263, k_fin=205, Pr_wall=7.0))\n\n    assert_close(ht.numba.h_ESDU_low_fin(m=0.914, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows, pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel, rho=1.217, Cp=1007., mu=1.8E-5, k=0.0253, k_fin=15),\n                 ht.h_ESDU_low_fin(m=0.914, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin, A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter, fin_diameter=AC.fin_diameter, bare_length=AC.bare_length, fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows, pitch_normal=AC.pitch_normal, pitch_parallel=AC.pitch_parallel, rho=1.217, Cp=1007., mu=1.8E-5, k=0.0253, k_fin=15))\n\n    AC = AirCooledExchanger(tube_rows=4, tube_passes=4, tubes_per_row=56, tube_length=36*foot,\n    tube_diameter=1*inch, fin_thickness=0.013*inch, fin_density=10/inch,\n    angle=30, pitch_normal=2.5*inch, fin_height=0.625*inch, corbels=True)\n\n    kwargs = dict(m=130.70315, A=AC.A, A_min=AC.A_min, A_increase=AC.A_increase, A_fin=AC.A_fin,\n        A_tube_showing=AC.A_tube_showing, tube_diameter=AC.tube_diameter,\n        fin_diameter=AC.fin_diameter, bare_length=AC.bare_length,\n        fin_thickness=AC.fin_thickness, tube_rows=AC.tube_rows,\n        pitch_parallel=AC.pitch_parallel, pitch_normal=AC.pitch_normal,\n        rho=1.2013848, Cp=1009.0188, mu=1.9304793e-05, k=0.027864828, k_fin=238)\n    h_numba = ht.numba.h_Ganguli_VDI(**kwargs)\n    h_normal = h_Ganguli_VDI(**kwargs)\n    assert_close(h_numba, h_normal, rtol=1e-11)\n\n\n\n\n@mark_as_numba\ndef test_boiling_flow():\n    assert_close(ht.numba.Thome(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, q=1E5),\n                 ht.Thome(m=1, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, q=1E5))\n    Te = 32.04944566414243\n    assert_close(ht.numba.Thome(m=10, x=0.5, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, Te=Te),\n                       ht.Thome(m=10, x=0.5, D=0.3, rhol=567., rhog=18.09, kl=0.086, kg=0.2, mul=156E-6, mug=1E-5, Cpl=2300, Cpg=1400, sigma=0.02, Hvap=9E5, Psat=1E5, Pc=22E6, Te=Te))\n\n    assert_close(ht.numba.Lazarek_Black(m=10, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6, Te=100),\n                 ht.Lazarek_Black(m=10, D=0.3, mul=1E-3, kl=0.6, Hvap=2E6, Te=100))\n\n    assert_close(ht.numba.Li_Wu(m=1, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, q=1E5),\n                 ht.Li_Wu(m=1, x=0.2, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, q=1E5))\n\n    kwargs = dict(m=1.0, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, sigma=0.02, Hvap=9E5, Te=10.0)\n    assert_close(ht.numba.Sun_Mishima(**kwargs), ht.Sun_Mishima(**kwargs))\n\n    kwargs = dict(m=1.0, x=0.4, D=0.3, rhol=567., mul=156E-6, sigma=0.02, Hvap=9E5, q=1E4)\n    assert_close(ht.numba.Yun_Heo_Kim(**kwargs), ht.Yun_Heo_Kim(**kwargs))\n\n    kwargs = dict(m=0.106, x=0.2, D=0.0212, rhol=567, rhog=18.09, mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730, Hvap=2E5, sigma=0.02, dPsat=1E5, Te=3)\n    assert_close(ht.numba.Chen_Edelstein(**kwargs), ht.Chen_Edelstein(**kwargs))\n\n    kwargs = dict(m=0.106, x=0.2, D=0.0212, rhol=567.0, rhog=18.09, mul=156E-6, mug=7.11E-6, kl=0.086, Cpl=2730.0, Hvap=2E5, sigma=0.02, dPsat=1E5, Te=3.0)\n    assert_close(ht.numba.Chen_Bennett(**kwargs), ht.Chen_Bennett(**kwargs))\n\n    kwargs = dict(m=1.0, x=0.4, D=0.3, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, Cpl=2300.0, P=1E6, Pc=22E6, MW=44.02, Te=7.0)\n    assert_close(ht.numba.Liu_Winterton(**kwargs), ht.Liu_Winterton(**kwargs))\n\n\n@mark_as_numba\ndef test_radiation():\n    assert_close(ht.numba.radiation. blackbody_spectral_radiance(800., 4E-6),\n                 ht.radiation. blackbody_spectral_radiance(800., 4E-6))\n\n\n@mark_as_numba\ndef test_conv_jacket():\n    assert_close(ht.Stein_Schmidt(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, rhow=971.8),\n                 ht.numba.Stein_Schmidt(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, rhow=971.8))\n\n    assert_close(ht.numba.Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6),\n                 ht.Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6))\n\n    assert_close(ht.numba.Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", isobaric_expansion=0.000303),\n                 ht.Lehrer(m=2.5, Dtank=0.6, Djacket=0.65, H=0.6, Dinlet=0.025, dT=20., rho=995.7, Cp=4178.1, k=0.615, mu=798E-6, muw=355E-6, inlettype=\"radial\", isobaric_expansion=0.000303))\n\n\n@mark_as_numba\ndef test_condensation():\n    assert_close(ht.numba.Nusselt_laminar(Tsat=370, Tw=350, rhog=7.0, rhol=585., kl=0.091, mul=158.9E-6, Hvap=776900, L=0.1),\n                 ht.Nusselt_laminar(Tsat=370, Tw=350, rhog=7.0, rhol=585., kl=0.091, mul=158.9E-6, Hvap=776900, L=0.1))\n\n    assert_close(ht.numba.Akers_Deans_Crosser(m=0.35, rhog=6.36, rhol=582.9, kl=0.098,  mul=159E-6, Cpl=2520., D=0.03, x=0.85),\n                 ht.Akers_Deans_Crosser(m=0.35, rhog=6.36, rhol=582.9, kl=0.098,  mul=159E-6, Cpl=2520., D=0.03, x=0.85))\n\n    assert_close(ht.numba.Cavallini_Smith_Zecchin(m=1, x=0.4, D=.3, rhol=800, rhog=2.5, mul=1E-5, mug=1E-3, kl=0.6, Cpl=2300),\n                 ht.Cavallini_Smith_Zecchin(m=1, x=0.4, D=.3, rhol=800, rhog=2.5, mul=1E-5, mug=1E-3, kl=0.6, Cpl=2300))\n\n\n    assert_close(ht.numba.Shah(m=1, x=0.4, D=.3, rhol=800, mul=1E-5, kl=0.6, Cpl=2300, P=1E6, Pc=2E7),\n                 ht.Shah(m=1, x=0.4, D=.3, rhol=800, mul=1E-5, kl=0.6, Cpl=2300, P=1E6, Pc=2E7))\n\n\n\n@mark_as_numba\ndef test_boiling_plate():\n    assert_close(ht.numba.h_boiling_Amalfi(m=3E-5, x=.4, Dh=0.00172, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=7.11E-6, sigma=0.02, Hvap=9E5, q=1E5, A_channel_flow=0.0003),\n                 ht.h_boiling_Amalfi(m=3E-5, x=.4, Dh=0.00172, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=7.11E-6, sigma=0.02, Hvap=9E5, q=1E5, A_channel_flow=0.0003))\n\n    assert_close(ht.numba.h_boiling_Lee_Kang_Kim(m=3E-5, x=.4, D_eq=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=9E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003),\n                 ht.h_boiling_Lee_Kang_Kim(m=3E-5, x=.4, D_eq=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6, mug=9E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003))\n\n    assert_close(ht.numba.h_boiling_Han_Lee_Kim(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6,  Hvap=9E5, Cpl=2200, q=1E5, A_channel_flow=0.0003, wavelength=3.7E-3, chevron_angle=45),\n                 ht.h_boiling_Han_Lee_Kim(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09, kl=0.086, mul=156E-6,  Hvap=9E5, Cpl=2200, q=1E5, A_channel_flow=0.0003, wavelength=3.7E-3, chevron_angle=45))\n\n    assert_close(ht.numba.h_boiling_Huang_Sheer(rhol=567., rhog=18.09, kl=0.086, mul=156E-6, Hvap=9E5, sigma=0.02, Cpl=2200, q=1E4, Tsat=279.15),\n                 ht.h_boiling_Huang_Sheer(rhol=567., rhog=18.09, kl=0.086, mul=156E-6, Hvap=9E5, sigma=0.02, Cpl=2200, q=1E4, Tsat=279.15))\n\n    assert_close(ht.numba.h_boiling_Yan_Lin(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09, kl=0.086, Cpl=2200, mul=156E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003),\n                 ht.h_boiling_Yan_Lin(m=3E-5, x=.4, Dh=0.002, rhol=567., rhog=18.09, kl=0.086, Cpl=2200, mul=156E-6, Hvap=9E5, q=1E5, A_channel_flow=0.0003))\n\n\n\n@mark_as_numba\ndef test_Ntubes_Phadkeb():\n    # Extremely impressive performance\n    Bundles = np.linspace(1, 2, 5)\n    Dos = np.linspace(.028, .029, 5)\n    pitches = np.linspace(.036, .037, 5)\n    Ntps = np.linspace(2, 2, 5, dtype=np.int64)\n    angles = np.linspace(45, 45, 5, dtype=np.int64)\n\n    assert 782 == ht.numba.Ntubes_Phadkeb(DBundle=1.200-.008*2, Do=.028, pitch=.036, Ntp=2, angle=45.)\n\n\n\n#    assert_close(ht.numba_vectorized.Ntubes_Phadkeb(Bundles, Dos, pitches, Ntps, angles),\n#                 [ 558,  862, 1252, 1700, 2196])\n\n\n@mark_as_numba\ndef test_boiling_nucleic():\n    assert_close(ht.numba.Rohsenow(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26),\n                 ht.Rohsenow(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26))\n\n    numba_methods = ht.numba.h_nucleic_methods(P=3E5, Pc=22048320., Te=4.0, CAS=\"7732-18-5\")\n    regular_methods = ht.h_nucleic_methods(P=3E5, Pc=22048320., Te=4.0, CAS=\"7732-18-5\")\n    assert numba_methods == regular_methods\n\n\n    # Has a TON of arguments, and numba wants them all to not be Nones.\n    assert_close(ht.numba.h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26, P=1e4, Pc=1e6, Tsat=10, MW=33.0, Method=\"Rohsenow\"),\n                 ht.h_nucleic(rhol=957.854, rhog=0.595593, mul=2.79E-4, kl=0.680, Cpl=4217, Hvap=2.257E6, sigma=0.0589, Te=4.9, Csf=0.011, n=1.26, P=1e4, Pc=1e6, Tsat=10, MW=33.0, Method=\"Rohsenow\"))\n\n    kwargs = dict(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567.0, rhog=18.09, P=1e6, Pc=1e7)\n    assert_close(ht.numba.qmax_boiling(**kwargs), ht.qmax_boiling(**kwargs))\n\n    kwargs = dict(D=0.0127, sigma=8.2E-3, Hvap=272E3, rhol=567, rhog=18.09)\n    assert ht.qmax_boiling_methods(**kwargs) == ht.numba.qmax_boiling_methods(**kwargs)\n\n\n\n@mark_as_numba\ndef test_packed_bed():\n    # All good\n    assert_close(ht.numba.Nu_packed_bed_Gnielinski(dp=8E-4, voidage=0.4, vs=1, rho=1E3, mu=1E-3, Pr=0.7),\n                 ht.Nu_packed_bed_Gnielinski(dp=8E-4, voidage=0.4, vs=1, rho=1E3, mu=1E-3, Pr=0.7))\n\n\n\n@mark_as_numba\ndef test_two_phase():\n    kwargs = dict(m=1.0, x=.9, D=.3, alpha=.9, rhol=1000.0, rhog=2.2, mug=1e-5, Cpl=2300.0, kl=.6, mul=1e-3, mu_b=1E-3, mu_w=1.2E-3, L=5)\n    assert_close(ht.numba.h_two_phase(**kwargs), ht.h_two_phase(**kwargs))\n\n\n@mark_as_numba\ndef test_supercritical():\n    assert_close(ht.numba.Nu_Griem(1E5, 1.2), ht.Nu_Griem(1E5, 1.2))\n\n    kwargs = dict(Re=1E5, Pr=1.2, rho_w=125.8, rho_b=249.0233,\n              Cp_avg=2080.845, Cp_b=2048.621, T_b=650, T_w=700, T_pc=300.0)\n    assert_close(ht.numba.Nu_Jackson(**kwargs), ht.Nu_Jackson(**kwargs))\n    assert_close(ht.numba.Nu_Jackson(1E5, 1.2), ht.Nu_Jackson(1E5, 1.2))\n\n    assert_close(ht.numba.Nu_Gupta(1E5, 1.2), ht.Nu_Gupta(1E5, 1.2))\n    assert_close(ht.numba.Nu_Swenson(1E5, 1.2), ht.Nu_Swenson(1E5, 1.2))\n    assert_close(ht.numba.Nu_Xu(1E5, 1.2), ht.Nu_Xu(1E5, 1.2))\n\n    assert_close(ht.numba.Nu_Mokry(1E5, 1.2), ht.Nu_Mokry(1E5, 1.2))\n    assert_close(ht.numba.Nu_Ornatsky(1E5, 1.2, 1.5), ht.Nu_Ornatsky(1E5, 1.2, 1.5))\n    assert_close(ht.numba.Nu_Zhu(1E5, 1.2), ht.Nu_Zhu(1E5, 1.2))\n\n    kwargs = dict(Re=1E5, Pr=1.2, Pr_pc=1.5, Cp_avg=2080.845, Cp_b=2048.621, T_b=650, T_w=700, T_pc=600.0)\n    assert_close(ht.numba.Nu_Yamagata(**kwargs), ht.Nu_Yamagata(**kwargs))\n\n    assert_close(ht.numba.Nu_Kitoh(1E5, 1.2), ht.Nu_Kitoh(1E5, 1.2))\n\n    assert_close(ht.numba.Nu_Krasnoshchekov_Protopopov(1E5, 1.2),\n                 ht.Nu_Krasnoshchekov_Protopopov(1E5, 1.2))\n\n    assert_close(ht.numba.Nu_Petukhov(1E5, 1.2),\n                 ht.Nu_Petukhov(1E5, 1.2))\n\n    assert_close(ht.numba.Nu_Krasnoshchekov(1E5, 1.2),\n                 ht.Nu_Krasnoshchekov(1E5, 1.2))\n\n\n\n\n@mark_as_numba\ndef test_conduction():\n    assert_close(ht.numba.R_value_to_k(1., SI=False), ht.numba.R_value_to_k(1., SI=False))\n\n    assert_close(ht.numba.S_isothermal_pipe_to_isothermal_pipe(.1, .2, 1, 1),\n                 ht.S_isothermal_pipe_to_isothermal_pipe(.1, .2, 1, 1))\n\n    # cylindrical_heat_transfer returns a dictionary, not supported by numba\n\n@mark_as_numba\ndef test_hx_tube_bundles():\n    kwargs = dict(Ntubes=782, Do=.028, pitch=.036, Ntp=2, angle=45.)\n    assert_close(ht.numba.DBundle_for_Ntubes_Phadkeb(**kwargs),\n                 ht.DBundle_for_Ntubes_Phadkeb(**kwargs))\n\n    kwargs = dict(DBundle=1.184, Do=.028, Ntp=2, angle=45)\n    assert_close(ht.numba.Ntubes_Perrys(**kwargs), ht.Ntubes_Perrys(**kwargs))\n\n    assert_close(ht.numba.Ntubes_VDI(DBundle=1.184, Ntp=2, Do=.028, pitch=.036, angle=30),\n                 ht.Ntubes_VDI(DBundle=1.184, Ntp=2, Do=.028, pitch=.036, angle=30) )\n\n    kwargs = dict(DBundle=1.2, Do=0.025, pitch=0.03125, Method=\"Phadkeb\")\n    assert ht.numba.Ntubes(**kwargs) == ht.Ntubes(**kwargs)\n\n    kwargs = dict(N=1285, Do=0.025, pitch=0.03125)\n    assert_close(ht.numba.size_bundle_from_tubecount(**kwargs),\n                 ht.size_bundle_from_tubecount(**kwargs))\n\n@mark_as_numba\ndef test_hx_data():\n    assert_close(ht.L_unsupported_max(Do=.0254, material=\"CS\"),\n                 ht.numba.L_unsupported_max(Do=.0254, material=\"CS\"))\n\n    assert_close(ht.numba.baffle_thickness(Dshell=.3, L_unsupported=50, service=\"R\"),\n                 ht.baffle_thickness(Dshell=.3, L_unsupported=50, service=\"R\"))\n\n@mark_as_numba\ndef test_hx_effectiveness_still_working():\n    assert_close(ht.numba.temperature_effectiveness_air_cooler(.5, 2, rows=10, passes=10),\n                 ht.temperature_effectiveness_air_cooler(.5, 2, rows=10, passes=10))\n\n    assert_close(ht.numba.hx.P_NTU_Pp(5, .4),  ht.hx.P_NTU_Pp(5, .4))\n    assert_close(ht.numba.hx.P_NTU_Pc(5, .4),  ht.hx.P_NTU_Pc(5, .4))\n\n\n# broken by numba in the 0.57 release\n# @mark_as_numba\n# def test_hx_effectiveness_basic():\n#     R1 = 3.811315897216142e-05\n#     NTU1 = 0.31156549511556475\n#     assert_close(ht.numba.temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype='crossflow'),\n#                  ht.temperature_effectiveness_basic(R1=R1, NTU1=NTU1, subtype='crossflow'))\n\n#     P1 = ht.numba.temperature_effectiveness_basic(R1=R1, NTU1=NTU1,\n#                                     subtype='crossflow')\n#     NTU1_calc = ht.numba.NTU_from_P_basic(P1, R1, subtype='crossflow')\n#     assert_close(NTU1, NTU1_calc)\n\n# # broken by numba in the 0.57 release\n# @mark_as_numba\n# def test_hx_effectiveness_broken():\n#     assert_close(ht.numba.NTU_from_P_J(P1=.99, R1=.01, Ntp=2),\n#                  ht.NTU_from_P_J(P1=.99, R1=.01, Ntp=2))\n#     assert_close(ht.numba.NTU_from_P_G(P1=.573, R1=1/3., Ntp=1),\n#                  ht.NTU_from_P_G(P1=.573, R1=1/3., Ntp=1))\n#     assert_close(ht.numba.NTU_from_P_E(P1=.58, R1=1/3., Ntp=2),\n#                  ht.NTU_from_P_E(P1=.58, R1=1/3., Ntp=2))\n\n#     assert_close(ht.numba.NTU_from_P_H(P1=0.573, R1=1/3., Ntp=1),\n#                  ht.NTU_from_P_H(P1=0.573, R1=1/3., Ntp=1))\n\n#     # Quite literally 20x faster than CPython; Pypy is unfortunately slow as there is a scipy function\n\n#     assert_close(ht.numba.NTU_from_P_plate(P1=0.5743, R1=1/3., Np1=3, Np2=1),\n#                  ht.NTU_from_P_plate(P1=0.5743, R1=1/3., Np1=3, Np2=1))\n\n\n\n@mark_as_numba\ndef test_conv_plate():\n    kwargs = dict(Re=2000, Pr=0.7, chevron_angle=30.0, mu=1E-3, mu_wall=8E-4)\n    assert_close(ht.numba.Nu_plate_Kumar(**kwargs), ht.Nu_plate_Kumar(**kwargs))\n\n    kwargs = dict(Re=2000, Pr=.7, chevron_angle=30.0)\n    assert_close(ht.numba.Nu_plate_Martin(**kwargs), ht.Nu_plate_Martin(**kwargs))\n"
  },
  {
    "path": "tests/test_radiation.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2016, 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport pytest\nfrom fluids.numerics import assert_close, assert_close1d\n\nfrom ht import blackbody_spectral_radiance, grey_transmittance, q_rad, solar_spectrum\n\n\ndef test_radiation():\n    assert_close(q_rad(1., 400), 1451.613952, rtol=1e-05)\n    assert_close(q_rad(.85, 400, 305.), 816.7821722650002, rtol=1e-05)\n\n    assert 0.0 == blackbody_spectral_radiance(5500., 5E-10)\n\n\n    assert_close(blackbody_spectral_radiance(800., 4E-6), 1311692056.2430143, rtol=1e-05)\n\n\n@pytest.mark.slow\ndef test_solar_spectrum():\n    from scipy.integrate import trapezoid\n    wavelengths, SSI, uncertainties = solar_spectrum()\n\n    min_maxes = [min(wavelengths), max(wavelengths), min(SSI), max(SSI)]\n    min_maxes_expect = [5.0000000000000003e-10, 2.9999000000000003e-06, 1330.0, 2256817820.0]\n    assert_close1d(min_maxes, min_maxes_expect)\n\n    assert_close(trapezoid(SSI, wavelengths), 1344.8029782379999)\n\ndef test_grey_transmittance():\n    tau =  grey_transmittance(3.8e-4, molar_density=55300, length=1e-2)\n    assert_close(tau, 0.8104707721191062)\n"
  },
  {
    "path": "tests/test_units.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nimport types\n\nimport pytest\nfrom fluids.numerics import assert_close\nfrom fluids.units import check_module_docstring_parameters\n\nimport ht\nfrom ht.units import P_NTU_method, R_to_k, R_value_to_k, effectiveness_NTU_method, k_to_R_value, u\n\n\ndef assert_pint_allclose(value, magnitude, units, rtol=1e-7):\n    assert_close(value.to_base_units().magnitude, magnitude, rtol=rtol)\n    assert dict(value.dimensionality) == units\n\ndef test_sample_cases():\n    ans = effectiveness_NTU_method(mh=5.2*u.kg/u.s, mc=1.45*u.kg/u.s,\n                                   Cph=1860.*u.J/u.K/u.kg, Cpc=1900*u.J/u.K/u.kg,\n                                   subtype=\"crossflow, mixed Cmax\", Tci=15*u.K,\n                                   Tco=85*u.K, Thi=130*u.K)\n\n    assert_pint_allclose(ans[\"Cmax\"], 9672.0, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"Cmin\"], 2755.0, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"Cr\"], 0.2848428453267163, {})\n    assert_pint_allclose(ans[\"UA\"], 3041.751170834494, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"Q\"], 192850, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"NTU\"], 1.1040839095588, {})\n    assert_pint_allclose(ans[\"effectiveness\"], 0.6086956521739131, {})\n    assert_pint_allclose(ans[\"Tci\"], 15, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"Tco\"], 85, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"Thi\"], 130, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"Tho\"], 110.06100082712986, {\"[temperature]\": 1.0})\n\n    ans = P_NTU_method(m1=5.2*u.kg/u.s, m2=1.45*u.kg/u.s, Cp1=1860.*u.J/u.kg/u.K,\n                       Cp2=1900*u.J/u.kg/u.K, subtype=\"E\", Ntp=4, T2i=15*u.K,\n                       T1i=130*u.K, UA=3041.75*u.W/u.K)\n\n    assert_pint_allclose(ans[\"C1\"], 9672.0, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"C2\"], 2755.0, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"UA\"], 3041.75, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"Q\"], 192514.71424206023, {\"[length]\": 2.0, \"[mass]\": 1.0, \"[time]\": -3.0})\n    assert_pint_allclose(ans[\"NTU1\"], 0.3144902812241522, {})\n    assert_pint_allclose(ans[\"NTU2\"], 1.1040834845735028, {})\n    assert_pint_allclose(ans[\"T2i\"], 15, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"T2o\"], 84.87829918042112, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"T1i\"], 130, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"T1o\"], 110.09566643485729, {\"[temperature]\": 1.0})\n    assert_pint_allclose(ans[\"P1\"], 0.1730811614360235, {})\n    assert_pint_allclose(ans[\"P2\"], 0.6076373841775751, {})\n    assert_pint_allclose(ans[\"R1\"], 3.5107078039927404, {})\n    assert_pint_allclose(ans[\"R2\"], 0.2848428453267163, {})\n\n\ndef test_custom_wraps():\n    k = R_to_k(R=1*u.K/u.W, t=.01*u.m)\n    assert_pint_allclose(k, 1E-2, {\"[length]\": 1.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n\n    k = R_to_k(R=1*u.K/u.W*u.m**2, t=.01*u.m, A=5*u.m**2)\n    assert_pint_allclose(k, .002, {\"[length]\": 1.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n\n    with pytest.raises(Exception):\n        R_to_k(R=1*u.K/u.W, t=.01*u.m, A=2*u.m**2)\n\n\n    # R_value_to_k\n    k = R_value_to_k(0.12*u.parse_expression(\"m^2*K/(W*inch)\"))\n    assert_pint_allclose(k, 0.2116666666666667, {\"[length]\": 1.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0})\n\n    k = R_value_to_k(0.71*u.parse_expression(\"ft^2*delta_degF*hour/(BTU*inch)\"))\n    assert_pint_allclose(k, 0.20313790001601909, {\"[length]\": 1.0, \"[mass]\": 1.0, \"[temperature]\": -1.0, \"[time]\": -3.0}, rtol=1e-4)\n\n    # k_to_R_value\n    R_value = k_to_R_value(k=0.2116666666666667*u.W/u.m/u.K, SI=True)\n    assert_pint_allclose(R_value.to_base_units(), 4.724409448818897, {\"[length]\": -1.0, \"[mass]\": -1.0, \"[temperature]\": 1.0, \"[time]\": 3.0}, rtol=1e-4)\n\n    R_value = k_to_R_value(k=0.71*u.W/u.m/u.K, SI=False)\n    assert_pint_allclose(R_value.to_base_units(), 1.4084507042253525, {\"[length]\": -1.0, \"[mass]\": -1.0, \"[temperature]\": 1.0, \"[time]\": 3.0}, rtol=1e-4)\n\n\ndef test_check_signatures():\n    from fluids.units import check_args_order\n    bad_names = {\"__getattr__\"}\n    for name in dir(ht):\n        if name in bad_names:\n            continue\n        obj = getattr(ht, name)\n        if isinstance(obj, types.FunctionType):\n            check_args_order(obj)\n\ndef test_parse_numpydoc_variables_units():\n    import ht\n    check_module_docstring_parameters(ht)\n"
  },
  {
    "path": "tests/test_vectorized.py",
    "content": "\"\"\"Chemical Engineering Design Library (ChEDL). Utilities for process modeling.\nCopyright (C) 2017 Caleb Bell <Caleb.Andrew.Bell@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\"\"\"\n\nfrom fluids.numerics import assert_close1d\n\nimport ht\nimport ht.vectorized\n\n\ndef test_LMTD_vect():\n    dTlms = [ht.LMTD(T, 60., 30., 40.2) for T in [100, 101]]\n    dTlms_vect = ht.vectorized.LMTD([100, 101], 60., 30., 40.2)\n    assert_close1d(dTlms, dTlms_vect)\n"
  }
]