diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml index aba1d8300..3979d73fb 100644 --- a/.github/workflows/packaging.yml +++ b/.github/workflows/packaging.yml @@ -16,7 +16,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ["3.10"] + python-version: ["3.11"] steps: - uses: actions/checkout@v1 @@ -26,9 +26,9 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools setuptools_scm twine wheel flit + python -m pip install --upgrade pip twine build flit - name: Create packages - run: python -m flit build + run: python -m build . - name: Run twine check run: twine check dist/* - uses: actions/upload-artifact@v2 diff --git a/.github/workflows/tox_checks.yml b/.github/workflows/tox_checks.yml index 5cd8e4117..2b8e5808d 100644 --- a/.github/workflows/tox_checks.yml +++ b/.github/workflows/tox_checks.yml @@ -22,7 +22,6 @@ jobs: strategy: matrix: toxenv: - - clean - check - docs @@ -30,10 +29,10 @@ jobs: - name: Git clone uses: actions/checkout@v2 - - name: Set up Python ${{ env.default_python || '3.10' }} + - name: Set up Python ${{ env.default_python || '3.11' }} uses: actions/setup-python@v2 with: - python-version: "${{ env.default_python || '3.10' }}" + python-version: "${{ env.default_python || '3.11' }}" - name: Pip cache uses: actions/cache@v2 @@ -46,7 +45,6 @@ jobs: - name: Install dependencies run: | python -m pip install -U pip - python -m pip install -U setuptools wheel python -m pip install -U tox - name: Run ${{ matrix.toxenv }} run: python -m tox -e ${{ matrix.toxenv }} diff --git a/.github/workflows/tox_pytest.yml b/.github/workflows/tox_pytest.yml index ba825bd49..0742818b1 100644 --- a/.github/workflows/tox_pytest.yml +++ b/.github/workflows/tox_pytest.yml @@ -14,7 +14,7 @@ on: - cron: "0 5 * * 6" # 5:00 UTC every Saturday jobs: - build: + pytest: runs-on: ubuntu-latest strategy: matrix: diff --git a/.readthedocs.yml b/.readthedocs.yml index 2c1c3ed1d..0d4b175e3 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,9 +5,10 @@ sphinx: # formats: all ## none appart from html required here python: install: - - requirements: docs/requirements.txt - method: pip path: . + extra_requirements: + - dev build: os: ubuntu-22.04 tools: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d13c31c25..bc0ea180d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,2 @@ -The developer rules can be found in the chapter -[developing TESPy](https://tespy.readthedocs.io/en/dev/developing_tespy.html) -of the tespy.documentation. +The developer rules can be found in the +[online documentation](https://tespy.readthedocs.io/). diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index fb89fc5b2..000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,19 +0,0 @@ -graft docs -graft src -graft tests -graft tutorial - -include .coveragerc -include .editorconfig - -include LICENSE -include README.rst -include *.bib -include *.md -include *.yml -recursive-include *.py - -include tox.ini - -global-exclude *.py[cod] __pycache__/* *.so *.dylib - diff --git a/docs/_static/images/basics/gas_turbine_fuel_composition.svg b/docs/_static/images/basics/gas_turbine_fuel_composition.svg index 71fa354b8..f40d5e2c4 100644 --- a/docs/_static/images/basics/gas_turbine_fuel_composition.svg +++ b/docs/_static/images/basics/gas_turbine_fuel_composition.svg @@ -1,23 +1,23 @@ - + - + - 2022-08-30T21:38:50.684785 + 2024-06-27T19:36:40.422628 image/svg+xml - Matplotlib v3.4.2, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ - + @@ -26,7 +26,7 @@ L 1152 576 L 1152 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> @@ -35,86 +35,30 @@ L 1132.56 511 L 1132.56 26.28 L 82.01 26.28 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - - + +" transform="scale(0.015625)"/> - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + - + - - + - + - + - + - + - + +" transform="scale(0.015625)"/> - - + - + - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + - +" clip-path="url(#p58556a9470)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - - + + - + - - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> @@ -1031,18 +1031,18 @@ Q 893.300625 35.28 893.300625 38.88 L 893.300625 89.92125 Q 893.300625 93.52125 896.900625 93.52125 z -" style="fill:#ffffff;opacity:0.8;stroke:#cccccc;stroke-linejoin:miter;"/> +" style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter"/> - + - + - - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + diff --git a/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg b/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg index 3eed407fe..b013bfc08 100644 --- a/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg +++ b/docs/_static/images/basics/gas_turbine_fuel_composition_darkmode.svg @@ -6,11 +6,11 @@ - 2022-09-23T14:40:19.299228 + 2024-06-27T19:34:25.974710 image/svg+xml - Matplotlib v3.5.3, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ @@ -37,82 +37,26 @@ L 82.01 26.28 z "/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - - + - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -383,7 +327,7 @@ L 1084.807727 26.28 - + +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - - + - + @@ -712,16 +656,16 @@ L -3.5 0 +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -731,16 +675,16 @@ L 1132.56 414.056 +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -750,16 +694,16 @@ L 1132.56 317.112 +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -769,16 +713,16 @@ L 1132.56 220.168 +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -788,16 +732,16 @@ L 1132.56 123.224 +" clip-path="url(#p482d049694)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -1128,7 +1128,7 @@ z - + diff --git a/docs/_static/images/basics/gas_turbine_oxygen.svg b/docs/_static/images/basics/gas_turbine_oxygen.svg index 8bf5af372..888a7829e 100644 --- a/docs/_static/images/basics/gas_turbine_oxygen.svg +++ b/docs/_static/images/basics/gas_turbine_oxygen.svg @@ -1,23 +1,23 @@ - + - + - 2022-08-30T21:38:39.150003 + 2024-06-27T19:36:01.814498 image/svg+xml - Matplotlib v3.4.2, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ - + @@ -26,7 +26,7 @@ L 1152 576 L 1152 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> @@ -35,53 +35,86 @@ L 1132.56 511 L 1132.56 19.44 L 93.53 19.44 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - +" style="stroke: #000000; stroke-width: 0.8"/> - + - - + + - + + + + + + + + + + + + + + + + + + + + + +" transform="scale(0.015625)"/> - + + - - - + + + - + - + - - - + + + - +" transform="scale(0.015625)"/> - + + - - - + + + - + - + - - - + + + - +" transform="scale(0.015625)"/> - + + - - - + + + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> - + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + - + - + - - + - + - + - + - + +" transform="scale(0.015625)"/> - - + - + - + - + - + - + - + - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - +" style="stroke: #000000; stroke-width: 0.8"/> - + - - - - - - - + + + + + + - - + + - + - + - - - + + + - - - + + + - - + + - + - + - - - + + + - - - + + + - - + + - + - + - - - + + + - - - + + + - - + + - + - + - - - - - - - + + + + + + + - + - + - - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> - - + + diff --git a/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg b/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg index 2a719b25a..88f54e2aa 100644 --- a/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg +++ b/docs/_static/images/basics/gas_turbine_oxygen_darkmode.svg @@ -6,11 +6,11 @@ - 2022-09-23T14:40:09.282863 + 2024-06-27T19:33:35.295604 image/svg+xml - Matplotlib v3.5.3, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ @@ -37,49 +37,82 @@ L 93.53 19.44 z "/> - - - - - - - - - - - - - - + - - + - - + + + + + + + + + + + + + + + + + + + + + + + - + + - - - + + + - + - + - - - + + + - + + - - - + + + - + - + - - - + + + - + + - - - + + + - + - + - - - + + + - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - - - + + + + - + - + - - + + - + - - + - - - - - + + + + + - - - + + - + - + - - - + + + - + - - + + - + - + - - - + + + - + - - + + - + - + - - - + + + - + - - + + - + - + - - - - - + + + + + - + - + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/gas_turbine_parametric.svg b/docs/_static/images/basics/gas_turbine_parametric.svg index 1b5f35181..66d4dca6f 100644 --- a/docs/_static/images/basics/gas_turbine_parametric.svg +++ b/docs/_static/images/basics/gas_turbine_parametric.svg @@ -1,23 +1,23 @@ - + - + - 2022-08-30T21:38:36.540618 + 2024-06-27T19:35:57.454335 image/svg+xml - Matplotlib v3.4.2, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ - + @@ -26,7 +26,7 @@ L 1152 576 L 1152 0 L 0 0 z -" style="fill:#ffffff;"/> +" style="fill: #ffffff"/> @@ -35,111 +35,83 @@ L 587.91564 253.75 L 587.91564 19.44 L 70.67 19.44 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - +" style="stroke: #000000; stroke-width: 0.8"/> - + - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#pa65af7d2a9)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -147,25 +119,25 @@ L 564.404475 19.44 - + - +" style="stroke: #000000; stroke-width: 0.8"/> - + - + - - + +" transform="scale(0.015625)"/> - + - + - + - + - +" transform="scale(0.015625)"/> - + - + - + - + - +" transform="scale(0.015625)"/> - + - + - - + - + - + - + - + - + +" transform="scale(0.015625)"/> - +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> @@ -548,129 +548,114 @@ L 1132.56 253.75 L 1132.56 19.44 L 615.31436 19.44 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - +" clip-path="url(#p2abe622765)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -678,60 +663,75 @@ L 1109.048835 19.44 - + - + - + - + - + - + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> @@ -741,53 +741,25 @@ L 587.91564 511 L 587.91564 276.69 L 70.67 276.69 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - + +" transform="scale(0.015625)"/> - - + + - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - - - + + + - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#pa43d553fae)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - + - - + - + - + - + - + - + - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - +" transform="scale(0.015625)"/> - + - + - + - + - +" transform="scale(0.015625)"/> - + - + - + - + - + - + - - + - + - + - + +" transform="scale(0.015625)"/> - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> @@ -1506,70 +1506,55 @@ L 1132.56 511 L 1132.56 276.69 L 615.31436 276.69 z -" style="fill:#ffffff;"/> - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - +" transform="scale(0.015625)"/> - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - +" clip-path="url(#p7673461340)" style="fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square"/> - + - + - - - + + + - + - +" transform="scale(0.015625)"/> - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> +" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/> - - + + - - + + - - + + - - + + diff --git a/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg b/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg index 5c42e5ddd..04e5b258d 100644 --- a/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg +++ b/docs/_static/images/basics/gas_turbine_parametric_darkmode.svg @@ -6,11 +6,11 @@ - 2022-09-23T14:40:06.522079 + 2024-06-27T19:33:30.794753 image/svg+xml - Matplotlib v3.5.3, https://matplotlib.org/ + Matplotlib v3.9.0, https://matplotlib.org/ @@ -37,49 +37,21 @@ L 70.67 19.44 z "/> - - - - - - - - - - - - - - - - - - +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -87,11 +59,11 @@ L 0 3.5 +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -99,11 +71,11 @@ L 188.225827 19.44 +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -111,11 +83,11 @@ L 282.270489 19.44 +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -123,11 +95,11 @@ L 376.315151 19.44 +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -135,11 +107,11 @@ L 470.359813 19.44 +" clip-path="url(#p198fc0f48f)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -147,23 +119,23 @@ L 564.404475 19.44 - + - - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -582,11 +567,11 @@ L 638.825525 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -594,11 +579,11 @@ L 697.603439 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -606,11 +591,11 @@ L 756.381352 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -618,11 +603,11 @@ L 815.159266 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -630,11 +615,11 @@ L 873.93718 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -642,11 +627,11 @@ L 932.715093 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -654,11 +639,11 @@ L 991.493007 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -666,11 +651,11 @@ L 1050.270921 19.44 +" clip-path="url(#p3df8ea0b37)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -678,41 +663,56 @@ L 1109.048835 19.44 - + - + - + - + - + - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -907,16 +879,16 @@ L 282.270489 276.69 +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -928,16 +900,16 @@ L 376.315151 276.69 +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -949,16 +921,16 @@ L 470.359813 276.69 +" clip-path="url(#p73df833680)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -968,7 +940,7 @@ L 564.404475 276.69 - + - + - + - + @@ -1261,18 +1233,18 @@ L 587.91564 489.384715 - + - + - + - + - + - + - + - + - + @@ -1371,7 +1343,7 @@ L 587.91564 314.545508 - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1627,16 +1612,16 @@ L 756.381352 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1648,16 +1633,16 @@ L 815.159266 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1669,16 +1654,16 @@ L 873.93718 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1690,16 +1675,16 @@ L 932.715093 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1711,16 +1696,16 @@ L 991.493007 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1732,16 +1717,16 @@ L 1050.270921 276.69 +" clip-path="url(#pd6edc6de27)" style="fill: none; stroke: #ffffff; stroke-width: 0.8; stroke-linecap: square"/> - + - + @@ -1751,7 +1736,7 @@ L 1109.048835 276.69 - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + - + - + - + diff --git a/docs/_static/images/basics/rankine_ts_diagram.svg b/docs/_static/images/basics/rankine_ts_diagram.svg new file mode 100644 index 000000000..ad8a048eb --- /dev/null +++ b/docs/_static/images/basics/rankine_ts_diagram.svg @@ -0,0 +1,3261 @@ + + + + + + + + 2024-05-23T08:06:38.979522 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/images/basics/rankine_ts_diagram_darkmode.svg b/docs/_static/images/basics/rankine_ts_diagram_darkmode.svg new file mode 100644 index 000000000..3f4cfebbe --- /dev/null +++ b/docs/_static/images/basics/rankine_ts_diagram_darkmode.svg @@ -0,0 +1,3261 @@ + + + + + + + + 2024-05-23T08:06:22.317888 + image/svg+xml + + + Matplotlib v3.7.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/basics/rankine_cycle.rst b/docs/basics/rankine_cycle.rst index 9ac3c31e5..9c3728b7d 100644 --- a/docs/basics/rankine_cycle.rst +++ b/docs/basics/rankine_cycle.rst @@ -81,6 +81,50 @@ water return flow temperature. After rerunning, we will see that the condensation temperature and pressure are both automatically calculated by the specified terminal temperature value. +Generating T-s Diagram +^^^^^^^^^^^^^^^^^^^^^^ +To visualize the Rankine cycle, we generate a temperature (T) versus entropy (s) +diagram using the fluprodia (Fluid Property Diagram) package. + +.. dropdown:: Click to expand to code section + + .. literalinclude:: /../tutorial/basics/rankine.py + :language: python + :start-after: [sec_5] + :end-before: [sec_6] + +The steps involved in generating the T-s diagram are as follows: + +- Import the Package: Import fluprodia and create an object by passing the + alias of the fluid. +- Specify the Unit System: Set the unit system for all fluid properties. +- Specify Custom Isolines: Define custom isolines for the diagram. +- Calculate and draw isolines: Calculate and draw the background isolines. +- Calculate and draw process points and change of state +- Save and Export the Diagram: Save and export the completed T-s diagram. + +.. figure:: /_static/images/basics/rankine_ts_diagram.svg + :align: center + :alt: T-s Diagram of Rankine Cycle + :figclass: only-light + + Figure: T-s Diagram of Rankine Cycle + +.. figure:: /_static/images/basics/rankine_ts_diagram_darkmode.svg + :align: center + :alt: T-s Diagram of Rankine Cycle + :figclass: only-dark + + Figure: T-s Diagram of Rankine Cycle + +Besides visualization, this feature is also useful for analysis purposes. +For example, if the T-s diagram forms a closed loop, validating the accuracy of +the model and that the operating fluid completes a successful Rankine Cycle. By +applying fluprodia, we can create and customize different types of diagrams for +all pure and pseudo-pure fluids available in CoolProp. For more information on +fluprodia, we refer users to the +`fluprodia documentation `__. + Assess Electrical Power ^^^^^^^^^^^^^^^^^^^^^^^ To assess the electrical power output we want to consider the power generated @@ -92,8 +136,8 @@ both components to the bus. .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_5] - :end-before: [sec_6] + :start-after: [sec_6] + :end-before: [sec_7] .. note:: @@ -121,11 +165,11 @@ replacing the mass flow specification at connection 1: .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_6] - :end-before: [sec_7] + :start-after: [sec_7] + :end-before: [sec_8] -Analyze Efficiency and Powergeneration -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Analyze Efficiency and power generation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In this section, we will analyze the power production and the efficiency of the cycle, given constant steam mass flow and with varying values for the @@ -144,8 +188,8 @@ can disable the printout of the convergence history. .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_7] - :end-before: [sec_8] + :start-after: [sec_8] + :end-before: [sec_9] .. figure:: /_static/images/basics/rankine_parametric.svg :align: center @@ -218,24 +262,24 @@ offdesign simulations. .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_8] - :end-before: [sec_9] + :start-after: [sec_9] + :end-before: [sec_10] We have to save the design state of the network and run the :code:`solve` method with the :code:`design_path` specified. .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_9] - :end-before: [sec_10] + :start-after: [sec_10] + :end-before: [sec_11] Finally, we can alter the mass flow from its design value of 20 kg/s to only 50 % of its value. In this example, we calculate the efficiency and plot it. .. literalinclude:: /../tutorial/basics/rankine.py :language: python - :start-after: [sec_10] - :end-before: [sec_11] + :start-after: [sec_11] + :end-before: [sec_12] .. figure:: /_static/images/basics/rankine_partload.svg :align: center diff --git a/docs/conf.py b/docs/conf.py index ad8982f2e..5312e4b2d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,7 +34,7 @@ # master_doc = 'contents' # names, years, etc project = 'TESPy' -year = '2023' +year = '2024' author = 'Francesco Witte' copyright = '{0}, {1}'.format(year, author) diff --git a/docs/modules/networks.rst b/docs/modules/networks.rst index d5dc41f77..b564fb1d4 100644 --- a/docs/modules/networks.rst +++ b/docs/modules/networks.rst @@ -43,7 +43,7 @@ be at 10 bar, use it as upper boundary. >>> my_plant.set_attr(p_range=[0.05, 10], h_range=[15, 2000]) >>> my_plant.p_unit 'bar' - >>> my_plant.p_range_SI.tolist() + >>> my_plant.p_range_SI [5000.0, 1000000.0] .. _printout_logging_label: diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 96ccfeaab..000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -furo -sphinx>=7.2.2 -sphinxcontrib-bibtex -sphinx-copybutton -sphinx-design diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 5d6796f1a..2268fa26b 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -3,6 +3,7 @@ What's New Discover notable new features and improvements in each release +.. include:: whats_new/v0-7-5.rst .. include:: whats_new/v0-7-4.rst .. include:: whats_new/v0-7-3.rst .. include:: whats_new/v0-7-2.rst diff --git a/docs/whats_new/v0-7-5.rst b/docs/whats_new/v0-7-5.rst new file mode 100644 index 000000000..922c335ac --- /dev/null +++ b/docs/whats_new/v0-7-5.rst @@ -0,0 +1,32 @@ +v0.7.5 - Newton's Nature (July, 8, 2024) +++++++++++++++++++++++++++++++++++++++++ + +Documentation +############# +- The Rankine cycle example has been adopted to integrate a T-s diagram of the + process into the results + (`PR #514 `__). +- A bug in the results plot of the gas turbine example has been fixed + (`PR #522 `__). + +Other Features +############## +- More isolines are now available for the drum + (`PR #521 `__). + +Other Changes +############# +- Remove unused features in the github workflows and tox testing + (`PR #523 `__). +- Simplify dependency installation readthedocs builds + (`PR #524 `__). +- Update various parts of the source code to implement more maintainer-friendly + features (`PR #525 `__). +- Create :code:`numpy` 2.0 compatibility + (`PR #527 `__). + +Contributors +############ +- Francesco Witte (`@fwitte `__) +- `@Nzb0731 `__ +- `@jfreissmann `__ diff --git a/pyproject.toml b/pyproject.toml index dd3340450..cabdd7f85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,6 @@ include = [ "CHANGELOG.rst", "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", - "MANIFEST.in", "LICENSE*", "PULL_REQUEST_TEMPLATE.md", ".coveragerc", @@ -25,7 +24,7 @@ exclude = ["docs/_build"] [project] name = "tespy" -version = "0.7.4" +version = "0.7.5" description = "Thermal Engineering Systems in Python (TESPy)" readme = "README.rst" authors = [ @@ -47,12 +46,12 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "CoolProp>=6.6,<7", + "CoolProp>=6.6", "jinja2", - "matplotlib>=3.2.1,<4", - "numpy>=1.13.3,<2", - "pandas>=1.3.0,<3", - "tabulate>=0.8.2,<0.9", + "matplotlib>=3.2.1", + "numpy>=1.13.3", + "pandas>=1.3.0", + "tabulate>=0.8.2", ] license = {text = "MIT"} @@ -66,6 +65,7 @@ Changelog = "https://tespy.readthedocs.io/en/main/whats_new.html" dev = [ "build", "flit", + "fluprodia", "furo", "iapws", "pyromat", @@ -92,6 +92,7 @@ addopts = """ --pyargs --ignore=docs/conf.py --ignore=docs/scripts + --ignore=docs/_build """ testpaths = [ "src/", diff --git a/src/tespy/__init__.py b/src/tespy/__init__.py index fa062803f..6b25da46d 100644 --- a/src/tespy/__init__.py +++ b/src/tespy/__init__.py @@ -3,7 +3,7 @@ import os __datapath__ = os.path.join(importlib.resources.files("tespy"), "data") -__version__ = '0.7.4 - Newton\'s Nature' +__version__ = '0.7.5 - Newton\'s Nature' # tespy data and connections import from . import connections # noqa: F401 diff --git a/src/tespy/components/basics/cycle_closer.py b/src/tespy/components/basics/cycle_closer.py index 4d761324c..e1a455d23 100644 --- a/src/tespy/components/basics/cycle_closer.py +++ b/src/tespy/components/basics/cycle_closer.py @@ -166,8 +166,9 @@ def preprocess(self, num_nw_vars): def calc_parameters(self): r"""Postprocessing parameter calculation.""" # calculate deviation in mass flow - self.mass_deviation.val = np.abs( - self.inl[0].m.val_SI - self.outl[0].m.val_SI) + self.mass_deviation.val = abs( + self.inl[0].m.val_SI - self.outl[0].m.val_SI + ) # calculate deviation in fluid composition d1 = self.inl[0].fluid.val diff --git a/src/tespy/components/combustion/engine.py b/src/tespy/components/combustion/engine.py index 47d7d3501..238daa6c2 100644 --- a/src/tespy/components/combustion/engine.py +++ b/src/tespy/components/combustion/engine.py @@ -182,7 +182,6 @@ class CombustionEngine(CombustionChamber): ... Splitter) >>> from tespy.connections import Connection, Ref >>> from tespy.networks import Network - >>> import numpy as np >>> import shutil >>> nw = Network(p_unit='bar', T_unit='C', iterinfo=False) >>> amb = Source('ambient') diff --git a/src/tespy/components/component.py b/src/tespy/components/component.py index 8f6f16ca4..52f01037f 100644 --- a/src/tespy/components/component.py +++ b/src/tespy/components/component.py @@ -12,6 +12,8 @@ SPDX-License-Identifier: MIT """ +import math + import numpy as np from tespy.tools import logger @@ -252,19 +254,7 @@ def set_attr(self, **kwargs): self.__dict__.update({key: kwargs[key]}) elif key == 'design_path' or key == 'fkt_group': - if isinstance(kwargs[key], str): - self.__dict__.update({key: kwargs[key]}) - elif kwargs[key] is None: - self.design_path = None - elif np.isnan(kwargs[key]): - self.design_path = None - else: - msg = ( - 'Please provide the design_path parameter as string. ' - 'For unsetting use None.' - ) - logger.error(msg) - raise TypeError(msg) + self.__dict__.update({key: kwargs[key]}) self.new_design = True @@ -813,7 +803,7 @@ def set_parameters(self, mode, data): if isinstance(dc, dc_cp): if ((mode == 'offdesign' and not self.local_design) or (mode == 'design' and self.local_offdesign)): - self.get_attr(key).design = data[key] + self.get_attr(key).design = float(data[key]) else: self.get_attr(key).design = np.nan @@ -1104,7 +1094,7 @@ def calc_zeta(self, i, o): return 0 else: return ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 + (i.p.val_SI - o.p.val_SI) * math.pi ** 2 / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) ) @@ -1161,7 +1151,7 @@ def zeta_func(self, zeta='', inconn=0, outconn=0): v_i = v_mix_ph(i.p.val_SI, i.h.val_SI, i.fluid_data, i.mixing_rule, T0=i.T.val_SI) v_o = v_mix_ph(o.p.val_SI, o.h.val_SI, o.fluid_data, o.mixing_rule, T0=o.T.val_SI) return ( - data.val - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 + data.val - (i.p.val_SI - o.p.val_SI) * math.pi ** 2 / (8 * abs(i.m.val_SI) * i.m.val_SI * (v_i + v_o) / 2) ) diff --git a/src/tespy/components/heat_exchangers/base.py b/src/tespy/components/heat_exchangers/base.py index 65f6adec9..ef0cea6e9 100644 --- a/src/tespy/components/heat_exchangers/base.py +++ b/src/tespy/components/heat_exchangers/base.py @@ -10,6 +10,8 @@ SPDX-License-Identifier: MIT """ +import math + import numpy as np from tespy.components.component import Component @@ -192,6 +194,7 @@ class HeatExchanger(Component): >>> round(he_ex.T.val, 1) 18.8 >>> shutil.rmtree('./tmp', ignore_errors=True) + >>> shutil.rmtree('./report', ignore_errors=True) """ @staticmethod @@ -403,7 +406,7 @@ def calculate_td_log(self): if ttd_u == ttd_l: td_log = ttd_l else: - td_log = (ttd_l - ttd_u) / np.log((ttd_l) / (ttd_u)) + td_log = (ttd_l - ttd_u) / math.log((ttd_l) / (ttd_u)) return td_log @@ -844,7 +847,7 @@ def calc_parameters(self): else: self.td_log.val = ( (self.ttd_l.val - self.ttd_u.val) - / np.log(self.ttd_l.val / self.ttd_u.val) + / math.log(self.ttd_l.val / self.ttd_u.val) ) self.kA.val = -self.Q.val / self.td_log.val diff --git a/src/tespy/components/heat_exchangers/condenser.py b/src/tespy/components/heat_exchangers/condenser.py index 32bd77ef6..2dc2b2700 100644 --- a/src/tespy/components/heat_exchangers/condenser.py +++ b/src/tespy/components/heat_exchangers/condenser.py @@ -11,6 +11,8 @@ SPDX-License-Identifier: MIT """ +import math + import numpy as np from tespy.components.component import component_registry @@ -347,7 +349,7 @@ def calculate_td_log(self): if ttd_u == ttd_l: td_log = ttd_l else: - td_log = (ttd_l - ttd_u) / np.log((ttd_l) / (ttd_u)) + td_log = (ttd_l - ttd_u) / math.log((ttd_l) / (ttd_u)) return td_log @@ -491,7 +493,7 @@ def calc_parameters(self): for num, (i, o) in enumerate(zip(self.inl, self.outl)): self.get_attr(f"pr{num + 1}").val = o.p.val_SI / i.p.val_SI self.get_attr(f"zeta{num + 1}").val = ( - (i.p.val_SI - o.p.val_SI) * np.pi ** 2 + (i.p.val_SI - o.p.val_SI) * math.pi ** 2 / (4 * i.m.val_SI ** 2 * (i.vol.val_SI + o.vol.val_SI)) ) @@ -503,6 +505,6 @@ def calc_parameters(self): else: self.td_log.val = ( (self.ttd_l.val - self.ttd_u.val) - / np.log(self.ttd_l.val / self.ttd_u.val) + / math.log(self.ttd_l.val / self.ttd_u.val) ) self.kA.val = -self.Q.val / self.td_log.val diff --git a/src/tespy/components/heat_exchangers/parabolic_trough.py b/src/tespy/components/heat_exchangers/parabolic_trough.py index fd8c0e005..0e4ae4e1f 100644 --- a/src/tespy/components/heat_exchangers/parabolic_trough.py +++ b/src/tespy/components/heat_exchangers/parabolic_trough.py @@ -163,7 +163,7 @@ class ParabolicTrough(SimpleHeatExchanger): >>> from tespy.components import Sink, Source, ParabolicTrough >>> from tespy.connections import Connection >>> from tespy.networks import Network - >>> import numpy as np + >>> import math >>> import shutil >>> nw = Network() >>> nw.set_attr(p_unit='bar', T_unit='C', h_unit='kJ / kg', iterinfo=False) @@ -182,7 +182,7 @@ class ParabolicTrough(SimpleHeatExchanger): :math:`\text{m}^2` for simplicity reasons. >>> aoi = 20 - >>> E = 1000 * np.cos(aoi / 180 * np.pi) + >>> E = 1000 * math.cos(aoi / 180 * math.pi) >>> pt.set_attr(pr=1, aoi=aoi, doc=1, ... Tamb=20, A=1, eta_opt=0.816, c_1=0.0622, c_2=0.00023, E=E, ... iam_1=-1.59e-3, iam_2=9.77e-5) @@ -208,7 +208,7 @@ class ParabolicTrough(SimpleHeatExchanger): well as the heat transfer at different operating points. >>> aoi = 30 - >>> E = 800 * np.cos(aoi / 180 * np.pi) + >>> E = 800 * math.cos(aoi / 180 * math.pi) >>> pt.set_attr(A=pt.A.val, aoi=aoi, Q=None, E=E) >>> inc.set_attr(T=150) >>> outg.set_attr(T=None) diff --git a/src/tespy/components/heat_exchangers/simple.py b/src/tespy/components/heat_exchangers/simple.py index 8615d644a..a8b7614a0 100644 --- a/src/tespy/components/heat_exchangers/simple.py +++ b/src/tespy/components/heat_exchangers/simple.py @@ -11,6 +11,7 @@ SPDX-License-Identifier: MIT """ +import math import warnings import numpy as np @@ -347,13 +348,13 @@ def darcy_func(self): v_i = i.calc_vol(T0=i.T.val_SI) v_o = o.calc_vol(T0=o.T.val_SI) - Re = 4 * abs(i.m.val_SI) / (np.pi * self.D.val * (visc_i + visc_o) / 2) + Re = 4 * abs(i.m.val_SI) / (math.pi * self.D.val * (visc_i + visc_o) / 2) return ( (i.p.val_SI - o.p.val_SI) - 8 * abs(i.m.val_SI) * i.m.val_SI * (v_i + v_o) / 2 * self.L.val * dff(Re, self.ks.val, self.D.val) - / (np.pi ** 2 * self.D.val ** 5) + / (math.pi ** 2 * self.D.val ** 5) ) def darcy_func_doc(self, label): @@ -450,10 +451,12 @@ def hazen_williams_func(self): v_o = o.calc_vol(T0=o.T.val_SI) return ( - (i.p.val_SI - o.p.val_SI) * np.sign(i.m.val_SI) - - (10.67 * abs(i.m.val_SI) ** 1.852 * self.L.val / - (self.ks_HW.val ** 1.852 * self.D.val ** 4.871)) * - (9.81 * ((v_i + v_o) / 2) ** 0.852)) + math.copysign(i.p.val_SI - o.p.val_SI, i.m.val_SI) + - ( + 10.67 * abs(i.m.val_SI) ** 1.852 * self.L.val / + (self.ks_HW.val ** 1.852 * self.D.val ** 4.871) + ) * (9.81 * ((v_i + v_o) / 2) ** 0.852) + ) def hazen_williams_func_doc(self, label): r""" @@ -545,9 +548,9 @@ def kA_group_func(self): if (ttd_1 / ttd_2) < 0: td_log = (ttd_2 + ttd_1) / 2 elif ttd_1 > ttd_2: - td_log = (ttd_1 - ttd_2) / np.log(ttd_1 / ttd_2) + td_log = (ttd_1 - ttd_2) / math.log(ttd_1 / ttd_2) elif ttd_1 < ttd_2: - td_log = (ttd_2 - ttd_1) / np.log(ttd_2 / ttd_1) + td_log = (ttd_2 - ttd_1) / math.log(ttd_2 / ttd_1) else: # both values are equal td_log = ttd_2 @@ -659,9 +662,9 @@ def kA_char_group_func(self): if (ttd_1 / ttd_2) < 0: td_log = (ttd_2 + ttd_1) / 2 elif ttd_1 > ttd_2: - td_log = (ttd_1 - ttd_2) / np.log(ttd_1 / ttd_2) + td_log = (ttd_1 - ttd_2) / math.log(ttd_1 / ttd_2) elif ttd_1 < ttd_2: - td_log = (ttd_2 - ttd_1) / np.log(ttd_2 / ttd_1) + td_log = (ttd_2 - ttd_1) / math.log(ttd_2 / ttd_1) else: # both values are equal td_log = ttd_2 @@ -895,9 +898,9 @@ def calc_parameters(self): if (ttd_1 / ttd_2) < 0: td_log = np.nan if ttd_1 > ttd_2: - td_log = (ttd_1 - ttd_2) / np.log(ttd_1 / ttd_2) + td_log = (ttd_1 - ttd_2) / math.log(ttd_1 / ttd_2) elif ttd_1 < ttd_2: - td_log = (ttd_2 - ttd_1) / np.log(ttd_2 / ttd_1) + td_log = (ttd_2 - ttd_1) / math.log(ttd_2 / ttd_1) else: # both values are equal td_log = ttd_1 diff --git a/src/tespy/components/nodes/drum.py b/src/tespy/components/nodes/drum.py index 598fa0914..cebb0fde8 100644 --- a/src/tespy/components/nodes/drum.py +++ b/src/tespy/components/nodes/drum.py @@ -10,6 +10,8 @@ SPDX-License-Identifier: MIT """ +import warnings + import numpy as np from tespy.components.component import component_registry @@ -99,7 +101,6 @@ class Drum(DropletSeparator): >>> from tespy.tools.characteristics import CharLine >>> from tespy.tools.characteristics import load_default_char as ldc >>> import shutil - >>> import numpy as np >>> nw = Network(T_unit='C', p_unit='bar', h_unit='kJ / kg', iterinfo=False) >>> fa = Source('feed ammonia') >>> amb_in = Source('air inlet') @@ -416,9 +417,22 @@ def get_plotting_data(self): data : dict A nested dictionary containing the keywords required by the :code:`calc_individual_isoline` method of the - :code:`FluidPropertyDiagram` class. First level keys are the - connection index ('in1' -> 'out1', therefore :code:`1` etc.). + :code:`FluidPropertyDiagram` class. The keys :code:`2` and + :code:`3` connect the saturated liquid-vapor mixture of 'in1' with + the saturated liquid ('out1') and saturated vapor ('out2'), while + the keys :code:`4` and :code:`5` connect the (superheated) gas of + 'in2' with the same. + The key :code:`1` connects both saturated states. """ + msg = ( + """ + The keys will change in the next major release. Keys '1' to '4' + will contain the isolines now available through the keys '2' to '5'. + The old contents of key '1' (outlet 1 to outlet 2) will be moved to + key '5'. + """ + ) + warnings.warn(msg, FutureWarning) return { 1: { 'isoline_property': 'p', @@ -428,4 +442,41 @@ def get_plotting_data(self): 'starting_point_value': self.outl[0].vol.val, 'ending_point_property': 'v', 'ending_point_value': self.outl[1].vol.val - }} + }, + 2: { + 'isoline_property': 'p', + 'isoline_value': self.inl[0].p.val, + 'isoline_value_end': self.outl[0].p.val, + 'starting_point_property': 'v', + 'starting_point_value': self.inl[0].vol.val, + 'ending_point_property': 'v', + 'ending_point_value': self.outl[0].vol.val + }, + 3: { + 'isoline_property': 'p', + 'isoline_value': self.inl[0].p.val, + 'isoline_value_end': self.outl[1].p.val, + 'starting_point_property': 'v', + 'starting_point_value': self.inl[0].vol.val, + 'ending_point_property': 'v', + 'ending_point_value': self.outl[1].vol.val + }, + 4: { + 'isoline_property': 'p', + 'isoline_value': self.inl[1].p.val, + 'isoline_value_end': self.outl[0].p.val, + 'starting_point_property': 'v', + 'starting_point_value': self.inl[1].vol.val, + 'ending_point_property': 'v', + 'ending_point_value': self.outl[0].vol.val + }, + 5: { + 'isoline_property': 'p', + 'isoline_value': self.inl[1].p.val, + 'isoline_value_end': self.outl[1].p.val, + 'starting_point_property': 'v', + 'starting_point_value': self.inl[1].vol.val, + 'ending_point_property': 'v', + 'ending_point_value': self.outl[1].vol.val + } + } diff --git a/src/tespy/components/nodes/merge.py b/src/tespy/components/nodes/merge.py index be8570fd5..53f8b9ba8 100644 --- a/src/tespy/components/nodes/merge.py +++ b/src/tespy/components/nodes/merge.py @@ -87,7 +87,6 @@ class Merge(NodeBase): >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> import shutil - >>> import numpy as np >>> nw = Network(p_unit='bar', iterinfo=False) >>> so1 = Source('source1') >>> so2 = Source('source2') diff --git a/src/tespy/components/nodes/separator.py b/src/tespy/components/nodes/separator.py index 16369fa40..17473fc30 100644 --- a/src/tespy/components/nodes/separator.py +++ b/src/tespy/components/nodes/separator.py @@ -93,9 +93,7 @@ class Separator(NodeBase): >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> import shutil - >>> import numpy as np - >>> nw = Network(p_unit='bar', T_unit='C', - ... iterinfo=False) + >>> nw = Network(p_unit='bar', T_unit='C', iterinfo=False) >>> so = Source('source') >>> si1 = Sink('sink1') >>> si2 = Sink('sink2') diff --git a/src/tespy/components/nodes/splitter.py b/src/tespy/components/nodes/splitter.py index 18faa3411..7ef70f7fd 100644 --- a/src/tespy/components/nodes/splitter.py +++ b/src/tespy/components/nodes/splitter.py @@ -83,9 +83,7 @@ class Splitter(NodeBase): >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> import shutil - >>> import numpy as np - >>> nw = Network(p_unit='bar', T_unit='C', - ... iterinfo=False) + >>> nw = Network(p_unit='bar', T_unit='C', iterinfo=False) >>> so = Source('source') >>> si1 = Sink('sink1') >>> si2 = Sink('sink2') diff --git a/src/tespy/components/turbomachinery/pump.py b/src/tespy/components/turbomachinery/pump.py index 87b10c597..43ed38d3f 100644 --- a/src/tespy/components/turbomachinery/pump.py +++ b/src/tespy/components/turbomachinery/pump.py @@ -110,7 +110,6 @@ class Pump(Turbomachine): >>> from tespy.connections import Connection >>> from tespy.networks import Network >>> from tespy.tools.characteristics import CharLine - >>> import numpy as np >>> import shutil >>> nw = Network(p_unit='bar', T_unit='C', h_unit='kJ / kg', v_unit='l / s', ... iterinfo=False) diff --git a/src/tespy/components/turbomachinery/turbine.py b/src/tespy/components/turbomachinery/turbine.py index be292eac7..ff1b8c494 100644 --- a/src/tespy/components/turbomachinery/turbine.py +++ b/src/tespy/components/turbomachinery/turbine.py @@ -269,13 +269,11 @@ def cone_func(self): vol = i.calc_vol(T0=i.T.val_SI) return ( - i.m.val_SI + i.m.design * i.p.val_SI / i.p.design - * np.sqrt(i.p.design * i.vol.design / (i.p.val_SI * vol)) - * np.sqrt( - abs( + * (i.p.design * i.vol.design / (i.p.val_SI * vol)) ** 0.5 + * abs( (1 - (o.p.val_SI / i.p.val_SI) ** ((n + 1) / n)) / (1 - (self.pr.design) ** ((n + 1) / n)) - ) - ) + ) ** 0.5 ) def cone_func_doc(self, label): diff --git a/src/tespy/connections/bus.py b/src/tespy/connections/bus.py index ddfd8e1a4..9f0b6a409 100644 --- a/src/tespy/connections/bus.py +++ b/src/tespy/connections/bus.py @@ -52,7 +52,6 @@ class Bus: >>> from tespy.connections import Connection, Ref, Bus >>> from tespy.networks import Network >>> from tespy.tools import CharLine - >>> import numpy as np >>> import shutil >>> nw = Network(p_unit='bar', T_unit='C', p_range=[0.5, 10], iterinfo=False) >>> amb = Source('ambient') diff --git a/src/tespy/connections/connection.py b/src/tespy/connections/connection.py index b60261628..4f5c20124 100644 --- a/src/tespy/connections/connection.py +++ b/src/tespy/connections/connection.py @@ -140,7 +140,6 @@ class Connection: >>> from tespy.components import Sink, Source >>> from tespy.connections import Connection, Ref - >>> import numpy as np >>> so1 = Source('source1') >>> so2 = Source('source2') >>> si1 = Sink('sink1') @@ -439,13 +438,8 @@ def set_attr(self, **kwargs): # design path elif key == 'design_path': - if isinstance(kwargs[key], str) or kwargs[key] is None: - self.__dict__.update({key: kwargs[key]}) - self.new_design = True - else: - msg = "Provide the a string or None for 'design_path'." - logger.error(msg) - raise TypeError(msg) + self.__dict__.update({key: kwargs[key]}) + self.new_design = True # other boolean keywords elif key in ['printout', 'local_design', 'local_offdesign']: diff --git a/src/tespy/networks/network.py b/src/tespy/networks/network.py index 0120b20c4..c41963a1f 100644 --- a/src/tespy/networks/network.py +++ b/src/tespy/networks/network.py @@ -14,6 +14,7 @@ SPDX-License-Identifier: MIT """ import json +import math import os from time import time @@ -217,17 +218,17 @@ def set_defaults(self): logger.debug(msg[:-1]) # generic value range - self.m_range_SI = np.array([-1e12, 1e12]) - self.p_range_SI = np.array([2e2, 300e5]) - self.h_range_SI = np.array([1e3, 7e6]) + self.m_range_SI = [-1e12, 1e12] + self.p_range_SI = [2e2, 300e5] + self.h_range_SI = [1e3, 7e6] for prop in ['m', 'p', 'h']: limits = self.get_attr(prop + '_range_SI') msg = ( - 'Default ' + fpd[prop]['text'] + ' limits\n' - 'min: ' + str(limits[0]) + ' ' + - self.get_attr(prop + '_unit') + '\n' - 'max: ' + str(limits[1]) + ' ' + self.get_attr(prop + '_unit')) + f"Default {fpd[prop]['text']} limits\n" + f"min: {limits[0]} {self.get_attr(prop + '_unit')}\n" + f"max: {limits[1]} {self.get_attr(prop + '_unit')}" + ) logger.debug(msg) def set_attr(self, **kwargs): @@ -289,10 +290,10 @@ def set_attr(self, **kwargs): if f'{prop}_range' in kwargs: if isinstance(kwargs[f'{prop}_range'], list): self.__dict__.update({ - f'{prop}_range_SI': hlp.convert_to_SI( - prop, np.array(kwargs[f'{prop}_range']), + f'{prop}_range_SI': [hlp.convert_to_SI( + prop, value, self.get_attr(f'{prop}_unit') - ) + ) for value in kwargs[f'{prop}_range']] }) else: msg = f'Specify the range as list: [{prop}_min, {prop}_max]' @@ -309,11 +310,12 @@ def set_attr(self, **kwargs): # update non SI value ranges for prop in ['m', 'p', 'h']: + SI_range = self.get_attr(f'{prop}_range_SI') self.__dict__.update({ - f'{prop}_range': hlp.convert_from_SI( - prop, self.get_attr(f'{prop}_range_SI'), + f'{prop}_range': [hlp.convert_from_SI( + prop, SI_value, self.get_attr(f'{prop}_unit') - ) + ) for SI_value in SI_range] }) self.iterinfo = kwargs.get('iterinfo', self.iterinfo) @@ -1304,9 +1306,7 @@ def init_design(self): if cp.local_offdesign: if cp.design_path is not None: # read design point information - path = hlp.modify_path_os( - f"{cp.design_path}/components/{c}.csv" - ) + path = os.path.join(cp.design_path, "components", f"{c}.csv") msg = ( f"Reading design point information for component " f"{cp.label} of type {c} from path {path}." @@ -1396,7 +1396,7 @@ def init_offdesign_params(self): df_comps = self.comps.loc[components_with_parameters].copy() # iter through unique types of components (class names) for c in df_comps['comp_type'].unique(): - path = hlp.modify_path_os(f"{self.design_path}/components/{c}.csv") + path = os.path.join(self.design_path, "components", f"{c}.csv") msg = ( f"Reading design point information for components of type {c} " f"from path {path}." @@ -1411,8 +1411,8 @@ def init_offdesign_params(self): comp = self.comps.loc[c_label, 'object'] # read data of components with individual design_path if comp.design_path is not None: - path_c = hlp.modify_path_os( - f"{comp.design_path}/components/{c}.csv" + path_c = os.path.join( + comp.design_path, "components", f"{c}.csv" ) msg = ( f"Reading design point information for component " @@ -1438,21 +1438,16 @@ def init_offdesign_params(self): logger.debug(msg) if len(self.busses) > 0: - path = hlp.modify_path_os(f"{self.design_path}/busses.json") + path = os.path.join(self.design_path, "busses.json") with open(path, "r", encoding="utf-8") as f: bus_data = json.load(f) for b in bus_data: for comp, value in bus_data[b].items(): comp = self.get_comp(comp) - self.busses[b].comps.loc[comp, "P_ref"] = value + self.busses[b].comps.loc[comp, "P_ref"] = float(value) # read connection design point information - msg = ( - "Reading design point information for connections from " - f"{self.design_path}/connections.csv." - ) - logger.debug(msg) df = self.init_read_connections(self.design_path) # iter through connections @@ -1520,11 +1515,14 @@ def init_conn_design_params(self, c, df): conn = df.loc[c.label] for var in fpd.keys(): c.get_attr(var).design = hlp.convert_to_SI( - var, conn[var], conn[f"{var}_unit"] + var, float(conn[var]), conn[f"{var}_unit"] ) - c.vol.design = c.v.design / c.m.design + if c.m.design != 0.0: + c.vol.design = c.v.design / c.m.design + else: + c.vol.design = math.inf for fluid in c.fluid.val: - c.fluid.design[fluid] = conn[fluid] + c.fluid.design[fluid] = float(conn[fluid]) def init_conn_params_from_path(self, c, df): r""" @@ -1551,12 +1549,12 @@ def init_conn_params_from_path(self, c, df): for prop in ['m', 'p', 'h']: data = c.get_attr(prop) - data.val0 = conn[prop] + data.val0 = float(conn[prop]) data.unit = conn[prop + '_unit'] for fluid in c.fluid.is_var: - c.fluid.val[fluid] = conn[fluid] - c.fluid.val0[fluid] = c.fluid.val[fluid] + c.fluid.val[fluid] = float(conn[fluid]) + c.fluid.val0[fluid] = float(c.fluid.val[fluid]) c.good_starting_values = True @@ -1630,8 +1628,7 @@ def init_offdesign(self): msg += var + ', ' if switched: - msg = (msg[:-2] + ' to design value at component ' + - cp.label + '.') + msg = f"{msg[:-2]} to design value at component {cp.label}." logger.debug(msg) # start component initialisation @@ -1805,7 +1802,7 @@ def init_val0(self, c, key): # starting value for mass flow is random between 1 and 2 kg/s # (should be generated based on some hash maybe?) if key == 'm': - c.get_attr(key).val0 = np.random.random() + 1 + c.get_attr(key).val0 = float(np.random.random() + 1) # generic starting values for pressure and enthalpy else: @@ -1841,7 +1838,11 @@ def init_read_connections(base_path): base_path : str Path to network information. """ - path = hlp.modify_path_os(base_path + '/connections.csv') + path = os.path.join(base_path, 'connections.csv') + msg = ( + f"Reading design point information for connections from {path}." + ) + logger.debug(msg) df = pd.read_csv(path, index_col=0, delimiter=';', decimal='.') return df @@ -2174,9 +2175,9 @@ def iterinfo_body(self, print_results=True): # This should not be hardcoded here. if residual_norm > np.finfo(float).eps * 100: - progress_min = np.log(ERR) - progress_max = np.log(ERR ** 0.5) * -1 - progress_val = np.log(max(residual_norm, ERR)) * -1 + progress_min = math.log(ERR) + progress_max = math.log(ERR ** 0.5) * -1 + progress_val = math.log(max(residual_norm, ERR)) * -1 # Scale to 0-1 progres_scaled = ( (progress_val - progress_min) @@ -2209,7 +2210,7 @@ def iterinfo_tail(self, print_results=True): """Print tail of convergence progress.""" num_iter = self.iter + 1 clc_time = self.end_time - self.start_time - num_ips = num_iter / clc_time if clc_time > 1e-10 else np.Inf + num_ips = num_iter / clc_time if clc_time > 1e-10 else np.inf msg = '-' * 7 + '+------------' * 7 logger.progress(100, msg) msg = ( @@ -2239,19 +2240,26 @@ def matrix_inversion(self): self.increment = self.residual * 0 def update_variables(self): + # cast dtype to float from numpy float64 + # this is necessary to keep the doctests running and note make them + # look ugly all over the place + # I have yet to come up with a better idea, or vectorize all operations + # which requires major changes in tespy + increment = [float(val) for val in self.increment] # add the increment for data in self.variables_dict.values(): if data["variable"] in ["m", "h"]: container = data["obj"].get_attr(data["variable"]) - container.val_SI += self.increment[container.J_col] + container.val_SI += increment[container.J_col] elif data["variable"] == "p": container = data["obj"].p - increment = self.increment[container.J_col] - relax = max(1, -2 * increment / container.val_SI) - container.val_SI += increment / relax + relax = max( + 1, -2 * increment[container.J_col] / container.val_SI + ) + container.val_SI += increment[container.J_col] / relax elif data["variable"] == "fluid": container = data["obj"].fluid - container.val[data["fluid"]] += self.increment[ + container.val[data["fluid"]] += increment[ container.J_col[data["fluid"]] ] @@ -2261,7 +2269,7 @@ def update_variables(self): container.val[data["fluid"]] = 1 else: # add increment - data["obj"].val += self.increment[data["obj"].J_col] + data["obj"].val += increment[data["obj"].J_col] # keep value within specified value range if data["obj"].val < data["obj"].min_val: @@ -2512,7 +2520,7 @@ def process_busses(self): result = [cmp_val, bus_val, eff, design_value] self.results[b.label].loc[cp.label] = result - b.P.val = self.results[b.label]['bus value'].sum() + b.P.val = float(self.results[b.label]['bus value'].sum()) def print_results(self, colored=True, colors=None, print_results=True): r"""Print the calculations results to prompt.""" @@ -2651,13 +2659,13 @@ def print_components(self, c, *args): def export(self, path): """Export the network structure and parametrization.""" - path, path_comps = self._modify_export_paths(path) + path, path_comps = self._create_export_paths(path) self.export_network(path) self.export_connections(path) self.export_components(path_comps) self.export_busses(path) - def save(self, path, **kwargs): + def save(self, path): r""" Save the results to results files. @@ -2676,28 +2684,21 @@ def save(self, path, **kwargs): characteristics as well as .csv files for all types of components within your network. """ - path, path_comps = self._modify_export_paths(path) + path, path_comps = self._create_export_paths(path) # save relevant design point information self.save_connections(path) self.save_components(path_comps) self.save_busses(path) - def _modify_export_paths(self, path): - - if path[-1] != '/' and path[-1] != '\\': - path += '/' - path = hlp.modify_path_os(path) - + def _create_export_paths(self, path): logger.debug('Saving network to path %s.', path) # creat path, if non existent - if not os.path.exists(path): - os.makedirs(path) + os.makedirs(path, exist_ok=True) # create path for component folder if non existent - path_comps = hlp.modify_path_os(path + 'components/') - if not os.path.exists(path_comps): - os.makedirs(path_comps) + path_comps = os.path.join(path, "components") + os.makedirs(path_comps, exist_ok=True) return path, path_comps @@ -2710,7 +2711,7 @@ def export_network(self, fn): fn : str Path/filename for the network configuration file. """ - with open(fn + 'network.json', 'w') as f: + with open(os.path.join(fn, 'network.json'), 'w') as f: json.dump(self._serialize(), f, indent=4) logger.debug('Network information saved to %s.', fn) @@ -2725,7 +2726,7 @@ def save_connections(self, fn): Path/filename for the file. """ self.results["Connection"].to_csv( - fn + "connections.csv", sep=';', decimal='.', index=True, na_rep='nan' + os.path.join(fn, "connections.csv"), sep=';', decimal='.', index=True, na_rep='nan' ) logger.debug('Connection information saved to %s.', fn) @@ -2739,7 +2740,7 @@ def save_components(self, path): Path/filename for the file. """ for c in self.comps['comp_type'].unique(): - fn = path + c + '.csv' + fn = os.path.join(path, f"{c}.csv") self.results[c].to_csv(fn, sep=';', decimal='.', index=True, na_rep='nan') logger.debug('Component information (%s) saved to %s.', c, fn) @@ -2756,7 +2757,7 @@ def save_busses(self, fn): bus_data = {} for label, bus in self.busses.items(): bus_data[label] = self.results[label]["design value"].to_dict() - fn = fn + 'busses.json' + fn = os.path.join(fn, "busses.json") with open(fn, "w", encoding="utf-8") as f: json.dump(bus_data, f, indent=4) logger.debug('Bus information saved to %s.', fn) @@ -2766,7 +2767,7 @@ def export_connections(self, fn): for c in self.conns["object"]: connections.update(c._serialize()) - fn = fn + "connections.json" + fn = os.path.join(fn, "connections.json") with open(fn, "w", encoding="utf-8") as f: json.dump(connections, f, indent=4) logger.debug('Connection information exported to %s.', fn) @@ -2777,7 +2778,7 @@ def export_components(self, fn): for cp in self.comps.loc[self.comps["comp_type"] == c, "object"]: components.update(cp._serialize()) - fname = f"{fn}{c}.json" + fname = os.path.join(fn, f"{c}.json") with open(fname, "w", encoding="utf-8") as f: json.dump(components, f, indent=4) logger.debug('Component information exported to %s.', fname) @@ -2787,7 +2788,7 @@ def export_busses(self, fn): busses = {} for bus in self.busses.values(): busses.update(bus._serialize()) - fn = fn + 'busses.json' + fn = os.path.join(fn, 'busses.json') with open(fn, "w", encoding="utf-8") as f: json.dump(busses, f, indent=4) logger.debug('Bus information exported to %s.', fn) diff --git a/src/tespy/networks/network_reader.py b/src/tespy/networks/network_reader.py index c69cb1197..77e038bb7 100644 --- a/src/tespy/networks/network_reader.py +++ b/src/tespy/networks/network_reader.py @@ -29,7 +29,6 @@ from tespy.tools.data_containers import DataContainer as dc from tespy.tools.data_containers import FluidProperties as dc_prop from tespy.tools.fluid_properties.wrappers import wrapper_registry -from tespy.tools.helpers import modify_path_os def load_network(path): @@ -73,7 +72,6 @@ def load_network(path): from a pipeline and throttled to the required pressure while keeping the temperature at a constant value. - >>> import numpy as np >>> from tespy.components import (Sink, Source, CombustionChamber, ... Compressor, Turbine, SimpleHeatExchanger) >>> from tespy.connections import Connection, Ref, Bus @@ -175,30 +173,26 @@ def load_network(path): >>> shutil.rmtree('./exported_nwk', ignore_errors=True) >>> shutil.rmtree('./design_state', ignore_errors=True) """ - if path[-1] != '/' and path[-1] != '\\': - path += '/' + path_comps = os.path.join(path, 'components') - path_comps = modify_path_os(path + 'components/') - path = modify_path_os(path) - - msg = 'Reading network data from base path ' + path + '.' + msg = f'Reading network data from base path {path}.' logger.info(msg) # load components comps = {} module_name = "tespy.components" - module = importlib.import_module(module_name) + _ = importlib.import_module(module_name) files = os.listdir(path_comps) for f in files: - fn = path_comps + f + fn = os.path.join(path_comps, f) component = f.replace(".json", "") msg = f"Reading component data ({component}) from {fn}." logger.debug(msg) - with open(path_comps + f, "r", encoding="utf-8") as c: + with open(fn, "r", encoding="utf-8") as c: data = json.load(c) target_class = component_registry.items[component] @@ -211,7 +205,7 @@ def load_network(path): nw = _construct_network(path) # load connections - fn = path + 'connections.json' + fn = os.path.join(path, 'connections.json') msg = f"Reading connection data from {fn}." logger.debug(msg) @@ -228,7 +222,7 @@ def load_network(path): logger.info(msg) # load busses - fn = path + 'busses.json' + fn = os.path.join(path, 'busses.json') if os.path.isfile(fn): msg = f"Reading bus data from {fn}." @@ -309,7 +303,8 @@ def _construct_network(path): TESPy network object. """ # read network .json-file - with open(path + 'network.json', 'r') as f: + fn = os.path.join(path, 'network.json') + with open(fn, 'r') as f: data = json.load(f) # create network object with its properties @@ -343,7 +338,7 @@ def _construct_connections(data, comps): arglist_ref = [_ for _ in data[list(data.keys())[0]] if "ref" in _] module_name = "tespy.tools.fluid_properties.wrappers" - module = importlib.import_module(module_name) + _ = importlib.import_module(module_name) for label, conn in data.items(): conns[label] = Connection( diff --git a/src/tespy/tools/analyses.py b/src/tespy/tools/analyses.py index c3dba2de3..5a246c953 100644 --- a/src/tespy/tools/analyses.py +++ b/src/tespy/tools/analyses.py @@ -272,7 +272,7 @@ class :py:class:`tespy.tools.analyses.ExergyAnalysis` >>> ean.analyse(pamb=pamb, Tamb=Tamb) >>> abs(round(ean.network_data['E_F'] - ean.network_data['E_P'] - ... ean.network_data['E_L'] - ean.network_data['E_D'], 3)) - 0.0 + np.float64(0.0) >>> ();ean.print_results();() # doctest: +ELLIPSIS (...) diff --git a/src/tespy/tools/characteristics.py b/src/tespy/tools/characteristics.py index 29c79992e..99d9440c2 100644 --- a/src/tespy/tools/characteristics.py +++ b/src/tespy/tools/characteristics.py @@ -68,13 +68,15 @@ def __init__( self.y = self.y.astype(float) if len(self.x) != len(self.y): - msg = ('Please provide the same amount of x-values and y-values. ' - 'Number of x-values is ' + str(len(self.x)) + ', number of ' - 'y-values is ' + str(len(self.y)) + ' for CharLine.') + msg = ( + "Please provide the same amount of x-values and y-values. " + f"Number of x-values is {len(self.x)}, number of y-values is " + f"{len(self.y)} for CharLine." + ) logger.error(msg) raise ValueError(msg) - msg = ('Created characteristic line function.') + msg = 'Created characteristic line function.' logger.debug(msg) def evaluate(self, x): @@ -113,15 +115,15 @@ def evaluate(self, x): if self.extrapolate: xpos = -1 else: - return self.y[-1] + return float(self.y[-1]) elif xpos == 0: if self.extrapolate: xpos = 1 else: - return self.y[0] + return float(self.y[0]) yfrac = (x - self.x[xpos - 1]) / (self.x[xpos] - self.x[xpos - 1]) - return self.y[xpos - 1] + yfrac * (self.y[xpos] - self.y[xpos - 1]) + return float(self.y[xpos - 1] + yfrac * (self.y[xpos] - self.y[xpos - 1])) def get_domain_errors(self, x, c): r""" @@ -133,14 +135,16 @@ def get_domain_errors(self, x, c): Input value for linear interpolation. """ if x > self.x[-1]: - msg = ('Operating point above characteristic line range: ' - 'X=' + str(round(x, 3)) + ' with maximum of ' + - str(self.x[-1]) + ' at component ' + c + '.') + msg = ( + "Operating point above characteristic line range: X=" + f"{round(x, 3)} with maximum of {self.x[-1]} at component {c}." + ) logger.warning(msg) elif x < self.x[0]: - msg = ('Operating point below characteristic line range: ' - 'X=' + str(round(x, 3)) + ' with minimum of ' + - str(self.x[0]) + ' at component ' + c + '.') + msg = ( + "Operating point belpw characteristic line range: X=" + f"{round(x, 3)} with minimum of {self.x[1]} at component {c}." + ) logger.warning(msg) def get_attr(self, key): @@ -342,7 +346,7 @@ def evaluate(self, x, y): z = z_0 + \frac{y-y_0}{y_1-y_0} \cdot \left(z_1-z_0 \right) """ - return self.evaluate_y(y, *self.evaluate_x(x)) + return float(self.evaluate_y(y, *self.evaluate_x(x))) def get_domain_errors_x(self, x, c): r""" diff --git a/src/tespy/tools/document_models.py b/src/tespy/tools/document_models.py index 4c26fb92b..67fefb37d 100644 --- a/src/tespy/tools/document_models.py +++ b/src/tespy/tools/document_models.py @@ -47,17 +47,10 @@ def document_model(nw, path='report', filename='report.tex', fmt={}): section in online documentation. """ # prepare filestructure - if path[-1] != '/' and path[-1] != '\\': - path += '/' - - path = hlp.modify_path_os(path) - fig_path = hlp.modify_path_os(path + 'figures/') + fig_path = os.path.join(path, "figures") # create paths, if non existent - if not os.path.exists(path): - os.makedirs(path) - if not os.path.exists(fig_path): - os.makedirs(fig_path) + os.makedirs(fig_path, exist_ok=True) rpt = set_defaults(nw) rpt = hlp.merge_dicts(rpt, fmt) @@ -72,7 +65,7 @@ def document_model(nw, path='report', filename='report.tex', fmt={}): if rpt['latex_body']: latex += r'\end{document}' - with open(path + filename, 'w') as f: + with open(os.path.join(path, filename), 'w') as f: f.write(latex) f.close() @@ -1047,7 +1040,7 @@ def create_latex_CharLine(component, param, data, path, group=None): local_path = ( 'figures/' + cp + '_CharLine_' + param + '_' + component.label.replace(' ', '_') + '.pdf') - figname = path + local_path + figname = os.path.join(path, local_path) xlabel = ( r'$X=' + component.get_char_expr_doc( data.param, **data.char_params) + '$') @@ -1091,7 +1084,7 @@ def create_latex_CharMap(component, param, data, path, group=None): local_path = ( 'figures/' + cp + '_CharMap_' + param + '_' + component.label.replace(' ', '_') + '.pdf') - figname = path + local_path + figname = os.path.join(path, local_path) xlabel = ('$Y$') ylabel = r'$f\left(Y,\vec{Y},\vec{Z}\right)$' data.char_func.plot(figname, '', xlabel, ylabel) diff --git a/src/tespy/tools/fluid_properties/helpers.py b/src/tespy/tools/fluid_properties/helpers.py index c085a4509..ede4b7641 100644 --- a/src/tespy/tools/fluid_properties/helpers.py +++ b/src/tespy/tools/fluid_properties/helpers.py @@ -11,6 +11,8 @@ SPDX-License-Identifier: MIT """ +import math + import CoolProp.CoolProp as CP import numpy as np @@ -291,7 +293,7 @@ def hanakov(re): darcy_friction_factor : float Darcy friction factor. """ - return (1.8 * np.log10(re) - 1.5) ** (-2) + return (1.8 * math.log10(re) - 1.5) ** (-2) def prandtl_karman(reynolds, darcy_friction_factor, **kwargs): @@ -314,7 +316,7 @@ def prandtl_karman(reynolds, darcy_friction_factor, **kwargs): Darcy friction factor. """ return ( - 2 * np.log10(reynolds * darcy_friction_factor ** 0.5) + 2 * math.log10(reynolds * darcy_friction_factor ** 0.5) - 0.8 - 1 / darcy_friction_factor ** 0.5 ) @@ -322,7 +324,7 @@ def prandtl_karman(reynolds, darcy_friction_factor, **kwargs): def prandtl_karman_derivative(reynolds, darcy_friction_factor, **kwargs): """Calculate derivative for Prandtl and v. Kármán equation.""" return ( - 1 / (darcy_friction_factor * np.log(10)) + 1 / (darcy_friction_factor * math.log(10)) + 0.5 * darcy_friction_factor ** (-1.5) ) @@ -353,7 +355,7 @@ def colebrook(reynolds, ks, diameter, darcy_friction_factor, **kwargs): Darcy friction factor. """ return ( - 2 * np.log10( + 2 * math.log10( 2.51 / (reynolds * darcy_friction_factor ** 0.5) + ks / (3.71 * diameter) ) + 1 / darcy_friction_factor ** 0.5 diff --git a/src/tespy/tools/fluid_properties/mixtures.py b/src/tespy/tools/fluid_properties/mixtures.py index 645537783..50eb7cf50 100644 --- a/src/tespy/tools/fluid_properties/mixtures.py +++ b/src/tespy/tools/fluid_properties/mixtures.py @@ -11,8 +11,9 @@ SPDX-License-Identifier: MIT """ +import math + import CoolProp as CP -import numpy as np from tespy.tools.global_vars import gas_constants @@ -260,7 +261,7 @@ def exergy_chemical_ideal_cond(pamb, Tamb, fluid_data, Chem_Ex): ex_cond += molar_liquid * y[0] y = [Chem_Ex[k][3] for k in fluid_aliases if k in Chem_Ex] - ex_dry += x * y[0] + Tamb * gas_constants['uni'] * 1e-3 * x * np.log(x) + ex_dry += x * y[0] + Tamb * gas_constants['uni'] * 1e-3 * x * math.log(x) ex_chemical = ex_cond + ex_dry * (1 - molar_liquid) ex_chemical *= 1 / calc_molar_mass_mixture( diff --git a/src/tespy/tools/helpers.py b/src/tespy/tools/helpers.py index d7dab3f10..7b9601b43 100644 --- a/src/tespy/tools/helpers.py +++ b/src/tespy/tools/helpers.py @@ -574,39 +574,6 @@ def central_difference(function=None, parameter=None, delta=None, **kwargs): return (function(**upper) - function(**lower)) / (2 * delta) -def modify_path_os(path): - """ - Modify a path according the os. - - Also detects weather the path specification is absolute or relative and - adjusts the path respectively. - - Parameters - ---------- - path : str - Path to modify. - - Returns - ------- - path : str - Modified path. - """ - if os.name == 'nt': - # windows - path = path.replace('/', '\\') - if path[0] != '\\' and path[1:2] != ':' and path[0] != '.': - # relative path - path = '.\\' + path - else: - # linux, mac - path = path.replace('\\', '/') - if path[0] != '/' and path[0] != '.': - # relative path - path = './' + path - - return path - - def get_basic_path(): """ Return the basic tespy path and creates it if necessary. diff --git a/tests/test_busses.py b/tests/test_busses.py index 074a6dbd6..f0976c81f 100644 --- a/tests/test_busses.py +++ b/tests/test_busses.py @@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT """ -import shutil import numpy as np @@ -28,12 +27,8 @@ class TestBusses: def setup_method(self): """Set up the model.""" - # %% network setup - fluid_list = ['Ar', 'N2', 'O2', 'CO2', 'CH4', 'H2O'] - self.nw = Network( - fluids=fluid_list, p_unit='bar', T_unit='C', p_range=[0.5, 20]) + self.nw = Network(p_unit='bar', T_unit='C') - # %% components amb = Source('ambient') sf = Source('fuel') cc = CombustionChamber('combustion') @@ -41,7 +36,6 @@ def setup_method(self): gt = Turbine('turbine') fg = Sink('flue gas outlet') - # %% connections amb_cp = Connection(amb, 'out1', cp, 'in1', label='ambient air flow') cp_cc = Connection(cp, 'out1', cc, 'in1') sf_cc = Connection(sf, 'out1', cc, 'in2') @@ -50,12 +44,10 @@ def setup_method(self): self.nw.add_conns(amb_cp, cp_cc, sf_cc, cc_gt, gt_fg) - # %% component parameters cc.set_attr(lamb=3) cp.set_attr(eta_s=0.9, pr=15) gt.set_attr(eta_s=0.9) - # %% connection parameters amb_cp.set_attr( T=20, p=1, m=100, fluid={'Ar': 0.0129, 'N2': 0.7553, 'CO2': 0.0004, 'O2': 0.2314}) @@ -104,12 +96,11 @@ def setup_method(self): power_bus_total, thermal_input, compressor_power_comp, compressor_power_bus) - # %% solving self.nw.solve('design') - self.nw.save('tmp') - def test_model(self): + def test_model(self, tmp_path): """Test the bus functionalities in a gas turbine model.""" + self.nw.save(tmp_path) tpo = self.nw.busses['total power output'] ti = self.nw.busses['thermal input'] cpi = self.nw.busses['compressor power input'] @@ -169,7 +160,7 @@ def test_model(self): self.nw.get_conn('ambient air flow').set_attr(m=None) P_design = cpibb.P.val cpibb.set_attr(P=P_design) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) eta_cpi = round(1 / cp.calc_bus_efficiency(cpi), 6) eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) @@ -202,7 +193,7 @@ def test_model(self): # 60 % load load = 0.6 cpibb.set_attr(P=P_design * load) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) eta_cp_tpo = round(cp.calc_bus_efficiency(tpo), 6) eta_cp_char = self.motor_bus_based.evaluate(load) @@ -242,5 +233,3 @@ def test_model(self): str(P_cp_cpi) + ') and bus ' + cpibb.label + ' (' + str(P_cp_cpibb) + ').') assert P_cp_tpo == P_cp_cpi and P_cp_tpo == P_cp_cpibb, msg - - shutil.rmtree('tmp', ignore_errors=True) diff --git a/tests/test_components/test_combustion.py b/tests/test_components/test_combustion.py index b8290babd..cf4d3dd6e 100644 --- a/tests/test_components/test_combustion.py +++ b/tests/test_components/test_combustion.py @@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT """ -import shutil import pytest @@ -172,20 +171,21 @@ def test_DiabaticCombustionChamber(self): self.nw.solve('design') assert self.nw.lin_dep, "Calculation must not converge in this case." - def test_CombustionEngine(self): + def test_CombustionEngine(self, tmp_path): """Test component properties of combustion engine.""" instance = CombustionEngine('combustion engine') self.setup_CombustionEngine_network(instance) - air = {'N2': 0.7556, 'O2': 0.2315, 'Ar': 0.0129, 'H2O': 0, 'CO2': 0, - 'CH4': 0} + air = {'N2': 0.7556, 'O2': 0.2315, 'Ar': 0.0129} fuel = {'CO2': 0.04, 'CH4': 0.96} water1 = {'H2O': 1} water2 = {'H2O': 1} # connection parametrisation - instance.set_attr(pr1=0.99, pr2=0.99, lamb=1.0, - design=['pr1', 'pr2'], offdesign=['zeta1', 'zeta2']) + instance.set_attr( + pr1=0.99, pr2=0.99, lamb=1.0, + design=['pr1', 'pr2'], offdesign=['zeta1', 'zeta2'] + ) self.c1.set_attr(p=5, T=30, fluid=air) self.c2.set_attr(T=30, fluid=fuel) self.c4.set_attr(p=3, T=60, m=50, fluid=water1) @@ -211,9 +211,11 @@ def test_CombustionEngine(self): TI.set_attr(P=ti) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + from tespy.tools import logger + logger.warning(tmp_path) + self.nw.save(tmp_path) # calculate in offdesign mode - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of thermal input must be ' + str(TI.P.val) + ', is ' + str(instance.ti.val) + '.') @@ -222,7 +224,7 @@ def test_CombustionEngine(self): # test specified thermal input in component TI.set_attr(P=None) instance.set_attr(ti=ti) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of thermal input must be ' + str(ti) + ', is ' + str(instance.ti.val) + '.') @@ -231,7 +233,7 @@ def test_CombustionEngine(self): # test specified heat output 1 bus value Q1.set_attr(P=instance.Q1.val) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # heat output is at design point value, thermal input must therefore # not have changed @@ -248,7 +250,7 @@ def test_CombustionEngine(self): # test specified heat output 2 bus value Q2.set_attr(P=1.2 * instance.Q2.val) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # calculate heat output over cooling loop @@ -260,7 +262,7 @@ def test_CombustionEngine(self): # test specified heat output 2 in component Q2.set_attr(P=None) instance.set_attr(Q2=-heat2) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() heat2 = self.c5.m.val_SI * (self.c7.h.val_SI - self.c5.h.val_SI) msg = ('Value of heat output 2 must be ' + str(-heat2) + ', is ' + @@ -270,7 +272,7 @@ def test_CombustionEngine(self): # test total heat output bus value instance.set_attr(Q2=None) Q.set_attr(P=1.5 * instance.Q1.val) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() heat = (self.c4.m.val_SI * (self.c6.h.val_SI - self.c4.h.val_SI) + self.c5.m.val_SI * (self.c7.h.val_SI - self.c5.h.val_SI)) @@ -281,9 +283,8 @@ def test_CombustionEngine(self): # test specified heat loss bus value Q.set_attr(P=None) Qloss.set_attr(P=-1e5) - self.nw.solve('offdesign', init_path='tmp', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of heat loss must be ' + str(Qloss.P.val) + ', is ' + str(instance.Qloss.val) + '.') assert round(Qloss.P.val, 1) == round(instance.Qloss.val, 1), msg - shutil.rmtree('./tmp', ignore_errors=True) diff --git a/tests/test_components/test_heat_exchangers.py b/tests/test_components/test_heat_exchangers.py index 1df513de3..170282dbe 100644 --- a/tests/test_components/test_heat_exchangers.py +++ b/tests/test_components/test_heat_exchangers.py @@ -9,7 +9,7 @@ SPDX-License-Identifier: MIT """ -import shutil +import math import numpy as np @@ -23,7 +23,6 @@ from tespy.connections import Bus from tespy.connections import Connection from tespy.networks import Network -from tespy.tools.fluid_properties import T_sat_p class TestHeatExchangers: @@ -253,7 +252,7 @@ def test_ParabolicTrough(self): self.nw._convergence_check() assert Q_loss == round(instance.Q_loss.val, 0), msg - def test_SolarCollector(self): + def test_SolarCollector(self, tmp_path): """Test component properties of solar collector.""" instance = SolarCollector('solar collector') self.setup_SimpleHeatExchanger_network(instance) @@ -328,7 +327,7 @@ def test_SolarCollector(self): self.nw._convergence_check() assert Q_loss == round(instance.Q_loss.val, 0), msg - def test_HeatExchanger(self): + def test_HeatExchanger(self, tmp_path): """Test component properties of heat exchanger.""" instance = HeatExchanger('heat exchanger') self.setup_HeatExchanger_network(instance) @@ -345,7 +344,7 @@ def test_HeatExchanger(self): self.nw.add_busses(b) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + self.nw.save(tmp_path) Q_design = instance.Q.val # test specified kA value @@ -369,13 +368,18 @@ def test_HeatExchanger(self): # check heat transfer Q = self.c1.m.val_SI * (self.c2.h.val_SI - self.c1.h.val_SI) - td_log = ((self.c2.T.val - self.c3.T.val - - self.c1.T.val + self.c4.T.val) / - np.log((self.c2.T.val - self.c3.T.val) / - (self.c1.T.val - self.c4.T.val))) + td_log = ( + (self.c2.T.val - self.c3.T.val - self.c1.T.val + self.c4.T.val) + / math.log( + (self.c2.T.val - self.c3.T.val) + / (self.c1.T.val - self.c4.T.val) + ) + ) kA = round(-Q / td_log, 0) - msg = ('Value of heat transfer must be ' + str(round(Q, 0)) + ', is ' + - str(round(instance.Q.val, 0)) + '.') + msg = ( + f"Value of heat transfer must be {round(Q, 0)}, is " + f"{round(instance.Q.val, 0)}." + ) assert round(Q, 0) == round(instance.Q.val, 0), msg # check upper terminal temperature difference @@ -402,7 +406,7 @@ def test_HeatExchanger(self): # to design state self.c2.set_attr(T=70) instance.set_attr(ttd_l=None) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of heat flow must be ' + str(instance.Q.val) + ', is ' + str(round(Q, 0)) + '.') @@ -435,9 +439,7 @@ def test_HeatExchanger(self): '.') assert instance.ttd_u.val < 0, msg - shutil.rmtree('./tmp', ignore_errors=True) - - def test_Condenser(self): + def test_Condenser(self, tmp_path): """Test component properties of Condenser.""" instance = Condenser('condenser') self.setup_HeatExchanger_network(instance) @@ -452,7 +454,7 @@ def test_Condenser(self): instance.set_attr(Q=-80e3) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + self.nw.save(tmp_path) Q_design = instance.Q.val # test specified kA value @@ -500,12 +502,11 @@ def test_Condenser(self): # check kA value with condensing pressure in offdesign mode: # no changes to design point means: identical pressure - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of condensing pressure be ' + str(p) + ', is ' + str(round(self.c1.p.val_SI, 5)) + '.') assert p == round(self.c1.p.val_SI, 5), msg - shutil.rmtree('./tmp', ignore_errors=True) def test_CondenserWithEvaporation(self): """Test a Condenser that evaporates a fluid.""" @@ -534,7 +535,7 @@ def test_CondenserWithEvaporation(self): ) assert instance.td_log.val == instance.ttd_l.val, msg - # self.nw.save('tmp') + # self.nw.save(tmp_path) # self.c1.set_attr(m=1) # self.nw.solve("offdesign", design_path="tmp") # self.nw._convergence_check() @@ -544,4 +545,3 @@ def test_CondenserWithEvaporation(self): # f"ttd_l={self.c3.m.val}." # ) # assert instance.td_log.val == instance.ttd_l.val, msg - shutil.rmtree('./tmp', ignore_errors=True) diff --git a/tests/test_components/test_reactors.py b/tests/test_components/test_reactors.py index ffdaae146..4fde67f95 100644 --- a/tests/test_components/test_reactors.py +++ b/tests/test_components/test_reactors.py @@ -10,8 +10,6 @@ SPDX-License-Identifier: MIT """ -import shutil - from tespy.components import Sink from tespy.components import Source from tespy.components import WaterElectrolyzer @@ -48,7 +46,7 @@ def setup_method(self): self.nw.add_conns(fw_el, el_o2, el_h2) - def test_WaterElectrolyzer(self): + def test_WaterElectrolyzer(self, tmp_path): """Test component properties of water electrolyzer.""" # check bus function: # power output on component and bus must be indentical @@ -89,13 +87,13 @@ def test_WaterElectrolyzer(self): msg = ('Value of heat flow must be ' + str(heat.P.val) + ', is ' + str(self.instance.Q.val) + '.') assert round(heat.P.val, 1) == round(self.instance.Q.val), msg - self.nw.save('tmp') + self.nw.save(tmp_path) # check bus function: # heat output on component and bus must identical (offdesign test) Q = heat.P.val * 0.9 heat.set_attr(P=Q) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of heat flow must be ' + str(Q) + ', is ' + str(self.instance.Q.val) + '.') @@ -147,8 +145,7 @@ def test_WaterElectrolyzer(self): self.instance.set_attr( pr=pr, e=None, eta=None, zeta='var', P=2e7, design=['pr']) self.nw.solve('design') - shutil.rmtree('./tmp', ignore_errors=True) - self.nw.save('tmp') + self.nw.save(tmp_path) self.nw._convergence_check() msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' + str(self.instance.pr.val) + '.') @@ -157,7 +154,7 @@ def test_WaterElectrolyzer(self): # use zeta as offdesign parameter, at design point pressure # ratio must not change self.instance.set_attr(zeta=None, offdesign=['zeta']) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of pressure ratio must be ' + str(pr) + ', is ' + str(self.instance.pr.val) + '.') @@ -166,9 +163,8 @@ def test_WaterElectrolyzer(self): # test heat output specification in offdesign mode Q = self.instance.Q.val * 0.9 self.instance.set_attr(Q=Q, P=None) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of heat must be ' + str(Q) + ', is ' + str(self.instance.Q.val) + '.') assert round(Q, 0) == round(self.instance.Q.val, 0), msg - shutil.rmtree('./tmp', ignore_errors=True) diff --git a/tests/test_components/test_turbomachinery.py b/tests/test_components/test_turbomachinery.py index 38901e8e9..cb727ac84 100644 --- a/tests/test_components/test_turbomachinery.py +++ b/tests/test_components/test_turbomachinery.py @@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT """ -import shutil import numpy as np @@ -38,7 +37,7 @@ def setup_network(self, instance): self.c2 = Connection(instance, 'out1', self.sink, 'in1') self.nw.add_conns(self.c1, self.c2) - def test_Compressor(self): + def test_Compressor(self, tmp_path): """Test component properties of compressors.""" instance = Compressor('compressor') self.setup_network(instance) @@ -50,7 +49,7 @@ def test_Compressor(self): instance.set_attr(eta_s=0.8) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + self.nw.save(tmp_path) # test isentropic efficiency value eta_s_d = ( @@ -86,7 +85,7 @@ def test_Compressor(self): eta_s=None, igva=0) # offdesign test, efficiency value should be at design value - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of isentropic efficiency (' + str(instance.eta_s.val) + ') must be identical to design case (' + str(eta_s) + ').') @@ -95,7 +94,7 @@ def test_Compressor(self): # move to highest available speedline, mass flow below lowest value # at that line self.c1.set_attr(v=None, m=self.c1.m.val * 0.8, T=-30) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # should be value @@ -107,7 +106,7 @@ def test_Compressor(self): # going below lowest available speedline, above highest mass flow at # that line self.c1.set_attr(T=175) - self.nw.solve('offdesign', design_path='tmp', init_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path, init_path=tmp_path) self.nw._convergence_check() # should be value eta_s = eta_s_d * instance.char_map_eta_s.char_func.z[0, 9] @@ -125,7 +124,7 @@ def test_Compressor(self): 'is_set': True, 'param': 'm'}) instance.char_map_eta_s.is_set = False instance.char_map_pr.is_set = False - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of isentropic efficiency must be ' + str(eta_s_d) + ', is ' + str(instance.eta_s.val) + '.') @@ -133,7 +132,7 @@ def test_Compressor(self): # move up in volumetric flow self.c1.set_attr(v=1.5) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() eta_s = round(eta_s_d * instance.eta_s_char.char_func.evaluate( self.c1.m.val_SI / self.c1.m.design), 3) @@ -145,7 +144,7 @@ def test_Compressor(self): instance.eta_s_char.set_attr(param='pr') self.c1.set_attr(v=1) self.c2.set_attr(p=6) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() expr = (self.c2.p.val_SI * self.c1.p.design / (self.c2.p.design * self.c1.p.val_SI)) @@ -154,9 +153,8 @@ def test_Compressor(self): msg = ('Value of isentropic efficiency must be ' + str(eta_s) + ', is ' + str(round(instance.eta_s.val, 3)) + '.') assert eta_s == round(instance.eta_s.val, 3), msg - shutil.rmtree('./tmp', ignore_errors=True) - def test_Pump(self): + def test_Pump(self, tmp_path): """Test component properties of pumps.""" instance = Pump('pump') self.setup_network(instance) @@ -189,7 +187,7 @@ def test_Pump(self): instance.set_attr(eta_s=eta_s_d) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + self.nw.save(tmp_path) self.c2.set_attr(p=None) # flow char (pressure rise vs. volumetric flow) @@ -201,7 +199,7 @@ def test_Pump(self): flow_char=char, eta_s=None, eta_s_char={ 'char_func': ldc('pump', 'eta_s_char', 'DEFAULT', CharLine), 'is_set': True}) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # value for difference pressure @@ -212,7 +210,7 @@ def test_Pump(self): # test ohter volumetric flow on flow char self.c1.set_attr(v=0.9) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() dp = 775000.0 msg = ('Value of pressure rise must be ' + str(dp) + ', is ' + @@ -244,9 +242,8 @@ def test_Pump(self): msg = ('Value of power must be 0, is ' + str(round(self.c2.p.val_SI - self.c1.p.val_SI, 0)) + '.') assert round(self.c2.p.val_SI - self.c1.p.val_SI, 0) == 0, msg - shutil.rmtree('./tmp', ignore_errors=True) - def test_Turbine(self): + def test_Turbine(self, tmp_path): """Test component properties of turbines.""" instance = Turbine('turbine') self.setup_network(instance) @@ -256,7 +253,7 @@ def test_Turbine(self): instance.set_attr(eta_s=0.85) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('tmp') + self.nw.save(tmp_path) # design value of isentropic efficiency eta_s_d = ( @@ -287,7 +284,7 @@ def test_Turbine(self): instance.cone.is_set = True instance.eta_s_char.is_set = True instance.eta_s.is_set = False - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # check efficiency msg = ('Value of isentropic efficiency (' + str(instance.eta_s.val) + @@ -301,7 +298,7 @@ def test_Turbine(self): # lowering mass flow, inlet pressure must sink according to cone law self.c1.set_attr(m=self.c1.m.val * 0.8) - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() msg = ('Value of pressure ratio (' + str(instance.pr.val) + ') must be at (' + str(0.128) + ').') @@ -311,7 +308,7 @@ def test_Turbine(self): # test parameter specification v self.c1.set_attr(m=10) instance.eta_s_char.param = 'v' - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() expr = self.c1.v.val_SI / self.c1.v.design eta_s = round(eta_s_d * instance.eta_s_char.char_func.evaluate(expr), 3) @@ -322,7 +319,7 @@ def test_Turbine(self): # test parameter specification pr instance.eta_s_char.param = 'pr' - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() expr = (self.c2.p.val_SI * self.c1.p.design / (self.c2.p.design * self.c1.p.val_SI)) @@ -331,7 +328,6 @@ def test_Turbine(self): str(round(instance.eta_s.val, 3)) + ') must be (' + str(eta_s) + ').') assert eta_s == round(instance.eta_s.val, 3), msg - shutil.rmtree('./tmp', ignore_errors=True) def test_Turbomachine(self): """Test component properties of turbomachines.""" diff --git a/tests/test_errors.py b/tests/test_errors.py index b71d53fb2..10e721de3 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -97,7 +97,6 @@ def test_set_attr_errors(): set_attr_TypeError(comb, tiP_char=7) set_attr_TypeError(comb, design='f') set_attr_TypeError(comb, lamb=dc_cc()) - set_attr_TypeError(comb, design_path=7) set_attr_TypeError(comb, local_design=5) set_attr_TypeError(comb, local_offdesign=5) set_attr_TypeError(comb, printout=5) @@ -106,7 +105,6 @@ def test_set_attr_errors(): set_attr_TypeError(conn, fluid_balance=1) set_attr_TypeError(conn, h0=[4]) set_attr_TypeError(conn, fluid=5) - set_attr_TypeError(conn, design_path=5) set_attr_TypeError(conn, local_design=5) set_attr_TypeError(conn, local_offdesign=5) set_attr_TypeError(conn, printout=5) diff --git a/tests/test_models/test_heat_pump_model.py b/tests/test_models/test_heat_pump_model.py index 9a54d47ae..8dfc72f1b 100644 --- a/tests/test_models/test_heat_pump_model.py +++ b/tests/test_models/test_heat_pump_model.py @@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT """ -import shutil import numpy as np @@ -32,10 +31,8 @@ class TestHeatPump: def setup_method(self): - # %% network setup self.nw = Network(T_unit='C', p_unit='bar', h_unit='kJ / kg', m_unit='kg / s') - # %% components # sources & sinks cc_refrigerant = CycleCloser('refrigerant cycle closer') cc_consumer = CycleCloser('consumer cycle closer') @@ -70,7 +67,6 @@ def setup_method(self): self.heat.add_comps({'comp': cd, 'char': -1}) self.nw.add_busses(self.power, self.heat) - # %% connections # consumer system c_in_cd = Connection(cc_refrigerant, 'out1', cd, 'in1') @@ -116,7 +112,6 @@ def setup_method(self): self.nw.add_conns(cp1_he, he_cp2, ic_in_he, he_ic_out, cp2_c_out) - # %% component parametrization # condenser system x = np.array( [0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, @@ -246,7 +241,7 @@ def setup_method(self): ic_in_he.set_attr(p=1, T=20, m=5, fluid={'water': 1}) he_ic_out.set_attr(p=Ref(ic_in_he, 1, -0.002), design=['p']) - def test_model(self): + def test_model(self, tmp_path): """ Test the operating points of the heat pump against a different model. @@ -254,7 +249,7 @@ def test_model(self): available in detail, thus perfect matching is not possible! """ self.nw.solve('design') - self.nw.save('tmp') + self.nw.save(tmp_path) self.nw.print_results() # input values from ebsilon @@ -276,11 +271,11 @@ def test_model(self): self.amb_in_su.set_attr(m=m) if j == 0: self.nw.solve( - 'offdesign', design_path='tmp', init_path='tmp' + 'offdesign', design_path=tmp_path, init_path=tmp_path ) else: - self.nw.solve('offdesign', design_path='tmp') + self.nw.solve('offdesign', design_path=tmp_path) self.nw._convergence_check() # relative deviation should not exceed 6.5 % @@ -295,4 +290,3 @@ def test_model(self): assert d_rel_COP < 0.07, msg j += 1 i += 1 - shutil.rmtree('./tmp', ignore_errors=True) diff --git a/tests/test_networks/test_network.py b/tests/test_networks/test_network.py index e9c92e52a..c49eb114a 100644 --- a/tests/test_networks/test_network.py +++ b/tests/test_networks/test_network.py @@ -11,9 +11,7 @@ """ import os -import shutil -import numpy as np from pytest import mark from pytest import raises @@ -118,14 +116,14 @@ def test_Network_delete_comps(self): self.nw.solve("design") self.nw._convergence_check() - def test_Network_missing_connection_in_init_path(self): + def test_Network_missing_connection_in_init_path(self, tmp_path): """Test debug message for missing connection in init_path.""" IF = SubsystemInterface('IF') a = Connection(self.source, 'out1', self.sink, 'in1') a.set_attr(fluid={"Air": 1}) self.nw.add_conns(a) self.nw.solve('design', init_only=True) - self.nw.save('tmp') + self.nw.save(tmp_path) msg = ('After the network check, the .checked-property must be True.') assert self.nw.checked, msg @@ -134,115 +132,97 @@ def test_Network_missing_connection_in_init_path(self): b = Connection(IF, 'out1', self.sink, 'in1') a.set_attr(fluid={"Air": 1}) self.nw.add_conns(a, b) - self.nw.solve('design', init_path='tmp', init_only=True) + self.nw.solve('design', init_path=tmp_path, init_only=True) msg = ('After the network check, the .checked-property must be True.') assert self.nw.checked, msg - shutil.rmtree('./tmp', ignore_errors=True) - - def test_Network_export_no_busses(self): - """Test export of network without characteristics or busses.""" - a = Connection(self.source, 'out1', self.sink, 'in1') - self.nw.add_conns(a) - a.set_attr(fluid={"H2O": 1}) - self.nw.solve('design', init_only=True) - self.nw.save('tmp') - - msg = ( - 'The exported network does not contain any busses, there must be ' - 'no file busses.csv!' - ) - assert not os.path.isfile('tmp/busses.csv'), msg - shutil.rmtree('./tmp', ignore_errors=True) - - def test_Network_reader_checked(self): - """Test import of network without characteristics or busses.""" + def test_Network_reader_checked(self, tmp_path): + """Test state of network if loaded successfully from export.""" a = Connection(self.source, 'out1', self.sink, 'in1') self.nw.add_conns(a) a.set_attr(fluid={"H2O": 1}) self.nw.solve('design', init_only=True) - self.nw.export('tmp') - - imported_nwk = load_network('tmp') + self.nw.export(tmp_path) + imported_nwk = load_network(tmp_path) imported_nwk.solve('design', init_only=True) msg = ('If the network import was successful the network check ' 'should have been successful, too, but it is not.') assert imported_nwk.checked, msg - shutil.rmtree('./tmp', ignore_errors=True) - def test_Network_missing_data_in_design_case_files(self): + def test_Network_missing_data_in_design_case_files(self, tmp_path_factory): """Test for missing data in design case files.""" + tmp_path = tmp_path_factory.mktemp("tmp") + tmp_path2 = tmp_path_factory.mktemp("tmp2") pi = Pipe('pipe', Q=0, pr=0.95, design=['pr'], offdesign=['zeta']) - a = Connection( - self.source, 'out1', pi, 'in1', m=1, p=1, T=20, fluid={'water': 1} - ) + a = Connection(self.source, 'out1', pi, 'in1') + a.set_attr(m=1, p=1, T=20, fluid={'water': 1}) b = Connection(pi, 'out1', self.sink, 'in1') self.nw.add_conns(a, b) self.nw.solve('design') - self.nw.save('tmp') - self.nw.save('tmp2') + self.nw.save(tmp_path) + self.nw.save(tmp_path2) - inputs = open('./tmp/connections.csv') + path = os.path.join(tmp_path, "connections.csv") + inputs = open(path) all_lines = inputs.readlines() all_lines.pop(len(all_lines) - 1) inputs.close() - with open('./tmp2/connections.csv', 'w') as out: + with open(os.path.join(tmp_path2, 'connections.csv'), 'w') as out: for line in all_lines: out.write(line.strip() + '\n') - self.offdesign_TESPyNetworkError(design_path='tmp2', init_only=True) - - shutil.rmtree('./tmp', ignore_errors=True) - shutil.rmtree('./tmp2', ignore_errors=True) + self.offdesign_TESPyNetworkError(design_path=tmp_path2, init_only=True) - def test_Network_missing_data_in_individual_design_case_file(self): + def test_Network_missing_data_in_individual_design_case_file(self, tmp_path_factory): """Test for missing data in individual design case files.""" + tmp_path = tmp_path_factory.mktemp("tmp") + tmp_path2 = tmp_path_factory.mktemp("tmp2") pi = Pipe('pipe', Q=0, pr=0.95, design=['pr'], offdesign=['zeta']) - a = Connection(self.source, 'out1', pi, 'in1', m=1, p=1, T=293.15, - fluid={'water': 1}) - b = Connection(pi, 'out1', self.sink, 'in1', design_path='tmp2') + a = Connection(self.source, 'out1', pi, 'in1') + a.set_attr(m=1, p=1, T=293.15, fluid={'water': 1}) + b = Connection(pi, 'out1', self.sink, 'in1') + b.set_attr(design_path=tmp_path2) self.nw.add_conns(a, b) self.nw.solve('design') - self.nw.save('tmp') - self.nw.save('tmp2') + self.nw.save(tmp_path) + self.nw.save(tmp_path2) - inputs = open('./tmp/connections.csv') + path = os.path.join(tmp_path, "connections.csv") + inputs = open(path) all_lines = inputs.readlines() all_lines.pop(len(all_lines) - 1) inputs.close() - with open('./tmp2/connections.csv', 'w') as out: + with open(os.path.join(tmp_path2, 'connections.csv'), 'w') as out: for line in all_lines: out.write(line.strip() + '\n') - self.offdesign_TESPyNetworkError(design_path='tmp', init_only=True) - - shutil.rmtree('./tmp', ignore_errors=True) - shutil.rmtree('./tmp2', ignore_errors=True) + self.offdesign_TESPyNetworkError(design_path=tmp_path, init_only=True) - def test_Network_missing_connection_in_design_path(self): + def test_Network_missing_connection_in_design_path(self, tmp_path): """Test for missing connection data in design case files.""" pi = Pipe('pipe', Q=0, pr=0.95, design=['pr'], offdesign=['zeta']) - a = Connection(self.source, 'out1', pi, 'in1', m=1, p=1, T=293.15, - fluid={'water': 1}) + a = Connection( + self.source, 'out1', pi, 'in1', m=1, p=1, T=293.15, + fluid={'water': 1} + ) b = Connection(pi, 'out1', self.sink, 'in1') self.nw.add_conns(a, b) self.nw.solve('design') - self.nw.save('tmp') + self.nw.save(tmp_path) - inputs = open('./tmp/connections.csv') + path = os.path.join(tmp_path, "connections.csv") + inputs = open(path) all_lines = inputs.readlines() all_lines.pop(len(all_lines) - 1) inputs.close() - with open('./tmp/connections.csv', 'w') as out: + with open(path, 'w') as out: for line in all_lines: out.write(line.strip() + '\n') - self.offdesign_TESPyNetworkError(design_path='tmp') - - shutil.rmtree('./tmp', ignore_errors=True) + self.offdesign_TESPyNetworkError(design_path=tmp_path) def test_Network_get_comp_without_connections_added(self): """Test if components are found prior to initialization.""" @@ -315,15 +295,17 @@ def setup_Network_individual_offdesign(self): self.nw.add_conns(inlet, outlet, self.sp_p1, self.p1_sc1, self.sc1_v1, v1_me, self.sp_p2, self.p2_sc2, self.sc2_v2, v2_me) - def test_individual_design_path_on_connections_and_components(self): + def test_individual_design_path_on_connections_and_components(self, tmp_path_factory): """Test individual design path specification.""" + tmp_path1 = tmp_path_factory.mktemp("tmp1") + tmp_path2 = tmp_path_factory.mktemp("tmp2") self.setup_Network_individual_offdesign() self.nw.solve('design') self.nw._convergence_check() self.sc2_v2.set_attr(m=0) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('design1') + self.nw.save(tmp_path1) v1_design = self.sc1_v1.v.val_SI zeta_sc1_design = self.sc1.zeta.val @@ -331,7 +313,7 @@ def test_individual_design_path_on_connections_and_components(self): self.sc1_v1.set_attr(m=0.001, T=None) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('design2') + self.nw.save(tmp_path2) v2_design = self.sc2_v2.v.val_SI zeta_sc2_design = self.sc2.zeta.val @@ -339,18 +321,18 @@ def test_individual_design_path_on_connections_and_components(self): self.sc1_v1.set_attr(design=['T'], offdesign=['v'], state='l') self.sc2_v2.set_attr(design=['T'], offdesign=['v'], state='l') - self.sc2.set_attr(design_path='design2') - self.pump2.set_attr(design_path='design2') - self.sp_p2.set_attr(design_path='design2') - self.p2_sc2.set_attr(design_path='design2') - self.sc2_v2.set_attr(design_path='design2') - self.nw.solve('offdesign', design_path='design1') + self.sc2.set_attr(design_path=tmp_path2) + self.pump2.set_attr(design_path=tmp_path2) + self.sp_p2.set_attr(design_path=tmp_path2) + self.p2_sc2.set_attr(design_path=tmp_path2) + self.sc2_v2.set_attr(design_path=tmp_path2) + self.nw.solve('offdesign', design_path=tmp_path1) self.nw._convergence_check() self.sc1.set_attr(E=500) self.sc2.set_attr(E=950) - self.nw.solve('offdesign', design_path='design1') + self.nw.solve('offdesign', design_path=tmp_path1) self.nw._convergence_check() self.sc2_v2.set_attr(design_path=None) @@ -382,33 +364,32 @@ def test_individual_design_path_on_connections_and_components(self): ) assert round(zeta_sc2_design, 0) == round(self.sc2.zeta.val, 0), msg - shutil.rmtree('./design1', ignore_errors=True) - shutil.rmtree('./design2', ignore_errors=True) - - def test_local_offdesign_on_connections_and_components(self): + def test_local_offdesign_on_connections_and_components(self, tmp_path_factory): """Test local offdesign feature.""" + tmp_path1 = tmp_path_factory.mktemp("tmp1") + tmp_path2 = tmp_path_factory.mktemp("tmp2") self.setup_Network_individual_offdesign() self.nw.solve('design') self.nw._convergence_check() self.sc2_v2.set_attr(m=0) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('design1') + self.nw.save(tmp_path1) self.sc1_v1.set_attr(design=['T'], offdesign=['v'], state='l') self.sc2_v2.set_attr(design=['T'], offdesign=['v'], state='l') - self.sc1.set_attr(local_offdesign=True, design_path='design1') - self.pump1.set_attr(local_offdesign=True, design_path='design1') - self.sp_p1.set_attr(local_offdesign=True, design_path='design1') - self.p1_sc1.set_attr(local_offdesign=True, design_path='design1') - self.sc1_v1.set_attr(local_offdesign=True, design_path='design1') + self.sc1.set_attr(local_offdesign=True, design_path=tmp_path1) + self.pump1.set_attr(local_offdesign=True, design_path=tmp_path1) + self.sp_p1.set_attr(local_offdesign=True, design_path=tmp_path1) + self.p1_sc1.set_attr(local_offdesign=True, design_path=tmp_path1) + self.sc1_v1.set_attr(local_offdesign=True, design_path=tmp_path1) self.sc1.set_attr(E=500) self.sc2_v2.set_attr(T=95, m=None) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('design2') + self.nw.save(tmp_path2) # connections and components on side 1 must have switched to offdesign @@ -426,10 +407,7 @@ def test_local_offdesign_on_connections_and_components(self): ) assert self.sc1_v1.v.is_set, msg - shutil.rmtree('./design1', ignore_errors=True) - shutil.rmtree('./design2', ignore_errors=True) - - def test_missing_design_path_local_offdesign_on_connections(self): + def test_missing_design_path_local_offdesign_on_connections(self, tmp_path): """Test missing design path on connections in local offdesign mode.""" self.setup_Network_individual_offdesign() self.nw.solve('design') @@ -437,15 +415,15 @@ def test_missing_design_path_local_offdesign_on_connections(self): self.sc2_v2.set_attr(m=0) self.nw.solve('design') self.nw._convergence_check() - self.nw.save('design1') + self.nw.save(tmp_path) self.sc1_v1.set_attr(design=['T'], offdesign=['v'], state='l') self.sc2_v2.set_attr(design=['T'], offdesign=['v'], state='l') - self.sc1.set_attr(local_offdesign=True, design_path='design1') - self.pump1.set_attr(local_offdesign=True, design_path='design1') - self.sp_p1.set_attr(local_offdesign=True, design_path='design1') - self.p1_sc1.set_attr(local_offdesign=True, design_path='design1') + self.sc1.set_attr(local_offdesign=True, design_path=tmp_path) + self.pump1.set_attr(local_offdesign=True, design_path=tmp_path) + self.sp_p1.set_attr(local_offdesign=True, design_path=tmp_path) + self.p1_sc1.set_attr(local_offdesign=True, design_path=tmp_path) self.sc1_v1.set_attr(local_offdesign=True) self.sc1.set_attr(E=500) @@ -455,9 +433,6 @@ def test_missing_design_path_local_offdesign_on_connections(self): except TESPyNetworkError: pass - shutil.rmtree('./design1', ignore_errors=True) - - class TestNetworkPreprocessing: def setup_method(self): diff --git a/tests/test_tools/test_characteristics.py b/tests/test_tools/test_characteristics.py index 40b2f382e..1c570f171 100644 --- a/tests/test_tools/test_characteristics.py +++ b/tests/test_tools/test_characteristics.py @@ -33,7 +33,7 @@ def test_custom_CharLine_import(): if os.path.exists(path): for f in os.listdir(path): - shutil.copy(src=path + '/' + f, dst=tmp_path) + shutil.copy(src=os.path.join(path, f), dst=tmp_path) with open(data_path) as f: raw_data = json.load(f) @@ -42,8 +42,9 @@ def test_custom_CharLine_import(): with open(os.path.join(path, 'char_lines.json'), 'w') as outfile: json.dump(data, outfile) - char_original = load_default_char('heat exchanger', 'kA_char2', - 'EVAPORATING FLUID', CharLine) + char_original = load_default_char( + 'heat exchanger', 'kA_char2', 'EVAPORATING FLUID', CharLine + ) char_custom = load_custom_char('EVAPORATING FLUID', CharLine) shutil.rmtree(path, ignore_errors=True) @@ -51,29 +52,30 @@ def test_custom_CharLine_import(): if os.path.exists(tmp_path): path = extend_basic_path('data') for f in os.listdir(tmp_path): - shutil.copy(src=tmp_path + '/' + f, dst=path) + shutil.copy(src=os.path.join(tmp_path, f), dst=path) shutil.rmtree(tmp_path, ignore_errors=True) x_cond = np.array_equal(char_original.x, char_custom.x) y_cond = np.array_equal(char_original.y, char_custom.y) - msg = ('The x values from the custom characteristic line ' + - str(char_custom.x) + ' must be identical to the x values from ' - 'the default characteristic line ' + str(char_original.x) + ' ' - 'as these have been duplicated before load.') + msg = ( + f'The x values from the custom characteristic line {char_custom.x} ' + 'must be identical to the x values from the default characteristic ' + f'line {char_original.x} as these have been duplicated before load.' + ) assert x_cond, msg - msg = ('The y values from the custom characteristic line ' + - str(char_custom.y) + ' must be identical to the y values from ' - 'the default characteristic line ' + str(char_original.y) + ' ' - 'as these have been duplicated before load.') + msg = ( + f'The y values from the custom characteristic line {char_custom.y} ' + 'must be identical to the y values from the default characteristic ' + f'line {char_original.y} as these have been duplicated before load.' + ) assert y_cond, msg def test_custom_CharMap_import(): """Test importing a custom characteristc map.""" - # we need to write some data to the path first, using defaults data_path = os.path.join(__datapath__, 'char_maps.json') path = extend_basic_path('data') @@ -81,7 +83,7 @@ def test_custom_CharMap_import(): if os.path.exists(path): for f in os.listdir(path): - shutil.copy(src=path + '/' + f, dst=tmp_path) + shutil.copy(src=os.path.join(path, f), dst=tmp_path) with open(data_path) as f: raw_data = json.load(f) @@ -103,26 +105,29 @@ def test_custom_CharMap_import(): if os.path.exists(tmp_path): path = extend_basic_path('data') for f in os.listdir(tmp_path): - shutil.copy(src=tmp_path + '/' + f, dst=path) + shutil.copy(src=os.path.join(tmp_path, f), dst=path) shutil.rmtree(tmp_path, ignore_errors=True) - msg = ('The x values from the custom characteristic line ' + - str(char_custom.x) + ' must be identical to the x values from ' - 'the default characteristic line ' + str(char_original.x) + ' ' - 'as these have been duplicated before load.') + msg = ( + f'The x values from the custom characteristic line {char_custom.x} ' + 'must be identical to the x values from the default characteristic ' + f'line {char_original.x} as these have been duplicated before load.' + ) assert x_cond, msg - msg = ('The y values from the custom characteristic line ' + - str(char_custom.y) + ' must be identical to the y values from ' - 'the default characteristic line ' + str(char_original.y) + ' ' - 'as these have been duplicated before load.') + msg = ( + f'The y values from the custom characteristic line {char_custom.y} ' + 'must be identical to the y values from the default characteristic ' + f'line {char_original.y} as these have been duplicated before load.' + ) assert y_cond, msg - msg = ('The z values from the custom characteristic line ' + - str(char_custom.z) + ' must be identical to the z values from ' - 'the default characteristic line ' + str(char_original.z) + ' ' - 'as these have been duplicated before load.') + msg = ( + f'The z values from the custom characteristic line {char_custom.z} ' + 'must be identical to the z values from the default characteristic ' + f'line {char_original.z} as these have been duplicated before load.' + ) assert z_cond, msg diff --git a/tox.ini b/tox.ini index 8e5d3fd79..d926e3676 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,10 @@ [tox] envlist = - clean, check, docs, py39, py310, - py311, - report + py311 [gh-actions] python = @@ -16,64 +14,31 @@ python = [testenv] basepython = - docs: {env:TOXPYTHON:python3.10} - {bootstrap,clean,check,report,coveralls}: {env:TOXPYTHON:python3} + {check,docs}: {env:TOXPYTHON:python3.11} setenv = PYTHONPATH={toxinidir}/tests PYTHONUNBUFFERED=yes passenv = * -deps = - .[dev] +extras = + dev commands = {posargs:pytest -vv --ignore=src} -[testenv:bootstrap] -deps = - jinja2 - matrix -skip_install = true -commands = - python ci/bootstrap.py --no-env - [testenv:check] deps = check-manifest - flit - readme-renderer - pygments isort skip_install = true commands = check-manifest {toxinidir} - isort --verbose --check-only --diff --recursive src tests + isort --verbose --check-only --diff src tests [testenv:docs] usedevelop = true -deps = - -r{toxinidir}/docs/requirements.txt commands = - sphinx-build {posargs:-E} -b html docs dist/docs - sphinx-build -b linkcheck docs dist/docs - -[testenv:coveralls] -deps = - coveralls -skip_install = true -commands = - coveralls [] - -[testenv:report] -deps = coverage -skip_install = true -commands = - coverage report - coverage html - -[testenv:clean] -commands = coverage erase -skip_install = true -deps = coverage[toml] + sphinx-build {posargs:-E} -b html docs docs/_build + sphinx-build -b linkcheck docs docs/_build [testenv:py39] basepython = {env:TOXPYTHON:python3.9} @@ -83,7 +48,6 @@ usedevelop = true commands = {posargs:pytest --cov --cov-report=term-missing -vv} deps = - {[testenv]deps} pytest-cov [testenv:py310] @@ -94,7 +58,6 @@ usedevelop = true commands = {posargs:pytest --cov --cov-report=term-missing -vv} deps = - {[testenv]deps} pytest-cov [testenv:py311] @@ -105,5 +68,4 @@ usedevelop = true commands = {posargs:pytest --cov --cov-report=term-missing -vv} deps = - {[testenv]deps} pytest-cov diff --git a/tutorial/basics/gas_turbine.py b/tutorial/basics/gas_turbine.py index fbb5d2332..6debae558 100755 --- a/tutorial/basics/gas_turbine.py +++ b/tutorial/basics/gas_turbine.py @@ -118,7 +118,7 @@ fig, ax = plt.subplots(2, 2, figsize=(16, 8), sharex='col', sharey='row') ax = ax.flatten() -[a.grid() for a in ax] +[(a.grid(), a.set_axisbelow(True)) for a in ax] i = 0 for key in data: @@ -145,6 +145,8 @@ nw.solve('design') T3 += [c3.T.val] +T3 = T3[::-1] + # reset to base value c3.fluid.is_set.remove("O2") c3.set_attr(T=1200) @@ -153,6 +155,7 @@ ax.scatter(data * 100, T3, s=100, color="#1f567d") ax.grid() +ax.set_axisbelow(True) ax.set_ylabel('Turbine inlet temperature in °C') ax.set_xlabel('Oxygen mass fraction in flue gas in %') @@ -185,6 +188,7 @@ ax.scatter(data, CH4, s=100, color="#1f567d", label="CH4 mass fraction") ax.scatter(data, H2, s=100, color="#18a999", label="H2 mass fraction") ax.grid() +ax.set_axisbelow(True) ax.legend() ax.set_ylabel('Mass fraction of the fuel in %') diff --git a/tutorial/basics/rankine.py b/tutorial/basics/rankine.py index 19115cff1..163ade647 100755 --- a/tutorial/basics/rankine.py +++ b/tutorial/basics/rankine.py @@ -51,7 +51,69 @@ my_plant.solve(mode='design') my_plant.print_results() + # %%[sec_5] +# Adding feature to plot the T-s Diagram using fluprodia library +# Importing necessary library +import matplotlib.pyplot as plt +import numpy as np +from fluprodia import FluidPropertyDiagram + +# Initial Setup +diagram = FluidPropertyDiagram('water') +diagram.set_unit_system(T='°C', p='bar', h='kJ/kg') + +# Storing the model result in the dictionary +result_dict = {} +result_dict.update( + {cp.label: cp.get_plotting_data()[1] for cp in my_plant.comps['object'] + if cp.get_plotting_data() is not None}) + +# Iterate over the results obtained from TESPy simulation +for key, data in result_dict.items(): + # Calculate individual isolines for T-s diagram + result_dict[key]['datapoints'] = diagram.calc_individual_isoline(**data) + +# Create a figure and axis for plotting T-s diagram +fig, ax = plt.subplots(1, figsize=(20, 10)) +isolines = { + 'Q': np.linspace(0, 1, 2), + 'p': np.array([1, 2, 5, 10, 20, 50, 100, 300]), + 'v': np.array([]), + 'h': np.arange(500, 3501, 500) +} + +# Set isolines for T-s diagram +diagram.set_isolines(**isolines) +diagram.calc_isolines() + +# Draw isolines on the T-s diagram +diagram.draw_isolines(fig, ax, 'Ts', x_min=0, x_max=7500, y_min=0, y_max=650) + +# Adjust the font size of the isoline labels +for text in ax.texts: + text.set_fontsize(10) + +# Plot T-s curves for each component +for key in result_dict.keys(): + datapoints = result_dict[key]['datapoints'] + _ = ax.plot(datapoints['s'], datapoints['T'], color='#ff0000', linewidth=2) + _ = ax.scatter(datapoints['s'][0], datapoints['T'][0], color='#ff0000') + +# Set labels and title for the T-s diagram +ax.set_xlabel('Entropy, s in J/kgK', fontsize=16) +ax.set_ylabel('Temperature, T in °C', fontsize=16) +ax.set_title('T-s Diagram of Rankine Cycle', fontsize=20) + +# Set font size for the x-axis and y-axis ticks +ax.tick_params(axis='x', labelsize=12) +ax.tick_params(axis='y', labelsize=12) +plt.tight_layout() + +# Save the T-s diagram plot as an SVG file +fig.savefig('rankine_ts_diagram.svg') + +# %%[sec_6] from tespy.connections import Bus powergen = Bus("electrical power output") @@ -65,18 +127,16 @@ my_plant.solve(mode='design') my_plant.print_results() -# %%[sec_6] +# %%[sec_7] powergen.set_attr(P=-10e6) c1.set_attr(m=None) my_plant.solve(mode='design') my_plant.print_results() -# %%[sec_7] +# %%[sec_8] my_plant.set_attr(iterinfo=False) c1.set_attr(m=20) powergen.set_attr(P=None) -import matplotlib.pyplot as plt -import numpy as np # make text reasonably sized plt.rc('font', **{'size': 18}) @@ -144,18 +204,18 @@ ax[4].set_xlabel('Feed water temperature in °C') ax[5].set_xlabel('Live steam pressure in bar') plt.tight_layout() -fig.savefig('rankine_parametric.svg') +fig.savefig('rankine_parametric-darkmode.svg') plt.close() -# %%[sec_8] +# %%[sec_9] mc.set_attr(design=["ttd_u"], offdesign=["kA"]) c11.set_attr(offdesign=["v"]) c12.set_attr(design=["T"]) c1.set_attr(design=["p"]) tu.set_attr(offdesign=["cone"]) -# %%[sec_9] +# %%[sec_10] my_plant.solve("design") my_plant.save("rankine_design") -# %%[sec_10] +# %%[sec_11] partload_efficiency = [] partload_m_range = np.linspace(20, 10, 11) @@ -174,4 +234,4 @@ plt.tight_layout() fig.savefig('rankine_partload.svg') plt.close() -# %%[sec_11] +# %%[sec_12]