flowstate 0.6.2__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flowstate-0.6.2 → flowstate-0.7.0}/.github/workflows/publish.yml +1 -1
- {flowstate-0.6.2 → flowstate-0.7.0}/.github/workflows/test.yml +1 -1
- {flowstate-0.6.2 → flowstate-0.7.0}/PKG-INFO +5 -2
- {flowstate-0.6.2 → flowstate-0.7.0}/README.md +1 -1
- {flowstate-0.6.2 → flowstate-0.7.0}/pyproject.toml +4 -1
- flowstate-0.7.0/src/flow_state/cli/__init__.py +15 -0
- flowstate-0.7.0/src/flow_state/cli/app.py +75 -0
- flowstate-0.7.0/src/flow_state/cli/callbacks.py +51 -0
- flowstate-0.7.0/src/flow_state/cli/cmd_examples.py +63 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/cli/cmd_init.py +9 -1
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/cli/cmd_recover.py +11 -0
- flowstate-0.6.2/src/flow_state/cli/cmd_solve.py → flowstate-0.7.0/src/flow_state/cli/cmd_run.py +22 -2
- flowstate-0.7.0/src/flow_state/cli/constants.py +11 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/cli/templates.py +6 -1
- flowstate-0.6.2/src/flow_state/examples/aedc_t9.toml → flowstate-0.7.0/src/flow_state/examples/aedc_t9/flow_config.toml +1 -1
- flowstate-0.6.2/src/flow_state/examples/bam6qt.toml → flowstate-0.7.0/src/flow_state/examples/bam6qt/flow_config.toml +1 -1
- flowstate-0.6.2/src/flow_state/examples/sandia.toml → flowstate-0.7.0/src/flow_state/examples/sandia/flow_config.toml +1 -1
- flowstate-0.6.2/src/flow_state/examples/stort.toml → flowstate-0.7.0/src/flow_state/examples/stort/flow_config.toml +1 -1
- flowstate-0.7.0/src/flow_state/io/examples.py +122 -0
- flowstate-0.7.0/src/flow_state/io/flow_config.py +244 -0
- flowstate-0.7.0/src/flow_state/io/read_config.py +73 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/PKG-INFO +5 -2
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/SOURCES.txt +7 -5
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/requires.txt +1 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/scm_file_list.json +7 -5
- flowstate-0.7.0/src/flowstate.egg-info/scm_version.json +8 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_cli.py +81 -8
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_io.py +89 -0
- flowstate-0.6.2/src/flow_state/cli/__init__.py +0 -8
- flowstate-0.6.2/src/flow_state/cli/app.py +0 -51
- flowstate-0.6.2/src/flow_state/cli/callbacks.py +0 -24
- flowstate-0.6.2/src/flow_state/cli/constants.py +0 -4
- flowstate-0.6.2/src/flow_state/io/examples.py +0 -95
- flowstate-0.6.2/src/flow_state/io/read_config.py +0 -75
- flowstate-0.6.2/src/flowstate.egg-info/scm_version.json +0 -8
- {flowstate-0.6.2 → flowstate-0.7.0}/.github/workflows/docs.yml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/.github/workflows/package.yml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/.gitignore +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/.vscode/extensions.json +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/.vscode/settings.json +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/CITATION.cff +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/LICENSE +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/apps/webapp/.streamlit/config.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/apps/webapp/app.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/apps/webapp/requirements.txt +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/architecture.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/atmosphere.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/core.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/solvers.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/api/transport.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/architecture.svg +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/atmosphere_dens_comparison.png +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/atmosphere_temp_comparison.png +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/cira86_latitude_grid.png +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/re1_hifire1.png +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/assets/re1_stort.png +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/cli-reference.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/configs/aedc_t9.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/configs/bam6qt.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/configs/hifire1.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/configs/stort_cira.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/examples.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/installation.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/javascripts/mathjax.js +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/nomenclature.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/atmosphere-comparison.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/atmosphere-models.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/definitions.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/gas-models.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/gas-properties.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/isentropic.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/theory/transport.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/basic-usage.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/cli.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/config-files.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/configuration.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/output.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/user-guide/workflow.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/vnv/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/vnv/validation/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/docs/vnv/verification/index.md +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/examples/bam6qt_conditions.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/examples/flight_conditions_cira86.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/examples/flight_conditions_ussa76.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/examples/flow_config_cira86.toml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/examples/mach8_re1_conditions.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/mkdocs.yml +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/atmosphere_density_plotter.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/generate_atmosphere_plots.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/generate_latitude_grid.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/stort_trajectory_reynolds_number_comparison.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/temp_graph_atmosphere_models.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/scripts/test_trajectory_1_calculation.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/setup.cfg +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/atmosphere/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/atmosphere/cira86.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/atmosphere/core.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/atmosphere/registry.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/atmosphere/ussa76.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/core.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/gas/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/gas/equilibrium.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/gas/park.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/gas/perfect.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/gas/registry.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/hdf5.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/legacy_dat.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/print_summary.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/read_data.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/io/write_data.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/isentropic.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/math_utils/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/math_utils/bisection.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/recover.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/solvers.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/core.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/keyes.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/power_law.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/registry.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/transport/sutherland.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/turbulence.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flow_state/units.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/dependency_links.txt +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/entry_points.txt +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/src/flowstate.egg-info/top_level.txt +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/stort_trajectory_reynolds_number_comparison.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/__init__.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_atmosphere.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_builders.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_equilibrium.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_gas.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_isentropic.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_park.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_recover.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_solvers.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_transport.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_turbulence.py +0 -0
- {flowstate-0.6.2 → flowstate-0.7.0}/tests/test_units.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowstate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Lightweight utility for computing flow states
|
|
5
5
|
Author-email: Christoph Hader <christoph.hader@gmail.com>
|
|
6
6
|
License-Expression: GPL-3.0-or-later
|
|
@@ -13,6 +13,8 @@ Classifier: Intended Audience :: Science/Research
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
18
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
17
19
|
Requires-Python: >=3.11
|
|
18
20
|
Description-Content-Type: text/markdown
|
|
@@ -20,6 +22,7 @@ License-File: LICENSE
|
|
|
20
22
|
Requires-Dist: h5py>=3.10.0
|
|
21
23
|
Requires-Dist: typer>=0.9.0
|
|
22
24
|
Requires-Dist: tomli-w>=1.0.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0
|
|
23
26
|
Provides-Extra: dev
|
|
24
27
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
28
|
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
@@ -105,7 +108,7 @@ contributors can focus on the physics rather than inventing formatting rules.
|
|
|
105
108
|
|---|---|---|
|
|
106
109
|
| [PEP 8](https://peps.python.org/pep-0008/) | Code formatting, naming, whitespace | Python standard style guide |
|
|
107
110
|
| [PEP 257](https://peps.python.org/pep-0257/) | Docstring structure (triple-quoted, imperative mood) | Python standard docstring conventions |
|
|
108
|
-
| [
|
|
111
|
+
| [Google style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) | Docstring sections (`Args`, `Returns`, `Raises`) | Google Python style guide |
|
|
109
112
|
| [Ruff](https://docs.astral.sh/ruff/) | Automated linting and formatting | Enforces PEP 8 compliance automatically |
|
|
110
113
|
| [typing / TYPE_CHECKING](https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING) | Type hints for IDE support and static analysis | Python standard library |
|
|
111
114
|
|
|
@@ -75,7 +75,7 @@ contributors can focus on the physics rather than inventing formatting rules.
|
|
|
75
75
|
|---|---|---|
|
|
76
76
|
| [PEP 8](https://peps.python.org/pep-0008/) | Code formatting, naming, whitespace | Python standard style guide |
|
|
77
77
|
| [PEP 257](https://peps.python.org/pep-0257/) | Docstring structure (triple-quoted, imperative mood) | Python standard docstring conventions |
|
|
78
|
-
| [
|
|
78
|
+
| [Google style](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) | Docstring sections (`Args`, `Returns`, `Raises`) | Google Python style guide |
|
|
79
79
|
| [Ruff](https://docs.astral.sh/ruff/) | Automated linting and formatting | Enforces PEP 8 compliance automatically |
|
|
80
80
|
| [typing / TYPE_CHECKING](https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING) | Type hints for IDE support and static analysis | Python standard library |
|
|
81
81
|
|
|
@@ -20,6 +20,8 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
21
|
"Programming Language :: Python :: 3.11",
|
|
22
22
|
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
23
25
|
"Topic :: Scientific/Engineering :: Physics",
|
|
24
26
|
]
|
|
25
27
|
keywords = ["compressible-flow", "aerodynamics", "gas-dynamics", "cfd"]
|
|
@@ -28,6 +30,7 @@ dependencies = [
|
|
|
28
30
|
"h5py>=3.10.0",
|
|
29
31
|
"typer>=0.9.0",
|
|
30
32
|
"tomli-w>=1.0.0",
|
|
33
|
+
"pydantic>=2.0",
|
|
31
34
|
]
|
|
32
35
|
|
|
33
36
|
[project.optional-dependencies]
|
|
@@ -51,7 +54,7 @@ Documentation = "https://uahypersonics.github.io/flow-state"
|
|
|
51
54
|
where = ["src"]
|
|
52
55
|
|
|
53
56
|
[tool.setuptools.package-data]
|
|
54
|
-
"flow_state" = ["examples
|
|
57
|
+
"flow_state" = ["examples/*/*"]
|
|
55
58
|
|
|
56
59
|
[tool.setuptools_scm]
|
|
57
60
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Command-line interface for flow-state."""
|
|
2
|
+
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
from flow_state.cli.app import app
|
|
7
|
+
|
|
8
|
+
# --------------------------------------------------
|
|
9
|
+
# cli public api
|
|
10
|
+
# --------------------------------------------------
|
|
11
|
+
|
|
12
|
+
# Preserve the existing ``flow_state.cli:cli`` console entry point.
|
|
13
|
+
cli = app
|
|
14
|
+
|
|
15
|
+
__all__ = ["app", "cli"]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Typer application for the flow-state command-line interface."""
|
|
2
|
+
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from flow_state.cli.callbacks import verbose_callback, version_callback
|
|
13
|
+
from flow_state.cli.cmd_examples import cmd_examples
|
|
14
|
+
from flow_state.cli.cmd_init import cmd_init
|
|
15
|
+
from flow_state.cli.cmd_recover import cmd_recover
|
|
16
|
+
from flow_state.cli.cmd_run import cmd_run
|
|
17
|
+
|
|
18
|
+
# --------------------------------------------------
|
|
19
|
+
# app
|
|
20
|
+
# --------------------------------------------------
|
|
21
|
+
app = typer.Typer(
|
|
22
|
+
name="flow-state",
|
|
23
|
+
help="Compute flow states.",
|
|
24
|
+
add_completion=False,
|
|
25
|
+
no_args_is_help=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --------------------------------------------------
|
|
30
|
+
# callback for --version and --verbose options
|
|
31
|
+
# version_callback and verbose_callback are defined in callbacks.py
|
|
32
|
+
# --------------------------------------------------
|
|
33
|
+
@app.callback()
|
|
34
|
+
def main(
|
|
35
|
+
version: Annotated[
|
|
36
|
+
bool | None,
|
|
37
|
+
typer.Option(
|
|
38
|
+
"--version",
|
|
39
|
+
"-V",
|
|
40
|
+
help="Show version and exit.",
|
|
41
|
+
callback=version_callback,
|
|
42
|
+
is_eager=True,
|
|
43
|
+
),
|
|
44
|
+
] = None,
|
|
45
|
+
verbose: Annotated[
|
|
46
|
+
bool,
|
|
47
|
+
typer.Option(
|
|
48
|
+
"--verbose",
|
|
49
|
+
"-v",
|
|
50
|
+
help="Enable verbose (debug) output.",
|
|
51
|
+
callback=verbose_callback,
|
|
52
|
+
),
|
|
53
|
+
] = False,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Compute flow states from freestream, stagnation, or atmospheric inputs."""
|
|
56
|
+
|
|
57
|
+
# both options act through their callbacks; nothing left to do here
|
|
58
|
+
del version, verbose
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# --------------------------------------------------
|
|
62
|
+
# register subcommands
|
|
63
|
+
# notes:
|
|
64
|
+
# - the order at which they are registered is the order in which they display
|
|
65
|
+
# --------------------------------------------------
|
|
66
|
+
app.command(name="init")(cmd_init)
|
|
67
|
+
app.command(name="run")(cmd_run)
|
|
68
|
+
app.command(name="recover")(cmd_recover)
|
|
69
|
+
app.command(name="examples")(cmd_examples)
|
|
70
|
+
|
|
71
|
+
# --------------------------------------------------
|
|
72
|
+
# main entry point
|
|
73
|
+
# --------------------------------------------------
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
app()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Shared callbacks for the flow-state command-line interface."""
|
|
2
|
+
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from flow_state import __version__
|
|
13
|
+
|
|
14
|
+
# --------------------------------------------------
|
|
15
|
+
# module constants
|
|
16
|
+
# --------------------------------------------------
|
|
17
|
+
|
|
18
|
+
# loggers that --verbose switches to debug: this tool and the uahypersonics
|
|
19
|
+
# packages it calls
|
|
20
|
+
DEBUG_LOGGERS = ("flow_state",)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# --------------------------------------------------
|
|
24
|
+
# verbose callback
|
|
25
|
+
# --------------------------------------------------
|
|
26
|
+
def verbose_callback(value: bool) -> None:
|
|
27
|
+
"""Configure console logging; --verbose adds debug output from our own packages.
|
|
28
|
+
|
|
29
|
+
Third-party libraries stay at the default level, so --verbose shows our
|
|
30
|
+
debug messages without theirs.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# default console logging for every logger
|
|
34
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
|
|
35
|
+
|
|
36
|
+
# debug output from this tool and the uahypersonics packages it calls
|
|
37
|
+
if value:
|
|
38
|
+
for logger_name in DEBUG_LOGGERS:
|
|
39
|
+
logging.getLogger(logger_name).setLevel(logging.DEBUG)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# --------------------------------------------------
|
|
43
|
+
# version callback
|
|
44
|
+
# --------------------------------------------------
|
|
45
|
+
def version_callback(value: bool) -> None:
|
|
46
|
+
"""Print the installed package version and exit."""
|
|
47
|
+
|
|
48
|
+
# print the version and stop before any command runs
|
|
49
|
+
if value:
|
|
50
|
+
typer.echo(f"flow-state version {__version__}")
|
|
51
|
+
raise typer.Exit()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""List bundled example cases, or copy one into the current folder."""
|
|
2
|
+
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Annotated
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
|
|
13
|
+
from flow_state.io.examples import copy_example, list_examples
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# --------------------------------------------------
|
|
17
|
+
# subcommand: examples
|
|
18
|
+
# --------------------------------------------------
|
|
19
|
+
def cmd_examples(
|
|
20
|
+
name: Annotated[
|
|
21
|
+
str | None,
|
|
22
|
+
typer.Argument(help="Example to copy into the current folder. Omit to list the examples."),
|
|
23
|
+
] = None,
|
|
24
|
+
force: Annotated[
|
|
25
|
+
bool,
|
|
26
|
+
typer.Option("--force", "-f", help="Overwrite files of the same name in this folder."),
|
|
27
|
+
] = False,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""List the bundled examples, or copy one into the current folder to run."""
|
|
30
|
+
|
|
31
|
+
# list: name and description of every example
|
|
32
|
+
examples = list_examples()
|
|
33
|
+
if name is None:
|
|
34
|
+
width = max(len(example_name) for example_name in [*examples, "<name>"])
|
|
35
|
+
typer.echo("")
|
|
36
|
+
typer.echo(f" {'<name>':<{width}} description")
|
|
37
|
+
typer.echo(f" {'-'*width} {'-'*11}")
|
|
38
|
+
for example_name, description in examples.items():
|
|
39
|
+
typer.echo(f" {example_name:<{width}} {description}")
|
|
40
|
+
typer.echo("")
|
|
41
|
+
typer.echo("command sequence:")
|
|
42
|
+
typer.echo(" - check out the example")
|
|
43
|
+
typer.echo(" flow-state examples <name>")
|
|
44
|
+
typer.echo(" - run the example")
|
|
45
|
+
typer.echo(" flow-state run")
|
|
46
|
+
typer.echo("")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
# copy the example into the current folder
|
|
50
|
+
try:
|
|
51
|
+
written = copy_example(name, Path("."), force=force)
|
|
52
|
+
except KeyError:
|
|
53
|
+
known = ", ".join(examples)
|
|
54
|
+
typer.echo(f"error: unknown example {name!r}; available: {known}", err=True)
|
|
55
|
+
raise typer.Exit(1) from None
|
|
56
|
+
except FileExistsError as error:
|
|
57
|
+
typer.echo(f"error: {error}", err=True)
|
|
58
|
+
raise typer.Exit(1) from None
|
|
59
|
+
|
|
60
|
+
# report the files and the next step
|
|
61
|
+
for path in written:
|
|
62
|
+
typer.echo(f"wrote {path}")
|
|
63
|
+
typer.echo("then: flow-state run")
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"""Generate a starter flow-state configuration."""
|
|
2
2
|
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
3
6
|
from __future__ import annotations
|
|
4
7
|
|
|
5
8
|
from pathlib import Path
|
|
@@ -11,6 +14,9 @@ from flow_state.cli.constants import DEFAULT_CONFIG
|
|
|
11
14
|
from flow_state.cli.templates import CONFIG_TEMPLATE
|
|
12
15
|
|
|
13
16
|
|
|
17
|
+
# --------------------------------------------------
|
|
18
|
+
# subcommand: init
|
|
19
|
+
# --------------------------------------------------
|
|
14
20
|
def cmd_init(
|
|
15
21
|
output: Annotated[
|
|
16
22
|
Path,
|
|
@@ -23,10 +29,12 @@ def cmd_init(
|
|
|
23
29
|
) -> None:
|
|
24
30
|
"""Generate a documented template configuration file."""
|
|
25
31
|
|
|
32
|
+
# check: don't overwrite an existing configuration unless asked to
|
|
26
33
|
if output.exists() and not force:
|
|
27
34
|
typer.echo(f"Error: {output} already exists. Use --force to overwrite", err=True)
|
|
28
35
|
raise typer.Exit(1)
|
|
29
36
|
|
|
37
|
+
# write the template and tell the user the next step
|
|
30
38
|
output.write_text(CONFIG_TEMPLATE)
|
|
31
39
|
typer.echo(f"Created {output}")
|
|
32
|
-
typer.echo("Edit the file, then run: flow-state
|
|
40
|
+
typer.echo("Edit the file, then run: flow-state run")
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"""Recover and write flow conditions from HDF5 metadata."""
|
|
2
2
|
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
3
6
|
from __future__ import annotations
|
|
4
7
|
|
|
5
8
|
from pathlib import Path
|
|
@@ -12,6 +15,9 @@ from flow_state.io import write_json
|
|
|
12
15
|
from flow_state.recover import recover_from_hdf5
|
|
13
16
|
|
|
14
17
|
|
|
18
|
+
# --------------------------------------------------
|
|
19
|
+
# subcommand: recover
|
|
20
|
+
# --------------------------------------------------
|
|
15
21
|
def cmd_recover(
|
|
16
22
|
input_file: Annotated[
|
|
17
23
|
Path,
|
|
@@ -31,14 +37,19 @@ def cmd_recover(
|
|
|
31
37
|
] = False,
|
|
32
38
|
) -> None:
|
|
33
39
|
"""Recover flow_conditions.json from HDF5 root attributes."""
|
|
40
|
+
|
|
41
|
+
# read: rebuild the flow state from the HDF5 root attributes
|
|
34
42
|
try:
|
|
35
43
|
state = recover_from_hdf5(input_file)
|
|
36
44
|
except (FileNotFoundError, OSError, TypeError, ValueError) as error:
|
|
37
45
|
typer.echo(f"Error recovering flow state: {error}", err=True)
|
|
38
46
|
raise typer.Exit(1) from error
|
|
39
47
|
|
|
48
|
+
# write the flow-state JSON
|
|
40
49
|
write_json(state, output)
|
|
41
50
|
typer.echo(f"Wrote {output}")
|
|
51
|
+
|
|
52
|
+
# print the summary unless --quiet
|
|
42
53
|
if not quiet:
|
|
43
54
|
typer.echo("")
|
|
44
55
|
typer.echo(str(state))
|
flowstate-0.6.2/src/flow_state/cli/cmd_solve.py → flowstate-0.7.0/src/flow_state/cli/cmd_run.py
RENAMED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"""Compute and write a flow state from CLI or TOML inputs."""
|
|
2
2
|
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# load necessary modules
|
|
5
|
+
# --------------------------------------------------
|
|
3
6
|
from __future__ import annotations
|
|
4
7
|
|
|
5
8
|
import logging
|
|
@@ -12,10 +15,16 @@ from flow_state.cli.constants import DEFAULT_CONFIG, DEFAULT_OUTPUT
|
|
|
12
15
|
from flow_state.io import read_config, write_flow_conditions_dat, write_json
|
|
13
16
|
from flow_state.solvers import solve
|
|
14
17
|
|
|
18
|
+
# --------------------------------------------------
|
|
19
|
+
# set up logger
|
|
20
|
+
# --------------------------------------------------
|
|
15
21
|
logger = logging.getLogger(__name__)
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
# --------------------------------------------------
|
|
25
|
+
# subcommand: run
|
|
26
|
+
# --------------------------------------------------
|
|
27
|
+
def cmd_run(
|
|
19
28
|
mach: Annotated[float | None, typer.Option("--mach", "-m", help="Mach number")] = None,
|
|
20
29
|
pres_stag: Annotated[
|
|
21
30
|
float | None,
|
|
@@ -93,8 +102,10 @@ def cmd_solve(
|
|
|
93
102
|
) -> None:
|
|
94
103
|
"""Compute a flow state from direct options or a configuration file."""
|
|
95
104
|
|
|
105
|
+
# check: direct options on the command line take precedence over a config file
|
|
96
106
|
has_direct_options = any([mach, pres_stag, temp_stag, altitude, pres, temp, re1])
|
|
97
107
|
|
|
108
|
+
# build the solver inputs from the direct options given (units as (value, unit) tuples)
|
|
98
109
|
if has_direct_options:
|
|
99
110
|
solve_kwargs: dict[str, object] = {}
|
|
100
111
|
if mach is not None:
|
|
@@ -118,7 +129,10 @@ def cmd_solve(
|
|
|
118
129
|
if lref is not None:
|
|
119
130
|
solve_kwargs["lref"] = lref
|
|
120
131
|
else:
|
|
132
|
+
# read the solver inputs from the config file (default: flow_config.toml)
|
|
121
133
|
config_path = config if config else Path(DEFAULT_CONFIG)
|
|
134
|
+
|
|
135
|
+
# check: the config exists, otherwise point to `flow-state init`
|
|
122
136
|
if not config_path.exists():
|
|
123
137
|
typer.echo(f"Error: {config_path} not found.", err=True)
|
|
124
138
|
typer.echo(
|
|
@@ -127,32 +141,38 @@ def cmd_solve(
|
|
|
127
141
|
)
|
|
128
142
|
raise typer.Exit(1)
|
|
129
143
|
|
|
144
|
+
# read and parse the config
|
|
130
145
|
try:
|
|
131
146
|
solve_kwargs = read_config(config_path)
|
|
132
|
-
except
|
|
147
|
+
except (OSError, ValueError) as error:
|
|
133
148
|
typer.echo(f"Error parsing {config_path}: {error}", err=True)
|
|
134
149
|
raise typer.Exit(1) from error
|
|
135
150
|
|
|
151
|
+
# compute the flow state
|
|
136
152
|
try:
|
|
137
153
|
state = solve(**solve_kwargs)
|
|
138
154
|
except (ValueError, TypeError) as error:
|
|
139
155
|
typer.echo(f"Error computing flow state: {error}", err=True)
|
|
140
156
|
raise typer.Exit(1) from error
|
|
141
157
|
|
|
158
|
+
# debug output for devs
|
|
142
159
|
if state.provenance:
|
|
143
160
|
for key, value in state.provenance.items():
|
|
144
161
|
logger.debug("%s: %s", key, value)
|
|
145
162
|
logger.debug("gas_model: %s", state.gas_model)
|
|
146
163
|
logger.debug("transport_model: %s", state.transport_model)
|
|
147
164
|
|
|
165
|
+
# write the flow-state JSON
|
|
148
166
|
write_json(state, output)
|
|
149
167
|
typer.echo(f"Wrote {output}")
|
|
150
168
|
|
|
169
|
+
# write the legacy flow_conditions.dat when asked for
|
|
151
170
|
if dat:
|
|
152
171
|
dat_path = Path("flow_conditions.dat")
|
|
153
172
|
write_flow_conditions_dat(state, dat_path)
|
|
154
173
|
typer.echo(f"Wrote {dat_path}")
|
|
155
174
|
|
|
175
|
+
# print the summary unless --quiet
|
|
156
176
|
if not quiet:
|
|
157
177
|
typer.echo("")
|
|
158
178
|
typer.echo(str(state))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Shared constants for flow-state CLI commands."""
|
|
2
|
+
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# default file names
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
|
|
7
|
+
# configuration file written by `flow-state init` and read by `flow-state run`
|
|
8
|
+
DEFAULT_CONFIG = "flow_config.toml"
|
|
9
|
+
|
|
10
|
+
# flow-state JSON written by `flow-state run` and `flow-state recover`
|
|
11
|
+
DEFAULT_OUTPUT = "flow_conditions.json"
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"""Configuration templates emitted by flow-state CLI commands."""
|
|
2
2
|
|
|
3
|
+
# --------------------------------------------------
|
|
4
|
+
# configuration template
|
|
5
|
+
# --------------------------------------------------
|
|
6
|
+
|
|
7
|
+
# starter flow_config.toml written by `flow-state init`
|
|
3
8
|
CONFIG_TEMPLATE = """\
|
|
4
9
|
# flow_state configuration file
|
|
5
10
|
# =============================
|
|
6
|
-
# Edit the values below and run: flow-state
|
|
11
|
+
# Edit the values below and run: flow-state run
|
|
7
12
|
|
|
8
13
|
# Supported units:
|
|
9
14
|
# pressure : Pa, psi, atm, bar, torr
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# --------------------------------------------------
|
|
2
2
|
# AEDC Tunnel 9 (Arnold Engineering Development Complex)
|
|
3
3
|
#
|
|
4
|
-
# Run: flow-state
|
|
4
|
+
# Run: flow-state run --config flow_config.toml
|
|
5
5
|
# --------------------------------------------------
|
|
6
6
|
|
|
7
7
|
# --------------------------------------------------
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# --------------------------------------------------
|
|
2
2
|
# BAM6QT — Boeing/AFOSR Mach 6 Quiet Tunnel (Purdue University)
|
|
3
3
|
#
|
|
4
|
-
# Run: flow-state
|
|
4
|
+
# Run: flow-state run --config flow_config.toml
|
|
5
5
|
# --------------------------------------------------
|
|
6
6
|
|
|
7
7
|
# --------------------------------------------------
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# --------------------------------------------------
|
|
2
2
|
# Sandia Hypersonic Wind Tunnel
|
|
3
3
|
#
|
|
4
|
-
# Run: flow-state
|
|
4
|
+
# Run: flow-state run --config flow_config.toml
|
|
5
5
|
# --------------------------------------------------
|
|
6
6
|
|
|
7
7
|
# --------------------------------------------------
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# --------------------------------------------------
|
|
2
2
|
# STORT (Short Range Transition)
|
|
3
3
|
#
|
|
4
|
-
# Run: flow-state
|
|
4
|
+
# Run: flow-state run --config flow_config.toml
|
|
5
5
|
# --------------------------------------------------
|
|
6
6
|
|
|
7
7
|
# --------------------------------------------------
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Bundled example cases for the flow-state CLI.
|
|
2
|
+
|
|
3
|
+
Each example is a folder under ``flow_state/examples/`` holding the files of
|
|
4
|
+
one case (here a ``flow_config.toml``). The folder name is the example's name
|
|
5
|
+
and the first text line of its config is the description, so the folders are
|
|
6
|
+
the registry: adding an example means adding a folder.
|
|
7
|
+
|
|
8
|
+
Adding a new example
|
|
9
|
+
--------------------
|
|
10
|
+
1. Add ``src/flow_state/examples/<name>/flow_config.toml``.
|
|
11
|
+
2. Start the file with a comment that names the case (shown in the listing).
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# --------------------------------------------------
|
|
15
|
+
# load necessary modules
|
|
16
|
+
# --------------------------------------------------
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from importlib.resources import files
|
|
20
|
+
from importlib.resources.abc import Traversable
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
# --------------------------------------------------
|
|
24
|
+
# module constants
|
|
25
|
+
# --------------------------------------------------
|
|
26
|
+
|
|
27
|
+
# config file every example holds (run's default config name)
|
|
28
|
+
EXAMPLE_CONFIG = "flow_config.toml"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# --------------------------------------------------
|
|
32
|
+
# helpers
|
|
33
|
+
# --------------------------------------------------
|
|
34
|
+
def _examples_root() -> Traversable:
|
|
35
|
+
"""Folder of the bundled examples inside the installed package."""
|
|
36
|
+
return files("flow_state") / "examples"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _description(config_text: str) -> str:
|
|
40
|
+
"""First text line of a config's header comment (dividers skipped)."""
|
|
41
|
+
|
|
42
|
+
# walk the leading comment block
|
|
43
|
+
for line in config_text.splitlines():
|
|
44
|
+
stripped = line.strip()
|
|
45
|
+
|
|
46
|
+
# the header ends at the first line that isn't a comment
|
|
47
|
+
if stripped and not stripped.startswith("#"):
|
|
48
|
+
break
|
|
49
|
+
|
|
50
|
+
# skip blank comment lines and dividers like "# -----"
|
|
51
|
+
text = stripped.lstrip("#").strip()
|
|
52
|
+
if text and set(text) - set("-=#"):
|
|
53
|
+
return text
|
|
54
|
+
|
|
55
|
+
return ""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# --------------------------------------------------
|
|
59
|
+
# public API
|
|
60
|
+
# --------------------------------------------------
|
|
61
|
+
def list_examples() -> dict[str, str]:
|
|
62
|
+
"""Return a name -> description mapping of the bundled examples.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dict of {name: description}, sorted by name.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# every folder with a config is an example
|
|
69
|
+
examples: dict[str, str] = {}
|
|
70
|
+
for folder in sorted(_examples_root().iterdir(), key=lambda item: item.name):
|
|
71
|
+
config = folder / EXAMPLE_CONFIG
|
|
72
|
+
if folder.is_dir() and config.is_file():
|
|
73
|
+
examples[folder.name] = _description(config.read_text(encoding="utf-8"))
|
|
74
|
+
|
|
75
|
+
return examples
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def copy_example(name: str, destination: str | Path, force: bool = False) -> list[Path]:
|
|
79
|
+
"""Copy a bundled example's files into a folder.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
name: Example name (see list_examples).
|
|
83
|
+
destination: Folder to copy the files into (created if missing).
|
|
84
|
+
force: Overwrite files of the same name in the folder.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The paths of the written files.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
KeyError: If there is no example of that name.
|
|
91
|
+
FileExistsError: If a file of the example already exists there and force
|
|
92
|
+
is False (nothing is written then).
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
# check: a known example
|
|
96
|
+
if name not in list_examples():
|
|
97
|
+
raise KeyError(name)
|
|
98
|
+
|
|
99
|
+
# the example's files
|
|
100
|
+
source = _examples_root() / name
|
|
101
|
+
items = sorted(
|
|
102
|
+
(entry for entry in source.iterdir() if entry.is_file()),
|
|
103
|
+
key=lambda entry: entry.name,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# check: don't overwrite the user's files unless asked to (before writing any)
|
|
107
|
+
destination = Path(destination)
|
|
108
|
+
existing = [item.name for item in items if (destination / item.name).exists()]
|
|
109
|
+
if existing and not force:
|
|
110
|
+
raise FileExistsError(
|
|
111
|
+
f"would overwrite {', '.join(existing)} (use --force to overwrite)"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# copy every file of the example folder
|
|
115
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
116
|
+
written: list[Path] = []
|
|
117
|
+
for item in items:
|
|
118
|
+
target = destination / item.name
|
|
119
|
+
target.write_bytes(item.read_bytes())
|
|
120
|
+
written.append(target)
|
|
121
|
+
|
|
122
|
+
return written
|